From 43759e60267b709bdd87e3351f727278e9d2355c Mon Sep 17 00:00:00 2001 From: marcobaye Date: Mon, 25 Mar 2024 00:51:11 +0000 Subject: [PATCH] cleaned up error messages git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@372 4df02467-bbd4-4a76-a152-e7ce94205b78 --- docs/Errors.txt | 72 +++++++++++++++++++++++++++------------------ src/alu.c | 6 ++-- src/flow.c | 4 +-- src/global.c | 12 ++++---- src/global.h | 2 +- src/input.c | 22 ++++++++++++-- src/input.h | 5 ++++ src/macro.c | 5 +--- src/mnemo.c | 27 +++++++---------- src/pseudoopcodes.c | 51 +++++++++++++------------------- src/version.h | 2 +- 11 files changed, 113 insertions(+), 95 deletions(-) diff --git a/docs/Errors.txt b/docs/Errors.txt index 6a3cfb2..c7e0c13 100644 --- a/docs/Errors.txt +++ b/docs/Errors.txt @@ -192,7 +192,7 @@ Section: Errors during assembly it, you can use the "--dialect" CLI switch to make ACME mimic an older version. -"!pseudopc/!realpc" is obsolete; use "!pseudopc {}" instead. +"!pseudopc/!realpc" are obsolete; use "!pseudopc {}" instead. This is given when one of the now obsolete !pseudopc/!realpc pseudo opcodes is encountered. If you want to assemble an old source code without first updating @@ -210,10 +210,6 @@ Section: Errors during assembly This is given when the pseudo opcode "!error" is executed. The actual message varies according to the pseudo opcode's arguments. -After ELSE, expected block or IF/IFDEF/IFNDEF. - There is something strange after ELSE: It must be "if", "ifdef", - "ifndef" or an opening brace. - Argument out of range. You called arcsin/arccos with something not in the [-1, 1] range. @@ -241,13 +237,40 @@ CPU does not support this postfix for this mnemonic. Division by zero. Guess what - you attempted to divide by zero. -Expected ELSE or end-of-statement. - There is something after the closing brace of an IF block that is - not an ELSE. +Expected '{' or IF/IFDEF/IFNDEF keyword after ELSE keyword. + There is something strange after ELSE: It must be "if", "ifdef", + "ifndef" or an opening brace. + +Expected ',' or IN keyword after loop variable. + You made a syntax error when using "!for": After the loop variable + there can either be a comma (for a simple counting loop) or the + "in" keyword (when iterating over string or list contents). + Anything else will give this error. Expected end-of-statement after ELSE block. There is something after the closing brace of an ELSE block. +Expected end-of-statement or ELSE keyword after '}'. + There is something after the closing brace of an IF block that is + not an ELSE. + +Expected end-of-statement, found 'CHAR' instead. + There are still arguments when there should not be any more. The + given character is the one where end-of-line was expected. + +Expected EOF, found '}' instead. + ACME encountered a '}' character when it expected the file to end + instead (because no blocks were open). + +Expected WHILE or UNTIL keyword, or an empty loop condition. + When using "!do", loop conditions are optional before and after + the block, but if one is given, it has to start with "while" or + "until". + +Expected index register after comma. + You used an addressing mode with a comma but did not supply a + valid index register (like 'x') after it. + Exponent is negative. Using negative exponents only give sensible results when using floating point maths. @@ -270,14 +293,6 @@ Force bits can only be given to numbers. You tried to give a force bit to a symbol and then assign a string or list to it. -Found '}' instead of end-of-file. - ACME encountered a '}' character when it expected the file to end - instead (because no blocks were open). - -Garbage data at end of statement (unexpected 'CHAR'). - There are still arguments when there should not be any more. The - given character is the one where end-of-line was expected. - Given object is not iterable. You used "!for VAR in ITERABLE", but the iterable was neither a string nor a list (likely a number). @@ -295,12 +310,6 @@ Index is undefined. Index out of range. The value for an indexing operation wasn't in the allowed range. -Loop var must be followed by either "in" keyword or comma. - You made a syntax error when using "!for": After the loop counter - symbol there can either be a comma (for a simple counting loop) or - the "in" keyword (when iterating over string or list contents). - Anything else will give this error. - Macro already defined. Macros can only be defined once. If you define a macro twice, ACME will help you find the definitions by giving a warning for the @@ -328,6 +337,7 @@ Negative value - cannot choose addressing mode. No string given. ACME expects a string but doesn't find it, or the string is empty. + This can also mean keywords or symbol names. Number does not fit in N bits. Number out of range. @@ -414,6 +424,9 @@ Unknown encoding. Unknown function. You used a mathematical function ACME does not know. +Unknown mnemonic. + You mistyped a mnemonic, or you forgot to select the correct cpu. + Unknown operator. You used an arithmetic/logical operator ACME does not know. @@ -458,7 +471,12 @@ Section: Serious errors (stopping assembly) This is given when the pseudo opcode "!serious" is executed. The actual message varies according to the pseudo opcode's arguments. -Found end-of-file instead of '}'. +Expected '{' character. + ACME didn't find the expected '{' character. Remember that '{' + characters must be given on the same line as the keyword they + belong to. + +Expected '}', found EOF instead. The file ended when ACME expected the block to be closed instead (because there was at least one block left open). @@ -467,11 +485,6 @@ Loop count is negative. (getting this error is only possible when using the now deprecated syntax). -Missing '{'. - ACME didn't find the expected '{' character. Remember that '{' - characters must be given on the same line as the keyword they - belong to. - Out of memory. When ACME runs out of memory, it stops assembly, giving this error. Free some memory and try again. It's highly unlikely anyone @@ -497,6 +510,9 @@ Too deeply nested. Recursive "!source"? The default limit is 64, this can be changed using the "--maxdepth" CLI switch. +Unexpected char when evaluating loop condition. + There was a syntax error while evaluating the loop condition. + Value not defined. A value could not be worked out. Maybe you mistyped a symbol name. Whether this is given as a "normal" or as a serious error depends diff --git a/src/alu.c b/src/alu.c index 0431c28..6c2964a 100644 --- a/src/alu.c +++ b/src/alu.c @@ -1160,12 +1160,12 @@ static void expect_dyadic_operator(struct expression *expression) // Multi-character dyadic operators case '!': // "!=" - if (GetByte() == '=') { + GetByte(); // eat '!' + if (input_expect('=')) { op = &ops_not_equal; - goto get_byte_and_push_dyadic; + goto push_dyadic_op; } - Throw_error(exception_syntax); alu_state = STATE_ERROR; break;//goto end; case '<': // "<", "<=", "<<" and "<>" diff --git a/src/flow.c b/src/flow.c index fd252bd..0fc30cc 100644 --- a/src/flow.c +++ b/src/flow.c @@ -193,7 +193,7 @@ void flow_store_doloop_condition(struct condition *condition, char terminator) } else if (strcmp(GlobalDynaBuf->buffer, "until") == 0) { condition->invert = TRUE; } else { - Throw_error(exception_syntax); + Throw_error("Expected WHILE or UNTIL keyword, or an empty loop condition."); return; } // write given condition into buffer @@ -228,7 +228,7 @@ static boolean check_condition(struct condition *condition) GetByte(); // proceed with next char ALU_defined_int(&intresult); if (GotByte) - Throw_serious_error(exception_syntax); + Throw_serious_error("Unexpected char when evaluating loop condition."); // FIXME - include that char in the error message! return condition->invert ? !intresult.val.intval : !!intresult.val.intval; } diff --git a/src/global.c b/src/global.c index e0488f1..56bcb14 100644 --- a/src/global.c +++ b/src/global.c @@ -35,9 +35,9 @@ char s_untitled[] = ""; // FIXME - this is actually const // Exception messages during assembly const char exception_missing_string[] = "No string given."; const char exception_negative_size[] = "Negative size argument."; -const char exception_no_left_brace[] = "Missing '{' character."; +const char exception_no_left_brace [] = "Expected '{' character."; const char exception_no_memory_left[] = "Out of memory."; -const char exception_no_right_brace[] = "Found end-of-file instead of '}'."; +const char exception_no_right_brace [] = "Expected '}', found EOF instead."; //const char exception_not_yet[] = "Sorry, feature not yet implemented."; // TODO - show actual value in error message const char exception_number_out_of_range[] = "Number out of range."; @@ -198,7 +198,7 @@ extern void parser_set_nowarn_prefix(void) static int first_symbol_of_statement(void) { if (statement_flags & SF_FOUND_SYMBOL) { - Throw_error(exception_syntax); + Throw_error("Unknown mnemonic"); input_skip_remainder(); return FALSE; } @@ -232,7 +232,7 @@ static void set_label(scope_t scope, bits force_bit, bits powers) } -// call with symbol name in GlobalDynaBuf and GotByte == '=' +// call with symbol name in GlobalDynaBuf and '=' already eaten. // 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) @@ -240,7 +240,6 @@ void parse_assignment(scope_t scope, bits force_bit, bits powers) struct symbol *symbol; struct object result; - GetByte(); // eat '=' symbol = symbol_find(scope); ALU_any_result(&result); // if wanted, mark as address reference @@ -267,6 +266,7 @@ static void parse_symbol_definition(scope_t scope) force_bit = input_get_force_bit(); // skips spaces after (yes, force bit is allowed for label definitions) if (GotByte == '=') { // explicit symbol definition (symbol = ) + GetByte(); // eat '=' parse_assignment(scope, force_bit, POWER_NONE); input_ensure_EOS(); } else { @@ -403,7 +403,7 @@ void parse_until_eob_or_eof(void) if (BYTE_STARTS_KEYWORD(GotByte)) { parse_mnemo_or_global_symbol_def(); } else { - Throw_error(exception_syntax); + Throw_error(exception_syntax); // FIXME - include char in error message! input_skip_remainder(); } } diff --git a/src/global.h b/src/global.h index 7ec8558..ceac4f3 100644 --- a/src/global.h +++ b/src/global.h @@ -179,7 +179,7 @@ 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 == '=' +// call with symbol name in GlobalDynaBuf and '=' already eaten. // "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/input.c b/src/input.c index c30f1df..49ba59c 100644 --- a/src/input.c +++ b/src/input.c @@ -72,7 +72,7 @@ void input_parse_and_close_platform_file(const char *eternal_plat_filename, FILE // parse block and check end reason parse_until_eob_or_eof(); if (GotByte != CHAR_EOF) - Throw_error("Found '}' instead of end-of-file."); + Throw_error("Expected EOF, found '}' instead." ); // close sublevel src // (this looks like we could just use "fd" as arg, but maybe the file // has been replaced with a different one in the meantime...) @@ -232,7 +232,7 @@ static char get_processed_from_file(void) default: // complain if byte is 0 - Throw_error("Source file contains illegal character."); + Throw_error("Source file contains illegal character."); // FIXME - throw some dynamic "did not expect XYZ character" error instead! return (char) from_file; } case INPUTSTATE_SKIPBLANKS: @@ -390,12 +390,13 @@ void input_ensure_EOS(void) // Now GotByte = first char to test { SKIPSPACE(); if (GotByte) { + // FIXME - move this to its own function! char buf[80]; // actually needed are 51 char quote; // character before and after // FIXME - change quoting: do not assume char is printable! quote = (GotByte == '\'') ? '"' : '\''; // use single quotes, unless byte is a single quote (then use double quotes) - sprintf(buf, "Garbage data at end of statement (unexpected %c%c%c).", quote, GotByte, quote); + sprintf(buf, "Expected end-of-statement, found %c%c%c instead.", quote, GotByte, quote); Throw_error(buf); input_skip_remainder(); } @@ -734,6 +735,21 @@ int input_accept_comma(void) return TRUE; } +// Try to read given character. +// If found, eat character and return TRUE. +// If not found, throw syntax error and return FALSE. +int input_expect(int chr) +{ + // one caller uses this to read the '=' part of "!=", so + // do not call SKIPSPACE() here! + if (GotByte == chr) { + GetByte(); // eat expected char + return TRUE; + } + Throw_error(exception_syntax); // FIXME - build "expected X, found Y" error msg! + return FALSE; +} + // read optional info about parameter length // FIXME - move to different file! bits input_get_force_bit(void) diff --git a/src/input.h b/src/input.h index 534bf1d..273b398 100644 --- a/src/input.h +++ b/src/input.h @@ -154,6 +154,11 @@ extern int input_read_output_filename(void); // found, otherwise FALSE. extern int input_accept_comma(void); +// Try to read given character. +// If found, eat character and return TRUE. +// If not found, throw syntax error and return FALSE. +extern int input_expect(int chr); + // read optional info about parameter length // FIXME - move to different file! extern bits input_get_force_bit(void); diff --git a/src/macro.c b/src/macro.c index 7d2639c..c5df90c 100644 --- a/src/macro.c +++ b/src/macro.c @@ -308,11 +308,8 @@ 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) { + 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/mnemo.c b/src/mnemo.c index 0d99820..b9c4c60 100644 --- a/src/mnemo.c +++ b/src/mnemo.c @@ -571,7 +571,7 @@ static int get_index(void) NEXTANDSKIPSPACE(); return INDEX_Z; } - Throw_error(exception_syntax); + Throw_error("Expected index register after comma."); return INDEX_NONE; } @@ -605,20 +605,17 @@ static bits get_addr_mode(struct number *result) address_mode_bits = AMB_IMPLIED; break; case '#': - GetByte(); // proceed with next char + GetByte(); // eat '#' address_mode_bits = AMB_IMMEDIATE; get_int_arg(result, FALSE); typesystem_want_nonaddr(result); // FIXME - this is wrong for 65ce02's PHW# break; case '[': - GetByte(); // proceed with next char + GetByte(); // eat '[' get_int_arg(result, FALSE); typesystem_want_addr(result); - if (GotByte == ']') { - GetByte(); + if (input_expect(']')) { address_mode_bits = AMB_LONGINDIRECT | AMB_INDEX(get_index()); - } else { - Throw_error(exception_syntax); } break; default: @@ -633,10 +630,8 @@ static bits get_addr_mode(struct number *result) // in case there are still open parentheses, // read internal index address_mode_bits |= AMB_PREINDEX(get_index()); - if (GotByte == ')') { - GetByte(); // go on with next char - } else { - Throw_error(exception_syntax); + if (input_expect(')')) { + // fn already does everything for us! } } // check for external index (after closing parenthesis) @@ -1049,12 +1044,10 @@ static void group_bbr_bbs(int opcode) get_int_arg(&zpmem, TRUE); typesystem_want_addr(&zpmem); - if (input_accept_comma()) { + if (input_expect(',')) { output_byte(opcode); output_byte(zpmem.val.intval); near_branch(3); - } else { - Throw_error(exception_syntax); } } @@ -1086,10 +1079,10 @@ static void group_mvn_mvp(int opcode) get_int_arg(&source, TRUE); typesystem_want_nonaddr(&source); // get comma - if (!input_accept_comma()) { - Throw_error(exception_syntax); + if (!input_expect(',')) { return; } + SKIPSPACE(); // get second arg if (GotByte == '#') { GetByte(); // eat char @@ -1103,7 +1096,7 @@ static void group_mvn_mvp(int opcode) output_8(source.val.intval); // sanity check if (unmatched_hash) - Throw_error(exception_syntax); + Throw_error(exception_syntax); // FIXME - maybe "Use ARG,ARG or #ARG,#ARG but do not mix and match"? input_ensure_EOS(); } diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index dd46ef5..8243f83 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -32,7 +32,7 @@ enum eos { }; // constants -static const char exception_missing_equals[] = "Missing '=' character."; +static const char exception_want_IN_or_comma[] = "Expected ',' or IN keyword after loop variable."; // helper function, just for old, deprecated, obsolete, stupid "realpc": @@ -335,7 +335,7 @@ static enum eos po_hex(void) // now GotByte = illegal char case CHAR_EOS: return AT_EOS_ANYWAY; // normal exit default: - Throw_error(exception_syntax); // all other characters are errors + Throw_error(exception_syntax); // FIXME - include character in error message! return SKIP_REMAINDER; // error exit } } @@ -442,11 +442,9 @@ static enum eos po_convtab(void) if (strcmp(GlobalDynaBuf->buffer, "file") == 0) { SKIPSPACE(); - if (GotByte != '=') { - Throw_error(exception_missing_equals); + if (!input_expect('=')) { return SKIP_REMAINDER; } - GetByte(); // eat '=' return use_encoding_from_file(); } @@ -524,11 +522,10 @@ static enum eos po_scrxor(void) intval_t xor; ALU_any_int(&xor); - if (input_accept_comma() == FALSE) { - Throw_error(exception_syntax); - return SKIP_REMAINDER; + if (input_expect(',')) { + return encode_string(&encoder_scr, xor); } - return encode_string(&encoder_scr, xor); + return SKIP_REMAINDER; } // include binary file ("!binary" pseudo opcode) @@ -650,12 +647,12 @@ static enum eos po_align(void) struct number pc; // TODO: - // now: !align ANDVALUE, EQUALVALUE [,FILLVALUE] - // new: !align BLOCKSIZE - // ...where block size must be a power of two + // 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 (!input_accept_comma()) - Throw_error(exception_syntax); + if (input_expect(',')) { + // fn already does everything for us + } ALU_defined_int(&equalresult); // ...allow addresses (unlikely, but possible) if (input_accept_comma()) ALU_any_int(&fill); @@ -680,11 +677,11 @@ static void old_offset_assembly(void) { if (config.dialect >= V0_94_8__DISABLED_OBSOLETE) { // now it's obsolete - Throw_error("\"!pseudopc/!realpc\" is obsolete; use \"!pseudopc {}\" instead."); // FIXME - amend msg, tell user how to use old behaviour! + Throw_error("\"!pseudopc/!realpc\" are obsolete; use \"!pseudopc {}\" instead."); // FIXME - amend msg, tell user how to use old behaviour! } else if (config.dialect >= V0_86__DEPRECATE_REALPC) { // earlier it was deprecated if (pass.number == 1) - Throw_warning("\"!pseudopc/!realpc\" is deprecated; use \"!pseudopc {}\" instead."); + Throw_warning("\"!pseudopc/!realpc\" are deprecated; use \"!pseudopc {}\" instead."); } else { // really old versions allowed it } @@ -830,10 +827,8 @@ static enum eos po_set(void) // now GotByte = illegal char return SKIP_REMAINDER; // zero length force_bit = input_get_force_bit(); // skips spaces after - if (GotByte != '=') { - Throw_error(exception_missing_equals); + if (!input_expect('=')) return SKIP_REMAINDER; - } // TODO: in versions before 0.97, force bit handling was broken in both // "!set" and "!for": @@ -1001,7 +996,7 @@ static enum eos ifelse(enum ifmode mode) // make sure it's "else" if (strcmp(GlobalDynaBuf->buffer, "else")) { - Throw_error("Expected ELSE or end-of-statement."); + Throw_error("Expected end-of-statement or ELSE keyword after '}'."); return SKIP_REMAINDER; // an error has been reported, so ignore rest of line } // anything more? @@ -1024,7 +1019,7 @@ static enum eos ifelse(enum ifmode mode) } else if (strcmp(GlobalDynaBuf->buffer, "ifndef") == 0) { mode = IFMODE_IFNDEF; } else { - Throw_error("After ELSE, expected block or IF/IFDEF/IFNDEF."); + Throw_error("Expected '{' or IF/IFDEF/IFNDEF keyword after ELSE keyword."); return SKIP_REMAINDER; // an error has been reported, so ignore rest of line } } @@ -1118,7 +1113,7 @@ static enum eos po_for(void) // now GotByte = illegal char loop.algorithm = FORALGO_ITERATE; // check for "in" keyword if ((GotByte != 'i') && (GotByte != 'I')) { - Throw_error(exception_syntax); + Throw_error(exception_want_IN_or_comma); return SKIP_REMAINDER; // FIXME - this ignores '{' and will then complain about '}' } /* checking for the first character explicitly here looks dumb, but actually @@ -1131,7 +1126,7 @@ knowing there is an "i" also makes sure that input_read_and_lower_keyword() does not fail. */ input_read_and_lower_keyword(); if (strcmp(GlobalDynaBuf->buffer, "in") != 0) { - Throw_error("Loop var must be followed by either \"in\" keyword or comma."); + Throw_error(exception_want_IN_or_comma); return SKIP_REMAINDER; // FIXME - this ignores '{' and will then complain about '}' } if (force_bit) { @@ -1380,10 +1375,9 @@ static enum eos po_debug(void) struct number debuglevel; ALU_defined_int(&debuglevel); - if (!input_accept_comma()) { - Throw_error("Expected comma after debug level."); + if (!input_expect(',')) return SKIP_REMAINDER; - } + // drop this one? if (debuglevel.val.intval > config.debuglevel) return SKIP_REMAINDER; @@ -1547,12 +1541,9 @@ void notreallypo_setpc(void) // GotByte is '*' // next non-space must be '=' NEXTANDSKIPSPACE(); - if (GotByte != '=') { - Throw_error(exception_missing_equals); + if (!input_expect('=')) goto fail; - } - GetByte(); ALU_defined_int(&intresult); // read new address // check for modifiers while (input_accept_comma()) { diff --git a/src/version.h b/src/version.h index 92d2a97..7210693 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 "14 Mar" // update before release FIXME +#define CHANGE_DATE "15 Mar" // 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