Slogo Grammar (BNF)
adapted from Brown University, modified by Steven C. Poloni


Overview



Lanuage Structure


Complete Grammar

<prog> ::= <ilist>

<ilist> ::= <instr> <ilist>
::= <fdecl> <ilist>

<instr> ::= <ifelse>
::= <if>
::= <repeat>
::= <expr>
::= <ask>
::= <tell>

<expr> ::= number
::= <var
::= <asgn>
::= <fcall>

<var> ::= :identifer

<asgn> ::= <var> = <expr>

<fcall> ::= identifier
::= <builtinfunction>

<strict_ilist> ::=
::= <instr> <strict_ilist>

<expr_list> ::=
::= <expr> <expr_list>

<repeat> ::= REPEAT <expr> [<strict_ilist>]

<if> ::= IF <expr> [<strict_ilist>]

<ifelse> ::= IFELSE <expr> [<strict_ilist>] [<strict_ilist>]

<ask> ::= ASK [<expr_list>] [<strict_ilist>]

<tell> ::= TELL [<expr_list>]


Description of Grammar

A program is an ilist
<prog> ::= <ilist>

An ilist is a list of instructions and function declarations
<ilist> ::= <instr> <ilist>
::= <fdecl> <ilist>

An instruction might be a control structure (ifelse, if, repeat), an expression, an ask, or a tell. This implies that you can write statements that are simply numbers or mathematical operations since these are both expressions. I did this to mimic C++ where it is perfectly valid to write the lines "3;" or "3 + 2;", although they absolutely have no effect in this context. I ended up doing this because the SLOGO specification states that all function calls (built-in and user defined) return a value (if no return value is defined, the function call returns 0), and this implies that every function call should be able to be assigned to a variable (which makes perfect sense for XCOR and YCOR). Only an expression can be assigned to be a variable, and this lead me to include function calls in the definition of an expression, but I still wanted to retain the ability to write function calls by themselves since that would make sense for functions like "FORWARD 50" and "RIGHT 90". Thus, I included expressions in the definition for an instruction. This seems a little weird in some cases, but I was comforted in the fact that C++ has the same weirdness.
<instr> ::= <ifelse>
::= <if>
::= <repeat>
::= <expr>
::= <ask>
::= <tell>

An expression is a number, a variable, an assignment, or a function call.
<expr> ::= number
::= <var
::= <asgn>
::= <fcall>

Variables always look the same, a variable followed by an identifier
<var> ::= :identifer

An assignment always looks the same; a variable gets an expression. If you take note aove, an assignment is also a valid expression. Thus, this BNF allows you to write "x = y = 3" - that is, an assignment to an assignment.
<asgn> ::= <var> = <expr>

A function call is either a user-defined function or a built-in function. Built-in functions include mathematical operations (SUM, DIFFERENCE, etc.), boolean operations (AND, OR, etc.), and turtle functions/commands.
<fcall> ::= identifier
::= <builtinfunction>

Blocks of code delimited by [] cannot contain function declarations, unlike the top-level instruction list, so we introduce strict_ilist to be a list only of instructions.
<strict_ilist> ::=
::= <instr> <strict_ilist>

The currently supported control structures are repeat, if, if/else, ask, and tell
<repeat> ::= REPEAT <expr> [<strict_ilist>]

<if> ::= IF <expr> [<strict_ilist>]

<ifelse> ::= IFELSE <expr> [<strict_ilist>] [<strict_ilist>]

<ask> ::= ASK [<expr_list>] [<strict_ilist>]

<tell> ::= TELL [<expr_list>]

This grammar represents expressions that conform to standard precedence rules. It's a right-recursive grammar hence useful in top-down parsing. The BNF almost completely determines parsing rules. For the most part, each BNF rule corresponds to a new parser since each rule is expanded in a different fashion. The different grammar elements defined by the BNF correspond to terminal/non-terminal nodes. The goal of the parser is to combine the tokens generated by the lexer into a construct of the language represented as an abstract syntax tree. The abstract syntax tree is then used to execute/interpret the construct when the time comes.