// File: /workspace/github_c_makefile_star2_O2/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 $0x88, %rsp
movq %rsi, %r15
movq %rdi, %r14
andl $0x0, (%rsi)
movl $0x1000, %edi           # imm = 0x1000
callq 0x2100
movq %rax, 0x8(%r15)
xorl %ebx, %ebx
movb %bl, 0xfff(%rax)
andl $0x0, 0x10(%r15)
movl $0x1000, %edi           # imm = 0x1000
callq 0x2100
movq %rax, 0x18(%r15)
movb %bl, 0xfff(%rax)
andl $0x0, 0x20(%r15)
andq $0x0, 0x28(%r15)
andl $0x0, 0x150c6(%rip)     # 0x182f8
movl $0x1001, %eax           # imm = 0x1001
addl (%r15), %eax
movl %eax, 0x7e70(%rip)      # 0xb0b0
leaq 0x3f96(%rip), %rdi      # 0x71dd
pushq $0x9
popq %rbx
movl %ebx, %esi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7e5a(%rip)      # 0xb0b4
leaq 0x3f86(%rip), %rdi      # 0x71e7
pushq $0x3
popq %rsi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7e46(%rip)      # 0xb0b8
leaq 0x3f72(%rip), %rdi      # 0x71eb
pushq $0x6
popq %rsi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7e32(%rip)      # 0xb0bc
leaq 0x3f61(%rip), %rdi      # 0x71f2
movl %ebx, %esi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7e1f(%rip)      # 0xb0c0
leaq 0x3f54(%rip), %rdi      # 0x71fc
pushq $0x7
popq %rsi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7e0b(%rip)      # 0xb0c4
leaq 0x3f44(%rip), %rdi      # 0x7204
pushq $0x8
popq %rsi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7df7(%rip)      # 0xb0c8
leaq 0x3f35(%rip), %rdi      # 0x720d
pushq $0xc
popq %rsi
movq %r15, %rdx
callq 0x2fff
movl %eax, 0x7de3(%rip)      # 0xb0cc
leaq 0x3f2a(%rip), %rdi      # 0x721a
movq %r14, %rsi
xorl %eax, %eax
callq 0x2090
leaq 0x3e41(%rip), %rsi      # 0x7142
movq %r14, %rdi
callq 0x2120
testq %rax, %rax
je 0x375c
movq %rax, %rbx
movq %r15, -0x50(%rbp)
xorl %r14d, %r14d
pushq $0x2
popq %rdx
movq %rax, %rdi
xorl %esi, %esi
callq 0x2110
movq %rbx, %rdi
callq 0x20f0
movq %rax, %r13
movq %rbx, %rdi
callq 0x20a0
movq %r13, %r12
shlq $0x20, %r12
movabsq $0x200000000, %rdi      # imm = 0x200000000
addq %r12, %rdi
sarq $0x20, %rdi
callq 0x2100
movq %rax, %r15
movq %r13, -0x40(%rbp)
movslq %r13d, %r13
pushq $0x1
popq %rsi
movq %rax, %rdi
movq %r13, %rdx
movq %rbx, %rcx
callq 0x2060
movq %rax, -0x38(%rbp)
movb $0xa, (%r15,%r13)
movabsq $0x100000000, %rax      # imm = 0x100000000
addq %r12, %rax
sarq $0x20, %rax
movb $0x0, (%r15,%rax)
movq %rbx, %rdi
callq 0x2070
leaq 0x3ea1(%rip), %rdi      # 0x7243
movq -0x38(%rbp), %rsi
movl %r13d, %edx
xorl %eax, %eax
callq 0x2090
testl %r13d, %r13d
je 0x3765
movq -0x50(%rbp), %r12
andl $0x0, 0x20(%r12)
movq -0x40(%rbp), %r9
movslq %r9d, %r10
movabsq $0x800000000002400, %rax # imm = 0x800000000002400
xorl %edx, %edx
xorl %ecx, %ecx
cmpl %r9d, %edx
jge 0x3434
movslq %edx, %rsi
movzbl (%r15,%rsi), %edi
testl %ecx, %ecx
je 0x33fc
cmpl $0xa, %edi
je 0x341d
incl %ecx
cmpl $0xd, %edi
jne 0x3430
movb $0x0, (%r15,%rsi)
jmp 0x3430
cmpl $0x3b, %edi
ja 0x33e9
movl %edi, %r8d
btq %r8, %rax
jae 0x33e9
xorl %ecx, %ecx
cmpq %r10, %rsi
jge 0x3429
cmpb $0xa, (%r15,%rsi)
je 0x342e
incq %rsi
jmp 0x340a
incl %r14d
movl %r14d, 0x20(%r12)
xorl %ecx, %ecx
jmp 0x3430
movl %r9d, %edx
jmp 0x3430
movl %esi, %edx
incl %edx
jmp 0x33d8
movq %r10, -0x58(%rbp)
leaq 0x3e1a(%rip), %rdi      # 0x7259
movl %r14d, %esi
xorl %eax, %eax
callq 0x2090
movslq 0x20(%r12), %rbx
incq %rbx
movl %ebx, 0x20(%r12)
movq %rbx, %rdi
shlq $0x4, %rdi
callq 0x2100
movq %rax, %r14
movq %rax, 0x28(%r12)
movl 0x14e88(%rip), %eax     # 0x182f8
movl %eax, (%r14)
pushq $0x60
popq %rdi
callq 0x2100
movq -0x40(%rbp), %rdi
movq %rax, 0x8(%r14)
movl 0x7c27(%rip), %ecx      # 0xb0b0
movl %ecx, (%rax)
andl $0x0, 0x4(%rax)
movl $0x1, 0x4(%r14)
movl %edi, %eax
addl $-0x2, %eax
cltq
movq %rax, -0x78(%rbp)
xorl %r13d, %r13d
movl $0x0, -0x2c(%rbp)
pushq $0x1
popq %rsi
movslq %ebx, %rax
cmpq %rax, %rsi
jge 0x3773
movq %rsi, -0x38(%rbp)
movslq %r14d, %rcx
movq -0x58(%rbp), %r8
movl -0x2c(%rbp), %esi
movabsq $0x800000000000401, %r9 # imm = 0x800000000000401
movslq %r13d, %rax
cmpl %edi, %r13d
jge 0x350e
movzbl (%r15,%rax), %edx
cmpq $0x3b, %rdx
ja 0x350e
btq %rdx, %r9
jae 0x350e
cmpl %r14d, %r13d
cmovlel %r14d, %r13d
cmpq %rcx, %rax
jge 0x3507
cmpb $0xa, (%r15,%rax)
je 0x3504
incq %rax
jmp 0x34f3
movl %eax, %r13d
incl %r13d
incl %esi
jmp 0x34d3
cmpl %edi, %r13d
cmovlel %edi, %r13d
movl %esi, -0x2c(%rbp)
cmpq %r8, %rax
jge 0x352c
cmpb $0x3c, (%r15,%rax)
je 0x3529
incq %rax
jmp 0x3518
movl %eax, %r13d
movslq %r13d, %rdi
leal 0x4(%rdi), %r13d
leaq 0x1(%rdi), %rbx
pushq $0x1
popq %rsi
movq %rdi, %rcx
cmpq %r8, %rax
jge 0x3556
cmpb $0x3e, (%r15,%rcx)
je 0x3556
incq %rcx
incl %esi
incl %r13d
incq %rbx
jmp 0x353d
addq %r15, %rdi
movq %r12, %rdx
callq 0x2f3e
testl %eax, %eax
je 0x3799
movl %eax, %r14d
movq 0x28(%r12), %rcx
movq -0x38(%rbp), %rax
shlq $0x4, %rax
movq %rax, -0x68(%rbp)
movl %r14d, (%rcx,%rax)
movq -0x78(%rbp), %rax
cmpq %rax, %rbx
jge 0x35a9
cmpb $0x3a, (%r15,%rbx)
jne 0x35a1
cmpb $0x3a, 0x1(%r15,%rbx)
jne 0x35a1
cmpb $0x3d, 0x2(%r15,%rbx)
je 0x35a9
incl %r13d
incq %rbx
jmp 0x3585
pushq $0x60
popq %rdi
movq %rcx, %rbx
callq 0x2100
movq %rbx, %r8
movq -0x68(%rbp), %rbx
movq %rax, 0x8(%r8,%rbx)
xorl %esi, %esi
movq -0x40(%rbp), %rdi
movq -0x58(%rbp), %rdx
movslq %r13d, %r13
movslq %esi, %r9
cmpl %edi, %r13d
jge 0x3710
cmpl $0x17, %esi
jg 0x3710
movb (%r15,%r13), %al
movzbl %al, %ecx
cmpl $0x20, %ecx
jne 0x35f3
incq %r13
jmp 0x35cd
testl %ecx, %ecx
je 0x3710
cmpl $0xa, %ecx
je 0x3710
cmpl $0x3c, %ecx
movl %esi, -0x44(%rbp)
movq %r9, -0x60(%rbp)
jne 0x36aa
movq %r8, -0x70(%rbp)
leaq (%r15,%r13), %rcx
xorl %ebx, %ebx
leaq 0x1(%r13), %r12
incl %ebx
cmpq %rdx, %r13
jge 0x3633
cmpb $0x3e, (%r15,%r13)
movq %r12, %r13
jne 0x361e
movq -0x50(%rbp), %rax
movups (%rax), %xmm0
movups 0x10(%rax), %xmm1
movups 0x20(%rax), %xmm2
movups %xmm2, 0x20(%rsp)
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
movq %rcx, %r13
movq %rcx, %rdi
movl %ebx, %esi
callq 0x30dd
movl %eax, %r14d
testl %eax, %eax
movq -0x70(%rbp), %r8
jne 0x3688
movq %r13, %rdi
movl %ebx, %esi
movq -0x50(%rbp), %rbx
movq %rbx, %rdx
callq 0x2f3e
testl %eax, %eax
je 0x3805
movl %eax, %r14d
movq 0x28(%rbx), %r8
movq -0x68(%rbp), %rbx
movq 0x8(%r8,%rbx), %rax
movq -0x60(%rbp), %rcx
movl %r14d, (%rax,%rcx,4)
movl -0x44(%rbp), %esi
incl %esi
movl %r12d, %r13d
movq -0x50(%rbp), %r12
jmp 0x35c2
leaq (%r15,%r13), %rdi
xorl %esi, %esi
cmpb $0x3c, %al
je 0x36cc
movzbl %al, %eax
testl %eax, %eax
je 0x36e5
cmpl $0xa, %eax
je 0x36e5
cmpl $0x20, %eax
je 0x36e5
cmpq %rdx, %r13
jl 0x36d9
jmp 0x36e5
cmpq %rdx, %r13
jge 0x36e5
cmpb $0x5c, -0x1(%r15,%r13)
jne 0x36e5
movb 0x1(%r15,%r13), %al
incq %r13
incl %esi
jmp 0x36b0
movq %r12, %rdx
callq 0x2fff
testl %eax, %eax
je 0x37f6
movq 0x28(%r12), %r8
movq 0x8(%r8,%rbx), %rcx
movq -0x60(%rbp), %rdx
movl %eax, (%rcx,%rdx,4)
movl -0x44(%rbp), %esi
incl %esi
jmp 0x35c2
movq 0x8(%r8,%rbx), %rax
andl $0x0, (%rax,%r9,4)
movl %esi, 0x4(%r8,%rbx)
cmpl $0x18, %esi
je 0x3731
testl %esi, %esi
movq -0x38(%rbp), %rsi
jne 0x374f
jmp 0x37c0
leaq 0x3c05(%rip), %rdi      # 0x733d
movq -0x38(%rbp), %rbx
movl %ebx, %esi
movl -0x2c(%rbp), %edx
xorl %eax, %eax
callq 0x2090
movq -0x40(%rbp), %rdi
movq %rbx, %rsi
incq %rsi
movl 0x20(%r12), %ebx
jmp 0x34af
leaq 0x3c6f(%rip), %rdi      # 0x73d2
jmp 0x376c
leaq 0x3c48(%rip), %rdi      # 0x73b4
callq 0x2050
jmp 0x37d1
cmpl $0x0, 0x7936(%rip)      # 0xb0b0
je 0x37ea
leaq 0x3bdf(%rip), %rdi      # 0x7362
xorl %r14d, %r14d
movl %ebx, %edx
xorl %eax, %eax
callq 0x2090
movq %r15, %rdi
callq 0x2030
jmp 0x37d5
movq -0x38(%rbp), %rsi
incl %esi
leaq 0x3acd(%rip), %rdi      # 0x7273
xorl %eax, %eax
callq 0x2090
leaq 0x3aef(%rip), %rdi      # 0x72a3
movl -0x2c(%rbp), %esi
xorl %eax, %eax
callq 0x2090
jmp 0x37d1
leaq 0x3b4a(%rip), %rdi      # 0x7311
movl -0x2c(%rbp), %edx
xorl %eax, %eax
callq 0x2090
pushq $0x1
popq %r14
movl %r14d, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3ba1(%rip), %rdi      # 0x7392
jmp 0x376c
movq -0x38(%rbp), %rsi
incl %esi
leaq 0x3ade(%rip), %rdi      # 0x72e1
jmp 0x37a6
movq -0x38(%rbp), %rsi
incl %esi
leaq 0x3a9e(%rip), %rdi      # 0x72b0
jmp 0x37a6