-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdpda.js
121 lines (100 loc) · 3.38 KB
/
dpda.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
119
120
121
/** Deterministic Push-Down Automaton */
class DPDA {
constructor(rules, init, ...accept) {
this.rules = rules
this.init = init
this.accept = accept
}
compute(input) {
const stack = new Stack()
let state = this.init
let i = 0
while (true) {
const symbol = input[i]
const pop = stack.pop()
const rule = this.rules.find(r =>
r.state === state &&
r.pop === pop && (
r.read === symbol ||
r.read === 'ε'))
if (!rule) {
if (i < input.length) state = null
break
}
if (rule.push !== 'ε') stack.push(rule.push)
if (rule.read !== 'ε') i++
state = rule.next
}
return this.accept.includes(state)
? 'accepted' : 'rejected'
}
}
class Rule {
constructor(state, read, pop, push, next) {
this.state = state
this.read = read
this.pop = pop
this.push = push
this.next = next
}
}
class Stack {
constructor(init = ['$']) {
this.store = [...init]
}
pop() {
return this.store.pop()
}
push(sequence) {
sequence.split('')
.reverse()
.forEach(s => this.store.push(s))
}
peek() {
return this.store[this.store.length - 1]
}
}
console.log('Rⁿrⁿ:')
const Rr = new DPDA([
new Rule('S', 'R', '$', 'X$', 'R'),
new Rule('R', 'R', 'X', 'XX', 'R'),
new Rule('R', 'r', 'X', 'ε', 'r'),
new Rule('r', 'r', 'X', 'ε', 'r'),
new Rule('r', 'ε', '$', '$', 'Rr')
], 'S', 'S', 'Rr'
)
console.log(Rr.compute('')) // accepted
console.log(Rr.compute('R')) // rejected
console.log(Rr.compute('r')) // rejected
console.log(Rr.compute('RR')) // rejected
console.log(Rr.compute('rr')) // rejected
console.log(Rr.compute('Rr')) // accepted
console.log(Rr.compute('RRr')) // rejected
console.log(Rr.compute('RRrr')) // accepted
console.log(Rr.compute('RRRrrr')) // accepted
console.log(Rr.compute('RrR')) // rejected
console.log(Rr.compute('RrRr')) // rejected
console.log(Rr.compute('rrRR')) // rejected
console.log('\nBalanced parenthesis:')
const balanced = new DPDA([
new Rule('S', '(', '$', 'X$', 'O'),
new Rule('O', '(', 'X', 'XX', 'O'),
new Rule('O', ')', 'X', 'ε', 'O'),
new Rule('O', 'ε', '$', '$', 'S')
], 'S', 'S', 'Rr'
)
console.log(balanced.compute('')) // accepted
console.log(balanced.compute('()')) // accepted
console.log(balanced.compute('(())')) // accepted
console.log(balanced.compute('((()))')) // accepted
console.log(balanced.compute('()()')) // accepted
console.log(balanced.compute('(())(())')) // accepted
console.log(balanced.compute('((())(()))')) // accepted
console.log(balanced.compute('(((())(())))')) // accepted
console.log(balanced.compute('(')) // rejected
console.log(balanced.compute(')')) // rejected
console.log(balanced.compute('())')) // rejected
console.log(balanced.compute('()(')) // rejected
console.log(balanced.compute('(()')) // rejected
console.log(balanced.compute('(()()')) // rejected
console.log(balanced.compute('()())')) // rejected