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:
parent
2092961bb8
commit
f660f26d2b
@ -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;
|
||||
|
117
src/global.c
117
src/global.c
@ -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");
|
||||
|
41
src/global.h
41
src/global.h
@ -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);
|
||||
|
10
src/macro.c
10
src/macro.c
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user