Skip to content

Pratt Parser for parsing different precedence levels in Odin

Notifications You must be signed in to change notification settings

evertonse/pratt-parser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Pratt Parsing (precedence climbing) for toy language

The file parser.odin that implements this parser, is full of commentaries how how it's done and why it works.

I try to make it as through as possible, everything that was necessary for me to understand and explain to my self is there for future reference.

I intend to simply copy this repo into any language i try to write a parser for.

The file test.odin, shows all the tests for the language, including correct parenthesizing (precedence), and correct interpretation.

Quick Startup

odin run src > log.txt

Now open log.txt, it should pretty print the abstract syntax tree (AST) and tokens for all tests, and the results

You can infer precedence from the tests in test.odin, and change some inputs. Or you can look at the produced AST. Or look at the precedence() function in parser.odin where it's defined all precedence for all operators including postfix, prefix, infix and mixfix types. Same goes for associativity() function.

Once I'm in the mood I'll put the precedence table in markdown right here. For now, that's all folks :P, it has been fun.

    epsilon = 0.001; # Close by this much

    abs = fn(a) a lt 0 or a lt -0 ? -a : a;

    float_close = fn(a, b) 
        abs(a - b) lt epsilon ? 
            1 : 0;

    # Classical fibonacci
    fib = fn(n)  
        float_close(n, 0) ? 
            0
        :float_close(n, 1) ?
            1
        :fib(n-1)  + fib(n-2);

    fib(10) # last statement is the return expression from main program
    fact = fn(a) a eq 1 ? 1 : a*fact(a-1);
    fact(10)
        a = 1;
        b = 2;
        c = 3;
        d = 4;

        val = fn(a,b,c,d) d-c-b-a; # we have access to outter scope, that is global
        val(a,b,c,d, 2, 4 ,4) # we allow to pass more
    cos = fn(a) a!;  # postfix '!' means cossine
    sin = fn(a) !a;  # prefix '!' means sine
    tan = fn(a) sin(a)/cos(a); # we have access to functions in outter scope
    val = tan(98);    
    val 

Resources I haven't listed on the comments

Quote I Like from Crafting Interpreter

Predictive parsing gets tricky when you may need to look ahead a large number of tokens to figure out what you’re sitting on. In practice, most languages are designed to avoid that. Even in cases where they aren’t, you can usually hack around it without too much pain. If you can parse C++ using recursive descent—which many C++ compilers do—you can parse anything. - ending of chapter 6 https://craftinginterpreters.com/parsing-expressions.html

Great C compiler codebase for learning, it uses a recursive descent pratt parser. Code is simply written and fill with comments:

Great Jonathan Blow talk about how simple it is to make a parser that understand precedence:

Eli precedence parsing:

Hydrogren

Less related but useful for compiler enthusiasts

Paper An Incremental Approach to Compiler Construction, it parser and compile Scheme like language

Multiple Return value implementation

Tree Shaking (dead code elimination)

Complete spec draft for c++, thousand plus pages, kekw:

About

Pratt Parser for parsing different precedence levels in Odin

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages