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 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 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 ) { 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; } }