expr_type make_expr_from_id(id_type id) { expr_type e = (expr_type) SafeMalloc(sizeof(expr_struct)); /* Id must be a parameter, local, property, constant, or resource */ lookup_id(id); switch(id->type) { case I_LOCAL: case I_PROPERTY: case I_CLASSVAR: e->type = E_IDENTIFIER; e->value.idval = id; break; case I_RESOURCE: { const_type c = (const_type) SafeMalloc(sizeof(const_struct)); /* Turn resource id reference into the resource # itself */ c->type = C_RESOURCE; c->value.numval = id->idnum; e->type = E_CONSTANT; e->value.constval = c; return e; } case I_CONSTANT: { const_type c = (const_type) SafeMalloc(sizeof(const_struct)); id_type temp; /* Turn constant id reference into the constant itself */ c->type = C_NUMBER; temp = (id_type) list_find_item(st.constants, id, id_compare); c->value.numval = temp->source; /* Value is stored in source field */ e->type = E_CONSTANT; e->value.constval = c; break; } case I_UNDEFINED: case I_MISSING: action_error("Unknown identifier %s", id->name); /* Put in something so that compilation can continue */ e = make_expr_from_constant(make_nil_constant()); break; default: action_error("Identifier %s in expression has wrong type", id->name); /* Put in something so that compilation can continue */ e = make_expr_from_constant(make_nil_constant()); break; } e->lineno = lineno; return e; }
/* * codegen_foreach: Generate code for a for loop statement. * numlocals should be # of local variables for message excluding temps. * Returns highest # local variable used in code for statement. * Here is how code is generated for a FOR statement: * for i in list ===> temp = list 1 * {body} top: if (temp = $) goto end 2 * i = First(temp) 3 * { body } * temp = Rest(temp) 4 * goto top 5 * end: * * Note that continue statements need to jump to statement 4. */ int codegen_foreach(foreach_stmt_type s, int numlocals) { opcode_type opcode; int our_maxlocal, numtemps; stmt_type temp_stmt = (stmt_type) SafeMalloc(sizeof(stmt_struct)); expr_type temp_expr = (expr_type) SafeMalloc(sizeof(expr_struct)); expr_type temp2_expr = (expr_type) SafeMalloc(sizeof(expr_struct)); assign_stmt_type assign_stmt = (assign_stmt_type) SafeMalloc(sizeof(assign_stmt_struct)); call_stmt_type call_stmt = (call_stmt_type) SafeMalloc(sizeof(call_stmt_struct)); arg_type arg = (arg_type) SafeMalloc(sizeof(arg_struct)); id_type temp_id, temp2_id; long toppos; list_type p; /* Make variable "temp" */ temp_id = make_temp_var(numlocals + 1); /**** Statement #1: temp = list ****/ assign_stmt->lhs = temp_id; assign_stmt->rhs = s->condition; temp_stmt->type = S_ASSIGN; temp_stmt->value.assign_stmt_val = assign_stmt; temp_stmt->lineno = 0; numtemps = codegen_statement(temp_stmt, numlocals); /* Reserve variable "temp" through entire loop by incrementing numlocals */ our_maxlocal = ++numlocals; if (numtemps > our_maxlocal) our_maxlocal = numtemps; toppos = FileCurPos(outfile); codegen_enter_loop(); /**** Statement #2: if (temp = $) goto end ****/ /* First put result of temp = $ into temp2 */ temp2_id = make_temp_var(numlocals + 1); if (numlocals + 1 > our_maxlocal) our_maxlocal = numlocals + 1; temp2_expr->type = E_IDENTIFIER; temp2_expr->value.idval = temp_id; temp_expr->type = E_BINARY_OP; temp_expr->value.binary_opval.op = EQ_OP; temp_expr->value.binary_opval.left_exp = temp2_expr; temp_expr->value.binary_opval.right_exp = make_expr_from_constant(make_nil_constant()); assign_stmt->lhs = temp2_id; assign_stmt->rhs = temp_expr; temp_stmt->type = S_ASSIGN; temp_stmt->value.assign_stmt_val = assign_stmt; /* YECHHH! */ temp_stmt->lineno = 0; codegen_statement(temp_stmt, numlocals); /* Won't require more temps */ /* Now perform jump if temp = $ is true */ memset(&opcode, 0, sizeof(opcode)); /* Set opcode to all zeros */ opcode.command = GOTO; opcode.source1 = LOCAL_VAR; opcode.dest = GOTO_IF_TRUE; OutputOpcode(outfile, opcode); /* Make believe goto is a break statement & leave space for backpatching */ current_loop->break_list = list_add_item(current_loop->break_list, (void *) FileCurPos(outfile)); OutputInt(outfile, 0); OutputInt(outfile, temp2_id->idnum); /* Jump if temp2 = TRUE */ /**** Statement #3: i = First(temp) ****/ temp_expr->type = E_IDENTIFIER; temp_expr->value.idval = temp_id; arg->type = ARG_EXPR; arg->value.expr_val = temp_expr; call_stmt->function = FIRST; call_stmt->args = list_create(arg); codegen_call(call_stmt, s->id, numlocals); /* Won't require more temps */ /* Write code for loop body */ for (p = s->body; p != NULL; p = p->next) { numtemps = codegen_statement( (stmt_type) p->data, numlocals); if (numtemps > our_maxlocal) our_maxlocal = numtemps; } /* Backpatch continue statements in loop body */ for (p = current_loop->for_continue_list; p != NULL; p = p->next) BackpatchGoto(outfile, (int) p->data, FileCurPos(outfile)); /**** Statement #4: temp = Rest(temp) ****/ /* Can reuse most of statement #3 above */ call_stmt->function = REST; codegen_call(call_stmt, temp_id, numlocals); /* Won't require more temps */ /**** Statement #5: goto top ****/ opcode.source1 = 0; opcode.source2 = GOTO_UNCONDITIONAL; opcode.dest = 0; OutputOpcode(outfile, opcode); OutputGotoOffset(outfile, FileCurPos(outfile), toppos); codegen_exit_loop(); /* Takes care of break statements */ return our_maxlocal; }