-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathexprparser.ts
More file actions
114 lines (100 loc) · 3.43 KB
/
exprparser.ts
File metadata and controls
114 lines (100 loc) · 3.43 KB
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
// adapted from
/**
* Author: Zijing Zhang (Pluveto)
* Date: 2023-01-11 15:28:00
* Description: A Pratt Parser implemented in TypeScript.
*/
namespace parser {
class Error {
constructor(public msg: string) {
console.log(msg)
}
}
type OperatorInfo = {
[key: string]: {
fun: (a: any, b: any) => any
prec: number
}
}
const infixOps: OperatorInfo = {
">": { fun: (a, b) => a > b, prec: 5 },
">=": { fun: (a, b) => a >= b, prec: 5 },
"<": { fun: (a, b) => a < b, prec: 5 },
"<=": { fun: (a, b) => a <= b, prec: 5 },
"==": { fun: (a, b) => a === b, prec: 5 },
"!=": { fun: (a, b) => a !== b, prec: 5 },
"+": { fun: (a, b) => a + b, prec: 10 },
"-": { fun: (a, b) => a - b, prec: 10 },
"*": { fun: (a, b) => a * b, prec: 20 },
"/": { fun: (a, b) => a / b, prec: 20 },
}
type PrefixFn = (token: string) => any
type InfixFn = (lhs: any, token: string) => any
type PostfixFn = (lhs: any, token: string) => any
export class Parser {
private index = 0
private next() {
return this.tokens[this.index++]
}
private peek() {
return this.tokens[this.index]
}
private prefixParser(t: string): PrefixFn {
const num = parseFloat(t)
if (!isNaN(num)) {
return t => num
} else if (t === "(") {
return t => {
const expr = this.parse(0)
const next = this.next()
if (next !== ")") {
throw new Error("expected )")
}
return expr
}
}
return undefined
}
private infixParser(t: string): InfixFn {
if (infixOps[t]) {
return (lhs: any, token: any) =>
infixOps[t].fun(lhs, this.parse(infixOps[t].prec))
}
return undefined
}
private postfixParser(t: string): PostfixFn {
// postfix: {
// [TokenType.Fac]: (lhs: ExprNode, token: Token) => {
// return new PostfixOpNode("!", lhs)
// },
// } as { [k: number]: PostfixFn },
return undefined
}
constructor(public tokens: string[]) {}
precOf(token: string): number {
return infixOps[token] ? infixOps[token].prec : 0
}
parse(prec: number = 0): any {
let token = this.next()
let prefixParser: PrefixFn = this.prefixParser(token)
if (!prefixParser) {
throw new Error(`Unexpected prefix token ${token}`)
}
let lhs: any = prefixParser(token)
let precRight = this.precOf(this.peek())
while (prec < precRight) {
token = this.next()
let infixParser: InfixFn | PostfixFn =
this.infixParser(token) || this.postfixParser(token)
if (!infixParser) {
throw new Error(
`Unexpected infix or postfix token ${token}`
)
}
lhs = infixParser(lhs, token)
precRight = this.precOf(this.peek())
}
return lhs
}
}
}