Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
            }
        }
    }
}
Пример #4
0
/* 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;
}
Пример #5
0
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;
    }
}
Пример #6
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;
        }
    }
}
Пример #7
0
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");
}
Пример #8
0
/* 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(',');
    }
}
Пример #9
0
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);
    }
}