From 10af90860d054f658abe33f10d374075389dc184 Mon Sep 17 00:00:00 2001 From: marcobaye Date: Sat, 10 Feb 2024 17:21:54 +0000 Subject: [PATCH] added "--strict" and "!nowarn" git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@333 4df02467-bbd4-4a76-a152-e7ce94205b78 --- src/acme.c | 4 ++ src/global.c | 117 +++++++++++++++++++++++++++++++------------- src/global.h | 19 ++++++- src/macro.c | 7 ++- src/pseudoopcodes.c | 62 +++++++++++++---------- src/typesystem.c | 28 +---------- src/typesystem.h | 9 ---- src/version.h | 2 +- 8 files changed, 147 insertions(+), 101 deletions(-) diff --git a/src/acme.c b/src/acme.c index d2fe0f2..ae63ddc 100644 --- a/src/acme.c +++ b/src/acme.c @@ -65,6 +65,7 @@ static const char arg_vicelabels[] = "VICE labels filename"; #define OPTION_FULLSTOP "fullstop" #define OPTION_IGNORE_ZEROES "ignore-zeroes" #define OPTION_STRICT_SEGMENTS "strict-segments" +#define OPTION_STRICT "strict" #define OPTION_DIALECT "dialect" #define OPTION_DEBUGLEVEL "debuglevel" #define OPTION_TEST "test" @@ -137,6 +138,7 @@ static void show_help_and_exit(void) " --" OPTION_MAXDEPTH " NUMBER set recursion depth for macro calls and !src\n" " --" OPTION_IGNORE_ZEROES " do not determine number size by leading zeroes\n" " --" OPTION_STRICT_SEGMENTS " turn segment overlap warnings into errors\n" +" --" OPTION_STRICT " treat all warnings like errors\n" " -vDIGIT set verbosity level\n" " -DSYMBOL=VALUE define global symbol\n" " -I PATH/TO/DIR add search path for input files\n" @@ -552,6 +554,8 @@ static const char *long_option(const char *string) config.honor_leading_zeroes = FALSE; else if (strcmp(string, OPTION_STRICT_SEGMENTS) == 0) config.segment_warning_is_error = TRUE; + else if (strcmp(string, OPTION_STRICT) == 0) + config.all_warnings_are_errors = TRUE; else if (strcmp(string, OPTION_DIALECT) == 0) set_dialect(cliargs_get_next()); // NULL is ok (handled like unknown) else if (strcmp(string, OPTION_DEBUGLEVEL) == 0) diff --git a/src/global.c b/src/global.c index a5ea1f4..e095a32 100644 --- a/src/global.c +++ b/src/global.c @@ -118,6 +118,7 @@ void config_default(struct config *conf) conf->msg_stream = stderr; // set to stdout by --use-stdout conf->honor_leading_zeroes = TRUE; // disabled by --ignore-zeroes conf->segment_warning_is_error = FALSE; // enabled by --strict-segments TODO - toggle default? + conf->all_warnings_are_errors = FALSE; // enabled by --strict conf->test_new_features = FALSE; // enabled by --test conf->wanted_version = VER_CURRENT; // changed by --dialect conf->debuglevel = DEBUGLEVEL_DEBUG; // changed by --debuglevel, used by "!debug" @@ -139,15 +140,56 @@ void *safe_malloc(size_t size) // Parser stuff -// Check and return whether first label of statement. Complain if not. -static int first_label_of_statement(bits *statement_flags) +static boolean in_addr_block = FALSE; +static boolean in_nowarn_block = FALSE; + +// set new value for "we are in !addr block" flag, +// return old value +// (called by "!addr { }") +boolean parser_change_addr_block_flag(boolean new_value) { - if ((*statement_flags) & SF_IMPLIED_LABEL) { + boolean old_value = in_addr_block; + + in_addr_block = new_value; + return old_value; +} +// set new value for "we are in !nowarn block" flag, +// return old value +// (called by "!nowarn { }") +boolean parser_change_nowarn_block_flag(boolean new_value) +{ + boolean old_value = in_nowarn_block; + + in_nowarn_block = new_value; + return old_value; +} + +#define SF_FOUND_BLANK (1u << 0) // statement had space or tab +#define SF_IMPLIED_LABEL (1u << 1) // statement had implied label def +#define SF_ADDR_PREFIX (1u << 2) // explicit symbol definition is an address +#define SF_NOWARN_PREFIX (1u << 3) // suppress warnings for this statement +static bits statement_flags; + +// called by "!addr" pseudo op if used without block +extern void parser_set_addr_prefix(void) +{ + statement_flags |= SF_ADDR_PREFIX; +} +// called by "!nowarn" pseudo op if used without block +extern void parser_set_nowarn_prefix(void) +{ + statement_flags |= SF_NOWARN_PREFIX; +} + +// Check and return whether first label of statement. Complain if not. +static int first_label_of_statement(void) +{ + if (statement_flags & SF_IMPLIED_LABEL) { Throw_error(exception_syntax); input_skip_remainder(); return FALSE; } - (*statement_flags) |= SF_IMPLIED_LABEL; // now there has been one + statement_flags |= SF_IMPLIED_LABEL; // now there has been one return TRUE; } @@ -156,13 +198,13 @@ static int first_label_of_statement(bits *statement_flags) // name must be held in GlobalDynaBuf. // called by parse_symbol_definition, parse_backward_anon_def, parse_forward_anon_def // "powers" is used by backward anons to allow changes -static void set_label(scope_t scope, bits stat_flags, bits force_bit, bits powers) +static void set_label(scope_t scope, bits force_bit, bits powers) { struct symbol *symbol; struct number pc; struct object result; - if ((stat_flags & SF_FOUND_BLANK) && config.warn_on_indented_labels) + if ((statement_flags & SF_FOUND_BLANK) && config.warn_on_indented_labels) Throw_first_pass_warning("Label name not in leftmost column."); symbol = symbol_find(scope); vcpu_read_pc(&pc); // FIXME - if undefined, check pass.complain_about_undefined and maybe throw "value not defined"! @@ -182,6 +224,7 @@ static void set_label(scope_t scope, bits stat_flags, bits force_bit, bits power // call with symbol name in GlobalDynaBuf and GotByte == '=' +// fn is exported so "!set" pseudo opcode can call it. // "powers" is for "!set" pseudo opcode so changes are allowed (see symbol.h for powers) void parse_assignment(scope_t scope, bits force_bit, bits powers) { @@ -192,7 +235,7 @@ void parse_assignment(scope_t scope, bits force_bit, bits powers) symbol = symbol_find(scope); ALU_any_result(&result); // if wanted, mark as address reference - if (typesystem_says_address()) { + if (in_addr_block || (statement_flags & SF_ADDR_PREFIX)) { // FIXME - checking types explicitly is ugly... if (result.type == &type_number) result.u.number.addr_refs = 1; @@ -205,7 +248,7 @@ void parse_assignment(scope_t scope, bits force_bit, bits powers) // parse symbol definition (can be either global or local, may turn out to be a label). // name must be held in GlobalDynaBuf. -static void parse_symbol_definition(scope_t scope, bits stat_flags) +static void parse_symbol_definition(scope_t scope) { bits force_bit; @@ -219,48 +262,48 @@ static void parse_symbol_definition(scope_t scope, bits stat_flags) input_ensure_EOS(); } else { // implicit symbol definition (label) - set_label(scope, stat_flags, force_bit, POWER_NONE); + set_label(scope, force_bit, POWER_NONE); } } // Parse global symbol definition or assembler mnemonic -static void parse_mnemo_or_global_symbol_def(bits *statement_flags) +static void parse_mnemo_or_global_symbol_def(void) { boolean is_mnemonic; is_mnemonic = CPU_state.type->keyword_is_mnemonic(input_read_keyword()); // It is only a label if it isn't a mnemonic if ((!is_mnemonic) - && first_label_of_statement(statement_flags)) { + && first_label_of_statement()) { // Now GotByte = illegal char // 04 Jun 2005: this fix should help to explain "strange" error messages. // 17 May 2014: now it works for UTF-8 as well. if ((*GLOBALDYNABUF_CURRENT == (char) 0xa0) || ((GlobalDynaBuf->size >= 2) && (GLOBALDYNABUF_CURRENT[0] == (char) 0xc2) && (GLOBALDYNABUF_CURRENT[1] == (char) 0xa0))) Throw_first_pass_warning("Label name starts with a shift-space character."); - parse_symbol_definition(SCOPE_GLOBAL, *statement_flags); + parse_symbol_definition(SCOPE_GLOBAL); } } // parse (cheap) local symbol definition -static void parse_local_symbol_def(bits *statement_flags) +static void parse_local_symbol_def(void) { scope_t scope; - if (!first_label_of_statement(statement_flags)) + if (!first_label_of_statement()) return; if (input_read_scope_and_symbol_name(&scope) == 0) - parse_symbol_definition(scope, *statement_flags); + parse_symbol_definition(scope); } // parse anonymous backward label definition. Called with GotByte == '-' -static void parse_backward_anon_def(bits *statement_flags) +static void parse_backward_anon_def(void) { - if (!first_label_of_statement(statement_flags)) + if (!first_label_of_statement()) return; dynabuf_clear(GlobalDynaBuf); @@ -269,14 +312,14 @@ static void parse_backward_anon_def(bits *statement_flags) } while (GetByte() == '-'); dynabuf_append(GlobalDynaBuf, '\0'); // backward anons change their value! - set_label(section_now->local_scope, *statement_flags, NO_FORCE_BIT, POWER_CHANGE_VALUE); + set_label(section_now->local_scope, NO_FORCE_BIT, POWER_CHANGE_VALUE); } // parse anonymous forward label definition. called with GotByte == ? -static void parse_forward_anon_def(bits *statement_flags) +static void parse_forward_anon_def(void) { - if (!first_label_of_statement(statement_flags)) + if (!first_label_of_statement()) return; dynabuf_clear(GlobalDynaBuf); @@ -288,7 +331,7 @@ static void parse_forward_anon_def(bits *statement_flags) symbol_fix_forward_anon_name(TRUE); // TRUE: increment counter dynabuf_append(GlobalDynaBuf, '\0'); //printf("[%d, %s]\n", section_now->local_scope, GlobalDynaBuf->buffer); - set_label(section_now->local_scope, *statement_flags, NO_FORCE_BIT, POWER_NONE); + set_label(section_now->local_scope, NO_FORCE_BIT, POWER_NONE); } @@ -297,20 +340,17 @@ static void parse_forward_anon_def(bits *statement_flags) // Has to be re-entrant. void parse_until_eob_or_eof(void) { - bits statement_flags; - -// // start with next byte, don't care about spaces -// NEXTANDSKIPSPACE(); // start with next byte + // (don't SKIPSPACE() here, we want to warn about "label not in leftmost column"!) GetByte(); // loop until end of block or end of file while ((GotByte != CHAR_EOB) && (GotByte != CHAR_EOF)) { // process one statement - statement_flags = 0; // no "label = pc" definition yet - typesystem_force_address_statement(FALSE); - // Parse until end of statement. Only loops if statement - // contains implicit label definition (=pc) and something else; or - // if "!ifdef/ifndef" is true/false, or if "!addr" is used without block. + statement_flags = 0; // no spaces, no labels, no !addr, no !nowarn + // Parse until end of statement. Only loops in these cases: + // - statement contains label and something else + // - "!ifdef"/"!ifndef" is used without block + // - "!addr"/"!nowarn" is used without block do { // check for pseudo opcodes was moved out of switch, // because prefix character is now configurable. @@ -329,7 +369,7 @@ void parse_until_eob_or_eof(void) GetByte(); // skip break; case '-': - parse_backward_anon_def(&statement_flags); + parse_backward_anon_def(); break; case '+': GetByte(); @@ -338,18 +378,18 @@ void parse_until_eob_or_eof(void) || (BYTE_CONTINUES_KEYWORD(GotByte))) macro_parse_call(); else - parse_forward_anon_def(&statement_flags); + parse_forward_anon_def(); break; case '*': notreallypo_setpc(); // define program counter (fn is in pseudoopcodes.c) break; case LOCAL_PREFIX: case CHEAP_PREFIX: - parse_local_symbol_def(&statement_flags); + parse_local_symbol_def(); break; default: if (BYTE_STARTS_KEYWORD(GotByte)) { - parse_mnemo_or_global_symbol_def(&statement_flags); + parse_mnemo_or_global_symbol_def(); } else { Throw_error(exception_syntax); input_skip_remainder(); @@ -433,9 +473,18 @@ void throw_message(enum debuglevel level, const char msg[]) case DEBUGLEVEL_WARNING: // output a warning // (something looks wrong, like "label name starts with shift-space character") + // first check if warnings should be suppressed right now: + if (in_nowarn_block || (statement_flags & SF_NOWARN_PREFIX)) + break; PLATFORM_WARNING(msg); throw_msg(msg, "\033[33m", "Warning"); // yellow ++pass.warning_count; + // then check if warnings should be handled like errors: + if (config.all_warnings_are_errors) { + ++pass.error_count; + if (pass.error_count >= config.max_errors) + exit(ACME_finalize(EXIT_FAILURE)); + } break; case DEBUGLEVEL_INFO: throw_msg(msg, "\033[32m", "Info"); // green diff --git a/src/global.h b/src/global.h index 40d0e05..daa8314 100644 --- a/src/global.h +++ b/src/global.h @@ -19,8 +19,6 @@ // Constants -#define SF_FOUND_BLANK (1u << 0) // statement had space or tab -#define SF_IMPLIED_LABEL (1u << 1) // statement had implied label def extern char s_untitled[]; // error messages during assembly extern const char exception_missing_string[]; @@ -75,6 +73,7 @@ struct config { FILE *msg_stream; // defaults to stderr, changed to stdout by --use-stdout boolean honor_leading_zeroes; // TRUE, disabled by --ignore-zeroes boolean segment_warning_is_error; // FALSE, enabled by --strict-segments + boolean all_warnings_are_errors; // FALSE, enabled by --strict boolean test_new_features; // FALSE, enabled by --test enum version wanted_version; // set by --dialect (and --test --test) signed long debuglevel; // set by --debuglevel, used by "!debug" @@ -127,6 +126,22 @@ extern void config_default(struct config *conf); // allocate memory and die if not available extern void *safe_malloc(size_t amount); +// set new value for "we are in !addr block" flag, +// return old value +// (called by "!addr { }") +extern boolean parser_change_addr_block_flag(boolean new_value); + +// set new value for "we are in !nowarn block" flag, +// return old value +// (called by "!nowarn { }") +extern boolean parser_change_nowarn_block_flag(boolean new_value); + +// called by "!addr" pseudo op if used without block +extern void parser_set_addr_prefix(void); + +// called by "!nowarn" pseudo op if used without block +extern void parser_set_nowarn_prefix(void); + // call with symbol name in GlobalDynaBuf and GotByte == '=' // "powers" is for "!set" pseudo opcode so changes are allowed (see symbol.h for powers) extern void parse_assignment(scope_t scope, bits force_bit, bits powers); diff --git a/src/macro.c b/src/macro.c index af9476e..8291b93 100644 --- a/src/macro.c +++ b/src/macro.c @@ -340,8 +340,11 @@ void macro_parse_call(void) // Now GotByte = first char of macro name GotByte = local_gotbyte; // CAUTION - ugly kluge // if needed, dump call stack - if (outer_msg_sum != pass.warning_count + pass.error_count) - Throw_warning("...called from here."); // FIXME - change to "info"! + if (outer_msg_sum != pass.warning_count + pass.error_count) { + Throw_warning("...called from here."); + // FIXME - use this instead: + //throw_message(DEBUGLEVEL_INFO, "...called from here."); + } input_ensure_EOS(); } diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index c419193..c71fd82 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -717,19 +717,6 @@ static enum eos po_rs(void) } -// force explicit label definitions to set "address" flag ("!addr"). Has to be re-entrant. -static enum eos po_address(void) // now GotByte = illegal char -{ - SKIPSPACE(); - if (GotByte == CHAR_SOB) { - typesystem_force_address_block(); - return ENSURE_EOS; - } - typesystem_force_address_statement(TRUE); - return PARSE_REMAINDER; -} - - #if 0 // enumerate constants ("!enum") static enum eos po_enum(void) // now GotByte = illegal char @@ -1253,23 +1240,46 @@ static enum eos po_watch(void) } */ -/* // disable warnings for a statement or block of code -static enum eos po_nowarn(void) +// force explicit symbol definitions to set "address" flag. +// if this is used without a block, it is only a prefix for a single statement. +// has to be re-entrant. +static enum eos po_address(void) // now GotByte = illegal char { - boolean flag_buf = global_inhibit_warnings; + boolean buf; - global_inhibit_warnings = TRUE; - // if there's a block, parse it and then restore old value + buf = parser_change_addr_block_flag(TRUE); if (parse_optional_block()) { - global_inhibit_warnings = flag_buf; + // when used with a block, is used throughout the block + parser_change_addr_block_flag(buf); // restore after block return ENSURE_EOS; } else { - return PARSE_REMAINDER; - TODO: restore previous state after the current statement, - do it like "!address" does it! + // without a block, it's only a "prefix" for the current statement + parser_change_addr_block_flag(buf); // there was no block, so restore... + parser_set_addr_prefix(); // ...and set flag... + return PARSE_REMAINDER; // ...just for this statement. + } +} + + +// disable warnings. +// if this is used without a block, it is only a prefix for a single statement. +// has to be re-entrant. +static enum eos po_nowarn(void) // now GotByte = illegal char +{ + boolean buf; + + buf = parser_change_nowarn_block_flag(TRUE); + if (parse_optional_block()) { + // when used with a block, is used throughout the block + parser_change_nowarn_block_flag(buf); // restore after block + return ENSURE_EOS; + } else { + // without a block, it's only a "prefix" for the current statement + parser_change_nowarn_block_flag(buf); // there was no block, so restore... + parser_set_nowarn_prefix(); // ...and set flag... + return PARSE_REMAINDER; // ...just for this statement. } } -*/ // variables @@ -1405,8 +1415,6 @@ static struct ronode pseudo_opcode_tree[] = { PREDEFNODE("as", po_as), PREDEFNODE("rl", po_rl), PREDEFNODE("rs", po_rs), - PREDEFNODE("addr", po_address), - PREDEFNODE("address", po_address), // PREDEFNODE("enum", po_enum), PREDEFNODE("set", po_set), PREDEFNODE("sl", po_symbollist), @@ -1426,7 +1434,9 @@ static struct ronode pseudo_opcode_tree[] = { PREDEFNODE("macro", po_macro), /* PREDEFNODE("trace", po_trace), PREDEFNODE("watch", po_watch), */ -// PREDEFNODE("nowarn", po_nowarn), + PREDEFNODE("addr", po_address), + PREDEFNODE("address", po_address), + PREDEFNODE("nowarn", po_nowarn), PREDEFNODE("debug", po_debug), PREDEFNODE("info", po_info), PREDEFNODE("warn", po_warn), diff --git a/src/typesystem.c b/src/typesystem.c index 6510886..49536f9 100644 --- a/src/typesystem.c +++ b/src/typesystem.c @@ -4,38 +4,11 @@ // // type system stuff #include "typesystem.h" -#include "config.h" -#include "alu.h" #include "global.h" -static boolean in_address_block = FALSE; -static boolean in_address_statement = FALSE; - // Functions -// return whether explicit symbol definitions should force "address" mode -boolean typesystem_says_address(void) -{ - return in_address_block || in_address_statement; -} - -// parse a block while forcing address mode -void typesystem_force_address_block(void) -{ - boolean buffer = in_address_block; - - in_address_block = TRUE; - parse_optional_block(); - in_address_block = buffer; -} - -// force address mode on or off for the next statement -void typesystem_force_address_statement(boolean value) -{ - in_address_statement = value; -} - // warn if result is not integer void typesystem_want_nonaddr(struct number *result) { @@ -50,6 +23,7 @@ void typesystem_want_nonaddr(struct number *result) //printf("refcount should be 0, but is %d\n", result->addr_refs); } } + // warn if result is not address void typesystem_want_addr(struct number *result) { diff --git a/src/typesystem.h b/src/typesystem.h index d50f456..4274ea7 100644 --- a/src/typesystem.h +++ b/src/typesystem.h @@ -10,15 +10,6 @@ #include "config.h" -// return whether explicit symbol definitions should force "address" mode -extern boolean typesystem_says_address(void); - -// parse a block while forcing address mode -extern void typesystem_force_address_block(void); - -// force address mode on or off for the next statement -extern void typesystem_force_address_statement(boolean value); - // warn if result is not integer extern void typesystem_want_nonaddr(struct number *result); diff --git a/src/version.h b/src/version.h index 94987de..bf30999 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 "9 Feb" // update before release FIXME +#define CHANGE_DATE "10 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