-
Notifications
You must be signed in to change notification settings - Fork 0
/
tinybasic.pest
72 lines (56 loc) · 1.35 KB
/
tinybasic.pest
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
NEWLINE = { "\n" }
WHITESPACE = _{ " " }
rem = _{ "REM" ~ (!NEWLINE ~ ASCII)* ~ NEWLINE }
// Keywords
print = { "PRINT" }
if = { "IF" }
else = { "ELSE" }
goto = { "GOTO" }
input = { "INPUT" }
let = { "LET" }
gosub = { "GOSUB" }
return = { "RETURN" }
end = { "END" }
// RELOP
eq = { "==" }
ne = { "<>" | "><"}
ge = { ">=" }
gt = { ">" }
le = { "<=" }
lt = { "<" }
relop = { eq | ne | ge | gt | le | lt }
// OP
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
// LITERALS
number = { ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT)? }
string = { "\"" ~ (!"\"" ~ ASCII)* ~ "\"" }
ident = { ("_" | ASCII_ALPHA) ~ ( "_" | ASCII_ALPHANUMERIC )* }
// ARITHMETICS
// Operator precedence is not defined in the grammar because this is not possible with pest.
// Operator precedence is handled in the code with the pratt parser.
// See mainly https://github.com/pest-parser/pest/issues/386
expr = { arexpr | string }
arexpr = { operand ~ (add | sub | mul | div | operand)* }
operand = _{
number
| "(" ~ arexpr ~ ")"
| ident
}
// COND
cond = { (number | ident) ~ relop ~ (number | ident) }
// LANGUAGE
stmt = {
print ~ expr
| if ~ cond ~ "THEN" ~ stmt ~ (else ~ stmt)?
| goto ~ arexpr
| gosub ~ arexpr
| input ~ ident
| let ~ ident ~ "=" ~ arexpr
| return
| end
}
line = { number? ~ stmt? ~ NEWLINE }
file = { SOI ~ (line | rem)* ~ EOI }