-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmercenary.ebnf
85 lines (72 loc) · 3.11 KB
/
mercenary.ebnf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
(* Mercenary's EBNF *)
(* Comments are able to be embedded between any two tokens, *)
COMMENTS := '/*' (? Any non-*/ character sequence ?) '*/'
program := {<declaration>} ;
declaration := <function-declaration> | <global-declaration> | <import-declaration> ;
(* Global variables, note that there's no way to specify a default value *)
global-declaration := 'global' <identifier> ';' ;
(* Imports the given file path if it hasn't been included yet *)
import-declaration := 'import' <string> ';' ;
(* Declares a basic function. No optional/default arguments. *)
function-declaration :=
'function' <identifier>
'(' [<identifier> {',' <identifier>}] ')'
<brace-statements>
;
brace-statements := '{' <statements> '}' ;
statements := <statement> {<statement>} ;
statement
:= <if-statement>
| <while-statement>
| <return-statement>
| <assignment>
| <declaration>
| 'do' <expression> ';' (* eg `do print(123);` *)
;
if-statement :=
'if' '(' <expression> ')' <brace-statements>
{ 'else' 'if' '(' <expression> ')' <brace-statements> }
[ 'else' <brace-statements> ]
;
while-statement := 'while' '(' <expression> ')' <brace-statements> ;
return-statement := 'return' [<expression>] ';' ;
assignment (* `set` is used when updating variables *)
:= 'let' <identifier> '=' <expression> ';' (* normal assignment *)
| 'set' <identifier> { '[' <expression> ']' } '=' <expression> ';' (* array assignment or updating values *)
;
(* No order of operations lol *)
expression := <primary> | <expression> {<operator> <expression>} ;
operator
:= '==' | '!=' | '>' | '>=' | '<' | '<='
| '&' | '|' (* no short circuit lol *)
| '+' | '-' | '*' | '/' | '%'
;
primary
:= <literal>
| '(' <expression> ')'
| ('-' | '!') <primary>
| <primary> '(' [<expression> {',' <expression>}] ')' (* function call *)
| <primary> '[' <expression> ']' (* array indexing *)
;
literal
:= 'true' | 'false' | 'null'
| <number>
| <string>
| <identifier>
| '[' [<expression> {',' <expression>}] ']' (* array literal *)
;
number := DIGIT {DIGIT} ; (* only base-10 integers are supported *)
identifier := (LETTER | '_') {LETTER | '_' | DIGIT} ;
string := <single-quoted-string> | <double-quoted-string> ;
(* single quoted strings only allow escaping single quotes. *)
single-quoted-string := "'" { "\'" (? any non-"'" character ?) } "'" ;)
double-quoted-string := '"' { <double-quoted-escape> | (? any non-'"' character ?) } '"' ;
double-quoted-escape := '\\' ('n' | 't' | 'f' | 'r' | '"' | "'" | 'x' HEX_CHAR HEX_CHAR ) ;
(* These are what you'd expect, but i figured i may as well write them out for clarity *)
HEX_CHAR := DIGIT | 'a' | 'A' | 'b' | 'B' | 'c' | 'C' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' ;
DIGIT := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;
(* this is all the lowercase and uppercase ascii letters *)
LETTER := 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o'
| 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 'A' | 'B' | 'C' | 'D' | 'E'
| 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U'
| 'V' | 'W' | 'X' | 'Y' | 'Z' ;