diff --git a/src/global.c b/src/global.c index 8998eba..289afd7 100644 --- a/src/global.c +++ b/src/global.c @@ -617,7 +617,7 @@ void throw_finalpass_warning(const char msg[]) throw_warning(msg); } -// throw "macro twice" error (FIXME - also use for "symbol twice"!) +// throw "macro twice"/"symbol twice" error // first output error as "error", then location of initial definition as "info" void throw_redef_error(const char error_msg[], struct location *old_def, const char info_msg[]) { diff --git a/src/global.h b/src/global.h index 163fdf7..513fa06 100644 --- a/src/global.h +++ b/src/global.h @@ -238,7 +238,7 @@ extern void throw_pass1_warning(const char msg[]); // final pass because values might be undefined earlier!) extern void throw_finalpass_warning(const char msg[]); -// throw "macro twice" error (FIXME - also use for "symbol twice"!) +// throw "macro twice"/"symbol twice" error // first output error as "error", then location of initial definition as "info" extern void throw_redef_error(const char error_msg[], struct location *old_def, const char info_msg[]); diff --git a/src/input.c b/src/input.c index bbfcb43..ed765b8 100644 --- a/src/input.c +++ b/src/input.c @@ -923,11 +923,10 @@ int input_read_input_filename(struct filespecflags *flags) return 1; // unterminated or escaping error GetByte(); // eat terminator -// new algo: +// new algo: (FIXME) // it should be possible to construct the name of input file from symbols, so // build environments can define a name at one place and use it at another. // FIXME - use expression parser to read filename string! -// see lines 416 and 1317 in pseudoopcodes.c for two more possible callers! } // check length, remember abs/rel, unescape, terminate, do platform conversion diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index 5366740..e62c47e 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -24,6 +24,15 @@ // TODO - make new, keyword-based argument parser for !bin, !fill and !align +// helper function to support switching from positional arguments to keyword arguments +static boolean line_uses_keyword_arguments(void) +{ + // to be on the safe side, return FALSE if dialect < 0.98! + // read line to buffer, check if it begins with '[a-zA-Z]+=' + // change input to RAM, return result + // ...and the caller needs to pass us some struct so it can change input back later on! + return FALSE; +} // different ways to handle end-of-statement: @@ -525,19 +534,54 @@ static enum eos po_scrxor(void) return SKIP_REMAINDER; } +// "backend" function for "!binary" +static void include_file(FILE *stream, intval_t size, intval_t offset) +{ + int byte, + amount; + + // check whether including is a waste of time + // FIXME - future changes ("several-projects-at-once") + // may be incompatible with this! + if ((size >= 0) && (!pass.flags.generate_output)) { + output_skip(size); // really including is useless anyway + return; + } + + // really insert file + fseek(stream, offset, SEEK_SET); // set read pointer + // read "size" bytes. if size is "NO_VALUE_GIVEN" (which is -1), + // decrementing it won't give zero, so we'll read until EOF, + // which is exactly what we want if no size was given: + while (size != 0) { + byte = getc(stream); + if (byte == EOF) + break; + output_byte(byte); + --size; + } + // if more should have been read, warn and add padding + if (size > 0) { + throw_warning("Padding with zeroes."); + do { + output_byte(0); + } while (--size); + } + // if verbose, produce some output + if (config.process_verbosity >= 2) { + amount = output_get_statement_size(); + printf("Loaded %d (0x%04x) bytes from file offset %d (0x%04x).\n", + amount, amount, offset, offset); + } +} // include binary file ("!binary" pseudo opcode) -// FIXME - split this into "parser" and "worker" fn and move worker fn somewhere else. static enum eos po_binary(void) { struct filespecflags flags; FILE *stream; - int byte; - struct number size, - skip; - int amount; - - size.val.intval = -1; // means "not given" => "until EOF" - skip.val.intval = 0; + struct number arg; + intval_t size = NO_VALUE_GIVEN, // means "until EOF" + skip = 0; // read file name and convert from UNIX style to platform style if (input_read_input_filename(&flags)) @@ -548,55 +592,36 @@ static enum eos po_binary(void) if (stream == NULL) return SKIP_REMAINDER; - // read optional arguments + // any more arguments? if (parser_accept_comma()) { - // any size given? - if ((GotByte != ',') && (GotByte != CHAR_EOS)) { - // then parse it - ALU_defined_int(&size); - if (size.val.intval < 0) - throw_serious_error(exception_negative_size); - } - // more? - if (parser_accept_comma()) { - // any skip given? - if (GotByte != CHAR_EOS) { - // then parse it - ALU_defined_int(&skip); + if (line_uses_keyword_arguments()) { + // read keyword arguments + // TODO! + BUG("KeywordArgsNotYet", 0); + } else { + // read old-style, positional arguments: + if ((GotByte != ',') && (GotByte != CHAR_EOS)) { + // first arg is "size" + ALU_defined_int(&arg); + size = arg.val.intval; + // CAUTION: do not move this check elsewhere, + // because the default value -1 is ok! + if (size < 0) + throw_serious_error(exception_negative_size); + } + // more? + if (parser_accept_comma()) { + // second arg is "skip" + if (GotByte != CHAR_EOS) { + // then parse it + ALU_defined_int(&arg); + skip = arg.val.intval; + } } } } - // check whether including is a waste of time - // FIXME - future changes ("several-projects-at-once") - // may be incompatible with this! - if ((size.val.intval >= 0) && (!pass.flags.generate_output)) { - output_skip(size.val.intval); // really including is useless anyway - } else { - // really insert file - fseek(stream, skip.val.intval, SEEK_SET); // set read pointer - // if "size" non-negative, read "size" bytes. - // otherwise, read until EOF. - while (size.val.intval != 0) { - byte = getc(stream); - if (byte == EOF) - break; - output_byte(byte); - --size.val.intval; - } - // if more should have been read, warn and add padding - if (size.val.intval > 0) { - throw_warning("Padding with zeroes."); - do { - output_byte(0); - } while (--size.val.intval); - } - // if verbose, produce some output - if (config.process_verbosity >= 2) { - amount = output_get_statement_size(); - printf("Loaded %d (0x%04x) bytes from file offset %d (0x%04x).\n", - amount, amount, skip.val.intval, skip.val.intval); - } - } + // FIXME - add check for "skip" and complain if negative! + include_file(stream, size, skip); fclose(stream); return ENSURE_EOS; } @@ -608,9 +633,17 @@ static enum eos po_fill(void) struct number sizeresult; intval_t fill = FILLVALUE_FILL; - ALU_defined_int(&sizeresult); // FIXME - forbid addresses! - if (parser_accept_comma()) - ALU_any_int(&fill); // FIXME - forbid addresses! + if (line_uses_keyword_arguments()) { + // read keyword arguments + // TODO! + BUG("KeywordArgsNotYet", 1); + } else { + // read old-style, positional arguments: + ALU_defined_int(&sizeresult); // FIXME - forbid addresses! + if (parser_accept_comma()) + ALU_any_int(&fill); // FIXME - forbid addresses! + } + while (sizeresult.val.intval--) output_8(fill); return ENSURE_EOS; @@ -633,25 +666,34 @@ static enum eos po_skip(void) // now GotByte = illegal char // insert byte until PC fits condition +// TODO: +// now: "!align ANDVALUE, EQUALVALUE [,FILLVALUE]" +// in future: use keyword arguments so "!align fillvalue=17, blocksize=64" is +// possible (where blocksize must be a power of two) static enum eos po_align(void) { - struct number andresult, - equalresult; - intval_t fill; + struct number arg; + intval_t andresult, + equalresult, + fill = cpu_current_type->default_align_value; struct number pc; - // TODO: - // now: "!align ANDVALUE, EQUALVALUE [,FILLVALUE]" - // in future: "!align BLOCKSIZE" where block size must be a power of two - ALU_defined_int(&andresult); // FIXME - forbid addresses! - if (parser_expect(',')) { - // fn already does everything for us + if (line_uses_keyword_arguments()) { + // read keyword arguments + // TODO! + BUG("KeywordArgsNotYet", 2); + } else { + // read old-style, positional arguments: + ALU_defined_int(&arg); // FIXME - forbid addresses! + andresult = arg.val.intval; + if (parser_expect(',')) { + // fn already does everything for us + } + ALU_defined_int(&arg); // ...allow addresses (unlikely, but possible) + equalresult = arg.val.intval; + if (parser_accept_comma()) + ALU_any_int(&fill); } - ALU_defined_int(&equalresult); // ...allow addresses (unlikely, but possible) - if (parser_accept_comma()) - ALU_any_int(&fill); - else - fill = cpu_current_type->default_align_value; // make sure PC is defined programcounter_read_pc(&pc); @@ -660,7 +702,7 @@ static enum eos po_align(void) return SKIP_REMAINDER; } - while ((pc.val.intval++ & andresult.val.intval) != equalresult.val.intval) + while ((pc.val.intval++ & andresult) != equalresult) output_8(fill); return ENSURE_EOS; } diff --git a/src/version.h b/src/version.h index 0e8662f..0bfce42 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ #define RELEASE "0.97" // update before release FIXME #define CODENAME "Zem" // update before release -#define CHANGE_DATE "24 Aug" // update before release FIXME +#define CHANGE_DATE "25 Aug" // 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