mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-10-06 13:59:41 +00:00
fixed two bugs, added test files, did cleanup
bug 1: in some cases "--format" could not override "!to" bug 2: "cannot open output file" resulted in "success" exit code git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@340 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
496fde6f1a
commit
7a4237eb3c
84
src/acme.c
84
src/acme.c
@ -221,20 +221,88 @@ int ACME_finalize(int exit_code)
|
||||
// save output file
|
||||
static void save_output_file(void)
|
||||
{
|
||||
FILE *fd;
|
||||
const char *body;
|
||||
intval_t amount,
|
||||
loadaddr;
|
||||
unsigned char header[4];
|
||||
int headersize = 0;
|
||||
FILE *fd;
|
||||
|
||||
// if no output file chosen, tell user and do nothing
|
||||
if (config.output_filename == NULL) {
|
||||
fputs("No output file specified (use the \"-o\" option or the \"!to\" pseudo opcode).\n", stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
// get memory pointer, block size and load address
|
||||
output_get_result(&body, &amount, &loadaddr);
|
||||
|
||||
// generate header according to file format
|
||||
switch (config.outfile_format) {
|
||||
case OUTFILE_FORMAT_UNSPECIFIED:
|
||||
case OUTFILE_FORMAT_PLAIN:
|
||||
headersize = 0; // no header
|
||||
break;
|
||||
case OUTFILE_FORMAT_CBM:
|
||||
if (loadaddr > 0xffff) {
|
||||
fprintf(stderr, "Error: Load address 0x%04lx too large for cbm file format.\n", loadaddr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
header[0] = loadaddr & 255;
|
||||
header[1] = loadaddr >> 8;
|
||||
headersize = 2; // 16-bit load address, little-endian
|
||||
break;
|
||||
case OUTFILE_FORMAT_APPLE:
|
||||
if (loadaddr > 0xffff) {
|
||||
fprintf(stderr, "Error: Load address 0x%04lx too large for apple file format.\n", loadaddr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (amount > 0xffff) {
|
||||
fprintf(stderr, "Error: File size 0x%04lx too large for apple file format.\n", loadaddr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
header[0] = loadaddr & 255;
|
||||
header[1] = loadaddr >> 8;
|
||||
header[2] = amount & 255;
|
||||
header[3] = amount >> 8;
|
||||
headersize = 4; // 16-bit load address and 16-bit length, little-endian
|
||||
break;
|
||||
default:
|
||||
BUG("IllegalOutformat1", config.outfile_format);
|
||||
}
|
||||
|
||||
// open file
|
||||
fd = fopen(config.output_filename, FILE_WRITEBINARY); // FIXME - what if filename is given via !to in sub-dir? fix path!
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr, "Error: Cannot open output file \"%s\".\n", config.output_filename);
|
||||
return;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
output_save_file(fd);
|
||||
|
||||
if (config.process_verbosity) {
|
||||
printf("Saving %ld (0x%04lx) bytes (0x%04lx - 0x%04lx exclusive).\n",
|
||||
amount, amount, loadaddr, loadaddr + amount);
|
||||
}
|
||||
|
||||
// write header and body
|
||||
fwrite(header, headersize, 1, fd);
|
||||
fwrite(body, amount, 1, fd);
|
||||
fclose(fd);
|
||||
|
||||
// set file type
|
||||
switch (config.outfile_format) {
|
||||
case OUTFILE_FORMAT_UNSPECIFIED:
|
||||
case OUTFILE_FORMAT_PLAIN:
|
||||
PLATFORM_SETFILETYPE_PLAIN(config.output_filename);
|
||||
break;
|
||||
case OUTFILE_FORMAT_APPLE:
|
||||
PLATFORM_SETFILETYPE_APPLE(config.output_filename);
|
||||
break;
|
||||
case OUTFILE_FORMAT_CBM:
|
||||
PLATFORM_SETFILETYPE_CBM(config.output_filename);
|
||||
break;
|
||||
default:
|
||||
BUG("IllegalOutformat2", config.outfile_format);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -247,7 +315,7 @@ static void perform_pass(void)
|
||||
++pass.number;
|
||||
// call modules' "pass init" functions
|
||||
output_passinit(); // disable output, PC undefined
|
||||
cputype_passinit(config.default_cpu); // set default cpu type
|
||||
cputype_passinit(config.initial_cpu_type);
|
||||
// if start address was given on command line, use it:
|
||||
if (config.initial_pc != NO_VALUE_GIVEN)
|
||||
vcpu_set_pc(config.initial_pc, 0); // 0 -> no segment flags
|
||||
@ -342,14 +410,15 @@ static void set_output_format(const char format_name[])
|
||||
// caution, name may be NULL!
|
||||
if (format_name) {
|
||||
keyword_to_dynabuf(format_name);
|
||||
if (!outputfile_set_format())
|
||||
config.outfile_format = outputformat_find();
|
||||
if (config.outfile_format != OUTFILE_FORMAT_UNSPECIFIED)
|
||||
return; // ok
|
||||
|
||||
fputs("Error: Unknown output format.\n", stderr);
|
||||
} else {
|
||||
fputs("Error: No output format specified.\n", stderr);
|
||||
}
|
||||
fprintf(stderr, "Supported formats are:\n\n\t%s\n\n", outputfile_formats);
|
||||
fprintf(stderr, "Supported formats are:\n\n\t%s\n\n", outputformat_names);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -364,7 +433,7 @@ static void set_starting_cpu(const char cpu_name[])
|
||||
keyword_to_dynabuf(cpu_name);
|
||||
new_cpu_type = cputype_find();
|
||||
if (new_cpu_type) {
|
||||
config.default_cpu = new_cpu_type;
|
||||
config.initial_cpu_type = new_cpu_type;
|
||||
return; // ok
|
||||
}
|
||||
fputs("Error: Unknown CPU type.\n", stderr);
|
||||
@ -676,6 +745,7 @@ int main(int argc, const char *argv[])
|
||||
|
||||
// init output buffer
|
||||
output_createbuffer();
|
||||
// do the actual work
|
||||
if (do_actual_work())
|
||||
save_output_file();
|
||||
return ACME_finalize(EXIT_SUCCESS); // dump labels, if wanted
|
||||
|
24
src/cpu.c
24
src/cpu.c
@ -14,7 +14,8 @@
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
// constants
|
||||
// predefined stuff
|
||||
|
||||
static struct cpu_type cpu_type_6502 = {
|
||||
keyword_is_6502_mnemo,
|
||||
CPUFLAG_WARN_ABOUT_FF_PTR | CPUFLAG_INDIRECTJMPBUGGY, // warn about "XYZ ($ff),y" and "jmp ($XYff)"
|
||||
@ -67,15 +68,8 @@ static struct cpu_type cpu_type_m65 = {
|
||||
234 // !align fills with "NOP"
|
||||
};
|
||||
|
||||
|
||||
// variables
|
||||
|
||||
boolean cpu_a_is_long = FALSE;
|
||||
boolean cpu_xy_are_long = FALSE;
|
||||
// predefined stuff
|
||||
static struct ronode cputype_tree[] = {
|
||||
PREDEF_START,
|
||||
#define KNOWN_TYPES "'6502', 'nmos6502', '6510', '65c02', 'r65c02', 'w65c02', '65816', '65ce02', '4502', 'm65', 'c64dtv2'" // shown in CLI error message for unknown types
|
||||
// PREDEFNODE("z80", &cpu_type_Z80),
|
||||
PREDEFNODE("6502", &cpu_type_6502),
|
||||
PREDEFNODE("nmos6502", &cpu_type_nmos6502),
|
||||
@ -90,7 +84,15 @@ static struct ronode cputype_tree[] = {
|
||||
PREDEF_END("c64dtv2", &cpu_type_c64dtv2),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
const char cputype_names[] = KNOWN_TYPES; // string to show if cputype_find() returns NULL
|
||||
// string shown in CLI error message if cputype_find() returns NULL:
|
||||
const char cputype_names[] = "'6502', 'nmos6502', '6510', '65c02', 'r65c02', 'w65c02', '65816', '65ce02', '4502', 'm65', 'c64dtv2'";
|
||||
|
||||
|
||||
// variables
|
||||
const struct cpu_type *cpu_current_type = NULL;
|
||||
boolean cpu_a_is_long = FALSE;
|
||||
boolean cpu_xy_are_long = FALSE;
|
||||
|
||||
|
||||
// lookup cpu type held in DynaBuf and return its struct pointer (or NULL on failure)
|
||||
const struct cpu_type *cputype_find(void)
|
||||
@ -111,7 +113,7 @@ const struct cpu_type *cputype_find(void)
|
||||
// initial change, but because of reverting back to old cpu type after "{}" block!
|
||||
void vcpu_check_and_set_reg_length(boolean *var, boolean make_long)
|
||||
{
|
||||
if (((CPU_state.type->flags & CPUFLAG_SUPPORTSLONGREGS) == 0) && make_long)
|
||||
if (((cpu_current_type->flags & CPUFLAG_SUPPORTSLONGREGS) == 0) && make_long)
|
||||
Throw_error("Chosen CPU does not support long registers.");
|
||||
else
|
||||
*var = make_long;
|
||||
@ -122,7 +124,7 @@ void vcpu_check_and_set_reg_length(boolean *var, boolean make_long)
|
||||
void cputype_passinit(const struct cpu_type *cpu_type)
|
||||
{
|
||||
// handle cpu type (default is 6502)
|
||||
CPU_state.type = cpu_type ? cpu_type : &cpu_type_6502;
|
||||
cpu_current_type = cpu_type ? cpu_type : &cpu_type_6502;
|
||||
cpu_a_is_long = FALSE; // short accu
|
||||
cpu_xy_are_long = FALSE; // short index regs
|
||||
}
|
||||
|
23
src/cpu.h
23
src/cpu.h
@ -1,5 +1,5 @@
|
||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||
// Copyright (C) 1998-2020 Marco Baye
|
||||
// Copyright (C) 1998-2024 Marco Baye
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// CPU type stuff
|
||||
@ -10,7 +10,8 @@
|
||||
#include "config.h"
|
||||
|
||||
|
||||
// CPU type structure definition
|
||||
// types
|
||||
|
||||
struct cpu_type {
|
||||
// This function is not allowed to change GlobalDynaBuf
|
||||
// because that's where the mnemonic is stored!
|
||||
@ -25,18 +26,30 @@ struct cpu_type {
|
||||
#define CPUFLAG_DECIMALSUBTRACTBUGGY (1u << 4) // warn if "sed" is assembled
|
||||
#define CPUFLAG_WARN_ABOUT_FF_PTR (1u << 5) // warn if MNEMO($ff) is assembled
|
||||
|
||||
|
||||
// constants
|
||||
|
||||
extern const char cputype_names[]; // string to show if cputype_find() returns NULL
|
||||
|
||||
|
||||
// variables
|
||||
extern boolean cpu_a_is_long;
|
||||
extern boolean cpu_xy_are_long;
|
||||
|
||||
extern const struct cpu_type *cpu_current_type;
|
||||
extern boolean cpu_a_is_long;
|
||||
extern boolean cpu_xy_are_long;
|
||||
|
||||
|
||||
// prototypes
|
||||
|
||||
// if cpu type and value match, set register length variable to value.
|
||||
// if cpu type and value don't match, complain instead.
|
||||
extern void vcpu_check_and_set_reg_length(boolean *var, boolean make_long);
|
||||
|
||||
// set default value for pass
|
||||
extern void cputype_passinit(const struct cpu_type *cpu_type);
|
||||
|
||||
// lookup cpu type held in DynaBuf and return its struct pointer (or NULL on failure)
|
||||
extern const struct cpu_type *cputype_find(void);
|
||||
extern const char cputype_names[]; // string to show if cputype_find() returns NULL
|
||||
|
||||
|
||||
#endif
|
||||
|
25
src/global.c
25
src/global.c
@ -123,10 +123,11 @@ void config_default(struct config *conf)
|
||||
conf->wanted_version = VER_CURRENT; // changed by --dialect
|
||||
conf->debuglevel = DEBUGLEVEL_DEBUG; // changed by --debuglevel, used by "!debug"
|
||||
conf->outbuf_size = 0x10000; // 64K, "--test" changes to 16M
|
||||
conf->default_cpu = NULL;
|
||||
conf->initial_cpu_type = NULL;
|
||||
conf->symbollist_filename = NULL;
|
||||
conf->vicelabels_filename = NULL;
|
||||
conf->output_filename = NULL;
|
||||
conf->outfile_format = OUTFILE_FORMAT_UNSPECIFIED;
|
||||
conf->report_filename = NULL;
|
||||
conf->mem_init_value = MEMINIT_USE_DEFAULT; // set by --initmem
|
||||
conf->initial_pc = NO_VALUE_GIVEN; // set by --setpc
|
||||
@ -281,7 +282,7 @@ static void parse_symbol_definition(scope_t scope)
|
||||
static void parse_mnemo_or_global_symbol_def(void)
|
||||
{
|
||||
// read keyword and ask current cpu type if it's a mnemonic
|
||||
if (CPU_state.type->keyword_is_mnemonic(input_read_keyword()))
|
||||
if (cpu_current_type->keyword_is_mnemonic(input_read_keyword()))
|
||||
return; // statement has been handled
|
||||
|
||||
// if we're here, it wasn't a mnemonic, so it can only be a symbol name
|
||||
@ -644,3 +645,23 @@ void output_le32(intval_t value)
|
||||
output_byte(value >> 16);
|
||||
output_byte(value >> 24);
|
||||
}
|
||||
|
||||
|
||||
// string shown in CLI error message if outputformat_set() returns nonzero:
|
||||
const char outputformat_names[] = "'plain', 'cbm', 'apple'";
|
||||
|
||||
// convert output format name held in DynaBuf to enum.
|
||||
// returns OUTFILE_FORMAT_UNSPECIFIED on error.
|
||||
enum outfile_format outputformat_find(void)
|
||||
{
|
||||
if (strcmp(GlobalDynaBuf->buffer, "plain") == 0)
|
||||
return OUTFILE_FORMAT_PLAIN;
|
||||
else if (strcmp(GlobalDynaBuf->buffer, "cbm") == 0)
|
||||
return OUTFILE_FORMAT_CBM;
|
||||
else if (strcmp(GlobalDynaBuf->buffer, "apple") == 0)
|
||||
return OUTFILE_FORMAT_APPLE;
|
||||
// else if (strcmp(GlobalDynaBuf->buffer, "o65") == 0)
|
||||
// return OUTFILE_FORMAT_O65;
|
||||
|
||||
return OUTFILE_FORMAT_UNSPECIFIED;
|
||||
}
|
||||
|
19
src/global.h
19
src/global.h
@ -69,6 +69,12 @@ enum debuglevel {
|
||||
// debug messages with higher levels are suppressed,
|
||||
// can be changed using "--debuglevel" cli switch.
|
||||
};
|
||||
enum outfile_format {
|
||||
OUTFILE_FORMAT_UNSPECIFIED, // default (uses "plain" actually)
|
||||
OUTFILE_FORMAT_PLAIN, // no header, just code
|
||||
OUTFILE_FORMAT_CBM, // 16-bit load address, code (default for "!to" pseudo opcode)
|
||||
OUTFILE_FORMAT_APPLE // 16-bit load address, 16-bit length, code
|
||||
};
|
||||
// configuration
|
||||
struct config {
|
||||
char pseudoop_prefix; // '!' or '.'
|
||||
@ -87,10 +93,11 @@ struct config {
|
||||
enum version wanted_version; // set by --dialect (and --test --test)
|
||||
signed long debuglevel; // set by --debuglevel, used by "!debug"
|
||||
signed long outbuf_size; // 64K, "--test" changes to 16M
|
||||
const struct cpu_type *default_cpu;
|
||||
const struct cpu_type *initial_cpu_type;
|
||||
const char *symbollist_filename;
|
||||
const char *vicelabels_filename;
|
||||
const char *output_filename; // TODO - put in "part" struct
|
||||
enum outfile_format outfile_format;
|
||||
const char *report_filename; // TODO - put in "part" struct
|
||||
#define MEMINIT_USE_DEFAULT 256 // default value for next field if cli switch not used:
|
||||
signed long mem_init_value; // set by --initmem
|
||||
@ -139,7 +146,7 @@ do { \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Prototypes
|
||||
// prototypes
|
||||
|
||||
// set configuration to default values
|
||||
extern void config_default(struct config *conf);
|
||||
@ -227,4 +234,12 @@ extern void output_be32(intval_t value);
|
||||
extern void output_le32(intval_t value);
|
||||
|
||||
|
||||
// string to show if outputformat_set() returns nonzero
|
||||
extern const char outputformat_names[];
|
||||
|
||||
// convert output format name held in DynaBuf to enum.
|
||||
// returns OUTFILE_FORMAT_UNSPECIFIED on error.
|
||||
extern enum outfile_format outputformat_find(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -133,6 +133,8 @@ extern int input_read_input_filename(boolean *uses_lib);
|
||||
// Returns nonzero on error. Filename in GlobalDynaBuf.
|
||||
// Errors are handled and reported, but caller should call
|
||||
// input_skip_remainder() then.
|
||||
// FIXME - the name suggests this fn reads "the" output filename, but it only
|
||||
// reads "an" output filename: either symbollist or the real output file.
|
||||
extern int input_read_output_filename(void);
|
||||
|
||||
// Try to read a comma, skipping spaces before and after. Return TRUE if comma
|
||||
|
10
src/mnemo.c
10
src/mnemo.c
@ -775,7 +775,7 @@ static void group_only_implied_addressing(int opcode)
|
||||
//bits force_bit = input_get_force_bit(); // skips spaces after // TODO - accept postfix and complain about it?
|
||||
// TODO - accept argument and complain about it? error message should tell more than "garbage data at end of line"!
|
||||
// for 65ce02 and 4502, warn about buggy decimal mode
|
||||
if ((opcode == 0xf8) && (CPU_state.type->flags & CPUFLAG_DECIMALSUBTRACTBUGGY))
|
||||
if ((opcode == 0xf8) && (cpu_current_type->flags & CPUFLAG_DECIMALSUBTRACTBUGGY))
|
||||
Throw_first_pass_warning("Found SED instruction for CPU with known decimal SBC bug.");
|
||||
output_byte(opcode);
|
||||
input_ensure_EOS();
|
||||
@ -898,7 +898,7 @@ static unsigned int imm_ops(bits *force_bit, unsigned char opcode, bits immediat
|
||||
BUG("IllegalImmediateMode", immediate_mode);
|
||||
}
|
||||
// if the CPU does not support long registers...
|
||||
if ((CPU_state.type->flags & CPUFLAG_SUPPORTSLONGREGS) == 0)
|
||||
if ((cpu_current_type->flags & CPUFLAG_SUPPORTSLONGREGS) == 0)
|
||||
return opcode; // result in bits 0..7 forces single-byte argument
|
||||
|
||||
// check force bits - if no force bits given, use cpu state and convert to force bit
|
||||
@ -913,7 +913,7 @@ static void check_zp_wraparound(struct number *result)
|
||||
{
|
||||
if ((result->ntype == NUMTYPE_INT)
|
||||
&& (result->val.intval == 0xff)
|
||||
&& (CPU_state.type->flags & CPUFLAG_WARN_ABOUT_FF_PTR))
|
||||
&& (cpu_current_type->flags & CPUFLAG_WARN_ABOUT_FF_PTR))
|
||||
Throw_warning("Zeropage pointer wraps around from $ff to $00");
|
||||
}
|
||||
|
||||
@ -1002,7 +1002,7 @@ static void group_misc(int index, bits immediate_mode)
|
||||
// below - "force_bit" might be undefined (depends on compiler).
|
||||
make_instruction(force_bit, &result, immediate_opcodes);
|
||||
// warn about unstable ANE/LXA (undocumented opcode of NMOS 6502)?
|
||||
if ((CPU_state.type->flags & CPUFLAG_8B_AND_AB_NEED_0_ARG)
|
||||
if ((cpu_current_type->flags & CPUFLAG_8B_AND_AB_NEED_0_ARG)
|
||||
&& (result.ntype == NUMTYPE_INT)
|
||||
&& (result.val.intval != 0x00)) {
|
||||
if (immediate_opcodes == 0x8b)
|
||||
@ -1137,7 +1137,7 @@ static void group_jump(int index)
|
||||
// check whether to warn about 6502's JMP() bug
|
||||
if ((result.ntype == NUMTYPE_INT)
|
||||
&& ((result.val.intval & 0xff) == 0xff)
|
||||
&& (CPU_state.type->flags & CPUFLAG_INDIRECTJMPBUGGY))
|
||||
&& (cpu_current_type->flags & CPUFLAG_INDIRECTJMPBUGGY))
|
||||
Throw_warning("Assembling buggy JMP($xxff) instruction");
|
||||
break;
|
||||
case X_INDEXED_INDIRECT_ADDRESSING: // ($ffff,x)
|
||||
|
199
src/output.c
199
src/output.c
@ -20,7 +20,6 @@
|
||||
#include "global.h"
|
||||
#include "input.h"
|
||||
#include "platform.h"
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
// constants
|
||||
@ -58,34 +57,10 @@ static struct pseudopc *pseudopc_current_context; // current struct (NULL when n
|
||||
|
||||
// variables
|
||||
static struct output default_output;
|
||||
static struct output *out = &default_output;
|
||||
static struct output *out = &default_output; // FIXME - never changes! is the ptr a preparation for "assembling several different parts in one go"?
|
||||
static int statement_size; // add to PC after statement
|
||||
// FIXME - make static
|
||||
struct vcpu CPU_state; // current CPU state
|
||||
|
||||
// FIXME - move output _file_ stuff to some other .c file!
|
||||
// possible file formats
|
||||
enum output_format {
|
||||
OUTPUT_FORMAT_UNSPECIFIED, // default (uses "plain" actually)
|
||||
OUTPUT_FORMAT_APPLE, // load address, length, code
|
||||
OUTPUT_FORMAT_CBM, // load address, code (default for "!to" pseudo opcode)
|
||||
OUTPUT_FORMAT_PLAIN // code only
|
||||
};
|
||||
// predefined stuff
|
||||
// tree to hold output formats (FIXME - a tree for three items, really?)
|
||||
static struct ronode file_format_tree[] = {
|
||||
PREDEF_START,
|
||||
#define KNOWN_FORMATS "'plain', 'cbm', 'apple'" // shown in CLI error message for unknown formats
|
||||
PREDEFNODE("apple", OUTPUT_FORMAT_APPLE),
|
||||
PREDEFNODE("cbm", OUTPUT_FORMAT_CBM),
|
||||
// PREDEFNODE("o65", OUTPUT_FORMAT_O65),
|
||||
PREDEF_END("plain", OUTPUT_FORMAT_PLAIN),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
// chosen file format
|
||||
static enum output_format output_format = OUTPUT_FORMAT_UNSPECIFIED;
|
||||
const char outputfile_formats[] = KNOWN_FORMATS; // string to show if outputfile_set_format() returns nonzero
|
||||
|
||||
static intval_t program_counter; // current program counter (pseudopc value)
|
||||
static enum numtype pc_ntype;
|
||||
|
||||
// report binary output
|
||||
static void report_binary(char value)
|
||||
@ -134,7 +109,7 @@ static void border_crossed(int current_offset)
|
||||
void (*output_byte)(intval_t byte);
|
||||
|
||||
|
||||
// send low byte to output buffer, automatically increasing program counter
|
||||
// send low byte to output buffer and remember to later increase program counter
|
||||
static void real_output(intval_t byte)
|
||||
{
|
||||
// CAUTION - there are two copies of these checks!
|
||||
@ -257,32 +232,7 @@ void outbuf_set_outfile_limit(void)
|
||||
}
|
||||
|
||||
|
||||
// try to set output format held in DynaBuf. Returns zero on success.
|
||||
int outputfile_set_format(void)
|
||||
{
|
||||
void *node_body;
|
||||
|
||||
// perform lookup
|
||||
if (!tree_easy_scan(file_format_tree, &node_body, GlobalDynaBuf))
|
||||
return 1;
|
||||
|
||||
output_format = (enum output_format) node_body;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if file format was already chosen, returns zero.
|
||||
// if file format isn't set, chooses CBM and returns 1.
|
||||
int outputfile_prefer_cbm_format(void)
|
||||
{
|
||||
if (output_format != OUTPUT_FORMAT_UNSPECIFIED)
|
||||
return 0;
|
||||
|
||||
output_format = OUTPUT_FORMAT_CBM;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// init output struct (done later)
|
||||
// init output struct
|
||||
void output_createbuffer(void)
|
||||
{
|
||||
char fill_value = 0; // default value for output buffer
|
||||
@ -302,66 +252,6 @@ void output_createbuffer(void)
|
||||
}
|
||||
|
||||
|
||||
// write used portion of output buffer to output file
|
||||
void output_save_file(FILE *fd)
|
||||
{
|
||||
intval_t start,
|
||||
limit, // end+1
|
||||
amount;
|
||||
|
||||
start = out->lowest_written;
|
||||
limit = out->highest_written + 1;
|
||||
// if pseudo opcodes were used, they override the actual values:
|
||||
if (force_file_start)
|
||||
start = forced_start_idx;
|
||||
if (force_file_limit)
|
||||
limit = forced_limit_idx;
|
||||
// if cli args were given, they override even harder:
|
||||
if (config.outfile_start != NO_VALUE_GIVEN)
|
||||
start = config.outfile_start;
|
||||
if (config.outfile_limit != NO_VALUE_GIVEN)
|
||||
limit = config.outfile_limit;
|
||||
|
||||
if (limit <= start) {
|
||||
// nothing written
|
||||
start = 0; // I could try to use some segment start, but what for?
|
||||
amount = 0;
|
||||
// FIXME - how about not writing anything in this case?
|
||||
// a CBM file would consist of a bogus load address and nothing else!
|
||||
} else {
|
||||
amount = limit - start;
|
||||
}
|
||||
if (config.process_verbosity) {
|
||||
printf("Saving %ld (0x%04lx) bytes (0x%04lx - 0x%04lx exclusive).\n",
|
||||
amount, amount, start, start + amount);
|
||||
}
|
||||
// output file header according to file format
|
||||
// FIXME - add checks and error messages for "start is above $ffff"!)
|
||||
switch (output_format) {
|
||||
case OUTPUT_FORMAT_APPLE:
|
||||
PLATFORM_SETFILETYPE_APPLE(config.output_filename);
|
||||
// output 16-bit load address in little-endian byte order
|
||||
putc(start & 255, fd);
|
||||
putc(start >> 8, fd);
|
||||
// output 16-bit length in little-endian byte order
|
||||
putc(amount & 255, fd);
|
||||
putc(amount >> 8, fd);
|
||||
break;
|
||||
case OUTPUT_FORMAT_UNSPECIFIED:
|
||||
case OUTPUT_FORMAT_PLAIN:
|
||||
PLATFORM_SETFILETYPE_PLAIN(config.output_filename);
|
||||
break;
|
||||
case OUTPUT_FORMAT_CBM:
|
||||
PLATFORM_SETFILETYPE_CBM(config.output_filename);
|
||||
// output 16-bit load address in little-endian byte order
|
||||
putc(start & 255, fd);
|
||||
putc(start >> 8, fd);
|
||||
}
|
||||
// dump output buffer to file
|
||||
fwrite(out->buffer + start, amount, 1, fd);
|
||||
}
|
||||
|
||||
|
||||
// link segment data into segment ring
|
||||
static void link_segment(intval_t start, intval_t length)
|
||||
{
|
||||
@ -435,11 +325,10 @@ void output_passinit(void)
|
||||
out->xor = 0;
|
||||
|
||||
//vcpu stuff:
|
||||
CPU_state.pc.ntype = NUMTYPE_UNDEFINED; // not defined yet
|
||||
CPU_state.pc.flags = 0;
|
||||
pc_ntype = NUMTYPE_UNDEFINED; // not defined yet
|
||||
// FIXME - number type is "undefined", but still the intval 0 below will
|
||||
// be used to calculate diff when pc is first set.
|
||||
CPU_state.pc.val.intval = 0; // same as output's write_idx on pass init
|
||||
program_counter = 0; // same as output's write_idx on pass init
|
||||
statement_size = 0; // increase PC by this at end of statement
|
||||
|
||||
// pseudopc stuff:
|
||||
@ -536,10 +425,9 @@ void vcpu_set_pc(intval_t new_pc, bits segment_flags)
|
||||
// stuff happens! i see no reason to try to mimic that.
|
||||
}
|
||||
}
|
||||
pc_change = new_pc - CPU_state.pc.val.intval;
|
||||
CPU_state.pc.val.intval = new_pc; // FIXME - oversized values are accepted without error and will be wrapped at end of statement!
|
||||
CPU_state.pc.ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
|
||||
CPU_state.pc.addr_refs = 1; // yes, PC counts as address
|
||||
pc_change = new_pc - program_counter;
|
||||
program_counter = new_pc; // FIXME - oversized values are accepted without error and will be wrapped at end of statement!
|
||||
pc_ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
|
||||
// now tell output buffer to start a new segment
|
||||
output_start_segment(pc_change, segment_flags);
|
||||
}
|
||||
@ -567,16 +455,19 @@ when encountering "*= VALUE":
|
||||
Problem: always check for "undefined"; there are some problematic combinations.
|
||||
I need a way to return the size of a generated code block even if PC undefined.
|
||||
Maybe like this:
|
||||
*= new_address [, invisible] [, overlay] [, &size_symbol_ref {]
|
||||
*= new_address [, invisible] [, overlay] [, size_counter = symbol {]
|
||||
...code...
|
||||
[} ; at end of block, size is written to size symbol given above!]
|
||||
[} ; at end of block, size is written to symbol given above!]
|
||||
*/
|
||||
|
||||
|
||||
// get program counter
|
||||
void vcpu_read_pc(struct number *target)
|
||||
{
|
||||
*target = CPU_state.pc;
|
||||
target->ntype = pc_ntype;
|
||||
target->flags = 0; // FIXME - if defined, check for FITS_BYTE etc.? use pc_flags?
|
||||
target->val.intval = program_counter;
|
||||
target->addr_refs = 1; // yes, PC counts as address
|
||||
}
|
||||
|
||||
|
||||
@ -590,11 +481,50 @@ int vcpu_get_statement_size(void)
|
||||
// adjust program counter (called at end of each statement)
|
||||
void vcpu_end_statement(void)
|
||||
{
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval + statement_size) & (config.outbuf_size - 1);
|
||||
program_counter = (program_counter + statement_size) & (config.outbuf_size - 1); // FIXME - this cannot be right!
|
||||
statement_size = 0; // reset
|
||||
}
|
||||
|
||||
|
||||
// return start and size of memory block to write to output file,
|
||||
// along with load address for cbm/apple headers.
|
||||
void output_get_result(const char **ptr, intval_t *size, intval_t *loadaddr)
|
||||
{
|
||||
intval_t start,
|
||||
limit, // end+1
|
||||
amount;
|
||||
|
||||
start = out->lowest_written;
|
||||
limit = out->highest_written + 1;
|
||||
// if pseudo opcodes were used, they override the actual values:
|
||||
if (force_file_start)
|
||||
start = forced_start_idx;
|
||||
if (force_file_limit)
|
||||
limit = forced_limit_idx;
|
||||
// if cli args were given, they override even harder:
|
||||
if (config.outfile_start != NO_VALUE_GIVEN)
|
||||
start = config.outfile_start;
|
||||
if (config.outfile_limit != NO_VALUE_GIVEN)
|
||||
limit = config.outfile_limit;
|
||||
|
||||
if (limit <= start) {
|
||||
// nothing written
|
||||
start = 0; // I could try to use some segment start, but what for?
|
||||
amount = 0;
|
||||
// FIXME - how about not writing anything in this case?
|
||||
// a CBM file would consist of a bogus load address and nothing else!
|
||||
} else {
|
||||
amount = limit - start;
|
||||
}
|
||||
|
||||
*ptr = out->buffer + start;
|
||||
*size = amount;
|
||||
*loadaddr = start;
|
||||
}
|
||||
|
||||
|
||||
// pseudopc stuff:
|
||||
|
||||
// struct to describe a pseudopc context
|
||||
struct pseudopc {
|
||||
struct pseudopc *outer; // next layer (to be able to "unpseudopc" labels by more than one level)
|
||||
@ -610,11 +540,11 @@ void pseudopc_start(struct number *new_pc)
|
||||
new_context->outer = pseudopc_current_context; // let it point to previous one
|
||||
pseudopc_current_context = new_context; // make it the current one
|
||||
|
||||
new_context->ntype = CPU_state.pc.ntype;
|
||||
new_context->offset = new_pc->val.intval - CPU_state.pc.val.intval;
|
||||
CPU_state.pc.val.intval = new_pc->val.intval;
|
||||
CPU_state.pc.ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
|
||||
//new: CPU_state.pc.flags = new_pc->flags & (NUMBER_IS_DEFINED | NUMBER_EVER_UNDEFINED);
|
||||
new_context->ntype = pc_ntype;
|
||||
new_context->offset = new_pc->val.intval - program_counter;
|
||||
program_counter = new_pc->val.intval;
|
||||
pc_ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
|
||||
//new: pc_flags = new_pc->flags & (NUMBER_IS_DEFINED | NUMBER_EVER_UNDEFINED);
|
||||
}
|
||||
// end offset assembly
|
||||
void pseudopc_end(void)
|
||||
@ -629,15 +559,16 @@ void pseudopc_end(void)
|
||||
if (config.wanted_version >= VER_DISABLED_OBSOLETE_STUFF)
|
||||
BUG("ClosingUnopenedPseudopcBlock", 0);
|
||||
} else {
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & (config.outbuf_size - 1); // pc might have wrapped around
|
||||
CPU_state.pc.ntype = pseudopc_current_context->ntype;
|
||||
program_counter = (program_counter - pseudopc_current_context->offset) & (config.outbuf_size - 1); // pc might have wrapped around
|
||||
pc_ntype = pseudopc_current_context->ntype;
|
||||
pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block
|
||||
}
|
||||
}
|
||||
// this is only for old, deprecated, obsolete, stupid "realpc":
|
||||
void pseudopc_end_all(void)
|
||||
{
|
||||
while (pseudopc_current_context)
|
||||
// FIXME - this needs changing if we start with a "offset is 0" struct in the future!
|
||||
while (pseudopc_current_context != NULL)
|
||||
pseudopc_end();
|
||||
}
|
||||
// un-pseudopc a label value by given number of levels
|
||||
|
51
src/output.h
51
src/output.h
@ -2,12 +2,11 @@
|
||||
// Copyright (C) 1998-2024 Marco Baye
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// Output stuff (FIXME - split into outbuf, outfile/format and vcpu parts)
|
||||
// output buffer stuff
|
||||
#ifndef output_H
|
||||
#define output_H
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "config.h"
|
||||
|
||||
|
||||
@ -18,35 +17,20 @@
|
||||
#define SEGMENT_FLAG_INVISIBLE (1u << 1) // do not warn about other segments overwriting this one
|
||||
|
||||
|
||||
// current CPU state
|
||||
// FIXME - move vcpu struct definition to .c file and change other .c files' accesses to fn calls. then replace "struct number" with minimized version.
|
||||
struct vcpu {
|
||||
const struct cpu_type *type; // current CPU type (default 6502) (FIXME - move out of struct again?)
|
||||
struct number pc; // current program counter (pseudo value)
|
||||
};
|
||||
// prototypes
|
||||
|
||||
|
||||
// variables
|
||||
extern struct vcpu CPU_state; // current CPU state FIXME - restrict visibility to .c file
|
||||
|
||||
|
||||
// Prototypes
|
||||
|
||||
// clear segment list and disable output
|
||||
extern void output_passinit(void);
|
||||
|
||||
|
||||
// outbuf stuff:
|
||||
|
||||
// alloc and init mem buffer (done later)
|
||||
// alloc and init mem buffer (called once on startup)
|
||||
extern void output_createbuffer(void);
|
||||
|
||||
// clear segment list and disable output (called on each pass)
|
||||
extern void output_passinit(void);
|
||||
|
||||
// skip over some bytes in output buffer without starting a new segment
|
||||
// (used by "!skip", and also called by "!binary" if really calling
|
||||
// output_byte would be a waste of time)
|
||||
extern void output_skip(int size);
|
||||
|
||||
// Send low byte of arg to output buffer and advance pointer
|
||||
// send low byte of arg to output buffer and advance pointer
|
||||
// FIXME - replace by output_sequence(char *src, size_t size)
|
||||
extern void (*output_byte)(intval_t);
|
||||
|
||||
@ -58,27 +42,14 @@ extern int output_setdefault(char content);
|
||||
extern void outbuf_set_outfile_start(void);
|
||||
extern void outbuf_set_outfile_limit(void);
|
||||
|
||||
// outfile stuff:
|
||||
|
||||
// try to set output format held in DynaBuf. Returns zero on success.
|
||||
extern int outputfile_set_format(void);
|
||||
extern const char outputfile_formats[]; // string to show if outputfile_set_format() returns nonzero
|
||||
|
||||
// if file format was already chosen, returns zero.
|
||||
// if file format isn't set, chooses CBM and returns 1.
|
||||
extern int outputfile_prefer_cbm_format(void);
|
||||
|
||||
// write used portion of output buffer to output file
|
||||
extern void output_save_file(FILE *fd);
|
||||
|
||||
// change output pointer and enable output
|
||||
extern void output_start_segment(intval_t address_change, bits segment_flags);
|
||||
|
||||
// Show start and end of current segment
|
||||
// show start and end of current segment
|
||||
extern void output_end_segment(void);
|
||||
|
||||
// get/set "encryption" byte
|
||||
extern char output_get_xor(void);
|
||||
|
||||
extern void output_set_xor(char xor);
|
||||
|
||||
// set program counter to defined value (TODO - allow undefined!)
|
||||
@ -93,6 +64,10 @@ extern int vcpu_get_statement_size(void);
|
||||
// adjust program counter (called at end of each statement)
|
||||
extern void vcpu_end_statement(void);
|
||||
|
||||
// return start and size of memory block to write to output file,
|
||||
// along with load address for cbm/apple headers.
|
||||
extern void output_get_result(const char **ptr, intval_t *size, intval_t *loadaddr);
|
||||
|
||||
|
||||
// pseudopc stuff:
|
||||
struct pseudopc;
|
||||
|
@ -140,13 +140,15 @@ static enum eos po_xor(void)
|
||||
// select output file name and format ("!to" pseudo opcode)
|
||||
static enum eos po_to(void)
|
||||
{
|
||||
enum outfile_format format;
|
||||
|
||||
// only process this pseudo opcode in first pass
|
||||
if (!FIRST_PASS)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// cli arg and earlier calls supersede this call
|
||||
// the "--outfile" cli arg and earlier calls have priority
|
||||
if (config.output_filename) {
|
||||
Throw_warning("Output file already chosen.");
|
||||
Throw_warning("Output file name already chosen.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
@ -159,27 +161,33 @@ static enum eos po_to(void)
|
||||
config.output_filename = dynabuf_get_copy(GlobalDynaBuf);
|
||||
|
||||
// select output format
|
||||
// if no comma found, use default file format
|
||||
if (input_accept_comma() == FALSE) {
|
||||
if (outputfile_prefer_cbm_format()) {
|
||||
// output deprecation warning (unless user requests really old behaviour)
|
||||
if (config.wanted_version >= VER_DEPRECATE_REALPC)
|
||||
Throw_warning("Used \"!to\" without file format indicator. Defaulting to \"cbm\".");
|
||||
if (input_accept_comma()) {
|
||||
// parse output format name
|
||||
// if no keyword given, give up
|
||||
if (input_read_and_lower_keyword() == 0)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
format = outputformat_find();
|
||||
if (format == OUTFILE_FORMAT_UNSPECIFIED) {
|
||||
Throw_error("Unknown output format.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
return ENSURE_EOS;
|
||||
} else {
|
||||
// no comma: complain unless user requested really old behaviour
|
||||
if (config.wanted_version >= VER_DEPRECATE_REALPC)
|
||||
Throw_warning("Used \"!to\" without file format indicator.");
|
||||
// default to cbm
|
||||
format = OUTFILE_FORMAT_CBM;
|
||||
}
|
||||
|
||||
// parse output format name
|
||||
// if no keyword given, give up
|
||||
if (input_read_and_lower_keyword() == 0)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
if (outputfile_set_format()) {
|
||||
// error occurred
|
||||
Throw_error("Unknown output format.");
|
||||
return SKIP_REMAINDER;
|
||||
// the "--format" cli arg has priority
|
||||
if (config.outfile_format != OUTFILE_FORMAT_UNSPECIFIED) {
|
||||
Throw_warning("Output file format already chosen.");
|
||||
} else {
|
||||
config.outfile_format = format;
|
||||
}
|
||||
return ENSURE_EOS; // success
|
||||
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
@ -210,7 +218,7 @@ static enum eos po_byte(void)
|
||||
// Insert 16-bit values ("!16" / "!wo" / "!word" pseudo opcode)
|
||||
static enum eos po_16(void)
|
||||
{
|
||||
return iterate((CPU_state.type->flags & CPUFLAG_ISBIGENDIAN) ? output_be16 : output_le16);
|
||||
return iterate((cpu_current_type->flags & CPUFLAG_ISBIGENDIAN) ? output_be16 : output_le16);
|
||||
}
|
||||
// Insert 16-bit values big-endian ("!be16" pseudo opcode)
|
||||
static enum eos po_be16(void)
|
||||
@ -227,7 +235,7 @@ static enum eos po_le16(void)
|
||||
// Insert 24-bit values ("!24" pseudo opcode)
|
||||
static enum eos po_24(void)
|
||||
{
|
||||
return iterate((CPU_state.type->flags & CPUFLAG_ISBIGENDIAN) ? output_be24 : output_le24);
|
||||
return iterate((cpu_current_type->flags & CPUFLAG_ISBIGENDIAN) ? output_be24 : output_le24);
|
||||
}
|
||||
// Insert 24-bit values big-endian ("!be24" pseudo opcode)
|
||||
static enum eos po_be24(void)
|
||||
@ -244,7 +252,7 @@ static enum eos po_le24(void)
|
||||
// Insert 32-bit values ("!32" pseudo opcode)
|
||||
static enum eos po_32(void)
|
||||
{
|
||||
return iterate((CPU_state.type->flags & CPUFLAG_ISBIGENDIAN) ? output_be32 : output_le32);
|
||||
return iterate((cpu_current_type->flags & CPUFLAG_ISBIGENDIAN) ? output_be32 : output_le32);
|
||||
}
|
||||
// Insert 32-bit values big-endian ("!be32" pseudo opcode)
|
||||
static enum eos po_be32(void)
|
||||
@ -625,7 +633,7 @@ static enum eos po_align(void)
|
||||
if (input_accept_comma())
|
||||
ALU_any_int(&fill);
|
||||
else
|
||||
fill = CPU_state.type->default_align_value;
|
||||
fill = cpu_current_type->default_align_value;
|
||||
|
||||
// make sure PC is defined
|
||||
vcpu_read_pc(&pc);
|
||||
@ -709,19 +717,19 @@ static enum eos po_realpc(void)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos po_cpu(void)
|
||||
{
|
||||
const struct cpu_type *cpu_buffer = CPU_state.type; // remember current cpu
|
||||
const struct cpu_type *cpu_buffer = cpu_current_type; // remember
|
||||
const struct cpu_type *new_cpu_type;
|
||||
|
||||
if (input_read_and_lower_keyword()) {
|
||||
new_cpu_type = cputype_find();
|
||||
if (new_cpu_type)
|
||||
CPU_state.type = new_cpu_type; // activate new cpu type
|
||||
cpu_current_type = new_cpu_type; // activate new cpu type
|
||||
else
|
||||
Throw_error("Unknown processor.");
|
||||
}
|
||||
// if there's a block, parse that and then restore old value
|
||||
if (parse_optional_block())
|
||||
CPU_state.type = cpu_buffer;
|
||||
cpu_current_type = cpu_buffer;
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define RELEASE "0.97" // update before release FIXME
|
||||
#define CODENAME "Zem" // update before release
|
||||
#define CHANGE_DATE "14 Feb" // update before release FIXME
|
||||
#define CHANGE_DATE "15 Feb" // update before release FIXME
|
||||
#define CHANGE_YEAR "2024" // update before release
|
||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||
|
@ -1,9 +1,9 @@
|
||||
|
||||
.SILENT:
|
||||
|
||||
.PHONY: auto bugfixes cpus errors warnings
|
||||
.PHONY: auto bugfixes cliargs cpus errors warnings
|
||||
|
||||
all: auto bugfixes cpus errors warnings
|
||||
all: auto bugfixes cliargs cpus errors warnings
|
||||
|
||||
auto:
|
||||
echo "Performing self-tests..."
|
||||
@ -15,6 +15,11 @@ bugfixes:
|
||||
echo
|
||||
make -C bugfixes
|
||||
|
||||
cliargs:
|
||||
echo "Testing cliargs..."
|
||||
echo
|
||||
make -C cliargs
|
||||
|
||||
cpus:
|
||||
echo "Testing CPUs..."
|
||||
echo
|
||||
|
14
testing/cliargs/Makefile
Normal file
14
testing/cliargs/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
#ACMEFLAGS = -v0
|
||||
|
||||
.PHONY: outformats
|
||||
|
||||
.SILENT:
|
||||
|
||||
all: outformats
|
||||
echo
|
||||
echo "Testing cliargs: PASSED"
|
||||
echo
|
||||
|
||||
outformats: outformats.a outformats.sh outformat-*.o
|
||||
echo "Testing output formats:"
|
||||
bash outformats.sh
|
14
testing/cliargs/outformats.a
Normal file
14
testing/cliargs/outformats.a
Normal file
@ -0,0 +1,14 @@
|
||||
!if FORMAT == 0 {
|
||||
!to "test.o"
|
||||
} else if FORMAT == 1 {
|
||||
!to "test.o", plain
|
||||
} else if FORMAT == 2 {
|
||||
!to "test.o", cbm
|
||||
} else if FORMAT == 3 {
|
||||
!to "test.o", apple
|
||||
} else {
|
||||
!error "unexpected FORMAT"
|
||||
}
|
||||
*=$1000
|
||||
lda #1
|
||||
rts
|
27
testing/cliargs/outformats.sh
Executable file
27
testing/cliargs/outformats.sh
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
check() {
|
||||
#echo "$@"
|
||||
FILE="$1"
|
||||
shift
|
||||
acme "$@" outformats.a || exit 1
|
||||
cmp test.o "$FILE" || exit 1
|
||||
rm test.o
|
||||
}
|
||||
|
||||
# if neither -o nor -f are given, use format from "!to", which defaults to cbm:
|
||||
check outformat-cbm.o -DFORMAT=0
|
||||
check outformat-plain.o -DFORMAT=1
|
||||
check outformat-cbm.o -DFORMAT=2
|
||||
check outformat-apple.o -DFORMAT=3
|
||||
|
||||
# if -o or -f are given, format from "!to" should be ignored:
|
||||
for f in 0 1 2 3 ; do
|
||||
check outformat-plain.o -DFORMAT=$f -f plain
|
||||
check outformat-cbm.o -DFORMAT=$f -f cbm
|
||||
check outformat-apple.o -DFORMAT=$f -f apple
|
||||
check outformat-plain.o -DFORMAT=$f -o test.o # defaults to plain
|
||||
check outformat-plain.o -DFORMAT=$f -o test.o -f plain
|
||||
check outformat-cbm.o -DFORMAT=$f -o test.o -f cbm
|
||||
check outformat-apple.o -DFORMAT=$f -o test.o -f apple
|
||||
done
|
4
testing/warnings/start2.a
Normal file
4
testing/warnings/start2.a
Normal file
@ -0,0 +1,4 @@
|
||||
*=$1000, outfilestart
|
||||
!tx "Hinz"
|
||||
!outfilestart ; -> "Start of output file already chosen."
|
||||
!tx "Kunz"
|
Loading…
Reference in New Issue
Block a user