Post Reply 
monic part 6: the mC programming language and compiler
06-22-2022, 01:50 AM (This post was last modified: 06-23-2022 04:29 AM by F-73P.)
Post: #11
RE: monic part 6: the mC programming language and compiler
Thanks Sylvain, you are right. Implementing switch is quite a challenge - I would like it to conform to standard C but I just can't figure it out. Below is the code for switch in the parser, there's already a lot going on!

Code:

void switch_stmt(void){
    uint16_t jumpArray1ReleaseIndexLocal;
    uint16_t jumpArray2ReleaseIndexLocal;
    uint16_t jumpArray3ReleaseIndexLocal; //to jump to statement-list when match in multiple labels in switch statement

    uint16_t jumpArray1DebugIndexLocal;
    uint16_t jumpArray2DebugIndexLocal;
    uint16_t jumpArray3DebugIndexLocal; //to jump to statement-list when match in multiple labels in switch statement

    _Bool flag=false;

    /*set breakpoint for debugging*/
    set_statement_to_line_number_array(statementTolineNoArrayIndex,get_line_no(​));
    set_prg_index_virtual_array(statementTolineNoArrayIndex,prgReleaseIndex);
    set_prg_debug(prgDebugIndex++,BKPT+statementTolineNoArrayIndex++);
    /****************/

    breakStackIndex++;
    breakStack[breakStackIndex-1].index=jumpArray1ReleaseIndexGlobal; //increment breakStack so if "break" statement in source jump out of switch statement
    breakStack[breakStackIndex-1].loop=SWITCHSTATEMENT;

    jumpArray1ReleaseIndexLocal = jumpArray1ReleaseIndexGlobal++;
    jumpArray1DebugIndexLocal = jumpArray1DebugIndexGlobal++;

    advance();
    match_check_advance(LPAREN)
    expression(); if(get_compiler_error_flag()) return;
    match_check_advance(RPAREN)
    match_check_advance(LBRACE)
    while(token==CASE) {
        if(flag) { //do not set jumpArray2 on first iteration
            set_jump_array2_release(jumpArray2ReleaseIndexLocal,prgReleaseIndex-1); //program jumps here if no match
            set_jump_array2_debug(jumpArray2DebugIndexLocal,prgDebugIndex-1);
        }
        else flag=true;
        /*DUP*/
        set_prg_release(prgReleaseIndex++,DUP);
        set_prg_debug(prgDebugIndex++,DUP);
        /************************************/
        advance();
        match(NUM); if(get_compiler_error_flag()) return;
        save_literal(); //convert tokenString to double and add to literal table
        /*push literal onto the stack*/
        set_prg_release(prgReleaseIndex++,PUSHLITERAL+literalTableIndex-1);
        set_prg_debug(prgDebugIndex++,PUSHLITERAL+literalTableIndex-1);
        /************************************/
        /*check if equal*/
        set_prg_release(prgReleaseIndex++,TESTEQ);
        set_prg_debug(prgDebugIndex++,TESTEQ);
        /************************************/
        advance();
        match_check_advance(COLON);
        if (token==CASE) { //multiple labels
            jumpArray3ReleaseIndexLocal = jumpArray3ReleaseIndexGlobal++;
            jumpArray3DebugIndexLocal = jumpArray3DebugIndexGlobal++;

            while(token==CASE) {
                /*jump to jumpArray3[jumpArray3IndexLocal] (statement-list) if match*/
                set_prg_release(prgReleaseIndex++,TRUEJUMPRELEASE2+jumpArray3ReleaseIndexLo​cal);
                set_prg_debug(prgDebugIndex++,TRUEJUMPDEBUG2+jumpArray3DebugIndexLocal);
                /************************************/
                /*DUP*/
                set_prg_release(prgReleaseIndex++,DUP);
                set_prg_debug(prgDebugIndex++,DUP);
                /************************************/
                advance();
                match(NUM); if(get_compiler_error_flag()) return;
                save_literal(); //convert tokenString to double and add to literal table
                /*push literal onto the stack*/
                set_prg_release(prgReleaseIndex++,PUSHLITERAL+literalTableIndex-1);
                set_prg_debug(prgDebugIndex++,PUSHLITERAL+literalTableIndex-1);
                /************************************/
                /*check if equal*/
                set_prg_release(prgReleaseIndex++,TESTEQ);
                set_prg_debug(prgDebugIndex++,TESTEQ);
                /************************************/
                advance();
                match_check_advance(COLON);
            }

            /*jump to jumpArray2[jumpArray2IndexLocal] if no match*/
            jumpArray2ReleaseIndexLocal = jumpArray2ReleaseIndexGlobal++;
            jumpArray2DebugIndexLocal = jumpArray2DebugIndexGlobal++;
            set_prg_release(prgReleaseIndex++,FALSEJUMPRELEASE+jumpArray2ReleaseIndexLo​cal);
            set_prg_debug(prgDebugIndex++,FALSEJUMPDEBUG+jumpArray2DebugIndexLocal);
            /************************************/

            set_jump_array3_release(jumpArray3ReleaseIndexLocal,prgReleaseIndex-1); //jump to statement-list if match
            set_jump_array3_debug(jumpArray3DebugIndexLocal,prgDebugIndex-1); //jump to statement-list if match

            /*DROP*/
            set_prg_release(prgReleaseIndex++,DROP);
            set_prg_debug(prgDebugIndex++,DROP);
            /************************************/
            statement_list(); if(get_compiler_error_flag()) return;

            /*jump to jumpArray1[jumpArray1Index] to exit*/ //implied "break" statement
            set_prg_release(prgReleaseIndex++,JUMPRELEASE+breakStack[breakStackIndex-1].index);
            set_prg_debug(prgDebugIndex++,JUMPDEBUG+breakStack[breakStackIndex-1].index);
            /************************************/
        }
        else { //not multiple labels
            /*jump to jumpArray2[jumpArray2IndexLocal] if no match*/
            jumpArray2ReleaseIndexLocal = jumpArray2ReleaseIndexGlobal++;
            jumpArray2DebugIndexLocal = jumpArray2DebugIndexGlobal++;
            set_prg_release(prgReleaseIndex++,FALSEJUMPRELEASE+jumpArray2ReleaseIndexLo​cal);
            set_prg_debug(prgDebugIndex++,FALSEJUMPDEBUG+jumpArray2DebugIndexLocal);
            /************************************/
            /*DROP*/
            set_prg_release(prgReleaseIndex++,DROP);
            set_prg_debug(prgDebugIndex++,DROP);
            /************************************/
            statement_list(); if(get_compiler_error_flag()) return;

            /*jump to jumpArray1[jumpArray1Index] to exit*/ //implied "break" statement
            set_prg_release(prgReleaseIndex++,JUMPRELEASE+breakStack[breakStackIndex-1].index);
            set_prg_debug(prgDebugIndex++,JUMPDEBUG+breakStack[breakStackIndex-1].index);
            /************************************/
        }
    }

    if(token==DEFAULT) {
        advance();
        match_check_advance(COLON)

        set_jump_array2_release(jumpArray2ReleaseIndexLocal,prgReleaseIndex-1); //program jumps here if no match
        set_jump_array2_debug(jumpArray2DebugIndexLocal,prgDebugIndex-1);

        /*DROP*/
        set_prg_release(prgReleaseIndex++,DROP);
        set_prg_debug(prgDebugIndex++,DROP);
        /************************************/

        statement_list(); if(get_compiler_error_flag()) return;
    }
    else {
        set_jump_array2_release(jumpArray2ReleaseIndexLocal,prgReleaseIndex-1); //program jumps here if no match
        set_jump_array2_debug(jumpArray2DebugIndexLocal,prgDebugIndex-1);

        /*DROP*/
        set_prg_release(prgReleaseIndex++,DROP);
        set_prg_debug(prgDebugIndex++,DROP);
        /************************************/
    }

    match_check_advance(RBRACE)

    set_jump_array1_release(jumpArray1ReleaseIndexLocal,prgReleaseIndex-1); //program jumps here if match
    set_jump_array1_debug(jumpArray1DebugIndexLocal,prgDebugIndex-1);

    breakStackIndex--; //decrement breakStack
}

It may be a little clearer how my implementation of switch works if we look at the bytecode into which program "switch test 5" (in my previous post) is translated:

[Image: 52163303047_57a2a36c6a.jpg][Image: 52164327116_120b4769cf.jpg]

Now if the implied break code generation instructions in the parser are removed the bytecode program becomes:

[Image: 52163775757_0f6284da29.jpg][Image: 52164800231_9be5f7d850.jpg]

There are two problems with this. The first is that in my implementation the switch expression ("n" in this example) is left on the stack (hence the "DUP" and "DROP" instructions). Without an implied break the program ends up just deleting "n". This can be fixed by saving the switch expression to a variable and pushing it onto the stack before testing the cases, so that "DUP" and "DROP" are not required.

But the other problem remains: when there's a match with one of the first two cases (i.e. the user entered "1" or "2") the program displays "10" but it won't fall through and display "20" as well.

Back to the drawing board Smile

The C language combines all the power of assembly language with all the ease-of-use of assembly language
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: monic part 6: the mC programming language and compiler - F-73P - 06-22-2022 01:50 AM



User(s) browsing this thread: 1 Guest(s)