-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.js
More file actions
71 lines (65 loc) · 1.67 KB
/
parser.js
File metadata and controls
71 lines (65 loc) · 1.67 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
function analyzeExpression(program) {
if (program[0] !== "(") {
throw "Error: not an expression"
}
const paranthesisStack = []
for (let i of program) {
if (i === "(") {
paranthesisStack.push(i)
} else if (i === ")") {
if (!paranthesisStack.length) {
throw "SyntaxError: expressions are not balanced '()'`"
}
if (paranthesisStack.slice(-1)[0] === "(") {
paranthesisStack.pop()
}
}
}
if (paranthesisStack.length) {
throw "SyntaxError: expressions are not balanced '()'`"
}
return true
}
function tokenize(program) {
return program
.replaceAll("(", " ( ")
.replaceAll(")", " ) ")
.split(" ")
.filter((it) => it !== "")
}
function buildAST(tokens, exp = []) {
if (!tokens.length) return exp
const [head, ...tail] = tokens
if (head === "(") {
// build sub-expression
const [remTail, subExp] = buildAST(tail, [])
// append the sub-expression to parent expression
return buildAST(remTail, remTail.length ? [...exp, subExp] : subExp)
}
if (head === ")") {
// return sub-expression
return [tail, exp]
}
// when token is atom
return buildAST(tail, [...exp, getAtom(head)])
}
function getAtom(token) {
const numberParsed = numberParser(token)
if (numberParsed !== null) return numberParsed
return token
}
function numberParser(token) {
const inputRegExp = RegExp(
/^-?(0(?=$)|0(?=\D+)|(0(?=\.))|[1-9][0-9]*)(\.?\d*([Ee][-+]?\d+)?)?$/
)
const matches = token.match(inputRegExp)
if (!matches) {
return null
}
return matches[0] * 1
}
function parse(program) {
analyzeExpression(program)
return buildAST(tokenize(program))
}
module.exports = parse