Overview
:var_name = COMMAND:var_name = number:var_name = :other_var_name:var_name = :other_var_name = number:foo = SUM 12 34:foo = 23:bar = :foo:bar = :foo = 20:TRUE should be defined to be 1, and :FALSE should be 0.
IF and IFELSE. If the command or variable has a value of 0, the body of the IF should be skipped, otherwise it should be executed. If the command or variable has a value of 0, the first body of the IFELSE should be skipped, and the second body should be executed.
REPEAT. The instructions in the body should be executed the number of times given by the value or variable.
TO denotes the beginning of a subroutine definition. The next argument should be the name of the subroutine. Then the body of the subroutine is specified.
| <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>]
|
| 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. | ||