This repo is my journey working through Crafting Interpreters by Bob Nystrom (munificent).
This is also my first time writing Java in literal years, and I don't really like the language :) I'm genuinely excited to start the parts in C though!
This is the Lox grammar so far, adapted from the bits and pieces Bob gives us starting in Chapter 5. I've combined productions to ways that make more sense to me while still hopefully preserving Bob's original design.
This is the Backus-Naur notation for "metasyntax". It's a syntax that in itself describes a programming language's syntax.
The sequence ::= indicates a "production", which is like a set of possibilities that can resursively refer to itself.
Like in regular expressions, the following apply:
*: match 0 or more of the left operand.?: match 0 or 1 of the left operand.+: match 1 or more of the left operand.(<pattern>|<pattern>): match one of the patterns inside the parentheses separated by|.
Sequences enclosed by outer square brackets and inner double quotes, like ["var"], mean that the sequence inside the quotes (e.g. var) should appear as-is in the source code.
Purely uppercase sequences, like IDENTIFIER, represent some arbitrary sequence, like a variable name or a number/string literal. EOF is unique in that it's not something you can write, but rather is (or should be!) implicitly encoded into your text files.
The following BNF grammar describes the exact order of operations for Lox, this is more true to the tidbits that we're given in the book.
Note that operations farther down are actually higher precedence, because they get evaluated earlier than the operations higher up the grammar.
So like in C, Lox treats logical and as being higher priority that logical or.
Assignment of existing variables is higher priority than declaration of a new variable, giving it a right associativity. Like in the following:
var a = 13;
var b = a = 4; // Looks like `var b = (a = 4);`
And of course, function calls have a very high precedence!
program ::= declaration* EOF
declaration ::= classdecl
| fundecl
| vardecl
| statement
classdecl ::= "class" IDENTIFIER inheritance? "{" function* "}"
inheritance ::= "<" IDENTIFIER
fundecl ::= "fun" function
function ::= IDENTIFIER "(" parameters? ")" block
parameters ::= IDENTIFIER ( "," IDENTIFIER )*
vardecl ::= "var" IDENTIFIER ( "=" expression )? ";"
statement ::= exprstmt
| block
| printstmt
| ifelsestmt
| whilestmt
| forstmt
| returnstmt
exprstmt ::= expression ";"
block ::= "{" declaration* "}"
printstmt ::= "print" expression ";"
ifelsestmt ::= "if" "(" expression ")" statement ( "else" statement )?
whilestmt ::= "while" "(" expression ")" statement
forstmt ::= "for" "(" forinit forcond foriter ")" statement
forinit ::= ( vardecl | exprstmt | ";" )
forcond ::= expression? ";"
foriter ::= expression?
expression ::= assignment
assignment ::= ( call "." )? IDENTIFIER "=" assignment
| logical_or
logical_or ::= logical_and ( "or" logical_and )*
logical_and ::= equality ( "and" equality )*
equality ::= comparison ( ( "!=" | "==" ) comparison )*
comparison ::= terminal ( ( ">" | ">=" | "<" | "<=" ) terminal )*
terminal ::= factor ( ( "-" | "+" ) factor )*
factor ::= unary ( ( "/" | "*" ) unary )*
unary ::= ( "!" | "-" ) unary
| invocation
invocation ::= primary ( "(" arguments? ")" | "." IDENTIFIER )*
arguments ::= expression ( "," expression )*
primary ::= literal | grouping | IDENTIFIER | super
literal ::= NUMBER | STRING | "true" | "false" | "nil"
grouping ::= "(" expression ")"
super ::= "super" "." IDENTIFIER
The super keyword is purely for access to a base class's methods. Invoking said methods is a separate expression!