// File: /workspace/github_c_makefile_star2_O3/gregtour[P]minimal-compiler/grammar.c
// Function: LoadGrammar
int LoadGrammar(const char*    file,
                GRAMMAR_TABLE* table)
{
    FILE* input;
    char* buffer;
    int   size;
    int   i, r, start, end;
    int   rhs, symbol, token;
    int   read, line, col;

    // initialize table
    table->numSymbols = 0;
    table->symbols = (char*)malloc(SYMBOL_BUFFER_SIZE);
    table->symbols[SYMBOL_BUFFER_SIZE - 1] = 0;
    table->numTokens = 0;
    table->tokens = (char*)malloc(TOKEN_BUFFER_SIZE);
    table->tokens[TOKEN_BUFFER_SIZE - 1] = 0;
    table->numRules = 0;
    table->rules = 0;

    // add built in symbols
    gSymbolRoot       = 0;
    gSymbolGoal       = K_SYMBOL + table->numSymbols + 1;
    gSymbolEpsilon    = AddToken("<epsilon>", 9, table);
    gSymbolEOF        = AddToken("<$>", 3, table);
    gSymbolEndLine    = AddToken("<endl>", 6, table);
    gSymbolInteger    = AddToken("<integer>", 9, table);
    gSymbolFloat      = AddToken("<float>", 7, table);
    gSymbolString     = AddToken("<string>", 8, table);
    gSymbolIdentifier = AddToken("<identifier>", 12, table);

    // read grammar file
    printf("Loading context free grammar from %s...\n", file);
    input = fopen(file, "rb");
    if (input == 0) {
        printf("Could not open grammar file.\n");
        return 1;
    }
    fseek(input, 0, SEEK_END);
    size = ftell(input);
    rewind(input);
    buffer = (char*)malloc(size+2);
    read = fread(buffer, 1, size, input);
    buffer[size] = '\n';
    buffer[size+1] = 0;
    fclose(input);
    
    printf("Read %i of %i bytes.\n", read, size);

    if (size == 0) {
        printf("Unable to read grammar rules.\n");
        return 1;
    }

    // count rules
    table->numRules = 0; col = 0;
    for (i = 0; i < size; i++)
    {
        // don't count comments or new lines
        if (col == 0 &&
            (buffer[i] == ';' || buffer[i] == '\r' || buffer[i] == '\n'))
        {
            while (i < size && buffer[i] != '\n')
                i++;
            continue;
        }
        col++;
        if (buffer[i] == '\r') buffer[i] = 0;
        else if (buffer[i] == '\n') { table->numRules++; col = 0; }
    }
    printf("Loaded %i grammar rules.\n", table->numRules);
    table->numRules++;

    // S' -> S
    table->rules = (RULE*)malloc(sizeof(RULE) * table->numRules);
    table->rules[0].lhs = gSymbolRoot;
    table->rules[0].rhs = (int*)malloc(sizeof(int) * RULE_RHS_SIZE);
    table->rules[0].rhs[0] = gSymbolGoal;
    table->rules[0].rhs[1] = 0;
    table->rules[0].rhsLength = 1;

    // parse rules
    start = 0; end = 0; line = 0;
    for (r = 1; r < table->numRules; r++)
    {
        // skip comments or blank lines
        while (start < size &&
                (buffer[start] == ';' || buffer[start] == '\n'
                 || buffer[start] == 0))
        {
            while (start < symbol && buffer[start] != '\n')
                start++;
            start++;
            line++;
        }
        // left hand symbol
        while (start < size && buffer[start] != '<')
            start++;
        end = start;
        while (start < size && buffer[end] != '>')
            end++;
        symbol = AddSymbol(&buffer[start], end - start + 1, table);
        if (symbol == 0) {
            printf("Could not identify left hand symbol in rule %i ", r+1);
            printf("on line %i.\n", line);
            return 1;
        }
        table->rules[r].lhs = symbol;
        start = end + 1;

        // ::= operator
        while (start < size - 2)
        {
            if (buffer[start] == ':' &&
                buffer[start+1] == ':' &&
                buffer[start+2] == '=')
            {
                break;
            }
            start++;
        }
        start = start + 3;

        // right hand side
        table->rules[r].rhs = (int*)malloc(sizeof(int) * RULE_RHS_SIZE);
        rhs = 0;
        while (start < size &&
               buffer[start] != '\n' &&
               buffer[start] != 0 &&
               rhs < RULE_RHS_SIZE)
        {
            if (buffer[start] == '<')
            {
                // symbol
                end = start;
                while (buffer[end] != '>' &&
                       end < size)
                {
                    end++;
                }

                symbol = FindToken(&buffer[start], end - start + 1, *table);
                if (symbol == 0)
                    symbol = AddSymbol(&buffer[start], end - start + 1, table);
                if (symbol == 0)
                {
                    printf("Could not identify right hand symbol in rule %i ", r+1);
                    printf("on line %i.\n", line);
                    return 1;
                }
                table->rules[r].rhs[rhs] = symbol;
                rhs++;
                start = end + 1;
            }
            else if (buffer[start] != ' ')
            {
                // token
                end = start;
                while (buffer[end] != ' ' &&
                      (buffer[end] != '<' ||
                       buffer[end-1] == '\\') &&
                       buffer[end] != '\n' &&
                       buffer[end] != 0 &&
                       end < size)
                {
                    end++;
                }

                token = AddToken(&buffer[start], end - start, table);
                if (token == 0)
                {
                    printf("Could not identify right hand token in rule %i ", r+1);
                    printf("on line %i.\n", line);
                    return 1;
                }
                table->rules[r].rhs[rhs] = token;
                rhs++;
                start = end;
            }
            else
            {
                // whitespace
                start++;
            }
        }
        table->rules[r].rhs[rhs] = 0;
        table->rules[r].rhsLength = rhs;
        if (rhs == 0) {
            printf("Rule %i on line %i has no right hand side.\n", r, line);
            return 1;
        } else if (rhs == RULE_RHS_SIZE) {
            printf("Rule %i on line %i may be too long.\n", r, line);
        }
    }

    if (gSymbolGoal == 0)
    {
        printf("Grammar is missing a goal symbol.\n");
        return 1;
    }

    printf("Parsed %i of %i rules.\n\n", r, table->numRules);

    free(buffer);
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movq %rsi, %r15
movq %rdi, %r14
xorl %ebx, %ebx
movl %ebx, (%rsi)
movl $0x1000, %edi           # imm = 0x1000
callq 0x2100
movq %rax, 0x8(%r15)
movb %bl, 0xfff(%rax)
movl %ebx, 0x10(%r15)
movl $0x1000, %edi           # imm = 0x1000
callq 0x2100
movq %rax, 0x18(%r15)
movb %bl, 0xfff(%rax)
movl %ebx, 0x20(%r15)
movq $0x0, 0x28(%r15)
movl %ebx, 0x160dd(%rip)     # 0x192f8
movl $0x1001, %eax           # imm = 0x1001
addl (%r15), %eax
movl %eax, 0x8e87(%rip)      # 0xc0b0
leaq 0x4fad(%rip), %rdi      # 0x81dd
movl $0x9, %esi
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8e71(%rip)      # 0xc0b4
leaq 0x4f9d(%rip), %rdi      # 0x81e7
movl $0x3, %esi
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8e5b(%rip)      # 0xc0b8
leaq 0x4f87(%rip), %rdi      # 0x81eb
movl $0x6, %esi
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8e45(%rip)      # 0xc0bc
leaq 0x4f74(%rip), %rdi      # 0x81f2
movl $0x9, %esi
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8e2f(%rip)      # 0xc0c0
leaq 0x4f64(%rip), %rdi      # 0x81fc
movl $0x7, %esi
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8e19(%rip)      # 0xc0c4
leaq 0x4f52(%rip), %rdi      # 0x8204
movl $0x8, %esi
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8e03(%rip)      # 0xc0c8
leaq 0x4f41(%rip), %rdi      # 0x820d
movl $0xc, %esi
movq %r15, -0x48(%rbp)
movq %r15, %rdx
callq 0x2f72
movl %eax, 0x8de9(%rip)      # 0xc0cc
leaq 0x4f30(%rip), %rdi      # 0x821a
movq %r14, %rsi
xorl %eax, %eax
callq 0x2090
leaq 0x4e47(%rip), %rsi      # 0x8142
movq %r14, %rdi
callq 0x2120
testq %rax, %rax
je 0x386f
movq %rax, %rbx
xorl %r12d, %r12d
movq %rax, %rdi
xorl %esi, %esi
movl $0x2, %edx
callq 0x2110
movq %rbx, %rdi
callq 0x20f0
movq %rax, %r15
movq %rbx, %rdi
callq 0x20a0
movq %r15, %r13
shlq $0x20, %r13
movabsq $0x200000000, %rdi      # imm = 0x200000000
addq %r13, %rdi
sarq $0x20, %rdi
callq 0x2100
movq %rax, %r14
movq %r15, -0x58(%rbp)
movslq %r15d, %r15
movl $0x1, %esi
movq %rax, %rdi
movq %r15, %rdx
movq %rbx, %rcx
callq 0x2060
movq %rax, -0x40(%rbp)
movb $0xa, (%r14,%r15)
movabsq $0x100000000, %rax      # imm = 0x100000000
addq %r13, %rax
sarq $0x20, %rax
movb $0x0, (%r14,%rax)
movq %rbx, %rdi
callq 0x2070
leaq 0x4ea7(%rip), %rdi      # 0x8243
movq -0x40(%rbp), %rsi
movl %r15d, %edx
xorl %eax, %eax
callq 0x2090
testl %r15d, %r15d
je 0x3878
movq -0x48(%rbp), %r10
movl $0x0, 0x20(%r10)
movq -0x58(%rbp), %r11
jle 0x344d
movl %r11d, %eax
andl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
xorl %r12d, %r12d
movabsq $0x800000000002400, %rcx # imm = 0x800000000002400
xorl %esi, %esi
xorl %edx, %edx
movslq %edx, %rdi
movzbl (%r14,%rdi), %r8d
testl %esi, %esi
je 0x3403
cmpl $0xa, %r8d
je 0x3439
incl %esi
cmpl $0xd, %r8d
jne 0x3446
movb $0x0, (%r14,%rdi)
jmp 0x3446
cmpl $0x3b, %r8d
ja 0x33ee
movl %r8d, %r9d
btq %r9, %rcx
jae 0x33ee
xorl %esi, %esi
cmpl %r11d, %edx
jge 0x3446
leaq (%r14,%rdi), %r8
movq %rax, %r9
subq %rdi, %r9
xorl %edi, %edi
cmpb $0xa, (%r8,%rdi)
je 0x3444
incq %rdi
cmpq %rdi, %r9
jne 0x3425
movl %r11d, %edx
jmp 0x3446
incl %r12d
movl %r12d, 0x20(%r10)
xorl %esi, %esi
jmp 0x3446
addl %edi, %edx
incl %edx
cmpl %r11d, %edx
jl 0x33e2
leaq 0x4e05(%rip), %rdi      # 0x8259
movl %r12d, %esi
xorl %eax, %eax
movq %r10, %r13
callq 0x2090
movslq 0x20(%r13), %r12
leaq 0x1(%r12), %r15
movl %r15d, 0x20(%r13)
movq %r15, %rdi
shlq $0x4, %rdi
callq 0x2100
movq %rax, %rbx
movq %rax, 0x28(%r13)
movl 0x15e71(%rip), %eax     # 0x192f8
movl %eax, (%rbx)
movl $0x60, %edi
callq 0x2100
movq %rax, 0x8(%rbx)
movl 0x8c13(%rip), %ecx      # 0xc0b0
movl %ecx, (%rax)
movl $0x0, 0x4(%rax)
movl $0x1, 0x4(%rbx)
testq %r12, %r12
jle 0x3881
movq -0x58(%rbp), %r13
leal -0x2(%r13), %eax
movslq %r13d, %r12
movl %eax, -0x68(%rbp)
cltq
movq %rax, -0x78(%rbp)
leal -0x3(%r13), %eax
movl %eax, -0x64(%rbp)
leaq -0x1(%r12), %rax
movq %rax, -0x80(%rbp)
leaq 0x1(%r14), %rax
movq %rax, -0x88(%rbp)
movl $0x1, %esi
movl $0x0, -0x2c(%rbp)
xorl %ebx, %ebx
movq -0x48(%rbp), %rdx
movq %r14, -0x60(%rbp)
movq %rsi, -0x38(%rbp)
cmpl %r13d, %ebx
jge 0x355b
movslq %r10d, %rax
movl -0x2c(%rbp), %r8d
movabsq $0x800000000000401, %r9 # imm = 0x800000000000401
movslq %ebx, %rdi
movzbl (%r14,%rdi), %ecx
cmpq $0x3b, %rcx
ja 0x355f
btq %rcx, %r9
jae 0x355f
cmpl %r10d, %ebx
jge 0x354f
leaq (%r14,%rdi), %rcx
movq %rax, %rsi
subq %rdi, %rsi
xorl %edi, %edi
cmpb $0xa, (%rcx,%rdi)
je 0x354d
incq %rdi
cmpq %rdi, %rsi
jne 0x353a
movl %r10d, %ebx
jmp 0x354f
addl %edi, %ebx
incl %ebx
incl %r8d
cmpl %r13d, %ebx
jl 0x3515
jmp 0x355f
movl -0x2c(%rbp), %r8d
cmpl %r13d, %ebx
movl %r8d, -0x2c(%rbp)
jge 0x35b6
movslq %ebx, %rcx
movb $0x1, %al
cmpb $0x3c, (%r14,%rcx)
movq -0x80(%rbp), %rsi
je 0x3599
cmpq %rcx, %rsi
je 0x3594
leaq 0x1(%rcx), %rbx
cmpb $0x3c, 0x1(%r14,%rcx)
movq %rbx, %rcx
jne 0x3578
cmpq %r12, %rbx
setl %al
jmp 0x3599
xorl %eax, %eax
movl %r13d, %ebx
testb %al, %al
je 0x35b6
movslq %ebx, %rdi
leal -0x1(%rdi), %r15d
leaq (%r14,%rdi), %rax
incl %r15d
cmpb $0x3e, (%rax)
leaq 0x1(%rax), %rax
jne 0x35a8
jmp 0x35bc
movslq %ebx, %rdi
movl %ebx, %r15d
addq %r14, %rdi
movl %r15d, %esi
subl %ebx, %esi
incl %esi
movq %rdx, %rbx
callq 0x2e6e
testl %eax, %eax
je 0x38ea
movq 0x28(%rbx), %r9
movq -0x38(%rbp), %rcx
shlq $0x4, %rcx
movq %rcx, -0x40(%rbp)
movl %eax, (%r9,%rcx)
movslq %r15d, %rdx
incq %rdx
cmpl -0x68(%rbp), %edx
movl %eax, -0x50(%rbp)
jge 0x363d
movl %r15d, %r8d
leaq (%r14,%rdx), %rcx
movq -0x78(%rbp), %rsi
subq %rdx, %rsi
xorl %edx, %edx
cmpb $0x3a, (%rcx,%rdx)
jne 0x3629
leaq (%r8,%rdx), %rdi
movslq %edi, %rdi
cmpb $0x3a, 0x2(%r14,%rdi)
jne 0x3629
cmpb $0x3d, 0x3(%r14,%rdi)
je 0x3861
incq %rdx
cmpq %rdx, %rsi
jne 0x3608
movq %r13, %r14
movq %r9, %r13
movl -0x64(%rbp), %r15d
jmp 0x3643
movq %r13, %r14
movq %r9, %r13
movl %r15d, %ebx
addl $0x4, %ebx
movl $0x60, %edi
callq 0x2100
movq -0x40(%rbp), %rcx
movq %r13, %r9
movq %rax, 0x8(%r13,%rcx)
movq %r14, %r13
cmpl %r13d, %ebx
jge 0x3911
xorl %r8d, %r8d
movq -0x48(%rbp), %rdx
movl -0x50(%rbp), %r10d
movq -0x60(%rbp), %r14
movslq %ebx, %rax
movzbl (%r14,%rax), %r11d
cmpl $0xa, %r11d
je 0x37f8
testb %r11b, %r11b
je 0x37f8
cmpl $0x17, %r8d
jg 0x37f8
cmpl $0x20, %r11d
je 0x3752
leaq (%r14,%rax), %rdi
cmpl $0x3c, %r11d
jne 0x3759
movq %r9, -0x50(%rbp)
movl %r8d, -0x6c(%rbp)
xorl %r15d, %r15d
incl %r15d
cmpq %r12, %rax
jge 0x36d5
cmpb $0x3e, (%r14,%rax)
leaq 0x1(%rax), %rax
jne 0x36c2
movups (%rdx), %xmm0
movups 0x10(%rdx), %xmm1
movups 0x20(%rdx), %xmm2
movups %xmm2, 0x20(%rsp)
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
movl %r15d, %esi
movq %rdi, %r13
callq 0x30a5
movq -0x48(%rbp), %rdx
movl %eax, %r10d
testl %eax, %eax
movq -0x50(%rbp), %r9
movq -0x58(%rbp), %rsi
jne 0x3730
movq %r13, %rdi
movl %r15d, %esi
movq %rdx, %r13
callq 0x2e6e
testl %eax, %eax
je 0x38db
movl %eax, %r10d
movq 0x28(%r13), %r9
movq %r13, %rdx
movq -0x58(%rbp), %rsi
movq -0x40(%rbp), %rax
movq 0x8(%r9,%rax), %rax
movl -0x6c(%rbp), %r8d
movslq %r8d, %rcx
movl %r10d, (%rax,%rcx,4)
incl %r8d
addl %r15d, %ebx
movq %rsi, %r13
jmp 0x37ef
incl %ebx
jmp 0x37ef
movq -0x88(%rbp), %rcx
addq %rax, %rcx
xorl %r15d, %r15d
leaq (%rax,%r15), %rsi
movzbl %r11b, %r9d
cmpl $0x3b, %r9d
jle 0x3789
cmpl $0x3c, %r9d
jne 0x379a
cmpq %r12, %rsi
jge 0x37a8
cmpb $0x5c, -0x2(%rcx,%r15)
je 0x379f
jmp 0x37a8
testl %r9d, %r9d
je 0x37a8
cmpl $0xa, %r9d
je 0x37a8
cmpl $0x20, %r9d
je 0x37a8
cmpq %r12, %rsi
jge 0x37a8
movb (%rcx,%r15), %r11b
incq %r15
jmp 0x3766
movl %r8d, %r14d
movl %r10d, -0x50(%rbp)
movl %r15d, %esi
movq %rdx, %r13
callq 0x2f72
testl %eax, %eax
je 0x38a7
movl %ebx, %ebx
addq %r15, %rbx
movq 0x28(%r13), %r9
movq -0x40(%rbp), %rcx
movq 0x8(%r9,%rcx), %rcx
movl %r14d, %r8d
movslq %r14d, %rdx
movl %eax, (%rcx,%rdx,4)
incl %r8d
movq %r13, %rdx
movq -0x58(%rbp), %r13
movl -0x50(%rbp), %r10d
movq -0x60(%rbp), %r14
cmpl %r13d, %ebx
jl 0x367a
movq -0x40(%rbp), %rsi
movq 0x8(%r9,%rsi), %rax
movslq %r8d, %rcx
movl $0x0, (%rax,%rcx,4)
movl %ecx, 0x4(%r9,%rsi)
cmpl $0x18, %ecx
je 0x3823
testl %r8d, %r8d
movq -0x38(%rbp), %rsi
jne 0x384c
jmp 0x3922
leaq 0x4b13(%rip), %rdi      # 0x833d
movq -0x38(%rbp), %r15
movl %r15d, %esi
movl -0x2c(%rbp), %edx
xorl %eax, %eax
movl %r10d, %r14d
callq 0x2090
movl %r14d, %r10d
movq -0x60(%rbp), %r14
movq %r15, %rsi
movq -0x48(%rbp), %rdx
incq %rsi
movslq 0x20(%rdx), %r15
cmpq %r15, %rsi
jl 0x34fb
jmp 0x3935
movq %r13, %r14
movq %r9, %r13
addl %edx, %r15d
jmp 0x3643
leaq 0x4b5c(%rip), %rdi      # 0x83d2
jmp 0x38bd
leaq 0x4b35(%rip), %rdi      # 0x83b4
jmp 0x38bd
movl $0x1, %esi
testl %ecx, %ecx
je 0x38b6
leaq 0x4ad1(%rip), %rdi      # 0x8362
xorl %ebx, %ebx
movl %r15d, %edx
xorl %eax, %eax
callq 0x2090
movq %r14, %rdi
callq 0x2030
jmp 0x38c7
movq -0x38(%rbp), %rsi
incl %esi
leaq 0x4a2d(%rip), %rdi      # 0x82e1
jmp 0x38f7
leaq 0x4ad5(%rip), %rdi      # 0x8392
callq 0x2050
movl $0x1, %ebx
movl %ebx, %eax
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq -0x38(%rbp), %rsi
incl %esi
leaq 0x49c8(%rip), %rdi      # 0x82b0
jmp 0x38f7
movq -0x38(%rbp), %rsi
incl %esi
leaq 0x497c(%rip), %rdi      # 0x8273
xorl %eax, %eax
callq 0x2090
leaq 0x499e(%rip), %rdi      # 0x82a3
movl -0x2c(%rbp), %esi
xorl %eax, %eax
callq 0x2090
jmp 0x38c2
xorl %ecx, %ecx
movl %ecx, (%rax)
movq -0x40(%rbp), %rax
movl %ecx, 0x4(%r9,%rax)
movq -0x38(%rbp), %rsi
leaq 0x49e8(%rip), %rdi      # 0x8311
movl -0x2c(%rbp), %edx
xorl %eax, %eax
callq 0x2090
jmp 0x38c2
movl 0x8775(%rip), %ecx      # 0xc0b0
jmp 0x3886