Since the GHI post was the inspiration for this little vacation project I thought I would share my progress and challenges here. I did not want to pollute the original BrainPad post with my posts, just because at this point this is still just a .NET core project until
- I get a better understanding of what BrainPad supports
- I actually get a BrainPad to play with
The language supports the following
- Recursion
- Passing functions as arguments - useful for callbacks (think interrupt handlers)
From a design perspective, I decided to generate an an AST (abstract syntax tree) during the parsing stage rather than directly executing the code from the source.
Using an AST makes things quite flexible, once you have compiled the AST you can do a few cool things
- Write a tree walker that can do a few simple code optimizations (I will implement some constant folding and dead code elimination as an example)
- Write a tree walker that executes directly from the AST. The advantage is that all the parsing, variable and function calls have been resolved so executing from the AST does not require any further scanning of the code to find function entry points etc.
- You could write a tree walker that generates code. This code could be some form of intermediate code that is cheap to execute or it could generate native code for the target system.
The current implementation has a simple tree executor back end.
For the curious, I started documenting what I have in the language so far using a syntax loosely based on EBNF. I have not documented everything yet, but what is documented is implemented.
Language Structure
<stmt> := <vardecl>
| <assignment>
| <funcdecl>
| <funccall>
| <return>
| <if>
| <while>
| <for>
| <break>
<stmtblock> := '{' <stmt>* '}'
<vardecl> := 'var' <ident> '=' <expr>
<assignment>:= <ident> '=' <expr>
<funcdecl> := 'func' <ident>'('<params>')' <stmtblock>
<params> := <ident> [',' <ident>]*
<funccall> := <ident>'(' <args> ')'
<args> := <expr> [',' <expr>]*
<return> := 'return' <expr>
<if> := 'if' <expr> <stmtblock> [<else>]
<else> := 'else' [<if> | <stmtblock>]
<while> := 'while' <expr> <stmtblock>
<for> := 'for' [<vardecl> | <assignment>] ';'
[<expr>] ';'
[<expr>] <stmtblock>
<break> := 'break'
<expr> := <relexpr> [<logicalop> <relexpr>]*
<relexpr> := <addexpr> [<relop> <addexpr>]*
<addexpr> := <multexpr> [<addop> <multexpr>]*
<multexpr> := <factor> [<mulop> <factor>]*
<factor> := '(' <expr> ')'
| <number>
| <string> [<indexer>]
| <funccall> [<indexer>]
| <ident> [<indexer>]
<indexer> := '['<expr>']'
<logicalop> := 'and' | 'or'
<relop> := '==' | '<>' | '<' | '<=' | '>' | '>='
<addop> := '+' | '-'
<mulop> := '*' | '/' | '%'
## Builtin Functions
print(<args>)
println(<args>)
len(string)
left(string, count)
right(string, count)
mid(string, index, count)
abs(value)
sqrt(value)
sin(radians)
cos(radians)
tan(radians)
asin(radians)
acos(radians)
atan(radians)
atan2(y, x)