# HG changeset patch # User lost # Date 1230956449 0 # Node ID 538e15927776824d969ae4681480133a4a90ba9c # Parent 99e3b3310bacd5040610bb604a62c80518c51142 Added symbol handling to expression subsystem; adpated instruction handlers to the new scheme; misc fixes diff -r 99e3b3310bac -r 538e15927776 src/Makefile.am --- a/src/Makefile.am Fri Jan 02 06:07:40 2009 +0000 +++ b/src/Makefile.am Sat Jan 03 04:20:49 2009 +0000 @@ -1,3 +1,3 @@ bin_PROGRAMS = lwasm -lwasm_SOURCES = main.c expr.c pass1.c pass2.c util.c instab.c parse.c lwasm.c insn_inh.c insn_rtor.c insn_rlist.c insn_rel.c insn_tfm.c insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c list.c +lwasm_SOURCES = main.c expr.c pass1.c pass2.c util.c instab.c parse.c lwasm.c insn_inh.c insn_rtor.c insn_rlist.c insn_rel.c insn_tfm.c insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c list.c symbol.c EXTRA_DIST = instab.h lwasm.h expr.h util.h diff -r 99e3b3310bac -r 538e15927776 src/expr.c --- a/src/expr.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/expr.c Sat Jan 03 04:20:49 2009 +0000 @@ -67,6 +67,8 @@ lwasm_expr_term_t *lwasm_expr_term_create_oper(int oper) { lwasm_expr_term_t *t; + +fprintf(stderr, "Creating operator term: %d\n", oper); t = lwasm_alloc(sizeof(lwasm_expr_term_t)); t -> term_type = LWASM_TERM_OPER; @@ -77,6 +79,7 @@ lwasm_expr_term_t *lwasm_expr_term_create_int(int val) { lwasm_expr_term_t *t; +fprintf(stderr, "Creating integer term: %d\n", val); t = lwasm_alloc(sizeof(lwasm_expr_term_t)); t -> term_type = LWASM_TERM_INT; @@ -88,6 +91,7 @@ { lwasm_expr_term_t *t; +fprintf(stderr, "Creating symbol term: %s\n", sym); t = lwasm_alloc(sizeof(lwasm_expr_term_t)); t -> term_type = LWASM_TERM_SYM; t -> symbol = lwasm_strdup(sym); @@ -177,10 +181,11 @@ int lwasm_expr_parse_term(lwasm_expr_stack_t *s, const char **p) { lwasm_expr_term_t *t; - +fprintf(stderr, "Expression string %s\n", *p); eval_next: if (**p == '(') { + fprintf(stderr, "Starting paren\n"); (*p)++; lwasm_expr_parse_expr(s, p, 0); if (**p != ')') @@ -191,6 +196,7 @@ if (**p == '+') { + fprintf(stderr, "Unary +\n"); (*p)++; goto eval_next; } @@ -424,6 +430,7 @@ { // otherwise we must be decimal (if we're still allowed one) val = decval; + fprintf(stderr, "End of decimal value\n"); break; } else @@ -492,7 +499,14 @@ dval -= '0'; if (dval > 9) dval -= 7; - + fprintf(stderr, "Got digit: %d\n", dval); +// if (dval > 1) +// valtype &= 14; +// if (dval > 7) +// valtype &= 12; +// if (dval > 9) +// valtype &= 8; + if (valtype & 8) { hexval = hexval * 16 + dval; @@ -520,11 +534,12 @@ } } // break out if we have a return value - if (valtype = -1) + if (valtype == -1) break; // return if no more valid possibilities! if (valtype == 0) return -1; + val = decval; // in case we fall through } // we get here when we have a value to return @@ -560,12 +575,15 @@ lwasm_expr_term_t *operterm; // return if we are at the end of the expression or a subexpression - if (!**p || isspace(**p) || **p == ')') + if (!**p || isspace(**p) || **p == ')' || **p == ',') return 0; -eval_next: if (lwasm_expr_parse_term(s, p) < 0) return -1; + +eval_next: + if (!**p || isspace(**p) || **p == ')' || **p == ',') + return 0; // expecting an operator here for (opern = 0; operators[opern].opernum != LWASM_OPER_NONE; opern++) @@ -625,15 +643,18 @@ contain the pointer to the next character after the expression if and only if there is no error. In the case of an error, *outp is undefined. */ -lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp) +lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp, int (*sfunc)(char *sym, void *state, int *val), void *state) { lwasm_expr_stack_t *s; const char *p; - + int rval; + // actually parse the expression p = inp; s = lwasm_expr_stack_create(); - if (lwasm_expr_parse_expr(s, &p, 0) < 0) + + rval = lwasm_expr_parse_expr(s, &p, 0); + if (rval < 0) goto cleanup_error; // save end of expression @@ -641,8 +662,11 @@ (*outp) = p; // return potentially partial expression - if (lwasm_expr_reval(s) < 0) + if (lwasm_expr_reval(s, sfunc, state) < 0) goto cleanup_error; + + if (lwasm_expr_is_constant(s)) + fprintf(stderr, "Constant expression evaluates to: %d\n", lwasm_expr_get_value(s)); return s; @@ -668,9 +692,26 @@ further operators or only a single term remains */ -int lwasm_expr_reval(lwasm_expr_stack_t *s) +int lwasm_expr_reval(lwasm_expr_stack_t *s, int (*sfunc)(char *sym, void *state, int *val), void *state) { lwasm_expr_stack_node_t *n; + int sval; + + // resolve symbols + // symbols that do not resolve to a constant are left alone + for (n = s -> head; n; n = n -> next) + { + if (n -> term -> term_type == LWASM_TERM_SYM) + { + if (sfunc(n -> term -> symbol, state, &sval) == 0) + { + n -> term -> term_type = LWASM_TERM_INT; + n -> term -> value = sval; + lwasm_free(n -> term -> symbol); + n -> term -> symbol = NULL; + } + } + } next_iter: // a single term diff -r 99e3b3310bac -r 538e15927776 src/expr.h --- a/src/expr.h Fri Jan 02 06:07:40 2009 +0000 +++ b/src/expr.h Sat Jan 03 04:20:49 2009 +0000 @@ -97,10 +97,10 @@ You must call lwasm_expr_stack_free() on the result when you are finished with it. */ -__expr_E__ lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp); +__expr_E__ lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp, int (*sfunc)(char *sym, void *state, int *val), void *state); // simplify expression -__expr_E__ int lwasm_expr_reval(lwasm_expr_stack_t *s); +__expr_E__ int lwasm_expr_reval(lwasm_expr_stack_t *s, int (*sfunc)(char *sym, void *state, int *val), void *state); // useful macros // is the expression "simple" (one term)? diff -r 99e3b3310bac -r 538e15927776 src/insn_bitbit.c --- a/src/insn_bitbit.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/insn_bitbit.c Sat Jan 03 04:20:49 2009 +0000 @@ -59,7 +59,7 @@ register_error(as, l, 1, "Bad operand"); return; } - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad operand"); @@ -83,7 +83,7 @@ } r = (r << 6) | (v1 << 3); - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad operand"); @@ -113,7 +113,7 @@ if (**p == '<') (*p)++; - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad operand"); diff -r 99e3b3310bac -r 538e15927776 src/insn_gen.c --- a/src/insn_gen.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/insn_gen.c Sat Jan 03 04:20:49 2009 +0000 @@ -61,7 +61,7 @@ (*optr)++; f16 = 1; } - s = lwasm_expr_eval(*optr, NULL); + s = lwasm_evaluate_expr(as, l, *optr, NULL); if (!s) { register_error(as, l, 1, "Bad expression"); @@ -138,7 +138,7 @@ { lwasm_emitop(as, l, instab[opnum].ops[3]); (*p)++; - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad expression"); @@ -169,7 +169,7 @@ { lwasm_emitop(as, l, instab[opnum].ops[3]); (*p)++; - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad expression"); @@ -199,7 +199,7 @@ { lwasm_emitop(as, l, instab[opnum].ops[3]); (*p)++; - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad expression"); @@ -231,7 +231,7 @@ { lwasm_emitop(as, l, instab[opnum].ops[0]); (*p)++; - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad expression"); diff -r 99e3b3310bac -r 538e15927776 src/insn_indexed.c --- a/src/insn_indexed.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/insn_indexed.c Sat Jan 03 04:20:49 2009 +0000 @@ -129,7 +129,7 @@ *b1 = 0x9f; *b2 = 0; *b3 = 0; - s = lwasm_expr_eval(*p, &p2); + s = lwasm_evaluate_expr(as, l, *p, &p2); if (!s) { register_error(as, l, 1, "Bad expression"); @@ -170,7 +170,7 @@ } // now we have to evaluate the expression - s = lwasm_expr_eval(*p, &p2); + s = lwasm_evaluate_expr(as, l, *p, &p2); *p = p2; if (!s) { diff -r 99e3b3310bac -r 538e15927776 src/insn_logicmem.c --- a/src/insn_logicmem.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/insn_logicmem.c Sat Jan 03 04:20:49 2009 +0000 @@ -40,7 +40,7 @@ if (**p == '#') (*p)++; - s = lwasm_expr_eval(*p, &p2); + s = lwasm_evaluate_expr(as, l, *p, &p2); *p = (char *)p2; if (!s) diff -r 99e3b3310bac -r 538e15927776 src/insn_rel.c --- a/src/insn_rel.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/insn_rel.c Sat Jan 03 04:20:49 2009 +0000 @@ -37,7 +37,7 @@ lwasm_emitop(as, l, instab[opnum].ops[0]); - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad operand"); @@ -62,7 +62,7 @@ lwasm_emitop(as, l, instab[opnum].ops[0]); - s = lwasm_expr_eval(*p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL); if (!s) { register_error(as, l, 1, "Bad operand"); diff -r 99e3b3310bac -r 538e15927776 src/lwasm.c --- a/src/lwasm.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/lwasm.c Sat Jan 03 04:20:49 2009 +0000 @@ -29,6 +29,7 @@ #include "lwasm.h" #include "util.h" +#include "expr.h" int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...) { @@ -147,3 +148,36 @@ (*str)+=3; return rval; } + +struct symstateinfo +{ + asmstate_t *as; + lwasm_line_t *l; +}; + +int lwasm_expr_lookup_symbol(char *sym, void *state, int *val) +{ + lwasm_symbol_ent_t *se; + struct symstateinfo *st; + + st = state; + + // look for local symbol first then global symbol + se = lwasm_find_symbol(st -> as, sym, st -> as -> context); + if (!se) + se = lwasm_find_symbol(st -> as, sym, -1); + if (!se) + return -1; + *val = se -> value; + return 0; +} + +lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp) +{ + struct symstateinfo st; + + st.as = as; + st.l = l; + + return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st)); +} diff -r 99e3b3310bac -r 538e15927776 src/lwasm.h --- a/src/lwasm.h Fri Jan 02 06:07:40 2009 +0000 +++ b/src/lwasm.h Sat Jan 03 04:20:49 2009 +0000 @@ -24,10 +24,13 @@ #ifndef __lwasm_h_seen__ #define __lwasm_h_seen__ +#include "expr.h" + #define OUTPUT_DECB 0 // DECB multirecord format #define OUTPUT_RAW 1 // raw sequence of bytes #define OUTPUT_OBJ 2 // proprietary object file format + // structure for tracking errors typedef struct lwasm_error_s lwasm_error_t; struct lwasm_error_s @@ -46,12 +49,25 @@ lwasm_line_t *prev; // previous line lwasm_error_t *err; // error messages int fsize; // forced size (0 = no forced size) + char *sym; // scratch area to record the presence of a symbol +}; + +// for keeping track of symbols +typedef struct lwasm_symbol_ent_s lwasm_symbol_ent_t; +struct lwasm_symbol_ent_s +{ + char *sym; // the symbol + int context; // the context number of the symbol (-1 for global) + int value; // the value of the symbol + lwasm_symbol_ent_t *next; // next symbol in the table + lwasm_symbol_ent_t *prev; // previous symbol in the table }; // keep track of current assembler state typedef struct { int dpval; // current dp value (setdp) int addr; // current address + int context; // context counter (for local symbols) int errorcount; // error count int passnum; // which pass are we on? int execaddr; // execution address for the program (END ....) @@ -59,6 +75,9 @@ lwasm_line_t *lineshead; // first line of source code lwasm_line_t *linestail; // last line of source code + + lwasm_symbol_ent_t *symhead; // first entry in symbol table + lwasm_symbol_ent_t *symtail; // last entry in symbol table const char *infile; // input file const char *outfile; // output file @@ -84,14 +103,23 @@ __lwasm_E__ int lwasm_lookupreg2(const char *reglist, char **str); __lwasm_E__ int lwasm_lookupreg3(const char *rlist, const char **str); +__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp); + #undef __lwasm_E__ -#ifndef __symtab_c_seen__ -//extern void register_symbol(asmstate_t *as, sourceline_t *cl, char *symstr, int val, int flags); -//extern int lookup_symbol(asmstate_t *as, char *symstr); -//extern void list_symbols(asmstate_t *as, FILE *f); +#ifndef __symbol_c_seen__ +#define __lwasm_E__ extern +#else +#define __lwasm_E__ #endif +__lwasm_E__ int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val); +__lwasm_E__ lwasm_symbol_ent_t *lwasm_find_symbol(asmstate_t *as, char *sym, int scontext); +__lwasm_E__ int lwasm_set_symbol(asmstate_t *as, char *sym, int scontext, int val); + +#undef __lwasm_E__ + + #endif //__lwasm_h_seen__ diff -r 99e3b3310bac -r 538e15927776 src/parse.c --- a/src/parse.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/parse.c Sat Jan 03 04:20:49 2009 +0000 @@ -37,17 +37,43 @@ char *p, *p2; char *opc; int opnum; + char *sym; p = l -> text; if (!*p) + { + as -> context += 1; return 0; + } if (!isspace(*p) && *p != '*' && *p != ';') { // we have a symbol specified here // parse it and define // need to handle local symbols here... + for (p2 = p; *p2 && !isspace(*p2); p2++) + /* do nothing */ ; + + sym = lwasm_alloc((p2 - p) + 1); + sym[p2 - p] = '\0'; + memcpy(sym, p, p2 - p); + + l -> sym = sym; + // have a symbol; now determine if it is valid and register it + // at the current address of the line + if (lwasm_register_symbol(as, l, sym, as -> addr) < 0) + l -> sym = NULL; + } + else + { + while (*p && isspace(*p)) + (*p)++; + if (!*p) + { + as -> context += 1; + return 0; + } } // skip white space @@ -56,7 +82,10 @@ // if comment or end of line, return if (!*p || *p == '*' || *p == ';') + { + lwasm_free(l -> sym); return 0; + } // parse the opcode for (p2 = p; *p2 && !isspace(*p2); p2++) @@ -83,6 +112,7 @@ { // invalid operation code, throw error register_error(as, l, 1, "Invalid operation code '%s'", opc); + lwasm_free(l -> sym); lwasm_free(opc); return -1; } @@ -91,4 +121,5 @@ (instab[opnum].fn)(as, l, &p2, opnum); lwasm_free(opc); + lwasm_free(sym); } diff -r 99e3b3310bac -r 538e15927776 src/pass1.c --- a/src/pass1.c Fri Jan 02 06:07:40 2009 +0000 +++ b/src/pass1.c Sat Jan 03 04:20:49 2009 +0000 @@ -135,6 +135,7 @@ nl -> prev = as -> linestail; nl -> err = NULL; nl -> fsize = 0; + nl -> sym = NULL; if (as -> linestail) as -> linestail -> next = nl; else diff -r 99e3b3310bac -r 538e15927776 src/symbol.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/symbol.c Sat Jan 03 04:20:49 2009 +0000 @@ -0,0 +1,120 @@ +/* +symbol.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +*/ + +/* +for handling the symbol table +*/ + +#define __symbol_c_seen__ + +#include + +#include "lwasm.h" +#include "util.h" + +int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val) +{ + lwasm_symbol_ent_t *se, *se2; + char *p; + + int scontext = -1; + + // first check if the symbol is valid + // the following characters are allowed in a symbol: + // [a-zA-Z0-9._$?@] and any byte value larger than 0x7F + // although symbols should be restricted to the 7 bit range + // symbols must start with [a-zA-Z._] + if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._@?", *sym)) + { + register_error(as, l, 1, "Bad symbol: %s", sym); + return -1; + } + + for (p = sym; *p; p++) + { + if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._$?@0123456789", *sym) && (unsigned char)*sym < 0x80) + { + register_error(as, l, 1, "Bad symbol: %s", sym); + return -1; + } + // flag local symbols while we're at it... + if (*p == '?' || *p == '@') + scontext = as -> context; + } + + // now look it for to see if it is a duplicate + se = lwasm_find_symbol(as, sym, scontext); + if (se) + { + register_error(as, l, 1, "Mulitply defined symbol: %s", sym); + return -1; + } + + // if not a duplicate, register it with the value + se = lwasm_alloc(sizeof(lwasm_symbol_ent_t)); + if (as -> symhead) + { + se -> prev = NULL; + se -> next = as -> symhead; + as -> symhead -> prev = se; + as -> symhead = se; + } + else + { + se -> next = NULL; + se -> prev = NULL; + as -> symhead = se; + as -> symtail = se; + } + se -> value = val; + se -> sym = lwasm_strdup(sym); + se -> context = scontext; + + return 0; +} + +lwasm_symbol_ent_t *lwasm_find_symbol(asmstate_t *as, char *sym, int scontext) +{ + lwasm_symbol_ent_t *se; + + for (se = as -> symhead; se; se = se -> next) + { + if (scontext == se -> context && !strcmp(sym, se -> sym)) + { + return se; + } + } + return NULL; +} + +// reset the value of a symbol - should not be used normally +// it is intended for use by such operations as EQU +// returns -1 if the symbol is not registered +int lwasm_set_symbol(asmstate_t *as, char *sym, int scontext, int val) +{ + lwasm_symbol_ent_t *se; + + se = lwasm_find_symbol(as, sym, scontext); + if (!se) + return -1; + + se -> value = val; + return 0; +} diff -r 99e3b3310bac -r 538e15927776 src/symtab.c --- a/src/symtab.c Fri Jan 02 06:07:40 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* -symtab.c -Copyright © 2008 William Astle - -This file is part of LWASM. - -LWASM is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see . - -Implements code for handling the symbol table. -*/ - -#include -#include -#include -#include -#include -#define __symtab_c_seen__ -#include "lwasm.h" - -void register_symbol(asmstate_t *as, sourceline_t *cl, char *symstr, int val, int flags) -{ - symtab_t *st; - symtab_t *prev; - int cv = -2; - - for (prev = NULL, st = as -> symbol_table; st; st = st -> next) - { - cv = strcasecmp(st -> symbol, symstr); - if (cv == 0) - { - cv = strcmp(st -> symbol, symstr); - } - if (cv >= 0) - break; - prev = st; - } - // cv is 0 if we found the symbol, > 0 if we didn't and found one - // later in order, or -2 if we never did a comparison - // if st is NULL, the value of cv is irrelevant as it means - // we fell off the end of the list - // if st is NULL and prev is not, then prev is the tail of the list - // if both are NULL, the list is empty - - // handle adding the symbol if needed - if (!st || cv != 0) - { - symtab_t *st2; - // register the symbol - st2 = malloc(sizeof(symtab_t)); - st2 -> symbol = strdup(symstr); - st2 -> addr = val; - st2 -> flags = 0; - if (flags & SYMFLAG_SET) - st2 -> flags |= SYMFLAG_SET; - - if (prev) - prev -> next = st2; - else - as -> symbol_table = st2; - - st2 -> next = st; - return; - } - - // st is NOT NULL here and cv IS 0 - if ((flags & SYMFLAG_SET) && ((st -> flags) & SYMFLAG_SET)) - { - // symbol already exists but it is a "SET" symbol so reset the value - st -> addr = val; - return; - } - if (st && as -> passnum == 1) - { - // duplicate symbol, flag error - errorp1(ERR_DUPSYM); - } - if (st -> addr != val) - errorp2(ERR_PHASE); -} - -int lookup_symbol(asmstate_t *as, char *symstr) -{ - symtab_t *st; - - for (st = as -> symbol_table; st; st = st -> next) - { - if (!strcmp(symstr, st -> symbol)) - break; - } - if (st) - return st -> addr; - return -1; -} - -void list_symbols(asmstate_t *as, FILE *f) -{ - symtab_t *st; - for (st = as -> symbol_table; st; st = st -> next) - { - fprintf(f, "%04X %s%s\n", st -> addr, st -> symbol, (st -> flags & SYMFLAG_SET) ? "(S)" : ""); - } -}