-
Notifications
You must be signed in to change notification settings - Fork 0
/
calc.peg
85 lines (67 loc) · 1.62 KB
/
calc.peg
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
%{
import 'peg_parser_runtime.dart';
export 'peg_parser_runtime.dart';
void main(List<String> args) {
const source = '1 + 2 * 3';
const parser = CalcParser();
final result = parseString(parser.parseStart, source);
print(result);
}
}%
%%
const CalcParser();
num _calcBinary(num? left, ({String op, num expr}) next) {
final op = next.op;
final right = next.expr;
left = left!;
switch (op) {
case '+':
return left += right;
case '-':
return left -= right;
case '/':
return left /= right;
case '*':
return left *= right;
default:
throw StateError('Unknown operator: $op');
}
}
num _prefix(String? operator, num operand) {
if (operator == null) {
return operand;
}
switch (operator) {
case '-':
return -operand;
default:
throw StateError('Unknown operator: $operator');
}
}
%%
Start = Spaces v:Expression @eof() ;
Expression = Add ;
num
Add = h:Mul t:(op:AddOp ↑ expr:Mul)* { $$ = t.isEmpty ? h : t.fold(h, _calcBinary); } ;
AddOp = v:('-' / '+') Spaces ;
num
Mul = h:Prefix t:(op:MulOp ↑ expr:Prefix)* { $$ = t.isEmpty ? h : t.fold(h, _calcBinary); } ;
MulOp = v:('/' / '*') Spaces ;
num
Prefix = @expected('expression', Prefix_) ;
@inline
num
Prefix_ = o:'-'? e:Primary { $$ = _prefix(o, e); } ;
@inline
Primary =
Number
/ OpenParenthesis v:Expression CloseParenthesis ;
num
Number = v:$(
([0] / [1-9][0-9]*)
([.] ↑ [0-9]+)?
([eE] ↑ [-+]? [0-9]+)?
) Spaces { $$ = num.parse(v); } ;
CloseParenthesis = ')' Spaces ;
OpenParenthesis = '(' Spaces ;
Spaces = [ \n\r\t]* ;