-
Notifications
You must be signed in to change notification settings - Fork 11
/
plus-minus.js
119 lines (84 loc) · 2.35 KB
/
plus-minus.js
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
const {Streams, F, N, C, X} = require('@masala/parser');
/*
Implementing general solution :
E -> T E'
E' -> + TE' | eps
T -> F T'
T' -> * FT' | eps
F -> DAY | ( E )
E== expr
T == subExpr
E'== optPlusExpr
T' == optMultExpr
F == terminal
expr -> subExpr optPlusExpr'
optPlusExpr -> ( + then subExpr then F.lazy(optPlusExpr) ).opt()
subExpr -> terminal then optMultExpr
optMultExpr -> ( * then terminal then F.lazy(optMultExpr) ).opt()
F -> F.try( '(' then expr then ')' ).or(N.litteral)
*/
const MULT = Symbol('MULT');
const PLUS = Symbol('PLUS');
function text() {
return (F.not(anyOperation().or(C.charIn('()'))))
.rep()
.map(v => parseInt(v.join('').trim()));
}
function blank() {
return C.char(' ').rep().returns(' ');
}
function operation() {
return andOperation().or(plusOperation())
}
function anyOperation() {
return C.string('*').returns(MULT)
.or(C.string('+').returns(PLUS));
}
function andOperation() {
return C.string('*').returns(MULT)
}
function plusOperation() {
return C.string('+').returns(PLUS)
}
function parenthesis(par) {
return C.char(' ').optrep().drop().then(C.char(par));
}
function parenthesisExpr() {
return parenthesis('(').then(blank().opt()).drop()
.then(F.lazy(expr))
.then(parenthesis(')').then(blank().opt()).drop());
}
function expr() {
return subExpr().then(optionalPlusExpr())
.map(([left,right]) => left + right.orElse(0));
}
function optionalPlusExpr() {
return plusExpr().opt();
}
function plusExpr() {
return plusOperation().drop().then(subExpr())
.then(F.lazy(optionalPlusExpr))
.map(([left,right])=>left+right.orElse(0));
}
function subExpr() {
return terminal().then(optionalMultExpr())
.map(([left,right]) => left * right.orElse(1));
}
function optionalMultExpr() {
return multExpr().opt();
}
function multExpr() {
return andOperation().drop().then(terminal())
.then(F.lazy(optionalMultExpr))
.map(([left,right]) => left * right.orElse(1));
}
function terminal() {
return F.try(parenthesisExpr()).or(text());
}
function combinator() {
return expr().then(F.eos().drop());
}
const string = '2 + 3 * ( ( 4 + 10) + ( 4) ) + 1 * -3';
let stream = Streams.ofString(string);
let parsing = combinator().parse(stream);
console.log(string+'='+parsing.value);