2016-12-28 20:32:00 +00:00
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
2020-04-25 10:20:52 +00:00
// Copyright (C) 1998-2020 Marco Baye
2014-06-07 00:12:10 +00:00
// Have a look at "acme.c" for further info
//
// symbol stuff
//
// 22 Nov 2007 "warn on indented labels" is now a CLI switch
// 25 Sep 2011 Fixed bug in !sl (colons in filename could be interpreted as EOS)
2014-11-23 23:40:01 +00:00
// 23 Nov 2014 Added label output in VICE format
2014-12-22 00:47:52 +00:00
# include "symbol.h"
2014-06-07 00:12:10 +00:00
# include <stdio.h>
# include "acme.h"
# include "alu.h"
# include "dynabuf.h"
2020-05-19 16:28:36 +00:00
# include "global.h"
2014-06-07 00:12:10 +00:00
# include "input.h"
# include "output.h"
# include "platform.h"
# include "section.h"
# include "tree.h"
# include "typesystem.h"
// variables
2014-12-03 22:18:06 +00:00
struct rwnode * symbols_forest [ 256 ] = { NULL } ; // because of 8-bit hash - must be (at least partially) pre-defined so array will be zeroed!
2014-06-07 00:12:10 +00:00
// Dump symbol value and flags to dump file
2014-11-24 14:52:05 +00:00
static void dump_one_symbol ( struct rwnode * node , FILE * fd )
2014-06-07 00:12:10 +00:00
{
struct symbol * symbol = node - > body ;
2020-05-13 23:26:40 +00:00
// if symbol is neither int nor float, skip
2020-05-29 10:57:01 +00:00
if ( ( symbol - > object . type ! = & type_int )
& & ( symbol - > object . type ! = & type_float ) )
2020-05-13 23:26:40 +00:00
return ;
2020-06-04 14:31:15 +00:00
// CAUTION: if more types are added, check for NULL before using type pointer!
2014-06-07 00:12:10 +00:00
// output name
2017-10-29 23:29:07 +00:00
if ( config . warn_on_type_mismatch
2020-05-29 10:57:01 +00:00
& & symbol - > object . u . number . addr_refs = = 1 )
2014-11-22 01:36:02 +00:00
fprintf ( fd , " !addr " ) ;
fprintf ( fd , " \t %s " , node - > id_string ) ;
2020-05-29 10:57:01 +00:00
switch ( symbol - > object . u . number . flags & NUMBER_FORCEBITS ) {
2020-04-28 16:02:09 +00:00
case NUMBER_FORCES_16 :
2014-06-07 00:12:10 +00:00
fprintf ( fd , " +2 \t = " ) ;
break ;
2020-04-28 16:02:09 +00:00
case NUMBER_FORCES_16 | NUMBER_FORCES_24 :
2014-06-07 00:12:10 +00:00
/*FALLTHROUGH*/
2020-04-28 16:02:09 +00:00
case NUMBER_FORCES_24 :
2014-06-07 00:12:10 +00:00
fprintf ( fd , " +3 \t = " ) ;
break ;
default :
fprintf ( fd , " \t = " ) ;
}
2020-05-29 10:57:01 +00:00
if ( symbol - > object . u . number . flags & NUMBER_IS_DEFINED ) {
if ( symbol - > object . type = = & type_int )
fprintf ( fd , " $%x " , ( unsigned ) symbol - > object . u . number . val . intval ) ;
else if ( symbol - > object . type = = & type_float )
fprintf ( fd , " %.30f " , symbol - > object . u . number . val . fpval ) ; //FIXME %g
2014-06-07 00:12:10 +00:00
else
2020-05-13 23:26:40 +00:00
Bug_found ( " BogusType " , 0 ) ; // FIXME - put in docs!
2014-06-07 00:12:10 +00:00
} else {
2017-10-21 19:59:56 +00:00
fprintf ( fd , " ? " ) ; // TODO - maybe write "UNDEFINED" instead? then the file could at least be parsed without errors
2014-06-07 00:12:10 +00:00
}
2020-05-29 10:57:01 +00:00
if ( symbol - > object . u . number . flags & NUMBER_EVER_UNDEFINED )
2017-10-21 19:59:56 +00:00
fprintf ( fd , " \t ; ? " ) ; // TODO - write "forward" instead?
2014-06-07 00:12:10 +00:00
if ( symbol - > usage = = 0 )
fprintf ( fd , " \t ; unused " ) ;
fprintf ( fd , " \n " ) ;
}
2014-11-23 23:40:01 +00:00
// output symbols in VICE format (example: "al C:09ae .nmi1")
2014-11-24 14:52:05 +00:00
static void dump_vice_address ( struct rwnode * node , FILE * fd )
2014-11-23 23:40:01 +00:00
{
struct symbol * symbol = node - > body ;
// dump address symbols even if they are not used
2020-05-29 10:57:01 +00:00
if ( ( symbol - > object . type = = & type_int )
& & ( symbol - > object . u . number . flags & NUMBER_IS_DEFINED )
& & ( symbol - > object . u . number . addr_refs = = 1 ) )
fprintf ( fd , " al C:%04x .%s \n " , ( unsigned ) symbol - > object . u . number . val . intval , node - > id_string ) ;
2014-11-23 23:40:01 +00:00
}
2014-11-24 14:52:05 +00:00
static void dump_vice_usednonaddress ( struct rwnode * node , FILE * fd )
2014-11-23 23:40:01 +00:00
{
struct symbol * symbol = node - > body ;
// dump non-addresses that are used
if ( symbol - > usage
2020-05-29 10:57:01 +00:00
& & ( symbol - > object . type = = & type_int )
& & ( symbol - > object . u . number . flags & NUMBER_IS_DEFINED )
& & ( symbol - > object . u . number . addr_refs ! = 1 ) )
fprintf ( fd , " al C:%04x .%s \n " , ( unsigned ) symbol - > object . u . number . val . intval , node - > id_string ) ;
2014-11-23 23:40:01 +00:00
}
2014-11-24 14:52:05 +00:00
static void dump_vice_unusednonaddress ( struct rwnode * node , FILE * fd )
2014-11-23 23:40:01 +00:00
{
struct symbol * symbol = node - > body ;
// dump non-addresses that are unused
if ( ! symbol - > usage
2020-05-29 10:57:01 +00:00
& & ( symbol - > object . type = = & type_int )
& & ( symbol - > object . u . number . flags & NUMBER_IS_DEFINED )
& & ( symbol - > object . u . number . addr_refs ! = 1 ) )
fprintf ( fd , " al C:%04x .%s \n " , ( unsigned ) symbol - > object . u . number . val . intval , node - > id_string ) ;
2014-11-23 23:40:01 +00:00
}
2020-06-05 01:11:51 +00:00
// search for symbol. if it does not exist, create with NULL object (CAUTION!).
// the symbol name must be held in GlobalDynaBuf.
struct symbol * symbol_find ( scope_t scope )
2020-06-03 16:30:13 +00:00
{
struct rwnode * node ;
struct symbol * symbol ;
boolean node_created ;
node_created = Tree_hard_scan ( & node , symbols_forest , scope , TRUE ) ;
// if node has just been created, create symbol as well
if ( node_created ) {
// create new symbol structure
symbol = safe_malloc ( sizeof ( * symbol ) ) ;
node - > body = symbol ;
// finish empty symbol item
symbol - > object . type = NULL ; // no object yet (CAUTION!)
symbol - > usage = 0 ; // usage count
symbol - > pass = pass . number ;
symbol - > has_been_reported = FALSE ;
symbol - > pseudopc = NULL ;
} else {
symbol = node - > body ;
}
return symbol ; // now symbol->object.type can be tested to see if this was freshly created.
// CAUTION: this only works if caller always sets a type pointer after checking! if NULL is kept, the struct still looks new later on...
}
2014-06-07 00:12:10 +00:00
2020-06-05 01:11:51 +00:00
// FIXME - merge with function below!
void symbol_forcebit ( struct symbol * symbol , int force_bit )
{
2020-06-03 16:30:13 +00:00
// if symbol has no object assigned to it, make it an int
if ( symbol - > object . type = = NULL ) {
2014-06-07 00:12:10 +00:00
// finish empty symbol item
2020-05-29 10:57:01 +00:00
symbol - > object . type = & type_int ;
2020-06-05 01:11:51 +00:00
symbol - > object . u . number . flags = force_bit ;
2020-05-29 10:57:01 +00:00
symbol - > object . u . number . addr_refs = 0 ;
symbol - > object . u . number . val . intval = 0 ;
2014-06-07 00:12:10 +00:00
} else {
2020-05-13 23:26:40 +00:00
// make sure the force bits don't clash
2020-05-29 10:57:01 +00:00
if ( ( symbol - > object . type = = & type_int )
| | ( symbol - > object . type = = & type_float ) ) {
2020-06-05 01:11:51 +00:00
if ( ( symbol - > object . u . number . flags & NUMBER_FORCEBITS ) ! = force_bit )
Throw_error ( " Too late for postfix. " ) ;
2020-05-13 23:26:40 +00:00
}
2014-06-07 00:12:10 +00:00
}
}
// assign value to symbol. the function acts upon the symbol's flag bits and
// produces an error if needed.
2020-06-04 14:31:15 +00:00
// TODO - split checks into two parts: first deal with object type. in case of number, then check value/flags/whatever
void symbol_set_object ( struct symbol * symbol , struct object * new_value , boolean change_allowed ) // FIXME - does "change_allowed" refer to type change or number value change?
2014-06-07 00:12:10 +00:00
{
2020-05-13 23:26:40 +00:00
int flags ; // for int/float re-definitions
// any new type?
2020-05-29 10:57:01 +00:00
if ( ( ( symbol - > object . type ! = & type_int ) & & ( symbol - > object . type ! = & type_float ) )
2020-05-13 23:26:40 +00:00
| | ( ( new_value - > type ! = & type_int ) & & ( new_value - > type ! = & type_float ) ) ) {
// changing value is ok, changing type needs extra flag:
2020-05-29 10:57:01 +00:00
if ( change_allowed | | ( symbol - > object . type = = new_value - > type ) )
symbol - > object = * new_value ;
2020-05-13 23:26:40 +00:00
else
Throw_error ( " Symbol already defined. " ) ;
return ;
}
// both old and new are either int or float, so keep old algo:
2014-06-07 00:12:10 +00:00
// value stuff
2020-05-29 10:57:01 +00:00
flags = symbol - > object . u . number . flags ;
2020-05-13 23:26:40 +00:00
if ( change_allowed | | ! ( flags & NUMBER_IS_DEFINED ) ) {
// symbol is not defined yet OR redefinitions are allowed
2020-05-29 10:57:01 +00:00
symbol - > object = * new_value ;
2020-05-13 23:26:40 +00:00
} else {
2014-06-07 00:12:10 +00:00
// symbol is already defined, so compare new and old values
// if different type OR same type but different value, complain
2020-05-29 10:57:01 +00:00
if ( ( symbol - > object . type ! = new_value - > type )
| | ( ( symbol - > object . type = = & type_float ) ? ( symbol - > object . u . number . val . fpval ! = new_value - > u . number . val . fpval ) : ( symbol - > object . u . number . val . intval ! = new_value - > u . number . val . intval ) ) )
2014-06-07 00:12:10 +00:00
Throw_error ( " Symbol already defined. " ) ;
}
// flags stuff
// Ensure that "unsure" symbols without "isByte" state don't get that
2020-05-13 23:26:40 +00:00
if ( ( flags & ( NUMBER_EVER_UNDEFINED | NUMBER_FITS_BYTE ) ) = = NUMBER_EVER_UNDEFINED )
new_value - > u . number . flags & = ~ NUMBER_FITS_BYTE ;
2014-06-07 00:12:10 +00:00
if ( change_allowed ) {
2020-05-13 23:26:40 +00:00
// take flags from new value, then OR EVER_UNDEFINED from old value
flags = ( flags & NUMBER_EVER_UNDEFINED ) | new_value - > u . number . flags ;
2014-06-07 00:12:10 +00:00
} else {
2020-05-13 23:26:40 +00:00
if ( ( flags & NUMBER_FORCEBITS ) = = 0 )
if ( ( flags & ( NUMBER_EVER_UNDEFINED | NUMBER_IS_DEFINED ) ) = = 0 ) // FIXME - this can't happen!?
flags | = new_value - > u . number . flags & NUMBER_FORCEBITS ;
flags | = new_value - > u . number . flags & ~ NUMBER_FORCEBITS ;
2014-06-07 00:12:10 +00:00
}
2020-05-29 10:57:01 +00:00
symbol - > object . u . number . flags = flags ;
2014-06-07 00:12:10 +00:00
}
2020-06-04 14:31:15 +00:00
// set global symbol to integer value, no questions asked (for "-D" switch)
2014-06-07 00:12:10 +00:00
// Name must be held in GlobalDynaBuf.
void symbol_define ( intval_t value )
{
2020-05-13 23:26:40 +00:00
struct object result ;
2014-06-07 00:12:10 +00:00
struct symbol * symbol ;
2020-05-13 23:26:40 +00:00
result . type = & type_int ;
result . u . number . flags = NUMBER_IS_DEFINED ;
result . u . number . val . intval = value ;
2020-06-05 01:11:51 +00:00
symbol = symbol_find ( SCOPE_GLOBAL ) ;
symbol - > object = result ;
2014-06-07 00:12:10 +00:00
}
// dump global symbols to file
2014-11-22 01:36:02 +00:00
void symbols_list ( FILE * fd )
2014-06-07 00:12:10 +00:00
{
2016-08-05 09:59:07 +00:00
Tree_dump_forest ( symbols_forest , SCOPE_GLOBAL , dump_one_symbol , fd ) ;
2014-06-07 00:12:10 +00:00
}
2014-11-23 23:40:01 +00:00
void symbols_vicelabels ( FILE * fd )
{
2016-02-21 12:58:22 +00:00
// FIXME - if type checking is enabled, maybe only output addresses?
2014-11-23 23:40:01 +00:00
// the order of dumped labels is important because VICE will prefer later defined labels
// dump unused labels
2016-08-05 09:59:07 +00:00
Tree_dump_forest ( symbols_forest , SCOPE_GLOBAL , dump_vice_unusednonaddress , fd ) ;
2014-11-23 23:40:01 +00:00
fputc ( ' \n ' , fd ) ;
// dump other used labels
2016-08-05 09:59:07 +00:00
Tree_dump_forest ( symbols_forest , SCOPE_GLOBAL , dump_vice_usednonaddress , fd ) ;
2014-11-23 23:40:01 +00:00
fputc ( ' \n ' , fd ) ;
// dump address symbols
2016-08-05 09:59:07 +00:00
Tree_dump_forest ( symbols_forest , SCOPE_GLOBAL , dump_vice_address , fd ) ;
2014-11-23 23:40:01 +00:00
}
2014-06-07 00:12:10 +00:00
// fix name of anonymous forward label (held in DynaBuf, NOT TERMINATED!) so it
// references the *next* anonymous forward label definition. The tricky bit is,
// each name length would need its own counter. But hey, ACME's real quick in
// finding symbols, so I'll just abuse the symbol system to store those counters.
2020-06-05 01:11:51 +00:00
// example:
// forward anon name is "+++"
// we look up that symbol's value in the current local scope -> $12
// we attach hex digits to name -> "+++21"
// that's the name of the symbol that _actually_ contains the address
// caller sets "increment" to TRUE for writing, FALSE for reading
2020-05-13 23:26:40 +00:00
void symbol_fix_forward_anon_name ( boolean increment )
2014-06-07 00:12:10 +00:00
{
struct symbol * counter_symbol ;
unsigned long number ;
// terminate name, find "counter" symbol and read value
DynaBuf_append ( GlobalDynaBuf , ' \0 ' ) ;
2020-06-05 01:11:51 +00:00
counter_symbol = symbol_find ( section_now - > local_scope ) ;
if ( counter_symbol - > object . type = = NULL ) {
// finish freshly created symbol item
counter_symbol - > object . type = & type_int ;
counter_symbol - > object . u . number . flags = NUMBER_IS_DEFINED ;
counter_symbol - > object . u . number . addr_refs = 0 ;
counter_symbol - > object . u . number . val . intval = 0 ;
} else if ( counter_symbol - > object . type ! = & type_int ) {
// sanity check: it must be an int!
2020-05-13 23:26:40 +00:00
Bug_found ( " ForwardAnonCounterNotInt " , 0 ) ;
2020-06-05 01:11:51 +00:00
}
2014-06-07 00:12:10 +00:00
// make sure it gets reset to zero in each new pass
2020-05-02 10:40:10 +00:00
if ( counter_symbol - > pass ! = pass . number ) {
counter_symbol - > pass = pass . number ;
2020-05-29 10:57:01 +00:00
counter_symbol - > object . u . number . val . intval = 0 ;
2014-06-07 00:12:10 +00:00
}
2020-05-29 10:57:01 +00:00
number = ( unsigned long ) counter_symbol - > object . u . number . val . intval ;
2014-06-07 00:12:10 +00:00
// now append to the name to make it unique
GlobalDynaBuf - > size - - ; // forget terminator, we want to append
do {
DYNABUF_APPEND ( GlobalDynaBuf , ' a ' + ( number & 15 ) ) ;
number > > = 4 ;
} while ( number ) ;
DynaBuf_append ( GlobalDynaBuf , ' \0 ' ) ;
if ( increment )
2020-05-29 10:57:01 +00:00
counter_symbol - > object . u . number . val . intval + + ;
2014-06-07 00:12:10 +00:00
}