// File: /workspace/github_c_makefile_star2_O0/gregtour[P]minimal-compiler/typechecker.c
// Function: StaticTypeChecking
int StaticTypeChecking(FSTMT* statement, void* funcHeader)
{
    FUNC_SEGMENT* segment = (FUNC_SEGMENT*)funcHeader;

    Assert(statement != NULL);
    Assert(funcHeader != NULL);

    switch (statement->production)
    {
    // <fstmt> ::= <type-declaration> ;
    case PROD_FSTMT_TYPE_DECLARATION:
    {
        // do nothing
        break;
    }
    // <fstmt> ::= <identifier> = <expr> ;
    case PROD_FSTMT_IDENTIFIER:
    {
        const char* identifier;
        VARLIST* assignee;
        EXPR* expr;

        Assert(statement->numChildren == 4);
        Assert(statement->children);
        Assert(statement->children[0] && statement->children[0]->string);

        expr = (EXPR*)(statement->children[2]);
        identifier = statement->children[0]->string;
        assignee = GetVariableFromList(segment->locals, identifier);
        if (assignee == NULL) { assignee = GetVariableFromList(segment->params, identifier); }
        if (assignee == NULL) { assignee = GetVariableFromList(gPrgrmVariables, identifier); }

        if (assignee == NULL)
        {
            CompilerError("Assignment to undeclared variable.");
            return 1;
        }

        if (CheckExpressionType(assignee->type, expr, segment) != 0)
        {
            CompilerError("Incorrect type in assignment.");
            return 1;
        }
        break;
    }
    // <fstmt> ::= <expr> ;
    case PROD_FSTMT_EXPR:
    {
        TYPE type;
        EXPR* expr;

        type.basic = TYPE_ANY;

        expr = (EXPR*)(statement->children[0]);
        if (CheckExpressionType(type, expr, segment) != 0)
        {
            CompilerError("Invalid expression.");
            return 1;
        }
        break;
    }
    // <fstmt> ::= if ( <expr> ) <block> <else>
    case PROD_FSTMT_IF:
    {
        SYNTAX_BLOCK* block;
        EXPR* expr;
        SYNTAX_TREE* elseBranch;
        TYPE nonvoid;

        expr = (EXPR*)(statement->children[2]);
        block = (SYNTAX_BLOCK*)(statement->children[4]);
        elseBranch = statement->children[5];
        nonvoid.basic = TYPE_NON_VOID;
        nonvoid.size = 4;

        if (CheckExpressionType(nonvoid, expr, segment) != 0)
        {
            CompilerError("Attempt to use void type as a conditional expression.");
            return 1;
        }

        Assert(block->token == SYMBOL_BLOCK);
        ProcessCodeBlock(block, StaticTypeChecking, funcHeader);

        if (elseBranch->production == PROD_ELSE_ELSE)
        {
            SYNTAX_BLOCK* elseBlock;
            Assert(elseBranch->children[1]->token == SYMBOL_BLOCK);
            // <else> ::= else <block>
            elseBlock = (SYNTAX_BLOCK*)(elseBranch->children[1]);
            ProcessCodeBlock(elseBlock, StaticTypeChecking, funcHeader);
        }

        break;
    }
    // <fstmt> ::= while ( <expr> ) <block>
    case PROD_FSTMT_WHILE:
    {
        TYPE nonvoid;
        SYNTAX_BLOCK* block;
        EXPR* expr;
        int loopFlag;

        expr = (EXPR*)(statement->children[2]);
        block = (SYNTAX_BLOCK*)(statement->children[4]);
        nonvoid.basic = TYPE_NON_VOID;
        nonvoid.size = 4;

        if (CheckExpressionType(nonvoid, expr, segment) != 0)
        {
            CompilerError("Attempt to use void type as loop condition.");
            return 1;
        }

        loopFlag = segment->isInLoop;
        segment->isInLoop = 1;
        Assert(block->token == SYMBOL_BLOCK);
        ProcessCodeBlock(block, StaticTypeChecking, funcHeader);
        segment->isInLoop = loopFlag;
        break;
    }
    // <fstmt> ::= return ;
    case PROD_FSTMT_RETURN_A:
    {
        if (segment->returnType.basic != TYPE_VOID)
        {
            CompilerError("Error, use of void return in non-void function.");
            return 1;
        }
        break;
    }
    // <fstmt> ::= break ;
    case PROD_FSTMT_BREAK:
    {
        if (segment->isInLoop == 0)
        {
            CompilerError("Error using break statement outside of loop body.");
            return 1;
        }
        break;
    }
    // <fstmt> ::= continue ; 
    case PROD_FSTMT_CONTINUE:
    {
        if (segment->isInLoop == 0)
        {
            CompilerError("Error using continue statement outside of loop.");
            return 1;
        }
        break;
    }
    // <fstmt> ::= return <expr> ;
    case PROD_FSTMT_RETURN_B:
    {
        EXPR* expr;
        Assert(statement->children && statement->children[1]);
        expr = (EXPR*)(statement->children[1]);
        CheckExpressionType(segment->returnType, expr, segment);
        break;
    }
    default:
        AssertS(0, "Unrecognized statement-level instruction encountered.");
        CompilerError("Unknown statement.");
        break;
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
addl $-0x15, %eax
movl %eax, %ecx
movq %rcx, -0xa0(%rbp)
subl $0xa, %eax
ja 0xa13c
movq -0xa0(%rbp), %rax
leaq 0x1aab(%rip), %rcx      # 0xb880
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
jmp 0xa154
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x10(%rax), %rax
movq %rax, -0x38(%rbp)
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq (%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x28(%rbp), %rsi
callq 0x9260
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x9e37
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x28(%rbp), %rsi
callq 0x9260
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x9e55
leaq 0x1251b(%rip), %rax     # 0x1c360
movq (%rax), %rdi
movq -0x28(%rbp), %rsi
callq 0x9260
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x9e80
leaq 0x1c3c(%rip), %rdi      # 0xba9f
leaq 0x1ab7(%rip), %rsi      # 0xb921
movl $0x10f, %edx            # imm = 0x10F
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
movq -0x30(%rbp), %rax
movq -0x38(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq (%rax), %rdi
callq 0xa170
cmpl $0x0, %eax
je 0x9ebd
leaq 0x1c22(%rip), %rdi      # 0xbac2
leaq 0x1a7a(%rip), %rsi      # 0xb921
movl $0x115, %edx            # imm = 0x115
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
jmp 0xa154
movl $0x7, -0x3c(%rbp)
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq (%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq -0x40(%rbp), %rdi
callq 0xa170
cmpl $0x0, %eax
je 0x9f12
leaq 0x1beb(%rip), %rdi      # 0xbae0
leaq 0x1a25(%rip), %rsi      # 0xb921
movl $0x125, %edx            # imm = 0x125
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
jmp 0xa154
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x10(%rax), %rax
movq %rax, -0x58(%rbp)
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x20(%rax), %rax
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x28(%rax), %rax
movq %rax, -0x60(%rbp)
movl $0x8, -0x64(%rbp)
movl $0x4, -0x68(%rbp)
movq -0x58(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq -0x68(%rbp), %rdi
callq 0xa170
cmpl $0x0, %eax
je 0x9f8f
leaq 0x1b82(%rip), %rdi      # 0xbaf4
leaq 0x19a8(%rip), %rsi      # 0xb921
movl $0x13a, %edx            # imm = 0x13A
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
movq -0x50(%rbp), %rdi
movq -0x18(%rbp), %rdx
leaq -0x20e(%rip), %rsi      # 0x9d90
callq 0x8c10
movq -0x60(%rbp), %rax
cmpl $0x19, 0x4(%rax)
jne 0x9fd1
movq -0x60(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rdi
movq -0x18(%rbp), %rdx
leaq -0x23c(%rip), %rsi      # 0x9d90
callq 0x8c10
jmp 0xa154
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x10(%rax), %rax
movq %rax, -0x88(%rbp)
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x20(%rax), %rax
movq %rax, -0x80(%rbp)
movl $0x8, -0x74(%rbp)
movl $0x4, -0x78(%rbp)
movq -0x88(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq -0x78(%rbp), %rdi
callq 0xa170
cmpl $0x0, %eax
je 0xa044
leaq 0x1b03(%rip), %rdi      # 0xbb2a
leaq 0x18f3(%rip), %rsi      # 0xb921
movl $0x15b, %edx            # imm = 0x15B
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
movq -0x20(%rbp), %rax
movl 0x28(%rax), %eax
movl %eax, -0x8c(%rbp)
movq -0x20(%rbp), %rax
movl $0x1, 0x28(%rax)
movq -0x80(%rbp), %rdi
movq -0x18(%rbp), %rdx
leaq -0x2db(%rip), %rsi      # 0x9d90
callq 0x8c10
movl -0x8c(%rbp), %ecx
movq -0x20(%rbp), %rax
movl %ecx, 0x28(%rax)
jmp 0xa154
movq -0x20(%rbp), %rax
cmpl $0x0, 0xc(%rax)
je 0xa0b0
leaq 0x1ac3(%rip), %rdi      # 0xbb56
leaq 0x1887(%rip), %rsi      # 0xb921
movl $0x16b, %edx            # imm = 0x16B
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
jmp 0xa154
movq -0x20(%rbp), %rax
cmpl $0x0, 0x28(%rax)
jne 0xa0e0
leaq 0x1ac0(%rip), %rdi      # 0xbb86
leaq 0x1854(%rip), %rsi      # 0xb921
movl $0x175, %edx            # imm = 0x175
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
jmp 0xa154
movq -0x20(%rbp), %rax
cmpl $0x0, 0x28(%rax)
jne 0xa10d
leaq 0x1ac5(%rip), %rdi      # 0xbbb8
leaq 0x1827(%rip), %rsi      # 0xb921
movl $0x17f, %edx            # imm = 0x17F
callq 0x6e20
movl $0x1, -0x4(%rbp)
jmp 0xa15b
jmp 0xa154
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x8(%rax), %rax
movq %rax, -0x98(%rbp)
movq -0x20(%rbp), %rax
movq -0x98(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq 0x8(%rax), %rdi
callq 0xa170
jmp 0xa154
leaq 0x1384(%rip), %rdi      # 0xb4c7
leaq 0x17d7(%rip), %rsi      # 0xb921
movl $0x18f, %edx            # imm = 0x18F
callq 0x6e20
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0xa0, %rsp
popq %rbp
retq
nopw (%rax,%rax)