Пример #1
0
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);
}
Пример #2
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);
}
Пример #3
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);
    }
}
Пример #4
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");
}
Пример #5
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();
	
	/* 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 ();
}
Пример #6
0
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);
}
Пример #7
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);
}
Пример #8
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 ();
}
Пример #9
0
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);
}
Пример #10
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");
}
Пример #11
0
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);
}
Пример #12
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 );
}
Пример #13
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);
}
Пример #14
0
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");
}
Пример #15
0
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);
}
Пример #16
0
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);
}
Пример #17
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);

}
Пример #18
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");
}
Пример #19
0
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;
    }
}
Пример #20
0
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;
    }
}
Пример #21
0
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);
}
Пример #22
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;
    }
}
Пример #23
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;
	}
}
Пример #24
0
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);
}
Пример #25
0
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);
}
Пример #26
0
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");
}
Пример #27
0
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);
}