1
0
mirror of https://github.com/uffejakobsen/acme.git synced 2025-04-11 09:37:17 +00:00

added --debuglevel cli switch and !debug/!info pseudo opcodes

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@332 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2024-02-10 12:43:56 +00:00
parent 2092961bb8
commit f660f26d2b
6 changed files with 115 additions and 110 deletions

@ -66,6 +66,7 @@ static const char arg_vicelabels[] = "VICE labels filename";
#define OPTION_IGNORE_ZEROES "ignore-zeroes"
#define OPTION_STRICT_SEGMENTS "strict-segments"
#define OPTION_DIALECT "dialect"
#define OPTION_DEBUGLEVEL "debuglevel"
#define OPTION_TEST "test"
// options for "-W"
#define OPTIONWNO_LABEL_INDENT "no-label-indent"
@ -148,9 +149,10 @@ static void show_help_and_exit(void)
//" -W show warning level options\n"
" --" OPTION_USE_STDOUT " fix for 'Relaunch64' IDE (see docs)\n"
" --" OPTION_MSVC " output errors in MS VS format\n"
" --" OPTION_COLOR " uses ANSI color codes for error output\n"
" --" OPTION_COLOR " use ANSI color codes for error output\n"
" --" OPTION_FULLSTOP " use '.' as pseudo opcode prefix\n"
" --" OPTION_DIALECT " VERSION behave like different version\n"
" --" OPTION_DEBUGLEVEL " VALUE drop all higher-level debug messages\n"
" --" OPTION_TEST " enable experimental features\n"
PLATFORM_OPTION_HELP
" -V, --" OPTION_VERSION " show version and exit\n");
@ -260,6 +262,7 @@ static void perform_pass(void)
pass.undefined_count = 0;
//pass.needvalue_count = 0; FIXME - use
pass.error_count = 0;
pass.warning_count = 0;
// Process toplevel files
for (ii = 0; ii < toplevel_src_count; ++ii) {
if ((fd = fopen(toplevel_sources[ii], FILE_READBINARY))) {
@ -551,6 +554,8 @@ static const char *long_option(const char *string)
config.segment_warning_is_error = 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)
config.debuglevel = string_to_number(cliargs_safe_get_next("debug level"));
else if (strcmp(string, OPTION_TEST) == 0) {
config.wanted_version = VER_FUTURE;
config.test_new_features = TRUE;

@ -120,6 +120,7 @@ void config_default(struct config *conf)
conf->segment_warning_is_error = FALSE; // enabled by --strict-segments TODO - toggle default?
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"
}
// memory allocation stuff
@ -381,44 +382,72 @@ int parse_optional_block(void)
// Error handling
// error/warning counter so macro calls can find out whether to show a call stack
static int throw_counter = 0;
int Throw_get_counter(void)
{
return throw_counter;
}
// This function will do the actual output for warnings, errors and serious
// errors. It shows the given message string, as well as the current
// context: file name, line number, source type and source title.
// TODO: make un-static so !info and !debug can use this.
static void throw_message(const char *message, const char *type)
static void throw_msg(const char *message, const char *ansicolor, const char *type)
{
++throw_counter;
const char *resetcolor = "\033[0m";
if (!config.format_color) {
ansicolor = "";
resetcolor = "";
}
if (config.format_msvc)
fprintf(config.msg_stream, "%s(%d) : %s (%s %s): %s\n",
fprintf(config.msg_stream, "%s(%d) : %s%s%s (%s %s): %s\n",
input_now->original_filename, input_now->line_number,
type, section_now->type, section_now->title, message);
ansicolor, type, resetcolor,
section_now->type, section_now->title, message);
else
fprintf(config.msg_stream, "%s - File %s, line %d (%s %s): %s\n",
type, input_now->original_filename, input_now->line_number,
fprintf(config.msg_stream, "%s%s%s - File %s, line %d (%s %s): %s\n",
ansicolor, type, resetcolor,
input_now->original_filename, input_now->line_number,
section_now->type, section_now->title, message);
}
// Output a warning.
// This means the produced code looks as expected. But there has been a
// situation that should be reported to the user, for example ACME may have
// assembled a 16-bit parameter with an 8-bit value.
void Throw_warning(const char *message)
// generate debug/info/warning/error message
void throw_message(enum debuglevel level, const char msg[])
{
PLATFORM_WARNING(message);
if (config.format_color)
throw_message(message, "\033[33mWarning\033[0m");
else
throw_message(message, "Warning");
// if level is taken from source, ensure valid value:
if (level < DEBUGLEVEL_SERIOUS)
level = DEBUGLEVEL_SERIOUS;
switch (level) {
case DEBUGLEVEL_SERIOUS:
// output a serious error
// (assembly stops, for example if outbuffer overruns).
PLATFORM_SERIOUS(msg);
throw_msg(msg, "\033[1m\033[31m", "Serious error"); // bold + red
//++pass.error_count; // FIXME - needed when problem below is solved
exit(ACME_finalize(EXIT_FAILURE)); // FIXME - this inhibits output of macro call stack
case DEBUGLEVEL_ERROR:
// output an error
// (something is wrong, no output file will be generated).
PLATFORM_ERROR(msg);
throw_msg(msg, "\033[31m", "Error"); // red
++pass.error_count;
if (pass.error_count >= config.max_errors)
exit(ACME_finalize(EXIT_FAILURE));
break;
case DEBUGLEVEL_WARNING:
// output a warning
// (something looks wrong, like "label name starts with shift-space character")
PLATFORM_WARNING(msg);
throw_msg(msg, "\033[33m", "Warning"); // yellow
++pass.warning_count;
break;
case DEBUGLEVEL_INFO:
throw_msg(msg, "\033[32m", "Info"); // green
break;
default:
// debug
throw_msg(msg, "\033[36m", "Debug"); // cyan
break;
}
}
// Output a warning if in first pass. See above.
// output a warning if in first pass. See above.
void Throw_first_pass_warning(const char *message)
{
if (FIRST_PASS)
@ -426,41 +455,7 @@ void Throw_first_pass_warning(const char *message)
}
// Output an error.
// This means something went wrong in a way that implies that the output
// almost for sure won't look like expected, for example when there was a
// syntax error. The assembler will try to go on with the assembly though, so
// the user gets to know about more than one of his typos at a time.
void Throw_error(const char *message)
{
PLATFORM_ERROR(message);
if (config.format_color)
throw_message(message, "\033[31mError\033[0m");
else
throw_message(message, "Error");
++pass.error_count;
if (pass.error_count >= config.max_errors)
exit(ACME_finalize(EXIT_FAILURE));
}
// Output a serious error, stopping assembly.
// Serious errors are those that make it impossible to go on with the
// assembly. Example: "!fill" without a parameter - the program counter cannot
// be set correctly in this case, so proceeding would be of no use at all.
void Throw_serious_error(const char *message)
{
PLATFORM_SERIOUS(message);
if (config.format_color)
throw_message(message, "\033[1m\033[31mSerious error\033[0m");
else
throw_message(message, "Serious error");
// FIXME - exiting immediately inhibits output of macro call stack!
exit(ACME_finalize(EXIT_FAILURE));
}
// Handle bugs
// handle bugs
void BUG(const char *message, int code)
{
Throw_warning("Bug in ACME, code follows");

@ -77,6 +77,7 @@ struct config {
boolean segment_warning_is_error; // FALSE, enabled by --strict-segments
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"
};
extern struct config config;
@ -85,6 +86,7 @@ struct pass {
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;
int warning_count;
boolean complain_about_undefined; // will be FALSE until error pass is needed
};
extern struct pass pass;
@ -139,30 +141,31 @@ extern void parse_until_eob_or_eof(void);
// Don't forget to call EnsureEOL() afterwards.
extern int parse_optional_block(void);
// error/warning counter so macro calls can find out whether to show a call stack
extern int Throw_get_counter(void);
enum debuglevel {
DEBUGLEVEL_SERIOUS = -3, // ACME stops right away
DEBUGLEVEL_ERROR = -2, // something is wrong
DEBUGLEVEL_WARNING = -1, // something looks wrong
DEBUGLEVEL_INFO = 0, // info msg ("173 bytes left in code area!")
DEBUGLEVEL_DEBUG = 1 // debug msg
// debug messages with higher levels are suppressed,
// can be changed using "--debuglevel" cli switch.
};
// generate a debug/info/warning/error message
void throw_message(enum debuglevel level, const char msg[]);
// Output a warning.
// This means the produced code looks as expected. But there has been a
// situation that should be reported to the user, for example ACME may have
// assembled a 16-bit parameter with an 8-bit value.
extern void Throw_warning(const char *msg);
// output a warning (something looks wrong, like "label name starts with shift-space character")
#define Throw_warning(msg) throw_message(DEBUGLEVEL_WARNING, msg)
// Output a warning if in first pass. See above.
// output a warning if in first pass. See above.
extern void Throw_first_pass_warning(const char *msg);
// Output an error.
// This means something went wrong in a way that implies that the output
// almost for sure won't look like expected, for example when there was a
// syntax error. The assembler will try to go on with the assembly though, so
// the user gets to know about more than one of his typos at a time.
extern void Throw_error(const char *msg);
// output an error (something is wrong, no output file will be generated).
// the assembler will try to go on with the assembly, so the user gets to know
// about more than one of his typos at a time.
#define Throw_error(msg) throw_message(DEBUGLEVEL_ERROR, msg)
// Output a serious error, stopping assembly.
// Serious errors are those that make it impossible to go on with the
// assembly. Example: "!fill" without a parameter - the program counter cannot
// be set correctly in this case, so proceeding would be of no use at all.
extern void Throw_serious_error(const char *msg);
// output a serious error (assembly stops, for example if outbuffer overruns).
#define Throw_serious_error(msg) throw_message(DEBUGLEVEL_SERIOUS, msg)
// handle bugs
extern void BUG(const char *msg, int code);

@ -222,7 +222,7 @@ void macro_parse_call(void) // Now GotByte = first char of macro name
scope_t macro_scope,
symbol_scope;
int arg_count = 0;
int outer_err_count;
int outer_msg_sum;
// make sure arg_table is ready (if not yet initialised, do it now)
if (arg_table == NULL)
@ -286,7 +286,7 @@ void macro_parse_call(void) // Now GotByte = first char of macro name
// activate new input
input_now = &new_input;
outer_err_count = Throw_get_counter(); // remember error count (for call stack decision)
outer_msg_sum = pass.warning_count + pass.error_count; // remember for call stack decision
// remember old section
outer_section = section_now;
@ -339,9 +339,9 @@ void macro_parse_call(void) // Now GotByte = first char of macro name
// restore old Gotbyte context
GotByte = local_gotbyte; // CAUTION - ugly kluge
// if needed, output call stack
if (Throw_get_counter() != outer_err_count)
Throw_warning("...called from here.");
// if needed, dump call stack
if (outer_msg_sum != pass.warning_count + pass.error_count)
Throw_warning("...called from here."); // FIXME - change to "info"!
input_ensure_EOS();
}

@ -1271,16 +1271,13 @@ static enum eos po_nowarn(void)
}
*/
// constants
#define USERMSG_INITIALSIZE 80
// variables
static STRUCT_DYNABUF_REF(user_message, USERMSG_INITIALSIZE); // for !warn/error/serious
static STRUCT_DYNABUF_REF(user_message, 80); // for !debug/info/warn/error/serious
// helper function to show user-defined messages
static enum eos throw_string(const char prefix[], void (*fn)(const char *))
static enum eos throw_src_string(enum debuglevel level, const char prefix[])
{
struct object object;
@ -1307,45 +1304,49 @@ static enum eos throw_string(const char prefix[], void (*fn)(const char *))
}
} while (input_accept_comma());
dynabuf_append(user_message, '\0');
fn(user_message->buffer);
throw_message(level, user_message->buffer);
return ENSURE_EOS;
}
#if 0
// show debug data given in source code
// show debug data as given in source code
static enum eos po_debug(void)
{
// FIXME - make debug output depend on some cli switch
// FIXME - add a number arg to this po so user can decide how much to display?
return throw_string("!debug: ", throw_message);
struct number debuglevel;
ALU_defined_int(&debuglevel);
if (!input_accept_comma()) {
Throw_error("Expected comma after debug level.");
return SKIP_REMAINDER;
}
// drop this one?
if (debuglevel.val.intval > config.debuglevel)
return SKIP_REMAINDER;
return throw_src_string(debuglevel.val.intval, "!debug: ");
}
// show info given in source code
// show info as given in source code
static enum eos po_info(void)
{
return throw_string("!info: ", throw_message);
return throw_src_string(DEBUGLEVEL_INFO, "!info: ");
}
#endif
// throw warning as given in source code
static enum eos po_warn(void)
{
return throw_string("!warn: ", Throw_warning);
return throw_src_string(DEBUGLEVEL_WARNING, "!warn: ");
}
// throw error as given in source code
static enum eos po_error(void)
{
return throw_string("!error: ", Throw_error);
return throw_src_string(DEBUGLEVEL_ERROR, "!error: ");
}
// throw serious error as given in source code
static enum eos po_serious(void)
{
return throw_string("!serious: ", Throw_serious_error);
return throw_src_string(DEBUGLEVEL_SERIOUS, "!serious: ");
}
@ -1385,6 +1386,7 @@ static struct ronode pseudo_opcode_tree[] = {
PREDEFNODE("ct", po_convtab),
PREDEFNODE("convtab", po_convtab),
PREDEFNODE("tx", po_text),
PREDEFNODE("txt", po_text),
PREDEFNODE("text", po_text),
PREDEFNODE("raw", po_raw),
PREDEFNODE("pet", po_pet),
@ -1425,8 +1427,8 @@ static struct ronode pseudo_opcode_tree[] = {
/* PREDEFNODE("trace", po_trace),
PREDEFNODE("watch", po_watch), */
// PREDEFNODE("nowarn", po_nowarn),
// PREDEFNODE("debug", po_debug),
// PREDEFNODE("info", po_info),
PREDEFNODE("debug", po_debug),
PREDEFNODE("info", po_info),
PREDEFNODE("warn", po_warn),
PREDEFNODE("error", po_error),
PREDEFNODE("serious", po_serious),

@ -9,7 +9,7 @@
#define RELEASE "0.97" // update before release FIXME
#define CODENAME "Zem" // update before release
#define CHANGE_DATE "8 Feb" // update before release FIXME
#define CHANGE_DATE "9 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