diff --git a/src/acme.c b/src/acme.c index fcac721..1ff24de 100644 --- a/src/acme.c +++ b/src/acme.c @@ -237,12 +237,13 @@ static void save_output_file(void) } -// perform a single pass. Returns number of "NeedValue" type errors. -static int perform_pass(void) +// increment pass number and perform a single pass +static void perform_pass(void) { FILE *fd; int ii; + ++pass.number; // call modules' "pass init" functions Output_passinit(); // disable output, PC undefined cputype_passinit(default_cpu); // set default cpu type @@ -252,8 +253,9 @@ static int perform_pass(void) encoding_passinit(); // set default encoding section_passinit(); // set initial zone (untitled) // init variables - pass_undefined_count = 0; // no "NeedValue" errors yet - pass_real_errors = 0; // no real errors yet + pass.undefined_count = 0; + //pass.needvalue_count = 0; FIXME - use + pass.error_count = 0; // Process toplevel files for (ii = 0; ii < toplevel_src_count; ++ii) { if ((fd = fopen(toplevel_sources[ii], FILE_READBINARY))) { @@ -262,7 +264,7 @@ static int perform_pass(void) fprintf(stderr, "Error: Cannot open toplevel file \"%s\".\n", toplevel_sources[ii]); if (toplevel_sources[ii][0] == '-') fprintf(stderr, "Options (starting with '-') must be given _before_ source files!\n"); - ++pass_real_errors; + ++pass.error_count; } } Output_end_segment(); @@ -270,50 +272,46 @@ static int perform_pass(void) if --save-start is given, parse arg string if --save-limit is given, parse arg string */ - if (pass_real_errors) + if (pass.error_count) exit(ACME_finalize(EXIT_FAILURE)); - return pass_undefined_count; } static struct report global_report; // do passes until done (or errors occurred). Return whether output is ready. -static int do_actual_work(void) +static boolean do_actual_work(void) { - int undefined_prev, // "NeedValue" errors of previous pass - undefined_curr; // "NeedValue" errors of current pass + int undefs_before; // number of undefined results in previous pass report = &global_report; // let global pointer point to something report_init(report); // we must init struct before doing passes if (config.process_verbosity > 1) puts("First pass."); - pass_count = 0; - undefined_curr = perform_pass(); // First pass - // now pretend there has been a pass before the first one - undefined_prev = undefined_curr + 1; - // As long as the number of "NeedValue" errors is decreasing but - // non-zero, keep doing passes. - while (undefined_curr && (undefined_curr < undefined_prev)) { - ++pass_count; - undefined_prev = undefined_curr; + pass.number = -1; // pre-init, will be incremented by perform_pass() + perform_pass(); // first pass + // pretend there has been a previous pass, with one more undefined result + undefs_before = pass.undefined_count + 1; + // keep doing passes as long as the number of undefined results keeps decreasing. + // stop on zero (FIXME - zero-check pass.needvalue_count instead!) + while (pass.undefined_count && (pass.undefined_count < undefs_before)) { + undefs_before = pass.undefined_count; if (config.process_verbosity > 1) puts("Further pass."); - undefined_curr = perform_pass(); + perform_pass(); } // any errors left? - if (undefined_curr == 0) { + if (pass.undefined_count == 0) { // FIXME - use pass.needvalue_count instead! // if listing report is wanted and there were no errors, // do another pass to generate listing report if (report_filename) { if (config.process_verbosity > 1) puts("Extra pass to generate listing report."); if (report_open(report, report_filename) == 0) { - ++pass_count; perform_pass(); report_close(report); } } - return 1; + return TRUE; } // There are still errors (unsolvable by doing further passes), // so perform additional pass to find and show them. @@ -322,9 +320,8 @@ static int do_actual_work(void) // activate error output ALU_optional_notdef_handler = Throw_error; - ++pass_count; perform_pass(); // perform pass, but now show "value undefined" - return 0; + return FALSE; } diff --git a/src/alu.c b/src/alu.c index a1cb79e..01fcf61 100644 --- a/src/alu.c +++ b/src/alu.c @@ -241,7 +241,7 @@ void (*ALU_optional_notdef_handler)(const char *) = NULL; // maybe split this into "_result_ is undefined" (in that case, count) and "symbol is undefined" (in that case, call handler) static void result_is_undefined(void) { - ++pass_undefined_count; + ++pass.undefined_count; if (ALU_optional_notdef_handler) ALU_optional_notdef_handler(value_not_defined()); } @@ -320,7 +320,7 @@ static intval_t my_asr(intval_t left, intval_t right) // if undefined, remember name for error output static void check_for_def(int flags, char optional_prefix_char, char *name, size_t length) { - if ((flags & NUMBER_IS_DEFINED) == 0) { + if (!(flags & NUMBER_IS_DEFINED)) { DYNABUF_CLEAR(undefsym_dyna_buf); if (optional_prefix_char) { DynaBuf_append(undefsym_dyna_buf, optional_prefix_char); @@ -351,7 +351,7 @@ static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t na // if needed, remember name for "undefined" error output check_for_def(symbol->result.flags, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length); // in first pass, count usage - if (pass_count == 0) + if (FIRST_PASS) symbol->usage++; // push operand, regardless of whether int or float operand_stack[operand_sp++] = symbol->result; @@ -573,6 +573,7 @@ static void parse_octal_value(void) // Now GotByte = "&" // Parse program counter ('*') +// FIXME - this function is similar to symbol lookup, so move it there static void parse_program_counter(void) // Now GotByte = "*" { struct number pc; @@ -1472,7 +1473,7 @@ static void parse_expression(struct expression *expression) result->flags &= ~(NUMBER_FORCES_16 | NUMBER_FORCES_8); else if (result->flags & NUMBER_FORCES_16) result->flags &= ~NUMBER_FORCES_8; - // if there was nothing to parse, mark as undefined + // if there was nothing to parse, mark as undefined FIXME - change this! make "nothing" its own result type; only numbers may be undefined // (so ALU_defined_int() can react) if (expression->is_empty) result->flags &= ~NUMBER_IS_DEFINED; @@ -1499,6 +1500,7 @@ static void parse_expression(struct expression *expression) } else { // State is STATE_ERROR. Errors have already been reported, // but we must make sure not to pass bogus data to caller. + // FIXME - just use the return value to indicate "there were errors, do not use result!" result->flags = 0; // maybe set DEFINED flag to suppress follow-up errors? result->val.intval = 0; result->addr_refs = 0; @@ -1514,8 +1516,7 @@ static void parse_expression(struct expression *expression) // Store int value if given. Returns whether stored. Throws error if undefined. // This function needs either a defined value or no expression at all. So // empty expressions are accepted, but undefined ones are not. -// If the result's "defined" flag is clear and the "exists" flag is set, it -// throws a serious error and therefore stops assembly. +// If the result is non-empty but undefined, a serious error is thrown, stopping assembly. // OPEN_PARENTHESIS: complain // EMPTY: allow // UNDEFINED: complain _seriously_ @@ -1527,8 +1528,8 @@ int ALU_optional_defined_int(intval_t *target) // ACCEPT_EMPTY parse_expression(&expression); if (expression.open_parentheses) Throw_error(exception_paren_open); - if ((expression.is_empty == FALSE) - && ((expression.number.flags & NUMBER_IS_DEFINED) == 0)) + if ((!expression.is_empty) + && (!(expression.number.flags & NUMBER_IS_DEFINED))) Throw_serious_error(value_not_defined()); if (expression.is_empty) return 0; @@ -1543,9 +1544,8 @@ int ALU_optional_defined_int(intval_t *target) // ACCEPT_EMPTY // Store int value and flags (floats are transformed to int) -// It the result's "exists" flag is clear (=empty expression), it throws an -// error. -// If the result's "defined" flag is clear, result_is_undefined() is called. +// For empty expressions, an error is thrown. +// For undefined results, result_is_undefined() is called. // OPEN_PARENTHESIS: complain // EMPTY: complain // UNDEFINED: allow @@ -1565,15 +1565,14 @@ void ALU_int_result(struct number *intresult) // ACCEPT_UNDEFINED } if (expression.is_empty) Throw_error(exception_no_value); - else if ((intresult->flags & NUMBER_IS_DEFINED) == 0) + else if (!(intresult->flags & NUMBER_IS_DEFINED)) result_is_undefined(); } -// return int value (if result is undefined, returns zero) -// If the result's "exists" flag is clear (=empty expression), it throws an -// error. -// If the result's "defined" flag is clear, result_is_undefined() is called. +// return int value (if undefined, return zero) +// For empty expressions, an error is thrown. +// For undefined results, result_is_undefined() is called. // OPEN_PARENTHESIS: complain // EMPTY: complain // UNDEFINED: allow @@ -1588,7 +1587,7 @@ intval_t ALU_any_int(void) // ACCEPT_UNDEFINED Throw_error(exception_paren_open); if (expression.is_empty) Throw_error(exception_no_value); - else if ((expression.number.flags & NUMBER_IS_DEFINED) == 0) + else if (!(expression.number.flags & NUMBER_IS_DEFINED)) result_is_undefined(); if (expression.number.flags & NUMBER_IS_FLOAT) return expression.number.val.fpval; @@ -1598,9 +1597,9 @@ intval_t ALU_any_int(void) // ACCEPT_UNDEFINED // stores int value and flags (floats are transformed to int) -// if result was undefined, serious error is thrown +// if result is empty or undefined, serious error is thrown // OPEN_PARENTHESIS: complain -// EMPTY: treat as UNDEFINED <= this is a problem - maybe use a wrapper fn for this use case? +// EMPTY: complain _seriously_ // UNDEFINED: complain _seriously_ // FLOAT: convert to int void ALU_defined_int(struct number *intresult) // no ACCEPT constants? @@ -1611,7 +1610,9 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants? *intresult = expression.number; if (expression.open_parentheses) Throw_error(exception_paren_open); - if ((intresult->flags & NUMBER_IS_DEFINED) == 0) + if (expression.is_empty) + Throw_serious_error(exception_no_value); + if (!(intresult->flags & NUMBER_IS_DEFINED)) Throw_serious_error(value_not_defined()); if (intresult->flags & NUMBER_IS_FLOAT) { intresult->val.intval = intresult->val.fpval; @@ -1623,8 +1624,7 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants? // Store int value and flags. // This function allows for one '(' too many. Needed when parsing indirect // addressing modes where internal indices have to be possible. -// If the result's "exists" flag is clear (=empty expression), it throws an -// error. +// For empty expressions, an error is thrown. // OPEN_PARENTHESIS: allow // UNDEFINED: allow // EMPTY: complain @@ -1645,15 +1645,13 @@ void ALU_liberal_int(struct expression *expression) // ACCEPT_UNDEFINED | ACCEPT } if (expression->is_empty) Throw_error(exception_no_value); - if ((expression->is_empty == FALSE) - && ((intresult->flags & NUMBER_IS_DEFINED) == 0)) + else if (!(intresult->flags & NUMBER_IS_DEFINED)) result_is_undefined(); } // Store value and flags (result may be either int or float) -// It the result's "exists" flag is clear (=empty expression), it throws an -// error. +// For empty expressions, an error is thrown. // If the result's "defined" flag is clear, result_is_undefined() is called. // OPEN_PARENTHESIS: complain // EMPTY: complain @@ -1669,10 +1667,12 @@ void ALU_any_result(struct number *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT Throw_error(exception_paren_open); if (expression.is_empty) Throw_error(exception_no_value); - else if ((result->flags & NUMBER_IS_DEFINED) == 0) + else if (!(result->flags & NUMBER_IS_DEFINED)) result_is_undefined(); } +// FIXME - find out where pass.needvalue_count must be incremented and do that! + /* TODO // stores int value and flags, allowing for one '(' too many (x-indirect addr). @@ -1694,12 +1694,12 @@ void ALU_int_result(struct number *intresult) // stores value and flags (result may be either int or float) void ALU_any_result(struct number *result) macro.c - macro call, when parsing call-by-value arg + macro call, when parsing call-by-value arg (FIXME: undefined does not mean needvalue!) pseudoopcodes.c - !set - when throwing user-specified errors + !set (FIXME: undefined does not mean needvalue!) + when throwing user-specified errors (FIXME: undefined does not mean needvalue!) symbol.c - explicit symbol definition + explicit symbol definition (FIXME: undefined does not mean needvalue!) // stores int value and flags (floats are transformed to int) // if result was undefined, serious error is thrown diff --git a/src/global.c b/src/global.c index 7bf0e18..5c1953e 100644 --- a/src/global.c +++ b/src/global.c @@ -109,15 +109,10 @@ const char global_byte_flags[256] = { // variables -int pass_count; // number of current pass (starts 0) char GotByte; // Last byte read (processed) -// global counters -int pass_undefined_count; // "NeedValue" type errors -int pass_real_errors; // Errors yet struct report *report = NULL; - -// configuration struct config config; +struct pass pass; // set configuration to default values void config_default(struct config *conf) @@ -371,7 +366,7 @@ void Throw_warning(const char *message) // Output a warning if in first pass. See above. void Throw_first_pass_warning(const char *message) { - if (pass_count == 0) + if (FIRST_PASS) Throw_warning(message); } @@ -388,8 +383,8 @@ void Throw_error(const char *message) throw_message(message, "\033[31mError\033[0m"); else throw_message(message, "Error"); - ++pass_real_errors; - if (pass_real_errors >= config.max_errors) + ++pass.error_count; + if (pass.error_count >= config.max_errors) exit(ACME_finalize(EXIT_FAILURE)); } diff --git a/src/global.h b/src/global.h index 5736c8c..2aea117 100644 --- a/src/global.h +++ b/src/global.h @@ -59,10 +59,7 @@ extern const char global_byte_flags[]; // bits 2, 1 and 0 are currently unused // TODO - put in runtime struct: -extern int pass_count; extern char GotByte; // Last byte read (processed) -extern int pass_undefined_count; // "NeedValue" type errors in current pass -extern int pass_real_errors; // Errors yet // configuration struct config { char pseudoop_prefix; // '!' or '.' @@ -80,6 +77,15 @@ struct config { }; extern struct config config; +struct pass { + int number; // counts up from zero + int undefined_count; // counts undefined expression results (if this stops decreasing, next pass must list them as errors) + //int needvalue_count; // counts undefined expression results actually needed for output (when this hits zero, we're done) FIXME - use + int error_count; +}; +extern struct pass pass; +#define FIRST_PASS (pass.number == 0) + // report stuff #define REPORT_ASCBUFSIZE 1024 #define REPORT_BINBUFSIZE 9 // eight are shown, then "..." diff --git a/src/macro.c b/src/macro.c index 5f05baf..bfa486b 100644 --- a/src/macro.c +++ b/src/macro.c @@ -323,7 +323,7 @@ void Macro_parse_call(void) // Now GotByte = dot or first char of macro name GetByte(); // skip '~' character Input_read_scope_and_keyword(&symbol_scope); if ((Tree_hard_scan(&symbol_node, symbols_forest, symbol_scope, TRUE) == FALSE) - && (pass_count == 0)) + && (FIRST_PASS)) Throw_error("Macro parameter twice."); symbol_node->body = arg_table[arg_count].symbol; } else { diff --git a/src/output.c b/src/output.c index 7d7bd0a..bc14d22 100644 --- a/src/output.c +++ b/src/output.c @@ -118,7 +118,7 @@ static void border_crossed(int current_offset) { if (current_offset >= OUTBUFFERSIZE) Throw_serious_error("Produced too much code."); - if (pass_count == 0) { + if (FIRST_PASS) { // TODO: make warn/err an arg for a general "Throw" function if (config.segment_warning_is_error) Throw_error("Segment reached another one, overwriting it."); @@ -303,8 +303,10 @@ int output_initmem(char content) // init memory fill_completely(content); // enforce another pass - if (pass_undefined_count == 0) - pass_undefined_count = 1; + if (pass.undefined_count == 0) + pass.undefined_count = 1; + //if (pass.needvalue_count == 0) FIXME - use? instead or additionally? + // pass.needvalue_count = 1; // FIXME - enforcing another pass is not needed if there hasn't been any // output yet. But that's tricky to detect without too much overhead. // The old solution was to add &&(out->lowest_written < out->highest_written+1) to "if" above @@ -506,7 +508,7 @@ void Output_end_segment(void) intval_t amount; // in later passes, ignore completely - if (pass_count) + if (!FIRST_PASS) return; // if there is no segment, there is nothing to do @@ -546,7 +548,7 @@ void Output_start_segment(intval_t address_change, int segment_flags) // allow writing to output buffer Output_byte = real_output; // in first pass, check for other segments and maybe issue warning - if (pass_count == 0) { + if (FIRST_PASS) { if (!(segment_flags & SEGMENT_FLAG_OVERLAY)) check_segment(out->segment.start); find_segment_max(out->segment.start); diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index 4b2b476..5e34bc1 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -82,7 +82,7 @@ static enum eos po_initmem(void) struct number intresult; // ignore in all passes but in first - if (pass_count) + if (!FIRST_PASS) return SKIP_REMAINDER; // get value @@ -129,7 +129,7 @@ static enum eos po_to(void) return SKIP_REMAINDER; // only act upon this pseudo opcode in first pass - if (pass_count) + if (!FIRST_PASS) return SKIP_REMAINDER; if (outputfile_set_filename()) @@ -442,7 +442,8 @@ static enum eos po_binary(void) // check whether including is a waste of time // FIXME - future changes ("several-projects-at-once") // may be incompatible with this! - if ((size >= 0) && (pass_undefined_count || pass_real_errors)) { + if ((size >= 0) && (pass.undefined_count || pass.error_count)) { + //if ((size >= 0) && (pass.needvalue_count || pass.error_count)) { FIXME - use! output_skip(size); // really including is useless anyway } else { // really insert file @@ -466,7 +467,7 @@ static enum eos po_binary(void) } fclose(stream); // if verbose, produce some output - if ((pass_count == 0) && (config.process_verbosity > 1)) { + if (FIRST_PASS && (config.process_verbosity > 1)) { int amount = vcpu_get_statement_size(); printf("Loaded %d (0x%04x) bytes from file offset %ld (0x%04lx).\n", @@ -707,7 +708,7 @@ static enum eos po_symbollist(void) return SKIP_REMAINDER; // only process this pseudo opcode in first pass - if (pass_count) + if (!FIRST_PASS) return SKIP_REMAINDER; // if symbol list file name already set, complain and exit @@ -838,7 +839,7 @@ static enum eos ifdef_ifndef(int is_ifndef) // now GotByte = illegal char if (node) { symbol = (struct symbol *) node->body; // in first pass, count usage - if (pass_count == 0) + if (FIRST_PASS) symbol->usage++; if (symbol->result.flags & NUMBER_IS_DEFINED) defined = TRUE; @@ -976,7 +977,7 @@ Throw_serious_error("Not yet"); // FIXME static enum eos po_macro(void) // now GotByte = illegal char { // in first pass, parse. In all other passes, skip. - if (pass_count == 0) { + if (FIRST_PASS) { Macro_parse_definition(); // now GotByte = '}' } else { // skip until CHAR_SOB ('{') is found. diff --git a/src/symbol.c b/src/symbol.c index 37bff07..da7a44e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -120,7 +120,7 @@ struct symbol *symbol_find(scope_t scope, int flags) else symbol->result.val.intval = 0; symbol->usage = 0; // usage count - symbol->pass = pass_count; + symbol->pass = pass.number; node->body = symbol; } else { symbol = node->body; @@ -264,8 +264,8 @@ void symbol_fix_forward_anon_name(int increment) DynaBuf_append(GlobalDynaBuf, '\0'); counter_symbol = symbol_find(section_now->local_scope, 0); // make sure it gets reset to zero in each new pass - if (counter_symbol->pass != pass_count) { - counter_symbol->pass = pass_count; + if (counter_symbol->pass != pass.number) { + counter_symbol->pass = pass.number; counter_symbol->result.val.intval = 0; } number = (unsigned long) counter_symbol->result.val.intval; diff --git a/src/version.h b/src/version.h index 13a5431..7ee6eeb 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ #define RELEASE "0.96.5" // update before release FIXME #define CODENAME "Fenchurch" // update before release -#define CHANGE_DATE "1 May" // update before release FIXME +#define CHANGE_DATE "2 May" // update before release FIXME #define CHANGE_YEAR "2020" // update before release //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME