// File: protonpopsicle[P]lang/src/compiler/Lexer.cpp
// Function: Lexer::scan()
Token Lexer::scan() {
    // skip white space & comments
    for (;; read()) {
        if (peek == ' ' || peek == '\t') {
            continue;
        }
        // increment line number by either LF or CRLF
        else if (peek == '\n' || peek == '\r' && read('\n')) {
            line++;
        }
        else if (peek == '/' && read('/')) {
            for (;; read()) {
                if (peek == '\n' || peek == '\r' && read('\n')) {
                    line++;
                    break;
                }
            }
        }
        else break;
    }
    // handle composite tokens
    switch (peek) {
        case '<': if (read('=')) return Token(LE);  return Token('<');
        case '>': if (read('=')) return Token(GE);  return Token('>');
        case '=': if (read('=')) return Token(EQ);  return Token('=');
        case '!': if (read('=')) return Token(NE);  return Token('!');
        case '&': if (read('&')) return Token(AND); return Token('&');
        case '|': if (read('|')) return Token(OR);  return Token('|');
    }
    // handle numeric literals
    if (peek >= '0' && peek <= '9') {
        int x = 0;
        do {
            x = 10 * x + peek - '0'; // peek - '0' converts peek char to int
            read();
        } while (peek >= '0' && peek <= '9');
        return Token(NUM, x);
        /*
        if (peek != '.') {
            return Token(NUM, x);
        }
        float x = i;
        float d = 10;
        for(;;) {
            read();
            if (peek < '0' || peek > '9') break;
            x = x + (peek - '0') / d;
            d = d * 10;
        }
        return Token(REAL, x);
        */
    }
    // handle reserved words and identifiers
    if (peek >= 'A' && peek <= 'Z' || peek >= 'a' && peek <= 'z') {
        std::string word;
        do {
            word += peek;
            read();
        } while (peek >= '0' && peek <= '9' || peek >= 'a' && peek <= 'z' ||
                 peek >= 'a' && peek <= 'z');
        // check if word is already mapped
        // if so it's a keyword, otherwise it's an identifier
        wordTable::iterator iter = keywords.find(word);
        if (iter != keywords.end()) {
            return Token(iter->second, word); // iter->second points to this keyword's tag
        }
        return Token(ID, word);
    }
    // handle string literals
    if (peek == '"') {
        std::string q;
        for (;;) {
            read();
            if (peek != '"') {
                q += peek;
            }
            else {
                read();
                break;
            }
        }
        return Token(QUOTE, q);
    }
    // if peek satisfies none of the above
    // return token with peek char as tag
    unsigned char c = peek;
    peek = ' '; // clear peek
    return Token(c);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movq %rdi, -0x100(%rbp)
movq %rdi, %rax
movq %rax, -0xf8(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x20, %eax
je 0x75bf
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x9, %eax
jne 0x75c4
jmp 0x769c
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0xa, %eax
je 0x75fb
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0xd, %eax
jne 0x7610
movq -0xf0(%rbp), %rdi
movl $0xa, %esi
callq 0x7520
testb $0x1, %al
jne 0x75fb
jmp 0x7610
movq -0xf0(%rbp), %rax
movl 0x3c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x3c(%rax)
jmp 0x7698
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x2f, %eax
jne 0x7694
movq -0xf0(%rbp), %rdi
movl $0x2f, %esi
callq 0x7520
testb $0x1, %al
jne 0x7637
jmp 0x7694
jmp 0x7639
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0xa, %eax
je 0x7670
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0xd, %eax
jne 0x7682
movq -0xf0(%rbp), %rdi
movl $0xa, %esi
callq 0x7520
testb $0x1, %al
jne 0x7670
jmp 0x7682
movq -0xf0(%rbp), %rax
movl 0x3c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x3c(%rax)
jmp 0x7692
jmp 0x7684
movq -0xf0(%rbp), %rdi
callq 0x74f0
jmp 0x7639
jmp 0x7696
jmp 0x76ad
jmp 0x7698
jmp 0x769a
jmp 0x769c
movq -0xf0(%rbp), %rdi
callq 0x74f0
jmp 0x759f
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
movl %eax, -0x104(%rbp)
subl $0x21, %eax
je 0x77e2
jmp 0x76c9
movl -0x104(%rbp), %eax
subl $0x26, %eax
je 0x7825
jmp 0x76da
movl -0x104(%rbp), %eax
subl $0x3c, %eax
je 0x7719
jmp 0x76e7
movl -0x104(%rbp), %eax
subl $0x3d, %eax
je 0x779f
jmp 0x76f8
movl -0x104(%rbp), %eax
subl $0x3e, %eax
je 0x775c
jmp 0x7705
movl -0x104(%rbp), %eax
subl $0x7c, %eax
je 0x7868
jmp 0x78ab
movq -0xf0(%rbp), %rdi
movl $0x3d, %esi
callq 0x7520
testb $0x1, %al
jne 0x7730
jmp 0x7746
movq -0x100(%rbp), %rdi
movl $0x12c, %esi            # imm = 0x12C
callq 0x9d10
jmp 0x7ca7
movq -0x100(%rbp), %rdi
movl $0x3c, %esi
callq 0x9d10
jmp 0x7ca7
movq -0xf0(%rbp), %rdi
movl $0x3d, %esi
callq 0x7520
testb $0x1, %al
jne 0x7773
jmp 0x7789
movq -0x100(%rbp), %rdi
movl $0x12d, %esi            # imm = 0x12D
callq 0x9d10
jmp 0x7ca7
movq -0x100(%rbp), %rdi
movl $0x3e, %esi
callq 0x9d10
jmp 0x7ca7
movq -0xf0(%rbp), %rdi
movl $0x3d, %esi
callq 0x7520
testb $0x1, %al
jne 0x77b6
jmp 0x77cc
movq -0x100(%rbp), %rdi
movl $0x12e, %esi            # imm = 0x12E
callq 0x9d10
jmp 0x7ca7
movq -0x100(%rbp), %rdi
movl $0x3d, %esi
callq 0x9d10
jmp 0x7ca7
movq -0xf0(%rbp), %rdi
movl $0x3d, %esi
callq 0x7520
testb $0x1, %al
jne 0x77f9
jmp 0x780f
movq -0x100(%rbp), %rdi
movl $0x12f, %esi            # imm = 0x12F
callq 0x9d10
jmp 0x7ca7
movq -0x100(%rbp), %rdi
movl $0x21, %esi
callq 0x9d10
jmp 0x7ca7
movq -0xf0(%rbp), %rdi
movl $0x26, %esi
callq 0x7520
testb $0x1, %al
jne 0x783c
jmp 0x7852
movq -0x100(%rbp), %rdi
movl $0x130, %esi            # imm = 0x130
callq 0x9d10
jmp 0x7ca7
movq -0x100(%rbp), %rdi
movl $0x26, %esi
callq 0x9d10
jmp 0x7ca7
movq -0xf0(%rbp), %rdi
movl $0x7c, %esi
callq 0x7520
testb $0x1, %al
jne 0x787f
jmp 0x7895
movq -0x100(%rbp), %rdi
movl $0x131, %esi            # imm = 0x131
callq 0x9d10
jmp 0x7ca7
movq -0x100(%rbp), %rdi
movl $0x7c, %esi
callq 0x9d10
jmp 0x7ca7
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x30, %eax
jl 0x7944
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x39, %eax
jg 0x7944
movl $0x0, -0x14(%rbp)
movq -0xf0(%rbp), %rdi
imull $0xa, -0x14(%rbp), %eax
movzbl 0x38(%rdi), %ecx
addl %ecx, %eax
subl $0x30, %eax
movl %eax, -0x14(%rbp)
callq 0x74f0
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %ecx
xorl %eax, %eax
cmpl $0x30, %ecx
movb %al, -0x105(%rbp)
jl 0x7921
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x39, %eax
setle %al
movb %al, -0x105(%rbp)
movb -0x105(%rbp), %al
testb $0x1, %al
jne 0x78d6
movq -0x100(%rbp), %rdi
movl -0x14(%rbp), %edx
movl $0x100, %esi            # imm = 0x100
callq 0x9d50
jmp 0x7ca7
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x41, %eax
jl 0x7964
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x5a, %eax
jle 0x798c
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x61, %eax
jl 0x7b8e
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x7a, %eax
jg 0x7b8e
leaq -0x38(%rbp), %rdi
callq 0x22f0
movq -0xf0(%rbp), %rax
movsbl 0x38(%rax), %esi
leaq -0x38(%rbp), %rdi
callq 0x2170
jmp 0x79ab
movq -0xf0(%rbp), %rdi
callq 0x74f0
jmp 0x79b9
jmp 0x79bb
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x30, %eax
jl 0x79e3
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %ecx
movb $0x1, %al
cmpl $0x39, %ecx
movb %al, -0x106(%rbp)
jle 0x7a46
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x61, %eax
jl 0x7a0b
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %ecx
movb $0x1, %al
cmpl $0x7a, %ecx
movb %al, -0x106(%rbp)
jle 0x7a46
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %ecx
xorl %eax, %eax
cmpl $0x61, %ecx
movb %al, -0x107(%rbp)
jl 0x7a3a
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x7a, %eax
setle %al
movb %al, -0x107(%rbp)
movb -0x107(%rbp), %al
movb %al, -0x106(%rbp)
movb -0x106(%rbp), %al
testb $0x1, %al
jne 0x7995
movq -0xf0(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x7e80
movq %rax, -0x110(%rbp)
jmp 0x7a6d
movq -0xf0(%rbp), %rdi
movq -0x110(%rbp), %rax
movq %rax, -0x50(%rbp)
callq 0x7ee0
movq %rax, -0x58(%rbp)
leaq -0x50(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x7eb0
testb $0x1, %al
jne 0x7a9b
jmp 0x7b17
leaq -0x50(%rbp), %rdi
callq 0x7f10
movw 0x20(%rax), %ax
movw %ax, -0x112(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x2100
jmp 0x7abe
movq -0x100(%rbp), %rdi
movw -0x112(%rbp), %ax
movswl %ax, %esi
leaq -0x78(%rbp), %rdx
callq 0x9d90
jmp 0x7ada
leaq -0x78(%rbp), %rdi
callq 0x2160
movl $0x1, -0x7c(%rbp)
jmp 0x7b72
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x7b80
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x2160
jmp 0x7b80
leaq -0xa0(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x2100
jmp 0x7b29
movq -0x100(%rbp), %rdi
movl $0x102, %esi            # imm = 0x102
leaq -0xa0(%rbp), %rdx
callq 0x9d90
jmp 0x7b43
leaq -0xa0(%rbp), %rdi
callq 0x2160
movl $0x1, -0x7c(%rbp)
jmp 0x7b72
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0xa0(%rbp), %rdi
callq 0x2160
jmp 0x7b80
leaq -0x38(%rbp), %rdi
callq 0x2160
jmp 0x7ca7
leaq -0x38(%rbp), %rdi
callq 0x2160
jmp 0x7cb7
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x22, %eax
jne 0x7c7d
leaq -0xc0(%rbp), %rdi
callq 0x22f0
movq -0xf0(%rbp), %rdi
callq 0x74f0
jmp 0x7bbc
movq -0xf0(%rbp), %rax
movzbl 0x38(%rax), %eax
cmpl $0x22, %eax
je 0x7bf5
movq -0xf0(%rbp), %rax
movsbl 0x38(%rax), %esi
leaq -0xc0(%rbp), %rdi
callq 0x2170
jmp 0x7be5
jmp 0x7c05
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x7c6f
movq -0xf0(%rbp), %rdi
callq 0x74f0
jmp 0x7c03
jmp 0x7c07
jmp 0x7bae
leaq -0xe0(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x2100
jmp 0x7c1c
movq -0x100(%rbp), %rdi
movl $0x101, %esi            # imm = 0x101
leaq -0xe0(%rbp), %rdx
callq 0x9d90
jmp 0x7c36
leaq -0xe0(%rbp), %rdi
callq 0x2160
movl $0x1, -0x7c(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x2160
jmp 0x7ca7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0xe0(%rbp), %rdi
callq 0x2160
leaq -0xc0(%rbp), %rdi
callq 0x2160
jmp 0x7cb7
movq -0x100(%rbp), %rdi
movq -0xf0(%rbp), %rax
movb 0x38(%rax), %cl
movb %cl, -0xe1(%rbp)
movb $0x20, 0x38(%rax)
movzbl -0xe1(%rbp), %eax
movswl %ax, %esi
callq 0x9d10
movq -0xf8(%rbp), %rax
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
movq -0x40(%rbp), %rdi
callq 0x2390