void gen_VARIABLE ( node_t *root, int scopedepth ) { int stackOffset = root->entry->stack_offset; instruction_add(LOAD, r1, fp, 0, stackOffset); instruction_add(PUSH, r1, NULL, 0, 0); }
void gen_CONSTANT (node_t * root, int scopedepth) { switch (root->data_type.base_type) { case INT_TYPE: { char temp[10]; int32_t t = (int32_t)root->int_const; sprintf(temp, "#%d", t); instruction_add(MOVE32, STRDUP(temp), r1, 0, 0); } break; case STRING_TYPE: { char temp[20]; int32_t t = (int32_t)root->string_index; sprintf(temp, "#.STRING%d", t); instruction_add(MOVE32, STRDUP(temp), r1, 0, 0); } break; case BOOL_TYPE: { char temp[2]; int32_t t = (root->bool_const) ? 1 : 0; sprintf(temp, "#%d", t); instruction_add(MOVE, r1, STRDUP(temp), 0, 0); } break; } instruction_add(PUSH, r1, NULL, 0, 0); }
void gen_DECLARATION_STATEMENT (node_t *root, int scopedepth) { if (root->entry->stack_offset < 0) { instruction_add(MOVE, r1, "#0", 0, 0); instruction_add(PUSH, r1, NULL, 0, 0); } }
void gen_ASSIGNMENT_STATEMENT ( node_t *root, int scopedepth ) { tracePrint ( "Starting ASSIGNMENT_STATEMENT\n"); //Generating the code for the expression part of the assignment. The result is //placed on the top of the stack root->children[1]->generate(root->children[1], scopedepth); // Left hand side may be a class field, which should be handled in this assignment if(root->children[0]->expression_type.index == CLASS_FIELD_E){ // Fetching address value from child 1, pushing to top of stack: root->children[0]->children[0]->generate(root->children[0]->children[0], scopedepth); // Now popping THIS (a.k.a. the objects address value) from stack into r2: instruction_add(POP, r2, NULL, 0,0); // Now popping result from expression into r1: instruction_add(POP, r1, NULL, 0,0); // Now storing to the address on the heap, based on address from child 1 and offset from child 2: instruction_add(STORE, r1, r2, 0, root->children[0]->children[1]->entry->stack_offset); } // or a variable, handled in previous assignment else{ ga(root,scopedepth); } tracePrint ( "End ASSIGNMENT_STATEMENT\n"); }
void gen_PROGRAM ( node_t *root, int scopedepth) { /* Output the data segment */ if( outputStage == 12 ) strings_output ( stderr ); instruction_add ( STRING, STRDUP( ".text" ), NULL, 0, 0 ); tracePrint("Starting PROGRAM\n"); gen_default(root, scopedepth);//RECUR(); TEXT_DEBUG_FUNC_ARM(); TEXT_HEAD_ARM(); /* Call the first defined function */ int last_child = root->n_children - 1; if (root->children[last_child] != NULL) { char *func_label = root->children[last_child]->children[0]->function_entry->label; instruction_add( CALL, STRDUP(func_label), NULL, 0, 0); } tracePrint("End PROGRAM\n"); TEXT_TAIL_ARM(); if( outputStage == 12 ) instructions_print ( stderr ); instructions_finalize (); }
void gen_RETURN_STATEMENT ( node_t *root, int scopedepth ) { root->children[0]->generate(root->children[0], scopedepth); instruction_add(POP, r0, NULL, 0, 0); // Return back to caller instruction_add(MOVE, sp, fp, 0, 0); instruction_add(POP, fp, NULL, 0, 0); instruction_add(POP, "pc", NULL, 0, 0); }
void gen_IF_STATEMENT ( node_t *root, int scopedepth ) { char end_label[15]; sprintf(end_label, "_endif_%d", if_count); char else_label[15]; sprintf(else_label, "_else_%d", if_count); if_count++; root->children[0]->generate(root->children[0], scopedepth); instruction_add(POP, r1, NULL, 0, 0); instruction_add(MOVE, r2, STRDUP("#0"), 0, 0); instruction_add(CMP, r1, r2, 0, 0); if (root->n_children == 3) { instruction_add(JUMPEQ, STRDUP(else_label), NULL, 0, 0); root->children[1]->generate(root->children[1], scopedepth); instruction_add(JUMP, STRDUP(end_label), NULL, 0, 0); instruction_add(LABEL, STRDUP(else_label+1), NULL, 0, 0); root->children[2]->generate(root->children[2], scopedepth); } else { instruction_add(JUMPEQ, STRDUP(end_label), NULL, 0, 0); root->children[1]->generate(root->children[1], scopedepth); } instruction_add(LABEL, STRDUP(end_label+1), NULL, 0, 0); }
void gen_PROGRAM ( node_t *root, int scopedepth) { /* Output the data segment */ if( outputStage == 12 ) strings_output ( stderr ); instruction_add ( STRING, STRDUP( ".text" ), NULL, 0, 0 ); tracePrint("Starting PROGRAM\n"); gen_default(root, scopedepth);//RECUR(); TEXT_DEBUG_FUNC_ARM(); TEXT_HEAD_ARM(); gp(root,scopedepth); tracePrint("End PROGRAM\n"); TEXT_TAIL_ARM(); if( outputStage == 12 ) instructions_print ( stderr ); instructions_finalize (); }
void gen_FUNCTION ( node_t *root, int scopedepth ) { // Generating label. This may need to be changed to handle labels for methods function_symbol_t* entry = root->function_entry; int len = strlen(entry->label); if (currentClass != NULL) { len += strlen(currentClass); } char *temp = (char*) malloc(sizeof(char) * (len + 4)); temp[0] = 0; strcat(temp, "_"); if (currentClass != NULL) { strcat(temp, currentClass); strcat(temp, "_"); } strcat(temp, entry->label); strcat(temp, ":"); instruction_add(STRING, STRDUP(temp), NULL, 0, 0); instruction_add(PUSH, lr, NULL, 0, 0); instruction_add(PUSH, fp, NULL, 0, 0); instruction_add(MOVE, fp, sp, 0, 0); gen_default(root, scopedepth); // In case we haven't already returned instruction_add(MOVE, sp, fp, 0, 0); instruction_add(POP, fp, NULL, 0, 0); instruction_add(POP, "pc", NULL, 0, 0); }
void gen_ASSIGNMENT_STATEMENT ( node_t *root, int scopedepth ) { tracePrint ( "Starting ASSIGNMENT_STATEMENT\n"); //Generating the code for the expression part of the assignment. The result is //placed on the top of the stack root->children[1]->generate(root->children[1], scopedepth); // Left hand side may be a class field, which should be handled in this assignment if(root->children[0]->expression_type.index == CLASS_FIELD_E){ root->children[0]->children[0]->generate(root->children[0]->children[0], scopedepth); instruction_add(POP, r2, NULL, 0, 0); char stack_offset[10]; sprintf(stack_offset, "#%d", root->children[0]->entry->stack_offset); instruction_add(MOVE, r1, STRDUP(stack_offset), 0, 0); instruction_add3(ADD, r0, r1, r2); instruction_add(POP, r1, NULL, 0, 0); instruction_add(STORE, r1, r0, 0, 0); } // or a variable, handled in previous assignment else{ instruction_add(POP, r0, NULL, 0, 0); instruction_add(STORE, r0, fp, 0, root->children[0]->entry->stack_offset); } tracePrint ( "End ASSIGNMENT_STATEMENT\n"); }
void gen_WHILE_STATEMENT ( node_t *root, int scopedepth ) { while_count ++; char while_string[100]; snprintf(while_string, 100, "while%d", while_count); //Max 99 digits char while_label[100]; snprintf(while_label, 100, "_while%d", while_count); //Max 99 digits char while_end_string[100]; snprintf(while_end_string, 100, "while_end%d", while_count); //Max 99 digits char while_end_label[100]; snprintf(while_end_label, 100, "_while_end%d", while_count); //Max 99 digits instruction_add(LABEL, STRDUP(while_string), NULL, 0, 0); // Evaluate expression if( root->children[0] != NULL ) root->children[0]->generate ( root->children[0], scopedepth ); // Compare to zero instruction_add(POP, r0, NULL, 0, 0); instruction_add(CMP, r0, "#0", 0, 0); // Jump is 0 instruction_add(JUMPZERO, STRDUP(while_end_label), NULL, 0, 0 ); // body if( root->children[1] != NULL ) root->children[1]->generate ( root->children[1], scopedepth ); // Jump to start of loop instruction_add(JUMP, STRDUP(while_label), NULL, 0, 0); /* */ instruction_add(LABEL, STRDUP(while_end_string), NULL, 0, 0); }
/* * Smart wrapper for "printf". * Makes a comment in the assembly to guide. * Also prints a copy to the debug stream if needed. */ void tracePrint( const char * string, ... ) { va_list args; char buff[1000]; char buff2[1000]; // va_start (args, string); vsprintf(buff, string, args); va_end (args); sprintf(buff2, "%d %s", nodeCounter++, buff); if( outputStage == 10 ) fprintf(stderr, "%s", buff2); instruction_add ( COMMMENT, STRDUP( buff2 ), NULL, 0, 0 ); }
void gen_FUNCTION ( node_t *root, int scopedepth ) { function_symbol_t* entry = root->function_entry; int len = strlen(entry->label); char *temp = (char*) malloc(sizeof(char) * (len + 3)); temp[0] = 0; strcat(temp, "_"); if(currentClass != NULL) { strcat(temp, currentClass); strcat(temp, "_"); } strcat(temp, entry->label); strcat(temp, ":"); instruction_add(STRING, STRDUP(temp), NULL, 0, 0); gf(root,scopedepth); }
void gen_IF_STATEMENT ( node_t *root, int scopedepth ) { tracePrint("Starting IF_STATEMENT\n"); if_count++; int our_count = if_count; // Expand If-expression node_t *cond = root->children[0]; cond->generate(cond, scopedepth); char tmp_if_end[20]; char tmp_if_else[20]; sprintf(tmp_if_end, "_if_end_%d", if_count); sprintf(tmp_if_else, "_if_else_%d", if_count); // Test truth value instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, "#0", 0, 0); node_t *statement_if = root->children[1]; if (root->n_children == 2) { // If-end statement // If code instruction_add(JUMPZERO, STRDUP(tmp_if_end), NULL, 0, 0); statement_if->generate(statement_if, scopedepth); } else { // If-else-end statement // If code instruction_add(JUMPZERO, STRDUP(tmp_if_else), NULL, 0, 0); statement_if->generate(statement_if, scopedepth); instruction_add(JUMP, STRDUP(tmp_if_end), NULL, 0, 0); // Else code instruction_add(LABEL, STRDUP(tmp_if_else + 1), NULL, 0, 0); node_t *statement_else = root->children[2]; statement_else->generate(statement_else, scopedepth); } // End label instruction_add(LABEL, STRDUP(tmp_if_end + 1), NULL, 0, 0); tracePrint("End IF_STATEMENT\n"); }
void gen_FUNCTION ( node_t *root, int scopedepth ) { // Generating label. This may need to be changed to handle labels for methods function_symbol_t* entry = root->function_entry; int len = strlen(entry->label); char *temp = (char*) malloc(sizeof(char) * (len + 3)); temp[0] = 0; //New code for handling labels for classes: if (currentClass!=NULL){ strcat(temp, "_"); strcat(temp, currentClass); } strcat(temp, "_"); strcat(temp, entry->label); strcat(temp, ":"); instruction_add(STRING, STRDUP(temp), NULL, 0, 0); gf(root,scopedepth); free(temp); }
void gen_WHILE_STATEMENT ( node_t *root, int scopedepth ) { char start_label[20]; sprintf(start_label, "_while_%d", while_count); char end_label[20]; sprintf(end_label, "_endwhile_%d", while_count); while_count++; instruction_add(LABEL, STRDUP(start_label+1), NULL, 0, 0); root->children[0]->generate(root->children[0], scopedepth); instruction_add(POP, r1, NULL, 0, 0); instruction_add(MOVE, r2, STRDUP("#0"), 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(JUMPEQ, STRDUP(end_label), NULL, 0, 0); root->children[1]->generate(root->children[1], scopedepth); instruction_add(JUMP, STRDUP(start_label), NULL, 0, 0); instruction_add(LABEL, STRDUP(end_label+1), NULL, 0, 0); }
void gen_IF_STATEMENT ( node_t *root, int scopedepth ) { if_count ++; char else_string[100]; snprintf(else_string, 100, "else%d", if_count); //Max 99 digits char else_label[100]; snprintf(else_label, 100, "_else%d", if_count); //Max 99 digits char end_string[100]; snprintf(end_string, 100, "if_end%d", if_count); //Max 99 digits char end_label[100]; snprintf(end_label, 100, "_if_end%d", if_count); //Max 99 digits bool have_else = root->n_children==3; // Evaluate the expression (this will place the value of the expression in r0) if( root->children[0] != NULL ) root->children[0]->generate ( root->children[0], scopedepth ); // Compare it to zero instruction_add(POP, r0, NULL, 0, 0); instruction_add(CMP, r0, "#0", 0, 0); // Jump to label if zero if(have_else) { instruction_add(JUMPZERO, STRDUP(else_label), NULL, 0, 0 ); } else { instruction_add(JUMPZERO, STRDUP(end_label), NULL, 0, 0 ); } // Run the code from the body if( root->children[1] != NULL ) root->children[1]->generate ( root->children[1], scopedepth ); if(have_else) { instruction_add(LABEL, STRDUP(else_string), NULL, 0, 0); if( root->children[2] != NULL ) root->children[2]->generate ( root->children[2], scopedepth ); } instruction_add(LABEL, STRDUP(end_string), NULL, 0, 0); }
void gen_WHILE_STATEMENT ( node_t *root, int scopedepth ) { tracePrint("Starting WHILE_STATEMENT\n"); while_count++; int our_count = while_count; char tmp_while_start[20]; char tmp_while_end[20]; sprintf(tmp_while_start, "_while_start_%d", our_count); sprintf(tmp_while_end, "_while_end_%d", our_count); // Set start label instruction_add(LABEL, STRDUP(tmp_while_start + 1), NULL, 0, 0); // Expand while-expression node_t *cond = root->children[0]; cond->generate(cond, scopedepth); // Test truth value, jump to end if zero instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, "#0", 0, 0); instruction_add(JUMPZERO, STRDUP(tmp_while_end), NULL, 0, 0); // Execute while-loop statement body node_t *while_body = root->children[1]; while_body->generate(while_body, scopedepth); // Return to top of while loop) instruction_add(JUMP, STRDUP(tmp_while_start), NULL, 0, 0); // Set end label instruction_add(LABEL, STRDUP(tmp_while_end + 1), NULL, 0 ,0); tracePrint("End WHILE_STATEMENT\n"); }
void generate ( FILE *stream, node_t *root ) { int length = 0; int elegant_solution; if ( root == NULL ) return; switch ( root->type.index ) { case PROGRAM: /* Output the data segment */ strings_output ( stream ); instruction_add ( STRING, STRDUP( ".text" ), NULL, 0, 0 ); RECUR(); TEXT_HEAD(); instruction_add(CALL, root->children[0]->children[0]->children[0]->entry->label, NULL, 0, 0); TEXT_TAIL(); instructions_print ( stream ); instructions_finalize (); break; case FUNCTION: /* * Function definitions: * Set up/take down activation record for the function, return value */ //Entering new scope, 'depth' is the depth of the current scope depth++; int len = strlen(root->children[0]->entry->label); //Generating the string needed for the label instruction func_name = (char*) malloc(sizeof(char)*len); strncpy(func_name, root->children[0]->entry->label, len); char *temp = (char*) malloc(sizeof(char) * (len + 3)); temp[0] = '_'; for(int c = 0; c < len; c++){ temp[c+1] = root->children[0]->entry->label[c]; } temp[len + 1] = ':'; temp[len + 2] = 0; //Generate the label for the function, and the code to update the base ptr instruction_add(STRING, temp, NULL, 0, 0); instruction_add(PUSH, ebp, NULL, 0,0); instruction_add(MOVE, esp, ebp, 0,0); //Generating code for the functions body //The body is the last child, the other children are the name of the function //the arguments etc generate(stream, root->children[root->n_children - 1]); //Generating code to restore the base ptr, and to return instruction_add(LEAVE, NULL, NULL, 0,0); instruction_add(RET, NULL, NULL, 0,0); free(func_name); //Leaving the scope, decreasing depth depth--; break; case BLOCK: /* * Blocks: * Set up/take down activation record, no return value */ //Entering new scope depth++; //Setting up the new activation record instruction_add(PUSH, ebp, NULL, 0,0); instruction_add(MOVE, esp, ebp, 0,0); //Generating code for the body of the block RECUR(); //Restoring the old activation record instruction_add(LEAVE, NULL, NULL, 0,0); //Leaving scope depth--; break; case DECLARATION: /* * Declarations: * Add space on local stack */ //The declarations first child is a VARIABLE_LIST, the number of children //of the VARIABLE_LIST is the number of variables declared. A 0 is pushed on //the stack for each for(uint32_t c = 0; c < root->children[0]->n_children; c++){ instruction_add(PUSH, STRDUP("$0"), NULL, 0,0); } break; case PRINT_LIST: /* * Print lists: * Emit the list of print items, followed by newline (0x0A) */ //Generate code for all the PRINT_ITEMs RECUR(); //Print a newline, push the newline, call 'putchar', and pop the argument //(overwriting the value returned from putchar...) instruction_add(PUSH, STRDUP("$0x0A"), NULL, 0, 0); instruction_add(SYSCALL, STRDUP("putchar"), NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); break; case PRINT_ITEM: /* * Items in print lists: * Determine what kind of value (string literal or expression) * and set up a suitable call to printf */ //Checking type of value, (of the child of the PRINT_ITEM, //which is what is going to be printed if(root->children[0]->type.index == TEXT){ //String, need to push '$.STRINGx' where x is the number of the string //The number can be found in the nodes data field, and must be transformed //to a string, and concatenated with the '$.STRING' part int32_t t = *((int32_t*)root->children[0]->data); char int_part[3]; //can have more than 999 strings... sprintf(int_part, "%d", t); char str_part[9] = "$.STRING"; strcat(str_part, int_part); //Generating the instructions, pushing the argument of printf //(the string), calling printf, and removing the argument from //the stack (overwriting the returnvalue from printf) instruction_add(PUSH, STRDUP(str_part), NULL, 0,0); instruction_add(SYSCALL, STRDUP("printf"), NULL, 0,0); instruction_add(POP, eax,NULL,0,0); } else{ //If the PRINT_ITEMs child isn't a string, it's an expression //The expression is evaluated, and its result, which is an integer //is printed //Evaluating the expression, the result is placed at the top of the stack RECUR(); //Pushing the .INTEGER constant, which will be the second argument to printf, //and cause the first argument, which is the result of the expression, and is //allready on the stack to be printed as an integer instruction_add(PUSH, STRDUP("$.INTEGER"), NULL, 0,0); instruction_add(SYSCALL, STRDUP("printf"), NULL,0,0); //Poping both the arguments to printf instruction_add(POP, eax, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); } break; case EXPRESSION: /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ switch (root->n_children){ case 1: //One child, and some data, this is the -exp expression if(root->data != NULL){ //Computing the exp part of -exp, the result is placed on the top of the stack RECUR(); //Negating the exp by computing 0 - exp instruction_add(POP, ebx, NULL, 0,0); instruction_add(MOVE, STRDUP("$0"), eax, 0,0); instruction_add(SUB, ebx, eax, 0,0); //Pushing the result on the stack instruction_add(PUSH, eax, NULL, 0,0); } else{ //One child, and no data, this is variables //They are handeled later RECUR(); } break; case 2: //Two children and no data, a function (call, not defenition) if(*(char*)(root->data) == 'F'){ //Generate the code for the second child, the arguments, this will place them on the stack generate(stream, root->children[1]); //The call instruction instruction_add(CALL, STRDUP(root->children[0]->entry->label), NULL, 0,0); //Removing the arguments, changing the stack pointer directly, rather than poping //since the arguments aren't needed if(root->children[1] != NULL){ for(int c = 0; c < root->children[1]->n_children; c++){ instruction_add(ADD, STRDUP("$4"), esp, 0,0); } } //Pushing the returnvalue from the function on the stack instruction_add(PUSH, eax, NULL, 0, 0); break; } //Two children and data, this is the arithmetic expressions //The two children are evaluated first, which places their values //at the top of the stack. More precisely, the result of the second //subexpression will be placed at the top of the stack, the result of //the first on the position below it RECUR(); if(strlen((char*)root->data) == 1){ switch (*(char*)root->data){ // Addition and subtraction is handeled equally // The arguments are placed in the eax and ebx registers // they are added/subtracted, and the result is pushed on the stack case '+': instruction_add(POP, eax, NULL, 0,0); instruction_add(POP, ebx, NULL, 0,0); instruction_add(ADD, ebx, eax, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '-': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(SUB, ebx, eax, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; //With multiplication/division it's also necessary to sign extend the //arguments, using the CLTD instruction, the MUL/DIV instructions only need //one argument, the other one is eax case '*': instruction_add(POP, eax, NULL, 0,0); instruction_add(POP, ebx, NULL, 0,0); instruction_add(CLTD, NULL, NULL, 0,0); instruction_add(MUL, ebx, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '/': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CLTD, NULL, NULL, 0,0); instruction_add(DIV, ebx, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '>': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETG, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '<': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETL, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; } } else{ switch (*(char*)root->data){ case '>': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETGE, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '<': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETLE, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '=': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETE, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; case '!': instruction_add(POP, ebx, NULL, 0,0); instruction_add(POP, eax, NULL, 0,0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETNE, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(PUSH, eax, NULL, 0,0); break; } } } break; case VARIABLE: /* * Occurrences of variables: (declarations have their own case) * - Find the variable's stack offset * - If var is not local, unwind the stack to its correct base */ //Finding the scope of the variable. If the difference is 0, it is //defined in this scope, if it is 1, the previous one and so on depth_difference = depth - root->entry->depth; //The offset of the variable is relative to its ebp. The current ebp is saved //on the stack, and the needed one retrived instruction_add(PUSH, ebp, NULL, 0,0); //The ebp points to the previous ebp, which points to the ebp before it and so on. //The ideal instruction to use would be 'movl (%ebp) %ebp', but that can't be done //with this framework. Rather than changing the framework, the following hack is used: // //The constant 4 and the contents of ebp is added and placed in eax, then the //the value pointed to by eax with an offset of -4, that is -4(%eax), is placed in ebp //since eax is ebp + 4, -4(%eax) is really (%ebp) for(int c = 0; c < depth_difference; c++){ instruction_add(MOVE, STRDUP("$4"), eax, 0,0); instruction_add(ADD, ebp, eax, 0,0); instruction_add(MOVE, eax, ebp, -4,0); } //The offset of the vaiable (from its ebp) int32_t offset = root->entry->stack_offset; //The value of the variable is placed in eax, the right ebp is used, because of //the system above instruction_add(MOVE, ebp, eax, offset, 0); //The current ebp is restored instruction_add(POP, ebp, NULL, 0,0); //The value of the variable is placed on the stack (since it's a kind of expression) instruction_add(PUSH, eax, NULL, 0,0); break; case INTEGER: /* * Integers: constants which can just be put on stack */ //We can't have a label followed by a declaration, so this is needed... elegant_solution = 0; //The value of the integer is fetched and converted to a string char temp1[10]; //ints are 4 bytes, so this is enough int32_t t = *((int32_t*)root->data); sprintf(temp1, "%d", t); char temp2[11] = "$"; strcat(temp2, temp1); //The value is pushed on the stack instruction_add(PUSH, STRDUP(temp2), NULL, 0,0); break; case ASSIGNMENT_STATEMENT: /* * Assignments: * Right hand side is an expression, find left hand side on stack * (unwinding if necessary) */ //Generating the code for the expression part of the assingment. The result is //placed on the top of the stack generate(stream, root->children[1]); //Using same scheme as above depth_difference = depth - root->children[0]->entry->depth; instruction_add(PUSH, ebp, NULL, 0,0); for(int c = 0; c < depth_difference; c++){ instruction_add(MOVE, STRDUP("$4"), eax, 0,0); instruction_add(ADD, ebp, eax, 0,0); instruction_add(MOVE, eax, ebp, -4,0); } int32_t offset_2 = root->children[0]->entry->stack_offset; //Putting the current ebp in ebx instruction_add(POP, ebx, NULL, 0,0); //Putting the result of the expression in eax instruction_add(POP, eax, NULL, 0,0); //Putting the result of the expression in the variable (ebp is the ebp of the variable) instruction_add(MOVE, eax, ebp, 0, offset_2); //Restoring the current ebp instruction_add(MOVE, ebx, ebp, 0, 0); break; case RETURN_STATEMENT: /* * Return statements: * Evaluate the expression and put it in EAX */ RECUR(); instruction_add(POP, eax, NULL, 0,0); for ( int u=0; u<depth-1; u++ ){ instruction_add ( LEAVE, NULL, NULL, 0, 0 ); } instruction_add ( RET, eax, NULL, 0, 0 ); break; case WHILE_STATEMENT: { //Increment the number of while loops. n_while++; //Create the start label for the while-loop. len = strlen(func_name); char start_label[100]; snprintf(start_label, 100, "%s%s", func_name, "_while_"); snprintf(start_label, 100, "%s%d", start_label, n_while); //Start label with added "_" for the jump. char jump_start_label[100]; snprintf(jump_start_label, 100, "_%s", start_label); //End label char end_label[100]; snprintf(end_label, 100, "%s%s", start_label, "_end"); //End label with added "_" for the jump. char jump_end_label[100]; snprintf(jump_end_label, 100, "_%s", end_label); instruction_add(LABEL, STRDUP(start_label), NULL, 0, 0); //Evaluate the expression generate(stream, root->children[0]); //Pop the result to eax instruction_add(POP, eax, NULL, 0, 0); //Compare and jump to end_label if eax equals zero. instruction_add(CMP, STRDUP("$0"), eax, 0, 0); instruction_add(JUMPEQ, STRDUP(jump_end_label), NULL, 0, 0); //Generate the statement instructions. generate(stream, root->children[1]); //Jump to start label instruction_add(JUMP, STRDUP(jump_start_label), NULL, 0, 0); //Add end label. instruction_add(LABEL, STRDUP(end_label), NULL, 0, 0); } break; case FOR_STATEMENT: { //Increment the number of the for loop. n_for++; /** LABELS **/ //Create the start label for the for loop. len = strlen(func_name); char start_label[100]; snprintf(start_label, 100, "%s%s", func_name, "_for_"); snprintf(start_label, 100, "%s%d", STRDUP(start_label), n_for); //Create the jump label with "_" in front. char jump_start_label[100]; snprintf(jump_start_label, 100, "_%s", start_label); //Create the end label if the condition is false. char end_label[100]; snprintf(end_label, 100, "%s%s", start_label, "_end"); //Create the jump end label, adding "_" in fron of end label. char jump_end_label[100]; snprintf(jump_end_label, 100, "_%s", end_label); /** SET COUNTER TO START VALUE **/ generate(stream, root->children[0]); /** START LABEL **/ instruction_add(LABEL, STRDUP(start_label), NULL, 0, 0); //The nodes that represent the counter and the end value expression, respectively. node_t *counter = root->children[0]->children[0]; node_t *endValue = root->children[1]; /** Test if counter >= endValue. If so, jump to end **/ generate(stream, counter); generate(stream, endValue); instruction_add(POP, ebx, NULL, 0, 0); instruction_add(POP, eax, NULL, 0, 0); instruction_add(CMP, ebx, eax, 0,0); instruction_add(SETGE, al, NULL, 0,0); instruction_add(CBW, NULL, NULL, 0,0); instruction_add(CWDE, NULL, NULL, 0,0); instruction_add(CMP, STRDUP("$1"), eax, 0, 0); instruction_add(JUMPEQ, STRDUP(jump_end_label), NULL, 0, 0); //Loop-body generate(stream, root->children[2]); /**Increment counter **/ depth_difference = depth - counter->entry->depth; instruction_add(PUSH, ebp, NULL, 0,0); for(int c = 0; c < depth_difference; c++){ instruction_add(MOVE, STRDUP("$4"), eax, 0,0); instruction_add(ADD, ebp, eax, 0,0); instruction_add(MOVE, eax, ebp, -4,0); } int32_t offset_2 = counter->entry->stack_offset; //Putting the current ebp in ebx instruction_add(POP, ebx, NULL, 0,0); //Putting the result of the expression in the variable (ebp is the ebp of the variable) instruction_add(ADD, STRDUP("$1"), ebp, 0, offset_2); //Restoring the current ebp instruction_add(MOVE, ebx, ebp, 0, 0); /** Jump to begining **/ instruction_add(JUMP, STRDUP(jump_start_label), NULL, 0, 0); //Add end label. instruction_add(LABEL, STRDUP(end_label), NULL, 0, 0); } break; case IF_STATEMENT: { n_if = n_if+1; len = strlen(func_name); //Label for the end of the if statement. char end_label[100]; snprintf(end_label, 100, "%s%s%d", func_name, "_endOfIf_", n_if); //Need to add "_" when jumping to label. char jump_end_label[100]; snprintf(jump_end_label, 100, "_%s", end_label); if (root->n_children == 2) { //Evaluate expression and pop result to eax and check if zero. generate(stream, root->children[0]); instruction_add(POP, eax, NULL, 0, 0); instruction_add(CMP, STRDUP("$0"), eax, 0, 0); //Jump to end if expression is zero. instruction_add(JUMPEQ, STRDUP(jump_end_label), NULL, 0, 0); //Generate the statement generate(stream, root->children[1]); //Add end label. } else { //Else label char else_label[100]; snprintf(else_label, 100, "%s%s%d", func_name, "_else_", n_if); //Evaluate expression and pop it to eax. Jmp if zero. generate(stream, root->children[0]); instruction_add(POP, eax, NULL, 0, 0); instruction_add(CMP, STRDUP("$0"), eax, 0, 0); //Need to add "_" before the label when jumping char jump_else_label[100]; snprintf(jump_else_label, 100, "_%s", else_label); instruction_add(JUMPEQ, STRDUP(jump_else_label), NULL, 0, 0); //Execute the "true statement". generate(stream, root->children[1]); //Jump to end of the if-statement. instruction_add(JUMP, STRDUP(jump_end_label), NULL, 0, 0); //Add the else label. instruction_add(LABEL, STRDUP(else_label), NULL, 0, 0); //Execute the else statement. generate(stream, root->children[2]); } instruction_add(LABEL, STRDUP(end_label), NULL, 0, 0); } break; case NULL_STATEMENT: RECUR(); break; default: /* Everything else can just continue through the tree */ RECUR(); break; } }
void generate ( FILE *stream, node_t *root ) { //Check if we've reached a return statement earlier. If we have we shall not procede. if (reachedReturnStatement == 1) return; int var_offset; int var_depth; int diff; const int BUFFER_LENGTH = 100; char buffer[BUFFER_LENGTH]; int elegant_solution; if ( root == NULL ) return; switch ( root->type.index ) { case PROGRAM: /* Output the data segment */ strings_output ( stream ); instruction_add ( STRING, STRDUP( ".text" ), NULL, 0, 0 ); RECUR(); TEXT_HEAD(); /* TODO: Insert a call to the first defined function here */ instruction_add(CALL, STRDUP((char*)root->children[0]->children[0]->children[0]->data), NULL, 0, 0); TEXT_TAIL(); instructions_print ( stream ); instructions_finalize (); break; case FUNCTION: /* * Function definitions: * Set up/take down activation record for the function, return value */ instruction_add(LABEL, STRDUP((char*)root->children[0]->entry->label), NULL, 0, 0); instruction_add(PUSH, ebp, NULL, 0, 0); instruction_add(MOVE, esp, ebp, 0, 0); depth++; generate(stream, root->children[2]); depth--; //We're done with this function, have to reset the reachedReturnStatement value to 0. reachedReturnStatement = 0; instruction_add(LEAVE, NULL, NULL, 0, 0); instruction_add(RET, NULL, NULL, 0, 0); break; case BLOCK: /* * Blocks: * Set up/take down activation record, no return value */ instruction_add(PUSH, ebp, NULL, 0, 0); instruction_add(MOVE, esp, ebp, 0, 0); depth++; RECUR(); depth--; instruction_add(MOVE, ebp, esp, 0, 0); instruction_add(POP, ebp, NULL, 0, 0); break; case DECLARATION: /* * Declarations: * Add space on local stack */ //Moves the stack pointer down 4 bytes for each variable that is to be declared. snprintf(buffer, BUFFER_LENGTH, "$%d", (root->children[0]->n_children)*4); instruction_add(SUB, STRDUP(buffer), esp, 0, 0); break; case PRINT_LIST: /* * Print lists: * Emit the list of print items, followed by newline (0x0A) */ //Continues down the tree to the print_items. RECUR(); //Add new line. instruction_add(PUSH, STRDUP("$0x0A"), NULL, 0, 0); instruction_add(SYSCALL, STRDUP("putchar"), NULL, 0, 0); instruction_add(ADD, STRDUP("$4"), esp, 0, 0); break; case PRINT_ITEM: /* * Items in print lists: * Determine what kind of value (string literal or expression) * and set up a suitable call to printf */ //Set up a suitable call for strings to printf. if (root->children[0]->type.index == TEXT) { snprintf(buffer, BUFFER_LENGTH, "$.STRING%d", *((int*)root->children[0]->data)); instruction_add(PUSH, STRDUP(buffer), NULL, 0, 0); instruction_add(SYSCALL, STRDUP("printf"), NULL, 0, 0); instruction_add(ADD, STRDUP("$4"), esp, 0, 0); } //Set up a suitable call for integers to printf. else { generate(stream, root->children[0]); instruction_add(PUSH, STRDUP("$.INTEGER"), NULL, 0, 0); instruction_add(SYSCALL, STRDUP("printf"), NULL, 0, 0); instruction_add(ADD, STRDUP("$8"), esp, 0, 0); } break; case EXPRESSION: /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ evaluate_expression(stream, root); break; case VARIABLE: /* * Occurrences of variables: (declarations have their own case) * - Find the variable's stack offset * - If var is not local, unwind the stack to its correct base */ //Variables depth and offset. var_offset = root->entry->stack_offset; var_depth = root->entry->depth; diff = depth - var_depth; //Uses ebx to find the correct frame. instruction_add(MOVE, ebp, ebx, 0, 0); for (int i = 0; i < diff; i++) { instruction_add(MOVE, STRDUP("(%ebx)"), ebx, 0, 0); } //Pushes the value of the variable on the stack. instruction_add(PUSH, ebx, NULL, var_offset, 0); break; case INTEGER: /* * Integers: constants which can just be put on stack */ //Creates the correct string for the integer, and pushes it on the stack. snprintf(buffer, BUFFER_LENGTH, "$%d", *((int*)root->data)); instruction_add(PUSH, STRDUP(buffer), NULL, 0, 0); break; case ASSIGNMENT_STATEMENT: /* * Assignments: * Right hand side is an expression, find left hand side on stack * (unwinding if necessary) */ //Evaluates the expression on the right side. Its value will be on top of stack afterwards, so pop it. generate(stream, root->children[1]); instruction_add(POP, eax, NULL, 0, 0); var_offset = root->children[0]->entry->stack_offset; var_depth = root->children[0]->entry->depth; diff = depth - var_depth; //Puts the adress to the next frame in ebx, and unwind until we find the variable's location. instruction_add(MOVE, ebp, ebx, 0, 0); for (int i = 0; i < diff; i++) { instruction_add(MOVE, STRDUP("(%ebx)"), ebx, 0, 0); } //Put the expression value in the location of the variable. instruction_add(MOVE, eax, ebx, 0, var_offset); break; case RETURN_STATEMENT: /* * Return statements: * Evaluate the expression and put it in EAX */ //Evalute the expression. Its value will be on stack afterwards, so pop it. RECUR(); instruction_add(POP, eax, NULL, 0, 0); //Signal that we have reached a return statement. No more instructions should be added for this //procedure. reachedReturnStatement = 1; break; default: /* Everything else can just continue through the tree */ RECUR(); break; } }
void evaluate_expression( FILE *stream, node_t *root ) { //If we've reached a function, call it. if (*((char *)root->data) == 'F') { node_t *para_list = root->children[1]; //Pushes the children on stack generate(stream, para_list); //Calls the function instruction_add(CALL, STRDUP((char*)root->children[0]->entry->label), NULL, 0, 0); //Pushes the return value on stack. instruction_add(PUSH, eax, NULL, 0, 0); return; } RECUR(); //Uminus. if (root->n_children == 1 && root->data != NULL) { instruction_add(POP, eax, NULL, 0, 0); instruction_add(NEG, eax, NULL, 0, 0); instruction_add(PUSH, eax, NULL, 0, 0); return; } //Normal arithmetic. instruction_add(POP, ebx, NULL, 0, 0); instruction_add(POP, eax, NULL, 0, 0); //First we deal with operands with a single char. if(strlen((char*)root->data) == 1) { switch ( *((char *)root->data) ) { case '+': instruction_add(ADD, ebx, eax, 0, 0); break; case '-': instruction_add(SUB, ebx, eax, 0, 0); break; case '*': instruction_add(MUL, ebx, NULL, 0, 0); break; case '/': instruction_add(CLTD, NULL, NULL, 0, 0); instruction_add(DIV, ebx, NULL, 0, 0); break; case '>': instruction_add(CMP, ebx, eax, 0, 0); instruction_add(SETG, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '<': instruction_add(CMP, ebx, eax, 0, 0); instruction_add(SETL, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; } } //Then we deal with operands with two chars. else { RECUR(); switch ( *((char *)root->data) ) { case '=': instruction_add(CMP, eax, ebx, 0, 0); instruction_add(SETE, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '!': instruction_add(CMP, eax, ebx, 0, 0); instruction_add(SETNE, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '<': instruction_add(CMP, ebx, eax, 0, 0); instruction_add(SETLE, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '>': instruction_add(CMP, ebx, eax, 0, 0); instruction_add(SETGE, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; } } instruction_add(PUSH, eax, NULL, 0, 0); }
void generate ( FILE *stream, node_t *root ) { char *char_buffer; int elegant_solution; if ( root == NULL ) return; switch ( root->type.index ) { case PROGRAM: /* Output the data segment */ strings_output ( stream ); instruction_add ( STRING, STRDUP( ".text" ), NULL, 0, 0 ); RECUR(); TEXT_HEAD(); /* * Calls the name of the first function, not pretty, but it works. */ instruction_add(CALL, STRDUP(root->children[0]->children[0]->children[0]->data), NULL, 0, 0); TEXT_TAIL(); instructions_print ( stream ); instructions_finalize (); break; case FUNCTION: /* * Function definitions: * Set up/take down activation record for the function, return value */ depth++; instruction_add(LABEL, STRDUP(root->children[0]->data), NULL, 0, 0); /* Callee saves old EBP on stack */ instruction_add(PUSH, ebp, NULL, 0, 0); /* Callee sets new EBP to top of stack. */ instruction_add(MOVE, esp, ebp, 0, 0); /* Callee executes function (overwriting registers if necessary.) */ generate(stream, root->children[2]); /* * Callee sets ESP to its EBP * Callee sets restores old EBP * Callee jumps back to caller, and pops return address. * * This part wouldn't be needed if every function had to RETURN * something, but from what I can see in the grammar, it's * legal to not return something. Functions that don't return * something may cause strange things to happen depending on the * implementation. */ instruction_add(LEAVE, NULL, NULL, 0, 0); instruction_add(RET, NULL, NULL, 0, 0); depth--; break; case BLOCK: /* * Blocks: * Set up/take down activation record, no return value */ depth++; /* Like a function, only that we don't have any return address. */ instruction_add(PUSH, ebp, NULL, 0, 0); instruction_add(MOVE, esp, ebp, 0, 0); RECUR(); /* Mom always told me to clean up after myself. */ instruction_add(LEAVE, NULL, NULL, 0, 0); depth--; break; case DECLARATION: /* * Declarations: * Add space on local stack */ /* * n_children is positive, so 12 bytes is enough to store $, an * int (10 digits) as well as the 0-byte. */ char_buffer = malloc(sizeof(*char_buffer) * 12); sprintf(char_buffer, "$%d", 4 * root->children[0]->n_children); /* * Clever little thing, growing the stack with 4 bytes for each * local variable that is to be added, no pushing or initialising * needed. Not very maintainable, though. */ instruction_add(SUB, STRDUP(char_buffer), esp, 0, 0); break; case PRINT_LIST: /* * Print lists: * Emit the list of print items, followed by newline (0x0A) */ /* Print all the PRINT_ITEMs */ RECUR(); /* * Put a newline out there after the contents have been printed in * order to follow the spec. */ instruction_add(PUSH, STRDUP("$0x0a"), NULL, 0, 0); instruction_add(SYSCALL, STRDUP("putchar"), NULL, 0, 0); break; case PRINT_ITEM: /* * Items in print lists: * Determine what kind of value (string literal or expression) * and set up a suitable call to printf */ if (root->children[0]->type.index == TEXT) { /* Text-elemtens, just print the appropriate string. */ char_buffer = malloc(sizeof(*char_buffer) * 19); sprintf(char_buffer, "$.STRING%d", *(int*)root->children[0]->data); instruction_add(PUSH, char_buffer, NULL, 0, 0); } else { /* A variable, add it's value to the stack. */ RECUR(); instruction_add(PUSH, STRDUP("$.INTEGER"), NULL, 0, 0); } /* printf whatever we pushed to the stack. */ instruction_add(SYSCALL, STRDUP("printf"), NULL, 0, 0); break; case EXPRESSION: /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ /* * Handle functions first as I find them a special case even though * the comments tell me to RECUR first. */ if (root->data != NULL && *(char*)root->data == 'F') { /* Caller pushes parameters on stack. */ generate(stream, root->children[1]); /* * Caller pushes return address on stack. * Caller jumps to called function address. */ instruction_add(CALL, root->children[0]->data, NULL, 0, 0); /* * Remove arguments from stack. The same as adding local * variables, really, except that we shrink the stack instead. * See DECLARATION-case for further description of the * procedure. */ if (root->children[1] != NULL) { char_buffer = malloc(sizeof(*char_buffer) * 12); sprintf(char_buffer, "$%d", 4 * root->children[1]->n_children); instruction_add(ADD, char_buffer, esp, 0, 0); } /* Push the return value to the stack. */ instruction_add(PUSH, eax, NULL, 0, 0); } else { RECUR(); if (root->n_children == 1 && root->data != NULL && *(char*) root->data == '-') { /* Unary minus, simple operation. */ instruction_add(POP, ebx, NULL, 0, 0); /* * The recitation didn't mention neg. I still chose to use * it as it was already in generator.c, and I think it's * more pretty than multiplying the number with -1, or * whatever other way there is to do this. */ instruction_add(NEG, ebx, NULL, 0, 0); instruction_add(PUSH, ebx, NULL, 0, 0); } else if (root->n_children == 2) { /* * Binary operation! ebx contains the rightmost operand, * eax the leftmost. */ instruction_add(POP, ebx, NULL, 0, 0); instruction_add(POP, eax, NULL, 0, 0); switch(*(char*)root->data) { case '+': instruction_add(ADD, ebx, eax, 0, 0); break; case '-': instruction_add(SUB, ebx, eax, 0, 0); break; case '*': instruction_add(MUL, ebx, NULL, 0, 0); break; case '/': instruction_add(CLTD, NULL, NULL, 0, 0); instruction_add(DIV, ebx, NULL, 0, 0); break; case '<': instruction_add(CMP, ebx, eax, 0, 0); /* '=' as opposed to '\0' */ if (*((char*) root->data + 1) == '=') { /* <= */ instruction_add(SETLE, al, NULL, 0, 0); } else { instruction_add(SETL, al, NULL, 0, 0); } instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '>': instruction_add(CMP, ebx, eax, 0, 0); if (*((char*) root->data + 1) != '\0' && *((char*) root->data + 1) == '=') { /* >= */ instruction_add(SETGE, al, NULL, 0, 0); } else { instruction_add(SETG, al, NULL, 0, 0); } instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '=': /* == */ instruction_add(CMP, ebx, eax, 0, 0); instruction_add(SETE, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; case '!': /* != */ instruction_add(CMP, ebx, eax, 0, 0); instruction_add(SETNE, al, NULL, 0, 0); instruction_add(CBW, NULL, NULL, 0, 0); instruction_add(CWDE, NULL, NULL, 0, 0); break; } /* Push the result back on the stack. */ instruction_add(PUSH, eax, NULL, 0, 0); } } break; case VARIABLE: /* * Occurrences of variables: (declarations have their own case) * - Find the variable's stack offset * - If var is not local, unwind the stack to its correct base */ /* * Here we want to push the value of a variable. * * The "if" is not really needed, but it decreases the amount of * instructions needed by one in cases where the variable is local. */ if (depth == root->entry->depth) { instruction_add(PUSH, ebp, NULL, root->entry->stack_offset, 0); } else { instruction_add(MOVE, ebp, ecx, 0, 0); for (int i = 0; i < (depth - root->entry->depth); i++) { /* Set ecx to the value pointed to by ecx. */ instruction_add(MOVE, STRDUP("(%ecx)"), ecx, 0, 0); } instruction_add(PUSH, ecx, NULL, root->entry->stack_offset, 0); } break; case INTEGER: /* * Integers: constants which can just be put on stack */ /* * We want to push the integer to the stack, that's how we do * calculations around here. * * Here the integers may be negative, so we need another byte for * the buffer. */ char_buffer = malloc(sizeof(*char_buffer) * 13); sprintf(char_buffer, "$%d", *(int*)root->data); instruction_add(PUSH, char_buffer, NULL, 0, 0); break; case ASSIGNMENT_STATEMENT: /* * Assignments: * Right hand side is an expression, find left hand side on stack * (unwinding if necessary) */ /* * Get the value of the right-hand side expression at the top of * the stack, then into eax. */ generate(stream, root->children[1]); instruction_add(POP, eax, NULL, 0, 0); /* * Get the left-hand side variable's offset, and store eax at that * location. See VARIABLE-case for comments on unwinding. */ if (depth == root->children[0]->entry->depth) { instruction_add(MOVE, eax, ebp, 0, root->children[0]->entry->stack_offset); } else { instruction_add(MOVE, ebp, ecx, 0, 0); for (int i = 0; i < (depth - root->children[0]->entry->depth); i++) { instruction_add(MOVE, STRDUP("(%ecx)"), ecx, 0, 0); } instruction_add(MOVE, eax, ecx, 0, root->children[0]->entry->stack_offset); } break; case RETURN_STATEMENT: /* * Return statements: * Evaluate the expression and put it in EAX */ /* Get the expression's value at the top of the stack. */ RECUR(); /* And into eax, the return register. */ instruction_add(POP, eax, NULL, 0, 0); /* One leave for every scope. */ for (int i = 1; i < depth; i++) { instruction_add(LEAVE, NULL, NULL, 0, 0); } instruction_add(RET, NULL, NULL, 0, 0); break; default: /* Everything else can just continue through the tree */ RECUR(); break; } }
void generate ( FILE *stream, node_t *root ) { int elegant_solution; if ( root == NULL ) return; switch ( root->type.index ) { case PROGRAM: { /* Output the data segment */ strings_output ( stream ); instruction_add ( STRING, STRDUP( ".text" ), NULL, 0, 0 ); RECUR (); TEXT_HEAD (); /* TODO: Insert a call to the first defined function here */ node_t *main_func = root->children[0]->children[0]; instruction_add ( CALL, STRDUP( (char *) main_func->children[0]->data ), NULL, 0, 0); TEXT_TAIL (); instructions_print ( stream ); instructions_finalize (); break; } case FUNCTION: { /* * Function definitions: * Set up/take down activation record for the function, return value */ depth += 1; instruction_add ( LABEL, STRDUP( root->children[0]->data ), NULL, 0, 0 ); instruction_add ( PUSH, ebp, NULL, 0, 0 ); instruction_add ( MOVE, esp, ebp, 0, 0 ); // Generate for the children, except for the BLOCK-statement generate ( stream, root->children[2]->children[0] ); generate ( stream, root->children[2]->children[1] ); instruction_add ( LEAVE, NULL, NULL, 0, 0 ); instruction_add ( RET, NULL, NULL, 0, 0 ); depth -= 1; break; } case BLOCK: { /* * Blocks: * Set up/take down activation record, no return value */ depth += 1; instruction_add ( PUSH, ebp, NULL, 0, 0 ); instruction_add ( MOVE, esp, ebp, 0, 0 ); generate ( stream, root->children[0] ); // This is done in order to avoid executing any statements in a STATEMENT_LIST, // that is occuring after a RETURN_STATEMENT node_t *statement_list_n = root->children[1]; for ( int i = 0; i < statement_list_n->n_children; i++ ) { generate ( stream, statement_list_n->children[i] ); if ( statement_list_n->children[i]->type.index == RETURN_STATEMENT ) break; } // Push a dummy value to the stack, so LEAVE works properly instruction_add ( PUSH, STRDUP( "$0" ), NULL, 0, 0 ); instruction_add ( LEAVE, NULL, NULL, 0, 0 ); depth -= 1; break; } case DECLARATION: { /* * Declarations: * Add space on local stack */ int offset = 0; for ( int i = 0; i < root->children[0]->n_children; i++ ) { offset -= 4; instruction_add ( PUSH, esp, NULL, offset, 0 ); } break; } case PRINT_LIST: { /* * Print lists: * Emit the list of print items, followed by newline (0x0A) */ instruction_add ( PUSH, ecx, NULL, 0, 0 ); RECUR (); instruction_add ( PUSH, STRDUP( "$10" ), NULL, 0, 0 ); instruction_add ( SYSCALL, STRDUP( "putchar" ), NULL, 0, 0 ); instruction_add ( ADD, STRDUP( "$4" ), esp, 0, 0 ); instruction_add ( POP, ecx, NULL, 0, 0 ); break; } case PRINT_ITEM: { /* * Items in print lists: * Determine what kind of value (string literal or expression) * and set up a suitable call to printf */ if ( root->children[0]->type.index == TEXT ) { char str[30]; sprintf ( str, "$.STRING%d", *(int *)root->children[0]->data ); instruction_add ( PUSH, STRDUP( str ), NULL, 0, 0 ); instruction_add ( SYSCALL, STRDUP( "printf" ), NULL, 0, 0 ); instruction_add ( ADD, STRDUP( "$4" ), esp, 0, 0 ); } else { // Add expression to top of stack, for use in printf generate ( stream, root->children[0] ); instruction_add ( PUSH, STRDUP( "$.INTEGER" ), NULL, 0, 0 ); instruction_add ( SYSCALL, STRDUP( "printf" ), NULL, 0, 0 ); instruction_add ( ADD, STRDUP( "$8" ), esp, 0, 0 ); } break; } case EXPRESSION: { /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ // The expression is a function call if ( root->n_children == 2 && ( root->children[1] == NULL || root->children[1]->type.index == EXPRESSION_LIST ) ) { // Push parameters on stack generate ( stream, root->children[1] ); instruction_add ( CALL, STRDUP( (char *) root->children[0]->data ), NULL, 0, 0); // The evaluated expression to the stack instruction_add ( PUSH, eax, NULL, 0, 0 ); } else if ( root->n_children == 2) { RECUR (); instruction_add ( POP, ebx, NULL, 0, 0 ); instruction_add ( POP, eax, NULL, 0, 0 ); char *data = (char *) root->data; switch ( data[0] ) { case '+': instruction_add ( ADD, ebx, eax, 0, 0 ); break; case '-': instruction_add ( SUB, ebx, eax, 0, 0 ); break; case '*': instruction_add ( MUL, ebx, NULL, 0, 0 ); break; case '/': instruction_add ( CLTD, NULL, NULL, 0, 0 ); instruction_add ( DIV, ebx, NULL, 0, 0 ); break; // The following cases is a bit repetative, I know // Maybe gcc will optimize it a bit? ;-) case '=': instruction_add ( CMP, ebx, eax, 0, 0 ); instruction_add ( SETE, al, NULL, 0, 0 ); instruction_add ( CBW, NULL, NULL, 0, 0 ); instruction_add ( CWDE, NULL, NULL, 0, 0 ); break; case '!': instruction_add ( CMP, ebx, eax, 0, 0 ); instruction_add ( SETNE, al, NULL, 0, 0 ); instruction_add ( CBW, NULL, NULL, 0, 0 ); instruction_add ( CWDE, NULL, NULL, 0, 0 ); break; case '>': instruction_add ( CMP, ebx, eax, 0, 0 ); if ( strlen( data ) == 2 ) instruction_add ( SETGE, al, NULL, 0, 0 ); else instruction_add ( SETG, al, NULL, 0, 0 ); instruction_add ( CBW, NULL, NULL, 0, 0 ); instruction_add ( CWDE, NULL, NULL, 0, 0 ); break; case '<': instruction_add ( CMP, ebx, eax, 0, 0 ); if ( strlen( data ) == 2 ) instruction_add ( SETLE, al, NULL, 0, 0 ); else instruction_add ( SETL, al, NULL, 0, 0 ); instruction_add ( CBW, NULL, NULL, 0, 0 ); instruction_add ( CWDE, NULL, NULL, 0, 0 ); break; } instruction_add ( PUSH, eax, NULL, 0, 0 ); } else if ( root->data != NULL && *(char *)root->data == '-' ) { // Unary minus RECUR (); instruction_add ( POP, eax, NULL, 0, 0 ); instruction_add ( NEG, eax, NULL, 0, 0 ); instruction_add ( PUSH, eax, NULL, 0, 0 ); } break; } case VARIABLE: { /* * Occurrences of variables: (declarations have their own case) * - Find the variable's stack offset * - If var is not local, unwind the stack to its correct base */ int stack_offset = root->entry->stack_offset; // If the variable is at right deapth, or it is a function argument, PUSH // the value of variable to the stack if ( depth == root->entry->depth || stack_offset > 0 && root->entry->depth == (depth-1) ) { instruction_add ( PUSH, ebp, NULL, stack_offset, 0 ); } else { // Else unwind instruction_add ( MOVE, ebp, ebx, 0, 0 ); // If the variable is an argument, the deapth, i.e. 'i', is decreased // by 1 int i = stack_offset > 0 ? -1 : 0; for ( i += depth-1; i >= root->entry->depth; i-- ) { instruction_add ( MOVE, STRDUP("(%ebx)"), ebx, 0, 0 ); } instruction_add ( PUSH, ebx, NULL, stack_offset, 0 ); } break; } case ASSIGNMENT_STATEMENT: { /* * Assignments: * Right hand side is an expression, find left hand side on stack * (unwinding if necessary) */ // This behaves almost the same as the VARIABLE case generate ( stream, root->children[1] ); root->entry = root->children[0]->entry; int stack_offset = root->entry->stack_offset; if ( depth == root->entry->depth ) { instruction_add ( POP, ebp, NULL, stack_offset, 0 ); } else { instruction_add ( MOVE, ebp, ebx, 0, 0 ); for ( int i = depth-1; i >= root->entry->depth; i-- ) { instruction_add ( MOVE, STRDUP("(%ebx)"), ebx, 0, 0 ); } instruction_add ( POP, ebx, NULL, stack_offset, 0 ); } break; } case INTEGER: { /* * Integers: constants which can just be put on stack */ char str[30]; sprintf ( str, "$%d", *(int *)root->data ); instruction_add ( PUSH, STRDUP( str ), NULL, 0, 0 ); break; } case RETURN_STATEMENT: { /* * Return statements: * Evaluate the expression and put it in EAX */ RECUR (); instruction_add ( POP, eax, NULL, 0, 0 ); break; } case WHILE_STATEMENT: { char whilestart[30]; char _whilestart[30]; char whileend[30]; char _whileend[30]; sprintf ( whilestart, "whilestart%d", while_label ); sprintf ( _whilestart, "_whilestart%d", while_label ); sprintf ( whileend, "whileend%d", while_label ); sprintf ( _whileend, "_whileend%d", while_label++ ); instruction_add ( LABEL, STRDUP( whilestart ), NULL, 0, 0 ); generate ( stream, root->children[0] ); instruction_add ( CMPZERO, eax, NULL, 0, 0 ); instruction_add ( JUMPZERO, STRDUP( _whileend ), NULL, 0, 0 ); generate ( stream, root->children[1] ); instruction_add ( JUMP, STRDUP( _whilestart ), NULL, 0, 0 ); instruction_add ( LABEL, STRDUP( whileend ), NULL, 0, 0 ); break; } case FOR_STATEMENT: { char forstart[30]; char _forstart[30]; char forend[30]; char _forend[30]; sprintf ( forstart, "forstart%d", for_label ); sprintf ( _forstart, "_forstart%d", for_label++ ); // Initialize ecx, i.e. the loop counter generate ( stream, root->children[0] ); instruction_add ( PUSH, eax, NULL, 0, 0 ); instruction_add ( MOVE, eax, edi, 0, 0 ); generate ( stream, root->children[1] ); instruction_add ( POP, eax, NULL, 0,0 ); instruction_add ( POP, ebx, NULL, 0,0 ); instruction_add ( SUB, ebx, eax, 0,0 ); instruction_add ( PUSH, eax, NULL, 0,0 ); instruction_add ( POP, ecx, NULL, 0, 0 ); // Start loop instruction_add ( LABEL, STRDUP( forstart ), NULL, 0, 0 ); generate ( stream, root->children[2] ); // Increment counter instruction_add ( ADD, STRDUP( "$1" ), edi, 0, 0 ); instruction_add ( PUSH, edi, NULL, 0, 0 ); depth_difference = depth - root->children[0]->children[0]->entry->depth; instruction_add(PUSH, ebp, NULL, 0,0); for(int c = 0; c < depth_difference; c++){ instruction_add(MOVE, STRDUP("$4"), eax, 0,0); instruction_add(ADD, ebp, eax, 0,0); instruction_add(MOVE, eax, ebp, -4,0); } int32_t offset_2 = root->children[0]->children[0]->entry->stack_offset; //Putting the current ebp in ebx instruction_add(POP, ebx, NULL, 0,0); //Putting the result of the expression in eax instruction_add(POP, eax, NULL, 0,0); //Putting the result of the expression in the variable (ebp is the ebp of the variable) instruction_add(MOVE, eax, ebp, 0, offset_2); //Restoring the current ebp instruction_add(MOVE, ebx, ebp, 0, 0); // Loop instruction_add ( LOOP, STRDUP( _forstart ), NULL, 0, 0 ); //instruction_add ( JUMPZERO, STRDUP( "TEST" ), NULL, 0, 0 ); break; } case IF_STATEMENT: { char ifend[30]; char _ifend[30]; char ifelse[30]; char _ifelse[30]; sprintf ( ifend, "ifend%d", if_label ); sprintf ( _ifend, "_ifend%d", if_label ); sprintf ( ifelse, "ifelse%d", if_label ); sprintf ( _ifelse, "_ifelse%d", if_label++ ); // IF-THEN-FI if ( root->n_children == 2 ) { char str[30]; node_t *expr = root->children[0]; sprintf ( str, "expr: n:%d", expr->n_children ); instruction_add ( JUMPZERO, STRDUP(str), NULL, 0, 0 ); generate ( stream, root->children[0] ); instruction_add ( CMPZERO, eax, NULL, 0, 0 ); instruction_add ( JUMPZERO, STRDUP( _ifend ), NULL, 0, 0 ); generate ( stream, root->children[1] ); instruction_add ( LABEL, STRDUP( ifend ), NULL, 0, 0 ); } // IF-THEN-ELSE-FI else { generate ( stream, root->children[0] ); instruction_add ( CMPZERO, eax, NULL, 0, 0 ); instruction_add ( JUMPZERO, STRDUP( _ifelse ), NULL, 0, 0 ); generate ( stream, root->children[1] ); instruction_add ( JUMP, STRDUP( _ifend ), NULL, 0, 0 ); instruction_add ( LABEL, STRDUP( ifelse ), NULL, 0, 0 ); generate ( stream, root->children[2] ); instruction_add ( JUMP, STRDUP( _ifend ), NULL, 0, 0 ); instruction_add ( LABEL, STRDUP( ifend ), NULL, 0, 0 ); } break; } default: /* Everything else can just continue through the tree */ RECUR(); break; } }
void gen_EXPRESSION ( node_t *root, int scopedepth ) { /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ tracePrint ( "Starting EXPRESSION of type %s\n", (char*) root->expression_type.text); switch(root->expression_type.index) { case FUNC_CALL_E: { if (root->children[1] != NULL) { // Push arguments on stack gen_default(root->children[1], scopedepth); } char *func_label = root->function_entry->label; instruction_add(CALL, STRDUP(func_label), NULL, 0, 0); // There is an issue where, if the parent node does not use the returned result, // this will pollute the stack, and offset any new local variables declared. // I see no easy way to fix this, and it also doesn't seem to be covered by // the tests. instruction_add(PUSH, r0, NULL, 0, 0); } break; case METH_CALL_E: { if (root->children[2] != NULL) { // Push arguments on stack gen_default(root->children[2], scopedepth); } tracePrint( "Pushing THIS\n" ); root->children[0]->generate(root->children[0], scopedepth); char *class_label = root->children[0]->data_type.class_name; char *func_label = root->function_entry->label; int len = strlen(class_label) + strlen(func_label); char *meth_label = malloc(sizeof(char) * (len+1)); meth_label[0] = 0; strcat(meth_label, class_label); strcat(meth_label, "_"); strcat(meth_label, func_label); instruction_add(CALL, STRDUP(meth_label), NULL, 0, 0); // There is an issue where, if the parent node does not use the returned result, // this will pollute the stack, and offset any new local variables declared. // I see no easy way to fix this, and it also doesn't seem to be covered by // the tests. instruction_add(PUSH, r0, NULL, 0, 0); } break; case NEW_E: { class_symbol_t *class_entry = root->children[0]->class_entry; char class_size[10]; int32_t class_entry_size = (int32_t)class_entry->size * 8; sprintf(class_size, "#%d", class_entry_size); instruction_add(MOVE32, STRDUP(class_size), r0, 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); instruction_add(CALL, STRDUP("malloc"), NULL, 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); } break; case CLASS_FIELD_E: { root->children[0]->generate(root->children[0], scopedepth); char stack_offset[10]; sprintf(stack_offset, "#%d", root->entry->stack_offset); instruction_add(POP, r1, NULL, 0, 0); instruction_add(MOVE, r2, STRDUP(stack_offset), 0, 0); instruction_add3(ADD, r3, r1, r2); instruction_add(LOAD, r0, r3, 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); } break; case THIS_E: { instruction_add(LOAD, r1, fp, 0, 8); instruction_add(PUSH, r1, NULL, 0, 0); } break; default: gen_default(root, scopedepth); } switch (root->expression_type.index) { case ADD_E: case OR_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add3(ADD, r0, r1, r2); instruction_add(PUSH, r0, NULL, 0, 0); break; case SUB_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add3(SUB, r0, r1, r2); instruction_add(PUSH, r0, NULL, 0, 0); break; case MUL_E: case AND_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add3(MUL, r0, r1, r2); instruction_add(PUSH, r0, NULL, 0, 0); break; case DIV_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add3(DIV, r0, r1, r2); instruction_add(PUSH, r0, NULL, 0, 0); break; case UMINUS_E: instruction_add(MOVE, r1, STRDUP("#0"), 0, 0); instruction_add(POP, r2, NULL, 0, 0); instruction_add3(SUB, r0, r1, r2); instruction_add(PUSH, r0, NULL, 0, 0); break; case EQUAL_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, STRDUP("#0"), 0, 0); instruction_add(MOVEQ, r0, STRDUP("#1"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; case NEQUAL_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, STRDUP("#1"), 0, 0); instruction_add(MOVEQ, r0, STRDUP("#0"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; case GEQUAL_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, STRDUP("#0"), 0, 0); instruction_add(MOVGE, r0, STRDUP("#1"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; case LEQUAL_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, STRDUP("#0"), 0, 0); instruction_add(MOVLE, r0, STRDUP("#1"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; case LESS_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, STRDUP("#0"), 0, 0); instruction_add(MOVLT, r0, STRDUP("#1"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; case GREATER_E: instruction_add(POP, r2, NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, STRDUP("#0"), 0, 0); instruction_add(MOVGT, r0, STRDUP("#1"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; case NOT_E: instruction_add(POP, r1, NULL, 0, 0); instruction_add(CMP, r1, STRDUP("#0"), 0, 0); instruction_add(MOVE, r0, STRDUP("#0"), 0, 0); instruction_add(MOVEQ, r0, STRDUP("#1"), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); break; } tracePrint ( "Ending EXPRESSION of type %s\n", (char*) root->expression_type.text); }
void gen_EXPRESSION ( node_t *root, int scopedepth ) { /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ tracePrint ( "Starting EXPRESSION of type %s\n", (char*) root->expression_type.text); switch(root->expression_type.index){ case FUNC_CALL_E: ge(root,scopedepth); break; /* Add cases for other expressions here */ case ADD_E: case SUB_E: case MUL_E: case DIV_E: case LEQUAL_E: case GEQUAL_E: case NEQUAL_E: case EQUAL_E: case LESS_E: case GREATER_E: case AND_E: case OR_E: ; node_t *left_child = root->children[0]; node_t *right_child = root->children[1]; right_child->generate(right_child, scopedepth); left_child->generate(left_child, scopedepth); instruction_add(POP, r1, NULL, 0, 0); instruction_add(POP, r2, NULL, 0, 0); switch(root->expression_type.index) { case ADD_E: case OR_E: instruction_add3(ADD, r0, r1, r2); break; case SUB_E: instruction_add3(SUB, r0, r1, r2); break; case MUL_E: case AND_E: instruction_add3(MUL, r0, r1, r2); break; case DIV_E: instruction_add3(DIV, r0, r1, r2); break; case EQUAL_E: instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, "#0", 0, 0); instruction_add(MOVEQ, r0, "#1", 0, 0); break; case GEQUAL_E: instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, "#0", 0, 0); instruction_add(MOVGE, r0, "#1", 0, 0); break; case NEQUAL_E: instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, "#0", 0, 0); instruction_add(MOVNE, r0, "#1", 0, 0); break; case LEQUAL_E: instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, "#0", 0, 0); instruction_add(MOVLE, r0, "#1", 0, 0); break; case LESS_E: instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, "#0", 0, 0); instruction_add(MOVLT, r0, "#1", 0, 0); break; case GREATER_E: instruction_add(CMP, r1, r2, 0, 0); instruction_add(MOVE, r0, "#0", 0, 0); instruction_add(MOVGT, r0, "#1", 0, 0); break; } instruction_add(PUSH, r0, NULL, 0, 0); break; } tracePrint ( "Ending EXPRESSION of type %s\n", (char*) root->expression_type.text); }
void gen_PRINT_STATEMENT(node_t* root, int scopedepth) { tracePrint("Starting PRINT_STATEMENT\n"); for(int i = 0; i < root->children[0]->n_children; i++){ root->children[0]->children[i]->generate(root->children[0]->children[i], scopedepth); //Pushing the .INTEGER constant, which will be the second argument to printf, //and cause the first argument, which is the result of the expression, and is //allready on the stack to be printed as an integer base_data_type_t t = root->children[0]->children[i]->data_type.base_type; switch(t) { case INT_TYPE: instruction_add(STRING, STRDUP("\tmovw r0, #:lower16:.INTEGER"), NULL, 0,0); instruction_add(STRING, STRDUP("\tmovt r0, #:upper16:.INTEGER"), NULL, 0,0); instruction_add(POP, r1, NULL, 0,0); break; case FLOAT_TYPE: instruction_add(LOADS, sp, s0, 0,0); instruction_add(CVTSD, s0, d0, 0,0); instruction_add(STRING, STRDUP("\tfmrrd r2, r3, d0"), NULL, 0,0); instruction_add(STRING, STRDUP("\tmovw r0, #:lower16:.FLOAT"), NULL, 0,0); instruction_add(STRING, STRDUP("\tmovt r0, #:upper16:.FLOAT"), NULL, 0,0); // And now the tricky part... 8-byte stack alignment :( // We have at least 4-byte alignment always. // Check if its only 4-byte aligned right now by anding that bit in the stack-pointer. // Store the answer in r5, and set the zero flag. instruction_add(STRING, STRDUP("\tandS r5, sp, #4"), NULL, 0,0); // Now use the zero flag as a condition to optionally change the stack-pointer instruction_add(STRING, STRDUP("\tpushNE {r5}"), NULL, 0,0); break; case BOOL_TYPE: instruction_add(STRING, STRDUP("\tmovw r0, #:lower16:.INTEGER"), NULL, 0,0); instruction_add(STRING, STRDUP("\tmovt r0, #:upper16:.INTEGER"), NULL, 0,0); instruction_add(POP, r1, NULL, 0,0); break; case STRING_TYPE: instruction_add(POP, r0, NULL, 0,0); break; default: instruction_add(PUSH, STRDUP("$.INTEGER"), NULL, 0,0); fprintf(stderr, "WARNING: attempting to print something not int, float or bool\n"); break; } instruction_add(SYSCALL, STRDUP("printf"), NULL,0,0); // Undo stack alignment. if(t == FLOAT_TYPE) { // Redo the zero flag test on r5, as it will give the same answer as the first test on sp. instruction_add(STRING, STRDUP("\tandS r5, #4"), NULL, 0,0); // Conditionally remove the alignment. instruction_add(STRING, STRDUP("\tpopNE {r5}"), NULL, 0,0); } } instruction_add(MOVE32, STRDUP("#0x0A"), r0, 0,0); instruction_add(SYSCALL, STRDUP("putchar"), NULL, 0,0); tracePrint("Ending PRINT_STATEMENT\n"); }
void gen_EXPRESSION ( node_t *root, int scopedepth ) { /* * Expressions: * Handle any nested expressions first, then deal with the * top of the stack according to the kind of expression * (single variables/integers handled in separate switch/cases) */ tracePrint ( "Starting EXPRESSION of type %s\n", (char*) root->expression_type.text); int size; char size_string[100]; switch(root->expression_type.index){ case FUNC_CALL_E: ge(root,scopedepth); break; /* Add cases for other expressions here */ case UMINUS_E: // Generate the child root->children[0]->generate(root->children[0], scopedepth); // Fetching the operand from stack instruction_add(POP, r0, NULL, 0, 0); instruction_add(MOVE, r1, "#-1", 0, 0); instruction_add3(MUL, r0, r0, r1); instruction_add(PUSH, r0, NULL, 0, 0); break; case METH_CALL_E: // Caller saves registers on stack. // Assuming that there might be something in registers r1-r3 // Assuming that r0 are used to handle different inputs and outputs, including function result. instruction_add(PUSH, r3, NULL, 0,0); instruction_add(PUSH, r2, NULL, 0,0); instruction_add(PUSH, r1, NULL, 0,0); // Caller pushes parameters on stack. // Must find number of parameters, and push each value to stack // When parameters, second child-node is a variable-list instead of NULL. Children of that node contain the parameters values int i; if (root->children[2]!=NULL){ for (i=0; i<root->children[2]->n_children; i++){ // Load parameter number i into register r0 by using the generate-method for that node (usually variable or constant) // r0 will automatically be pushed by either gen_CONSTANT or gen_VARIABLE root->children[2]->children[i]->generate(root->children[2]->children[i], scopedepth); } } // IMPORTANT: Difference from func_call is also that the object (value is address on heap) is pushed as final argument // Loading object as variable into r0 and pushing r0 in stack, by generate root->children[0]->generate(root->children[0], scopedepth); //Performing method call from correct class: //function_symbol_t* entry = root->children[1]->function_entry; symbol_t* p1 = root->children[0]->entry; data_type_t p2 = p1->type; int len2 = strlen(p2.class_name); char *temp2 = (char*) malloc(sizeof(char) * (len2 + 3)); temp2[0] = 0; //temp3 = test.type->class_name; //temp3= root->children[0]->entry.type->class_name; strcat(temp2, p2.class_name); strcat(temp2, "_"); strcat(temp2, root->children[1]->label); instruction_add(CALL, STRDUP(temp2), NULL, 0, 0 ); free(temp2); // Poping THIS as argument from the stack instruction_add(POP, "r8", NULL, 0,0); // Callee jumps back to caller, and pops return address. Caller removes parameters, restores registers, uses result. // Using r0 for result storing from the function if (root->children[2]!=NULL){ for (i=0; i<root->children[2]->n_children; i++){ // Poping parameters from stack, by loading into r8, that is otherwise never used. This includes the objects heap parameter instruction_add(POP, "r8", NULL, 0,0); } } // Restoring original registers instruction_add(POP, r1, NULL, 0,0); instruction_add(POP, r2, NULL, 0,0); instruction_add(POP, r3, NULL, 0,0); // NOTE: Have to hack in order to make sure printing works when including functions straight in print statement // by setting data_type root->data_type = root->function_entry->return_type; if (root->data_type.base_type!=VOID_TYPE){ // Adding result in r0 to stack as return result instruction_add(PUSH, r0, NULL, 0,0); } break; // Binary expressions: case ADD_E: case SUB_E: case MUL_E: case DIV_E: case AND_E: case OR_E: case EQUAL_E: case NEQUAL_E: case LEQUAL_E: case GEQUAL_E: case LESS_E: case GREATER_E: // The two operands are in the two child-nodes. They must be generated. root->children[0]->generate(root->children[0], scopedepth); root->children[1]->generate(root->children[1], scopedepth); // Fetching the operands from stack instruction_add(POP, r2, NULL, 0,0); instruction_add(POP, r1, NULL, 0,0); // Calculating, and pushing to stack // Now the current operation itself: switch(root->expression_type.index){ // Arithmetic and logical expressions: case ADD_E: case OR_E: instruction_add3(ADD, r0, r1, r2); break; case SUB_E: instruction_add3(SUB, r0, r1, r2); break; case MUL_E: case AND_E: instruction_add3(MUL, r0, r1, r2); break; case DIV_E: instruction_add3(DIV, r0, r1, r2); break; // Comparison expressions: case GREATER_E: instruction_add(MOVE, r0, "#0", 0,0); instruction_add(CMP, r1, r2, 0,0); instruction_add(MOVGT, r0, "#1", 0,0); break; case LESS_E: instruction_add(MOVE, r0, "#0", 0,0); instruction_add(CMP, r1, r2, 0,0); instruction_add(MOVLT, r0, "#1", 0,0); break; case EQUAL_E: instruction_add(MOVE, r0, "#0", 0,0); instruction_add(CMP, r1, r2, 0,0); instruction_add(MOVEQ, r0, "#1", 0,0); break; case NEQUAL_E: instruction_add(MOVE, r0, "#0", 0,0); instruction_add(CMP, r1, r2, 0,0); instruction_add(MOVNE, r0, "#1", 0,0); break; case GEQUAL_E: instruction_add(MOVE, r0, "#0", 0,0); instruction_add(CMP, r1, r2, 0,0); instruction_add(MOVGE, r0, "#1", 0,0); break; case LEQUAL_E: instruction_add(MOVE, r0, "#0", 0,0); instruction_add(CMP, r1, r2, 0,0); instruction_add(MOVLE, r0, "#1", 0,0); break; } // Pushing to stack: instruction_add(PUSH, r0, NULL, 0, 0); break; case CLASS_FIELD_E: // Fetching address value from child 1, pushing to top of stack: root->children[0]->generate(root->children[0], scopedepth); // Now poping from stack into r0: instruction_add(POP, r1, NULL, 0,0); // Now loading from heap, based on address from child 1 and offset from child 2: instruction_add(LOAD, r0, r1, 0, root->children[1]->entry->stack_offset); // Pushing class field access result to stac: instruction_add(PUSH, r0, NULL, 0,0); break; case THIS_E: //TODO: Double check that this works, double check that the value at class position in stack indeed is the address, or if it needs to be fetched using node field instruction_add(LOAD, r0, fp, 0, 8); instruction_add(PUSH, r0, NULL, 0, 0); break; case NEW_E: size = root->children[0]->class_entry->size; snprintf(size_string, 100, "#%d", size); //Max 99 digits instruction_add(MOVE, r0, STRDUP(size_string), 0, 0); instruction_add(PUSH, r0, NULL, 0, 0); //Pushing constant to stack, in case of print statement instruction_add(CALL, STRDUP("malloc"), NULL, 0, 0); instruction_add(POP, r1, NULL, 0, 0); //instruction_add(STORE, r0, sp, 0, 8); instruction_add(PUSH, r0, NULL, 0, 0); break; } tracePrint ( "Ending EXPRESSION of type %s\n", (char*) root->expression_type.text); }