/* Parse and emit initializer code for target variable in statements such as * int b[] = {0, 1, 2, 3}. Generate a series of assignment operations on * references to target variable. */ static struct block *initializer(struct block *block, struct var target) { assert(target.kind == DIRECT); /* Do not care about cv-qualifiers here. */ target.type = unwrapped(target.type); if (peek().token == '{') { block = object_initializer(block, target); } else { block = assignment_expression(block); if (!target.symbol->depth && block->expr.kind != IMMEDIATE) { error("Initializer must be computable at load time."); exit(1); } if (target.kind == DIRECT && !target.type->size) { assert(!target.offset); assert(is_string(block->expr)); assert(is_array(block->expr.type)); /* Complete type based on string literal. Evaluation does not have * the required context to do this logic. */ ((struct symbol *) target.symbol)->type.size = block->expr.type->size; target.type = block->expr.type; } eval_assign(block, target, block->expr); } return block; }
struct block *assignment_expression(struct block *block) { struct var target; block = conditional_expression(block); target = block->expr; switch (peek().token) { case '=': consume('='); block = assignment_expression(block); break; case MUL_ASSIGN: consume(MUL_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_MUL, target, block->expr); break; case DIV_ASSIGN: consume(DIV_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_DIV, target, block->expr); break; case MOD_ASSIGN: consume(MOD_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_MOD, target, block->expr); break; case PLUS_ASSIGN: consume(PLUS_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_ADD, target, block->expr); break; case MINUS_ASSIGN: consume(MINUS_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_SUB, target, block->expr); break; case AND_ASSIGN: consume(AND_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_AND, target, block->expr); break; case OR_ASSIGN: consume(OR_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_OR, target, block->expr); break; case XOR_ASSIGN: consume(XOR_ASSIGN); block = assignment_expression(block); block->expr = eval_expr(block, IR_OP_XOR, target, block->expr); break; default: return block; } block->expr = eval_assign(block, target, block->expr); return block; }
/** Evaluate a function call */ value_t eval_call( clos_t* callee, array_t* arg_exprs, clos_t* caller, value_t* caller_locals ) { ast_fun_t* fptr = callee->fun; assert (fptr != NULL); if (arg_exprs->len != fptr->param_decls->len) { printf("argument count mismatch\n"); exit(-1); } // Allocate space for the local variables value_t* callee_locals = alloca( sizeof(value_t) * fptr->local_decls->len ); // Allocate mutable cells for the escaping variables for (size_t i = 0; i < fptr->esc_locals->len; ++i) { ast_decl_t* decl = array_get(fptr->esc_locals, i).word.decl; assert (decl->esc); assert (decl->idx < fptr->local_decls->len); callee_locals[decl->idx] = value_from_obj((heapptr_t)cell_alloc()); } // Evaluate the argument values for (size_t i = 0; i < arg_exprs->len; ++i) { //printf("evaluating arg %ld\n", i); heapptr_t param_decl = array_get_ptr(fptr->param_decls, i); // Evaluate the parameter value value_t arg_val = eval_expr( array_get_ptr(arg_exprs, i), caller, caller_locals ); // Assign the value to the parameter eval_assign( param_decl, arg_val, callee, callee_locals ); } // Evaluate the unit function body in the local frame return eval_expr(fptr->body_expr, callee, callee_locals); }
static struct block *unary_expression(struct block *block) { struct var value; switch (peek().token) { case '&': consume('&'); block = cast_expression(block); block->expr = eval_addr(block, block->expr); break; case '*': consume('*'); block = cast_expression(block); block->expr = eval_deref(block, block->expr); break; case '!': consume('!'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_EQ, var_int(0), block->expr); break; case '~': consume('~'); block = cast_expression(block); block->expr = eval_expr(block, IR_NOT, block->expr); break; case '+': consume('+'); block = cast_expression(block); block->expr.lvalue = 0; break; case '-': consume('-'); block = cast_expression(block); block->expr = eval_expr(block, IR_OP_SUB, var_int(0), block->expr); break; case SIZEOF: { struct typetree *type; struct block *head = cfg_block_init(), *tail; consume(SIZEOF); if (peek().token == '(') { switch (peekn(2).token) { case FIRST(type_name): consume('('); type = declaration_specifiers(NULL); if (peek().token != ')') { type = declarator(type, NULL); } consume(')'); break; default: tail = unary_expression(head); type = (struct typetree *) tail->expr.type; break; } } else { tail = unary_expression(head); type = (struct typetree *) tail->expr.type; } if (is_function(type)) { error("Cannot apply 'sizeof' to function type."); } if (!size_of(type)) { error("Cannot apply 'sizeof' to incomplete type."); } block->expr = var_int(size_of(type)); break; } case INCREMENT: consume(INCREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_ADD, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; case DECREMENT: consume(DECREMENT); block = unary_expression(block); value = block->expr; block->expr = eval_expr(block, IR_OP_SUB, value, var_int(1)); block->expr = eval_assign(block, value, block->expr); break; default: block = postfix_expression(block); break; } return block; }
static struct block *postfix_expression(struct block *block) { struct var root; block = primary_expression(block); root = block->expr; while (1) { const struct member *field; const struct typetree *type; struct var expr, copy, *arg; struct token tok; int i, j; switch ((tok = peek()).token) { case '[': do { /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic * takes care of multiplying b with the correct width. */ consume('['); block = expression(block); root = eval_expr(block, IR_OP_ADD, root, block->expr); root = eval_deref(block, root); consume(']'); } while (peek().token == '['); break; case '(': type = root.type; if (is_pointer(root.type) && is_function(root.type->next)) type = type_deref(root.type); else if (!is_function(root.type)) { error("Expression must have type pointer to function, was %t.", root.type); exit(1); } consume('('); arg = calloc(nmembers(type), sizeof(*arg)); for (i = 0; i < nmembers(type); ++i) { if (peek().token == ')') { error("Too few arguments, expected %d but got %d.", nmembers(type), i); exit(1); } block = assignment_expression(block); arg[i] = block->expr; /* todo: type check here. */ if (i < nmembers(type) - 1) { consume(','); } } while (is_vararg(type) && peek().token != ')') { consume(','); arg = realloc(arg, (i + 1) * sizeof(*arg)); block = assignment_expression(block); arg[i] = block->expr; i++; } consume(')'); for (j = 0; j < i; ++j) param(block, arg[j]); free(arg); root = eval_call(block, root); break; case '.': consume('.'); tok = consume(IDENTIFIER); field = find_type_member(root.type, tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } root.type = field->type; root.offset += field->offset; break; case ARROW: consume(ARROW); tok = consume(IDENTIFIER); if (is_pointer(root.type) && is_struct_or_union(root.type->next)) { field = find_type_member(type_deref(root.type), tok.strval); if (!field) { error("Invalid field access, no member named '%s'.", tok.strval); exit(1); } /* Make it look like a pointer to the field type, then perform * normal dereferencing. */ root.type = type_init(T_POINTER, field->type); root = eval_deref(block, root); root.offset = field->offset; } else { error("Invalid field access."); exit(1); } break; case INCREMENT: consume(INCREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_ADD, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; case DECREMENT: consume(DECREMENT); copy = create_var(root.type); eval_assign(block, copy, root); expr = eval_expr(block, IR_OP_SUB, root, var_int(1)); eval_assign(block, root, expr); root = copy; break; default: block->expr = root; return block; } } }
/** Evaluate an expression in a given frame */ value_t eval_expr( heapptr_t expr, clos_t* clos, value_t* locals ) { //printf("eval_expr\n"); // Get the shape of the AST node // Note: AST nodes must match the shapes defined in init_parser, // otherwise this interpreter can't handle it shapeidx_t shape = get_shape(expr); // Variable or constant declaration (let/var) if (shape == SHAPE_AST_DECL) { ast_decl_t* decl = (ast_decl_t*)expr; // Let declarations should be initialized assert (decl->cst == false); return VAL_FALSE; } // Variable reference (read) if (shape == SHAPE_AST_REF) { ast_ref_t* ref = (ast_ref_t*)expr; assert (ref->decl != NULL); //printf("evaluating ref to %s\n", string_cstr(ref->name)); // If this is a variable from an outer function if (ref->decl->fun != clos->fun) { //printf("ref from outer fun\n"); assert (ref->idx < clos->fun->free_vars->len); cell_t* cell = clos->cells[ref->idx]; assert (cell != NULL); value_t value; value.word = cell->word; value.tag = cell->tag; return value; } // Check that the ref index is valid if (ref->idx > clos->fun->local_decls->len) { printf("invalid variable reference\n"); printf("ref->name=%s\n", string_cstr(ref->name)); printf("ref->idx=%d\n", ref->idx); printf("local_decls->len=%d\n", clos->fun->local_decls->len); exit(-1); } // If this an escaping variable (captured by a closure) if (ref->decl->esc) { // Free variables are stored in mutable cells // Pointers to the cells are found on the closure object cell_t* cell = locals[ref->idx].word.cell; value_t value; value.word = cell->word; value.tag = cell->tag; //printf("read value from cell\n"); return value; } /* printf("reading normal local\n"); string_print(ref->name); printf("\n"); */ // Read directly from the stack frame return locals[ref->idx]; } if (shape == SHAPE_AST_CONST) { //printf("constant\n"); ast_const_t* cst = (ast_const_t*)expr; return cst->val; } if (shape == SHAPE_STRING) { return value_from_heapptr(expr, TAG_STRING); } // Array literal expression if (shape == SHAPE_ARRAY) { array_t* array_expr = (array_t*)expr; // Array of values to be produced array_t* val_array = array_alloc(array_expr->len); for (size_t i = 0; i < array_expr->len; ++i) { heapptr_t expr = array_get(array_expr, i).word.heapptr; value_t value = eval_expr(expr, clos, locals); array_set(val_array, i, value); } return value_from_heapptr((heapptr_t)val_array, TAG_ARRAY); } // Object literal expression if (shape == SHAPE_AST_OBJ) { //printf("obj literal expr\n"); ast_obj_t* obj_expr = (ast_obj_t*)expr; object_t* obj = object_alloc(OBJ_MIN_CAP); // TODO: set prototype // Do this in object_alloc? for (size_t i = 0; i < obj_expr->name_strs->len; ++i) { string_t* prop_name = array_get(obj_expr->name_strs, i).word.string; heapptr_t val_expr = array_get(obj_expr->val_exprs, i).word.heapptr; value_t value = eval_expr(val_expr, clos, locals); object_set_prop( obj, prop_name, value, ATTR_DEFAULT ); } return value_from_obj((heapptr_t)obj); } // Binary operator (e.g. a + b) if (shape == SHAPE_AST_BINOP) { //printf("binop\n"); ast_binop_t* binop = (ast_binop_t*)expr; // Assignment if (binop->op == &OP_ASSIGN) { value_t val = eval_expr(binop->right_expr, clos, locals); return eval_assign( binop->left_expr, val, clos, locals ); } value_t v0 = eval_expr(binop->left_expr, clos, locals); value_t v1 = eval_expr(binop->right_expr, clos, locals); int64_t i0 = v0.word.int64; int64_t i1 = v1.word.int64; string_t* s0 = v0.word.string; string_t* s1 = v1.word.string; if (binop->op == &OP_MEMBER) return eval_get_prop(v0, v1); if (binop->op == &OP_INDEX) return eval_get_index(v0, v1); if (binop->op == &OP_ADD) return value_from_int64(i0 + i1); if (binop->op == &OP_SUB) return value_from_int64(i0 - i1); if (binop->op == &OP_MUL) return value_from_int64(i0 * i1); if (binop->op == &OP_DIV) return value_from_int64(i0 / i1); if (binop->op == &OP_MOD) return value_from_int64(i0 % i1); if (binop->op == &OP_LT) return (i0 < i1)? VAL_TRUE:VAL_FALSE; if (binop->op == &OP_LE) { if (v0.tag == TAG_STRING && v1.tag == TAG_STRING) return (strcmp(string_cstr(s0), string_cstr(s1)) <= 0)? VAL_TRUE:VAL_FALSE; if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64) return (i0 <= i1)? VAL_TRUE:VAL_FALSE; assert (false); } if (binop->op == &OP_GT) return (i0 > i1)? VAL_TRUE:VAL_FALSE; if (binop->op == &OP_GE) { if (v0.tag == TAG_STRING && v1.tag == TAG_STRING) return (strcmp(string_cstr(s0), string_cstr(s1)) >= 0)? VAL_TRUE:VAL_FALSE; if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64) return (i0 >= i1)? VAL_TRUE:VAL_FALSE; assert (false); } if (binop->op == &OP_EQ) return value_equals(v0, v1)? VAL_TRUE:VAL_FALSE; if (binop->op == &OP_NE) return value_equals(v0, v1)? VAL_FALSE:VAL_TRUE; printf("unimplemented binary operator: %s\n", binop->op->str); return VAL_FALSE; } // Unary operator (e.g.: -x, not a) if (shape == SHAPE_AST_UNOP) { ast_unop_t* unop = (ast_unop_t*)expr; value_t v0 = eval_expr(unop->expr, clos, locals); if (unop->op == &OP_NEG) return value_from_int64(-v0.word.int64); if (unop->op == &OP_NOT) return eval_truth(v0)? VAL_FALSE:VAL_TRUE; printf("unimplemented unary operator: %s\n", unop->op->str); return VAL_FALSE; } // Sequence/block expression if (shape == SHAPE_AST_SEQ) { ast_seq_t* seqexpr = (ast_seq_t*)expr; array_t* expr_list = seqexpr->expr_list; value_t value = VAL_TRUE; for (size_t i = 0; i < expr_list->len; ++i) { heapptr_t expr = array_get(expr_list, i).word.heapptr; value = eval_expr(expr, clos, locals); } // Return the value of the last expression return value; } // If expression if (shape == SHAPE_AST_IF) { ast_if_t* ifexpr = (ast_if_t*)expr; value_t t = eval_expr(ifexpr->test_expr, clos, locals); if (eval_truth(t)) return eval_expr(ifexpr->then_expr, clos, locals); else return eval_expr(ifexpr->else_expr, clos, locals); } // Function/closure expression if (shape == SHAPE_AST_FUN) { //printf("creating closure\n"); ast_fun_t* nested = (ast_fun_t*)expr; // Allocate a closure of the nested function clos_t* new_clos = clos_alloc(nested); // For each free (closure) variable of the nested function for (size_t i = 0; i < nested->free_vars->len; ++i) { ast_decl_t* decl = array_get(nested->free_vars, i).word.decl; // If the variable is from this function if (decl->fun == clos->fun) { new_clos->cells[i] = locals[decl->idx].word.cell; } else { uint32_t free_idx = array_indexof_ptr(clos->fun->free_vars, (heapptr_t)decl); assert (free_idx < clos->fun->free_vars->len); new_clos->cells[i] = clos->cells[free_idx]; } } assert (new_clos->fun == nested); return value_from_heapptr((heapptr_t)new_clos, TAG_CLOS); } // Call expression if (shape == SHAPE_AST_CALL) { //printf("evaluating call\n"); ast_call_t* callexpr = (ast_call_t*)expr; // Evaluate the closure expression value_t callee_clos = eval_expr(callexpr->fun_expr, clos, locals); if (callee_clos.tag == TAG_CLOS) { return eval_call( callee_clos.word.clos, callexpr->arg_exprs, clos, locals ); } if (callee_clos.tag == TAG_HOSTFN) { return eval_host_call( callee_clos.word.hostfn, callexpr->arg_exprs, clos, locals ); } printf("invalid callee in function call\n"); exit(-1); } printf("eval error, unknown expression type, shapeidx=%d\n", get_shape(expr)); exit(-1); }
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); } }
static void eval_expr(m1_expression *e) { if (e == NULL) return; switch (e->type) { case EXPR_NUMBER: eval_number(e->expr.l->value.fval); break; case EXPR_INT: eval_int(e->expr.l->value.ival); break; case EXPR_BINARY: eval_binary(e->expr.b); break; case EXPR_UNARY: eval_unary(e->expr.u); break; case EXPR_FUNCALL: eval_funcall(e->expr.f); break; case EXPR_ASSIGN: eval_assign(e->expr.a); break; case EXPR_IF: eval_if(e->expr.i); break; case EXPR_WHILE: eval_while(e->expr.w); break; case EXPR_DOWHILE: eval_dowhile(e->expr.w); break; case EXPR_FOR: eval_for(e->expr.o); break; case EXPR_RETURN: eval_return(e->expr.e); break; case EXPR_NULL: eval_null(); break; case EXPR_DEREF: eval_deref(e->expr.t); break; case EXPR_ADDRESS: eval_address(e->expr.t); break; case EXPR_OBJECT: eval_obj(e->expr.t); break; case EXPR_BREAK: eval_break(); break; case EXPR_CONTINUE: eval_continue(); break; case EXPR_CONSTDECL: case EXPR_VARDECL: break; default: fprintf(stderr, "unknown expr type"); exit(EXIT_FAILURE); } }