building a compiler frontend in go

system

why write a compiler

compilers are the most educational programs you can write. lexers teach you string processing and state machines. parsers teach you recursive descent and grammar. the AST teaches you tree traversal and visitor patterns.

i built a compiler frontend for a small expression language in go.

the lexer

the lexer turns a stream of characters into a stream of tokens.

type TokenType int

const (
    TOK_NUMBER TokenType = iota
    TOK_PLUS
    TOK_MINUS
    TOK_STAR
    TOK_SLASH
    TOK_LPAREN
    TOK_RPAREN
    TOK_EOF
)

type Token struct {
    Type    TokenType
    Lexeme  string
    Line    int
}

the parser

i used recursive descent — one function per grammar rule. the grammar for expressions:

expr   → term (("+"|"-") term)*
term   → factor (("*"|"/") factor)*
factor → NUMBER | "(" expr ")"
func (p *Parser) expr() Node {
    left := p.term()
    for p.match(TOK_PLUS, TOK_MINUS) {
        op := p.previous()
        right := p.term()
        left = BinaryNode{Left: left, Op: op, Right: right}
    }
    return left
}

the AST

the abstract syntax tree is just a tree of nodes. each node type represents a language construct. walking the tree with a visitor generates code, evaluates expressions, or checks types.

Command Palette

Search for a command to run...