mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-02-07 06:31:03 +00:00
"symbol twice" error now outputs location of previous definition,
just as "macro twice" does. git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@406 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
45ce8164e9
commit
158379ce9a
@ -399,9 +399,9 @@ static void perform_pass(bits passflags)
|
||||
}
|
||||
// now increment pass number
|
||||
// this must be done _after_ the pass because assignments done via
|
||||
// "-DSYMBOL=VALUE" cli args must be handled as if they were done at the
|
||||
// start of pass 1, so we cannot change that variable at the start of
|
||||
// the pass.
|
||||
// "-D SYMBOL=VALUE" cli args must be handled as if they were done at
|
||||
// the start of pass 1, so we cannot change that variable at the start
|
||||
// of the pass.
|
||||
++pass.number;
|
||||
}
|
||||
|
||||
@ -788,7 +788,7 @@ int main(int argc, const char *argv[])
|
||||
if (argc == 1)
|
||||
show_help_and_exit();
|
||||
cliargs_init(argc, argv);
|
||||
// init pass number because any assignments done via "-DSYMBOL=VALUE"
|
||||
// init pass number because any assignments done via "-D SYMBOL=VALUE"
|
||||
// cli args must be handled as if they happened at the start of pass 1:
|
||||
pass.number = 1;
|
||||
// init platform-specific stuff.
|
||||
|
30
src/alu.c
30
src/alu.c
@ -1405,7 +1405,7 @@ static boolean string_differs(const struct object *self, const struct object *ot
|
||||
|
||||
// int/float:
|
||||
// assign new value
|
||||
static void number_assign(struct object *self, const struct object *new_value, boolean accept_change)
|
||||
static boolean number_assign(struct object *self, const struct object *new_value, boolean accept_change)
|
||||
{
|
||||
bits own_flags = self->u.number.flags,
|
||||
other_flags = new_value->u.number.flags;
|
||||
@ -1427,10 +1427,9 @@ static void number_assign(struct object *self, const struct object *new_value, b
|
||||
} else {
|
||||
// symbol is already defined, so compare new and old values
|
||||
// if values differ, complain and return
|
||||
if (number_differs(self, new_value)) {
|
||||
throw_error(exception_symbol_defined);
|
||||
return;
|
||||
}
|
||||
if (number_differs(self, new_value))
|
||||
return TRUE; // -> throw "symbol already defined" error
|
||||
|
||||
// values are the same, so only fiddle with flags
|
||||
}
|
||||
|
||||
@ -1448,29 +1447,30 @@ static void number_assign(struct object *self, const struct object *new_value, b
|
||||
own_flags |= other_flags & (NUMBER_FITS_BYTE | NUMBER_EVER_UNDEFINED);
|
||||
|
||||
self->u.number.flags = own_flags;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// list:
|
||||
// assign new value
|
||||
static void list_assign(struct object *self, const struct object *new_value, boolean accept_change)
|
||||
static boolean list_assign(struct object *self, const struct object *new_value, boolean accept_change)
|
||||
{
|
||||
if ((!accept_change) && list_differs(self, new_value)) {
|
||||
throw_error(exception_symbol_defined);
|
||||
return;
|
||||
}
|
||||
if ((!accept_change) && list_differs(self, new_value))
|
||||
return TRUE; // -> throw "symbol already defined" error
|
||||
|
||||
*self = *new_value;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// string:
|
||||
// assign new value
|
||||
static void string_assign(struct object *self, const struct object *new_value, boolean accept_change)
|
||||
static boolean string_assign(struct object *self, const struct object *new_value, boolean accept_change)
|
||||
{
|
||||
if ((!accept_change) && string_differs(self, new_value)) {
|
||||
throw_error(exception_symbol_defined);
|
||||
return;
|
||||
}
|
||||
if ((!accept_change) && string_differs(self, new_value))
|
||||
return TRUE; // -> throw "symbol already defined" error
|
||||
|
||||
*self = *new_value;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ struct type {
|
||||
const char *name;
|
||||
boolean (*is_defined)(const struct object *self);
|
||||
boolean (*differs)(const struct object *self, const struct object *other);
|
||||
void (*assign)(struct object *self, const struct object *new_value, boolean accept_change);
|
||||
boolean (*assign)(struct object *self, const struct object *new_value, boolean accept_change);
|
||||
void (*monadic_op)(struct object *self, const struct op *op);
|
||||
void (*dyadic_op)(struct object *self, const struct op *op, struct object *other);
|
||||
void (*fix_result)(struct object *self);
|
||||
|
@ -22,7 +22,7 @@ typedef signed int intval_t; // at least 32 bits
|
||||
typedef unsigned int uintval_t; // at least 32 bits (only used for logical shift right)
|
||||
#define OUTBUF_MAXSIZE 0x1000000 // 16 MiB ought to be enough for anybody
|
||||
|
||||
// struct to remember where macros were defined (FIXME - use for symbols as well!)
|
||||
// struct to remember where macros/symbols were defined
|
||||
struct location {
|
||||
const char *plat_filename; // filename in platform style
|
||||
int line_number;
|
||||
|
@ -627,12 +627,19 @@ void throw_redef_error(const char error_msg[], struct location *old_def, const c
|
||||
// show error with current location
|
||||
throw_error(error_msg);
|
||||
|
||||
// symbol structs do not necessarily have valid location data:
|
||||
if (old_def->plat_filename == NULL)
|
||||
return;
|
||||
|
||||
// CAUTION, ugly kluge: fiddle with section_now data to generate
|
||||
// "earlier definition" section.
|
||||
// buffer old section
|
||||
buffered_section_type = section_now->type;
|
||||
buffered_section_title = section_now->title;
|
||||
// set new (fake) section
|
||||
// FIXME - maybe store section in definition, just as location is stored?
|
||||
// then we could use real data here instead of faking it, but it would
|
||||
// take a bit more memory...
|
||||
section_now->type = "earlier";
|
||||
section_now->title = "section";
|
||||
// show info message with location of earlier definition
|
||||
|
19
src/symbol.c
19
src/symbol.c
@ -123,6 +123,10 @@ struct symbol *symbol_find(scope_t scope)
|
||||
symbol->has_been_read = FALSE;
|
||||
symbol->has_been_reported = FALSE;
|
||||
symbol->pseudopc = NULL;
|
||||
// we must set "definition" fields to dummy data, because the object
|
||||
// has been created, but not necessarily set to a defined value:
|
||||
symbol->definition.plat_filename = NULL;
|
||||
symbol->definition.line_number = 0;
|
||||
} else {
|
||||
symbol = node->body;
|
||||
}
|
||||
@ -142,6 +146,8 @@ struct symbol *symbol_find(scope_t scope)
|
||||
// CAUTION: actual incrementing of counter is then done directly without calls here!
|
||||
void symbol_set_object(struct symbol *symbol, struct object *new_value, bits powers)
|
||||
{
|
||||
boolean complain;
|
||||
|
||||
if (symbol->object.type == NULL) {
|
||||
// symbol has no object assigned to it yet
|
||||
symbol->object = *new_value; // copy whole struct including type
|
||||
@ -154,22 +160,27 @@ void symbol_set_object(struct symbol *symbol, struct object *new_value, bits pow
|
||||
// if too different, needs power (or complains)
|
||||
if (symbol->object.type != new_value->type) {
|
||||
if (!(powers & POWER_CHANGE_OBJTYPE))
|
||||
throw_error(exception_symbol_defined);
|
||||
// CAUTION: if above line throws error, we still go ahead and change type!
|
||||
complain = TRUE;
|
||||
// CAUTION: if line above triggers, we still go ahead and change type!
|
||||
// this is to keep "!for" working, where the counter var is accessed.
|
||||
symbol->object = *new_value; // copy whole struct including type
|
||||
// clear flag so caller can adjust force bits:
|
||||
symbol->has_been_read = FALSE; // it's basically a new symbol now
|
||||
} else {
|
||||
// symbol and new value have compatible types, so call handler:
|
||||
symbol->object.type->assign(&symbol->object, new_value, !!(powers & POWER_CHANGE_VALUE));
|
||||
complain = symbol->object.type->assign(&symbol->object, new_value, !!(powers & POWER_CHANGE_VALUE));
|
||||
}
|
||||
// if needed, throw "already defined" error with location of previous definition
|
||||
if (complain)
|
||||
throw_redef_error(exception_symbol_defined, &symbol->definition, "Previous definition.");
|
||||
}
|
||||
// if symbol is an address, give it a pseudopc context:
|
||||
if ((symbol->object.type == &type_number)
|
||||
&& (symbol->object.u.number.addr_refs == 1)) {
|
||||
symbol->pseudopc = pseudopc_get_context();
|
||||
}
|
||||
// remember current location for "symbol twice" errors in future:
|
||||
input_get_location(&symbol->definition);
|
||||
}
|
||||
|
||||
|
||||
@ -212,6 +223,8 @@ void symbol_define(intval_t value)
|
||||
result.u.number.val.intval = value;
|
||||
symbol = symbol_find(SCOPE_GLOBAL);
|
||||
symbol->object = result;
|
||||
symbol->definition.plat_filename = "\"-D SYMBOL=VALUE\"";
|
||||
symbol->definition.line_number = 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ struct symbol {
|
||||
boolean has_been_read; // to find out if actually used
|
||||
boolean has_been_reported; // indicates "has been reported as undefined"
|
||||
struct pseudopc *pseudopc; // for "unpseudopc"-Operator '&', may be NULL
|
||||
//TODO struct location definition; // for "label twice" error
|
||||
struct location definition; // for "label twice" error
|
||||
};
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define RELEASE "0.97" // update before release FIXME
|
||||
#define CODENAME "Zem" // update before release
|
||||
#define CHANGE_DATE "8 Aug" // update before release FIXME
|
||||
#define CHANGE_DATE "9 Aug" // 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
ACMEFLAGS = -v0
|
||||
ACMEFLAGS = -v0 --color
|
||||
FILES := $(wildcard *.a)
|
||||
TESTS = $(subst .a,.test,$(FILES))
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
ACMEFLAGS = -v0
|
||||
ACMEFLAGS = -v0 --color
|
||||
FILES := $(wildcard *.a)
|
||||
FAILTESTS = $(subst .a,.fail,$(FILES))
|
||||
SUCCTESTS = $(subst .a,.succ,$(FILES))
|
||||
|
Loading…
x
Reference in New Issue
Block a user