obj_ptr obj_alloc_symbol(cptr val) { obj_ptr res = gc_alloc(); res->type = TYPE_SYMBOL; res->data.as_symbol = sym_add(val); return res; }
static struct block *primary_expression(struct block *block) { const struct symbol *sym; struct token tok; switch ((tok = next()).token) { case IDENTIFIER: sym = sym_lookup(&ns_ident, tok.strval); if (!sym) { error("Undefined symbol '%s'.", tok.strval); exit(1); } /* Special handling for builtin pseudo functions. These are expected to * behave as macros, thus should be no problem parsing as function call * in primary expression. Constructs like (va_arg)(args, int) will not * work with this scheme. */ if (!strcmp("__builtin_va_start", sym->name)) { block = parse__builtin_va_start(block); } else if (!strcmp("__builtin_va_arg", sym->name)) { block = parse__builtin_va_arg(block); } else { block->expr = var_direct(sym); } break; case INTEGER_CONSTANT: block->expr = var_int(tok.intval); break; case '(': block = expression(block); consume(')'); break; case STRING: sym = sym_add(&ns_ident, ".LC", type_init(T_ARRAY, &basic_type__char, strlen(tok.strval) + 1), SYM_STRING_VALUE, LINK_INTERN); /* Store string value directly on symbol, memory ownership is in string * table from previously called str_register. The symbol now exists as * if it was declared static char .LC[] = "...". */ ((struct symbol *) sym)->string_value = tok.strval; /* Result is an IMMEDIATE of type [] char, with a reference to the new * symbol containing the string literal. Will decay into char * on * evaluation. */ block->expr = var_direct(sym); assert(block->expr.kind == IMMEDIATE); break; default: error("Unexpected '%s', not a valid primary expression.", tok.strval); exit(1); } return block; }
void sym_patchnames(void) { int i,j; char *p; for(j=0; ospatch[j]; j++) { p=strchr(ospatch[j],' '); if(!p) { print("ERROR in ospatch.h (%s)\n",ospatch[j]); return; } else { if(p[-1]=='*') { ospatchwild[j]=1; ospatchlen[j]=p-ospatch[j]-1; } else { ospatchwild[j]=0; ospatchlen[j]=p-ospatch[j]; } } } for(i=0; i<symnum; i++) { p=strchr(sym[i].text,'%'); if(p) continue; // patch disabled p=strchr(sym[i].text,'#'); if(!p) { // no patch yet, add one from ospatch[] if applicable for(j=0; ospatch[j]; j++) { if(strlen(sym[i].text)<ospatchlen[j]) continue; if(memicmp(sym[i].text,ospatch[j],ospatchlen[j])) continue; if(!ospatchwild[j] && sym[i].text[ospatchlen[j]]>32) continue; // match { char buf[256]; // print("- symbol patch %s [%s,%i] => ",sym[i].text,ospatch[j],ospatchlen[j]); sprintf(buf,"%s %s",sym[i].text,ospatch[j]+ospatchlen[j]+1); p=strchr(ospatch[j],'#'); if(!p) p="0"; sym_add(sym[i].addr,buf,atoi(p+1)); // print("%s\n",sym[i].text); } break; } } } }
/* C99: Define __func__ as static const char __func__[] = sym->name; */ static void define_builtin__func__(const char *name) { struct typetree *type; struct symbol *sym; assert(ns_ident.current_depth == 1); /* Just add the symbol directly as a special string value. No explicit * assignment reflected in the IR. */ type = type_init(T_ARRAY, &basic_type__char, strlen(name) + 1); sym = sym_add(&ns_ident, "__func__", type, SYM_STRING_VALUE, LINK_INTERN); sym->string_value = name; }
void sym_clear(void) { int i; // who cares about memory loss :) symnum=0; // default null symbol sym_add(0,"(null)",0); // clear ospatches for(i=0; oscall[i][15]; i++) { oscall[i][12]=0; oscall[i][13]=0; } }
/* * init_lex - initialize lexical analyzer. */ void init_lex() { struct sym_entry *sym; int i; static int first_time = 1; if (first_time) { first_time = 0; ident = spec_str(ident); /* install ident in string table */ /* * install C keywords into the symbol table */ sym_add(Auto, spec_str("auto"), OtherDcl, 0); sym_add(Break, spec_str("break"), OtherDcl, 0); sym_add(Case, spec_str("case"), OtherDcl, 0); sym_add(TokChar, spec_str("char"), OtherDcl, 0); sym_add(Const, spec_str("const"), OtherDcl, 0); sym_add(Continue, spec_str("continue"), OtherDcl, 0); sym_add(Default, spec_str("default"), OtherDcl, 0); sym_add(Do, spec_str("do"), OtherDcl, 0); sym_add(Doubl, spec_str("double"), OtherDcl, 0); sym_add(Else, spec_str("else"), OtherDcl, 0); sym_add(TokEnum, spec_str("enum"), OtherDcl, 0); sym_add(Extern, spec_str("extern"), OtherDcl, 0); sym_add(Float, spec_str("float"), OtherDcl, 0); sym_add(For, spec_str("for"), OtherDcl, 0); sym_add(Goto, spec_str("goto"), OtherDcl, 0); sym_add(If, spec_str("if"), OtherDcl, 0); sym_add(Int, spec_str("int"), OtherDcl, 0); sym_add(TokLong, spec_str("long"), OtherDcl, 0); sym_add(TokRegister, spec_str("register"), OtherDcl, 0); sym_add(Return, spec_str("return"), OtherDcl, 0); sym_add(TokShort, spec_str("short"), OtherDcl, 0); sym_add(Signed, spec_str("signed"), OtherDcl, 0); sym_add(Sizeof, spec_str("sizeof"), OtherDcl, 0); sym_add(Static, spec_str("static"), OtherDcl, 0); sym_add(Struct, spec_str("struct"), OtherDcl, 0); sym_add(Switch, spec_str("switch"), OtherDcl, 0); sym_add(Typedef, spec_str("typedef"), OtherDcl, 0); sym_add(Union, spec_str("union"), OtherDcl, 0); sym_add(Unsigned, spec_str("unsigned"), OtherDcl, 0); sym_add(Void, spec_str("void"), OtherDcl, 0); sym_add(Volatile, spec_str("volatile"), OtherDcl, 0); sym_add(While, spec_str("while"), OtherDcl, 0); /* * Install keywords from run-time interface language. */ sym_add(Abstract, spec_str("abstract"), OtherDcl, 0); sym_add(All_fields, spec_str("all_fields"), OtherDcl, 0); sym_add(Any_value, spec_str("any_value"), OtherDcl, 0); sym_add(Arith_case, spec_str("arith_case"), OtherDcl, 0); sym_add(Body, spec_str("body"), OtherDcl, 0); sym_add(C_Double, spec_str("C_double"), OtherDcl, 0); sym_add(C_Integer, spec_str("C_integer"), OtherDcl, 0); sym_add(C_String, spec_str("C_string"), OtherDcl, 0); sym_add(Cnv, spec_str("cnv"), OtherDcl, 0); sym_add(Constant, spec_str("constant"), OtherDcl, 0); sym_add(Declare, spec_str("declare"), OtherDcl, 0); sym_add(Def, spec_str("def"), OtherDcl, 0); sym_add(Empty_type, spec_str("empty_type"), OtherDcl, 0); sym_add(End, spec_str("end"), OtherDcl, 0); sym_add(Errorfail, spec_str("errorfail"), OtherDcl, 0); sym_add(Exact, spec_str("exact"), OtherDcl, 0); sym_add(Fail, spec_str("fail"), OtherDcl, 0); sym_add(TokFunction, spec_str("function"), OtherDcl, 0); sym_add(Inline, spec_str("inline"), OtherDcl, 0); sym_add(Is, spec_str("is"), OtherDcl, 0); sym_add(Keyword, spec_str("keyword"), OtherDcl, 0); sym_add(Len_case, spec_str("len_case"), OtherDcl, 0); sym_add(Named_var, spec_str("named_var"), OtherDcl, 0); sym_add(New, spec_str("new"), OtherDcl, 0); sym_add(Of, spec_str("of"), OtherDcl, 0); sym_add(Operator, spec_str("operator"), OtherDcl, 0); str_rslt = spec_str("result"); sym_add(Runerr, spec_str("runerr"), OtherDcl, 0); sym_add(Store, spec_str("store"), OtherDcl, 0); sym_add(Struct_var, spec_str("struct_var"), OtherDcl, 0); sym_add(Suspend, spec_str("suspend"), OtherDcl, 0); sym_add(Tended, spec_str("tended"), OtherDcl, 0); sym_add(Then, spec_str("then"), OtherDcl, 0); sym_add(Tmp_cset, spec_str("tmp_cset"), OtherDcl, 0); sym_add(Tmp_string, spec_str("tmp_string"), OtherDcl, 0); sym_add(TokType, spec_str("type"), OtherDcl, 0); sym_add(Type_case, spec_str("type_case"), OtherDcl, 0); sym_add(Underef, spec_str("underef"), OtherDcl, 0); sym_add(Variable, spec_str("variable"), OtherDcl, 0); for (i = 0; i < num_typs; ++i) { icontypes[i].id = spec_str(icontypes[i].id); sym = sym_add(IconType, icontypes[i].id, OtherDcl, 0); sym->u.typ_indx = i; } for (i = 0; i < num_cmpnts; ++i) { typecompnt[i].id = spec_str(typecompnt[i].id); sym = sym_add(Component, typecompnt[i].id, OtherDcl, 0); sym->u.typ_indx = i; } } }
void sym_load(char *file) { FILE *f1; int findoscalls=1; sym_clear(); cart.simplegfx=1; // default to 1 unless cart named f1=fopen(file,"rt"); if(!f1) { *cart.symname=0; } else { while(!feof(f1)) { char buf[256]; dword addr; char *text=buf+9; char *patch=text; int patchcode; *buf=0; fgets(buf,255,f1); buf[strlen(buf)-1]=0; while(*patch && *patch!='#') patch++; if(*patch) patchcode=atoi(patch+1); else patchcode=0; addr=0; sscanf(buf,"%X",&addr); addr&=ADDRMASK; if(addr>0 && buf) { sym_add(addr,text,patchcode); } } fclose(f1); } if(!*cart.symname) print("No symbols. "); else print("Loaded %i symbols from %s. ",symnum,file); findoscalls=1; cart.simplegfx=0; if(!memcmp(cart.title,"SUPER MARIO",11)) cart.ismario=1; if(!memcmp(cart.title,"THE LEGEND ",11)) cart.iszelda=1; print("Mode %i%i. ",cart.ismario,cart.iszelda); if(cart.simplegfx) { showwire=0; showinfo=1; printf("debuggfxmode "); } print("\n"); }
/* Cover both external declarations, functions, and local declarations (with * optional initialization code) inside functions. */ struct block *declaration(struct block *parent) { struct typetree *base; enum symtype symtype; enum linkage linkage; int stc = '$'; base = declaration_specifiers(&stc); switch (stc) { case EXTERN: symtype = SYM_DECLARATION; linkage = LINK_EXTERN; break; case STATIC: symtype = SYM_TENTATIVE; linkage = LINK_INTERN; break; case TYPEDEF: symtype = SYM_TYPEDEF; linkage = LINK_NONE; break; default: if (!ns_ident.current_depth) { symtype = SYM_TENTATIVE; linkage = LINK_EXTERN; } else { symtype = SYM_DEFINITION; linkage = LINK_NONE; } break; } while (1) { struct definition *def; const char *name = NULL; const struct typetree *type; struct symbol *sym; type = declarator(base, &name); if (!name) { consume(';'); return parent; } sym = sym_add(&ns_ident, name, type, symtype, linkage); if (ns_ident.current_depth) { assert(ns_ident.current_depth > 1); def = current_func(); def->locals = sym_list_add(def->locals, sym); } switch (peek().token) { case ';': consume(';'); return parent; case '=': if (sym->symtype == SYM_DECLARATION) { error("Extern symbol '%s' cannot be initialized.", sym->name); exit(1); } if (!sym->depth && sym->symtype == SYM_DEFINITION) { error("Symbol '%s' was already defined.", sym->name); exit(1); } consume('='); sym->symtype = SYM_DEFINITION; if (sym->linkage == LINK_NONE) { assert(parent); parent = initializer(parent, var_direct(sym)); } else { assert(sym->depth || !parent); def = push_back_definition(sym); initializer(def->body, var_direct(sym)); } assert(size_of(&sym->type) > 0); if (peek().token != ',') { consume(';'); return parent; } break; case '{': { int i; if (!is_function(&sym->type) || sym->depth) { error("Invalid function definition."); exit(1); } assert(!parent); assert(sym->linkage != LINK_NONE); sym->symtype = SYM_DEFINITION; def = push_back_definition(sym); push_scope(&ns_ident); define_builtin__func__(sym->name); for (i = 0; i < nmembers(&sym->type); ++i) { name = get_member(&sym->type, i)->name; type = get_member(&sym->type, i)->type; symtype = SYM_DEFINITION; linkage = LINK_NONE; if (!name) { error("Missing parameter name at position %d.", i + 1); exit(1); } def->params = sym_list_add(def->params, sym_add(&ns_ident, name, type, symtype, linkage)); } parent = block(def->body); pop_scope(&ns_ident); return parent; } default: break; } consume(','); } }
static void member_declaration_list(struct typetree *type) { struct namespace ns = {0}; struct typetree *decl_base, *decl_type; const char *name; push_scope(&ns); do { decl_base = declaration_specifiers(NULL); do { name = NULL; decl_type = declarator(decl_base, &name); if (!name) { error("Missing name in member declarator."); exit(1); } else if (!size_of(decl_type)) { error("Field '%s' has incomplete type '%t'.", name, decl_type); exit(1); } else { sym_add(&ns, name, decl_type, SYM_DECLARATION, LINK_NONE); type_add_member(type, name, decl_type); } if (peek().token == ',') { consume(','); continue; } } while (peek().token != ';'); consume(';'); } while (peek().token != '}'); pop_scope(&ns); } static struct typetree *struct_or_union_declaration(void) { struct symbol *sym = NULL; struct typetree *type = NULL; enum type kind = (next().token == STRUCT) ? T_STRUCT : T_UNION; if (peek().token == IDENTIFIER) { const char *name = consume(IDENTIFIER).strval; sym = sym_lookup(&ns_tag, name); if (!sym) { type = type_init(kind); sym = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE); } else if (is_integer(&sym->type)) { error("Tag '%s' was previously declared as enum.", sym->name); exit(1); } else if (sym->type.type != kind) { error("Tag '%s' was previously declared as %s.", sym->name, (sym->type.type == T_STRUCT) ? "struct" : "union"); exit(1); } /* Retrieve type from existing symbol, possibly providing a complete * definition that will be available for later declarations. Overwrites * existing type information from symbol table. */ type = &sym->type; if (peek().token == '{' && type->size) { error("Redefiniton of '%s'.", sym->name); exit(1); } } if (peek().token == '{') { if (!type) { /* Anonymous structure; allocate a new standalone type, * not part of any symbol. */ type = type_init(kind); } consume('{'); member_declaration_list(type); assert(type->size); consume('}'); } /* Return to the caller a copy of the root node, which can be overwritten * with new type qualifiers without altering the tag registration. */ return (sym) ? type_tagged_copy(&sym->type, sym->name) : type; } static void enumerator_list(void) { struct var val; struct symbol *sym; int enum_value = 0; consume('{'); do { const char *name = consume(IDENTIFIER).strval; if (peek().token == '=') { consume('='); val = constant_expression(); if (!is_integer(val.type)) { error("Implicit conversion from non-integer type in enum."); } enum_value = val.imm.i; } sym = sym_add( &ns_ident, name, &basic_type__int, SYM_ENUM_VALUE, LINK_NONE); sym->enum_value = enum_value++; if (peek().token != ',') break; consume(','); } while (peek().token != '}'); consume('}'); } static struct typetree *enum_declaration(void) { struct typetree *type = type_init(T_SIGNED, 4); consume(ENUM); if (peek().token == IDENTIFIER) { struct symbol *tag = NULL; const char *name = consume(IDENTIFIER).strval; tag = sym_lookup(&ns_tag, name); if (!tag || tag->depth < ns_tag.current_depth) { tag = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE); } else if (!is_integer(&tag->type)) { error("Tag '%s' was previously defined as aggregate type.", tag->name); exit(1); } /* Use enum_value as a sentinel to represent definition, checked on * lookup to detect duplicate definitions. */ if (peek().token == '{') { if (tag->enum_value) { error("Redefiniton of enum '%s'.", tag->name); } enumerator_list(); tag->enum_value = 1; } } else { enumerator_list(); } /* Result is always integer. Do not care about the actual enum definition, * all enums are ints and no type checking is done. */ return type; } static struct typetree get_basic_type_from_specifier(unsigned short spec) { switch (spec) { case 0x0001: /* void */ return basic_type__void; case 0x0002: /* char */ case 0x0012: /* signed char */ return basic_type__char; case 0x0022: /* unsigned char */ return basic_type__unsigned_char; case 0x0004: /* short */ case 0x0014: /* signed short */ case 0x000C: /* short int */ case 0x001C: /* signed short int */ return basic_type__short; case 0x0024: /* unsigned short */ case 0x002C: /* unsigned short int */ return basic_type__unsigned_short; case 0x0008: /* int */ case 0x0010: /* signed */ case 0x0018: /* signed int */ return basic_type__int; case 0x0020: /* unsigned */ case 0x0028: /* unsigned int */ return basic_type__unsigned_int; case 0x0040: /* long */ case 0x0050: /* signed long */ case 0x0048: /* long int */ case 0x0058: /* signed long int */ case 0x00C0: /* long long */ case 0x00D0: /* signed long long */ case 0x00D8: /* signed long long int */ return basic_type__long; case 0x0060: /* unsigned long */ case 0x0068: /* unsigned long int */ case 0x00E0: /* unsigned long long */ case 0x00E8: /* unsigned long long int */ return basic_type__unsigned_long; case 0x0100: /* float */ return basic_type__float; case 0x0200: /* double */ case 0x0240: /* long double */ return basic_type__double; default: error("Invalid type specification."); exit(1); } } /* Parse type, qualifiers and storage class. Do not assume int by default, but * require at least one type specifier. Storage class is returned as token * value, unless the provided pointer is NULL, in which case the input is parsed * as specifier-qualifier-list. */ struct typetree *declaration_specifiers(int *stc) { struct typetree *type = NULL; struct token tok; int done = 0; /* Use a compact bit representation to hold state about declaration * specifiers. Initialize storage class to sentinel value. */ unsigned short spec = 0x0000; enum qualifier qual = Q_NONE; if (stc) *stc = '$'; #define set_specifier(d) \ if (spec & d) error("Duplicate type specifier '%s'.", tok.strval); \ next(); spec |= d; #define set_qualifier(d) \ if (qual & d) error("Duplicate type qualifier '%s'.", tok.strval); \ next(); qual |= d; #define set_storage_class(t) \ if (!stc) error("Unexpected storage class in qualifier list."); \ else if (*stc != '$') error("Multiple storage class specifiers."); \ next(); *stc = t; do { switch ((tok = peek()).token) { case VOID: set_specifier(0x001); break; case CHAR: set_specifier(0x002); break; case SHORT: set_specifier(0x004); break; case INT: set_specifier(0x008); break; case SIGNED: set_specifier(0x010); break; case UNSIGNED: set_specifier(0x020); break; case LONG: if (spec & 0x040) { set_specifier(0x080); } else { set_specifier(0x040); } break; case FLOAT: set_specifier(0x100); break; case DOUBLE: set_specifier(0x200); break; case CONST: set_qualifier(Q_CONST); break; case VOLATILE: set_qualifier(Q_VOLATILE); break; case IDENTIFIER: { struct symbol *tag = sym_lookup(&ns_ident, tok.strval); if (tag && tag->symtype == SYM_TYPEDEF && !type) { consume(IDENTIFIER); type = type_init(T_STRUCT); *type = tag->type; } else { done = 1; } break; } case UNION: case STRUCT: if (!type) { type = struct_or_union_declaration(); } else { done = 1; } break; case ENUM: if (!type) { type = enum_declaration(); } else { done = 1; } break; case AUTO: case REGISTER: case STATIC: case EXTERN: case TYPEDEF: set_storage_class(tok.token); break; default: done = 1; break; } if (type && spec) { error("Invalid combination of declaration specifiers."); exit(1); } } while (!done); #undef set_specifier #undef set_qualifier #undef set_storage_class if (type) { if (qual & type->qualifier) { error("Duplicate type qualifier:%s%s.", (qual & Q_CONST) ? " const" : "", (qual & Q_VOLATILE) ? " volatile" : ""); } } else if (spec) { type = type_init(T_STRUCT); *type = get_basic_type_from_specifier(spec); } else { error("Missing type specifier."); exit(1); } type->qualifier |= qual; return type; } /* Set var = 0, using simple assignment on members for composite types. This * rule does not consume any input, but generates a series of assignments on the * given variable. Point is to be able to zero initialize using normal simple * assignment rules, although IR can become verbose for large structures. */ static void zero_initialize(struct block *block, struct var target) { int i; struct var var; assert(target.kind == DIRECT); switch (target.type->type) { case T_STRUCT: case T_UNION: target.type = unwrapped(target.type); var = target; for (i = 0; i < nmembers(var.type); ++i) { target.type = get_member(var.type, i)->type; target.offset = var.offset + get_member(var.type, i)->offset; zero_initialize(block, target); } break; case T_ARRAY: assert(target.type->size); var = target; target.type = target.type->next; assert(is_struct(target.type) || !target.type->next); for (i = 0; i < var.type->size / var.type->next->size; ++i) { target.offset = var.offset + i * var.type->next->size; zero_initialize(block, target); } break; case T_POINTER: var = var_zero(8); var.type = type_init(T_POINTER, &basic_type__void); eval_assign(block, target, var); break; case T_UNSIGNED: case T_SIGNED: var = var_zero(target.type->size); eval_assign(block, target, var); break; default: error("Invalid type to zero-initialize, was '%t'.", target.type); exit(1); } }