-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.py
More file actions
94 lines (89 loc) · 3.33 KB
/
parser.py
File metadata and controls
94 lines (89 loc) · 3.33 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
import os
import sys
from lexer.lexer import Lexer
import parser.table
import parser.rules
class Parser():
def __init__(self, lexer, debug=False):
self.debug = debug
self.lexer = lexer
self.table = parser.table.table
self.rules = parser.rules.rules
self.START = parser.rules.START
self.stack = [0]
def is_valid(self, state, symbol):
if self.debug:
print('Is', state, symbol, 'valid?', state in self.table and symbol in self.table[state])
return state in self.table and symbol in self.table[state]
def reduce(self, rule):
non_terminal, pop_count = self.rules[rule]
if pop_count > 0:
self.stack = self.stack[:-pop_count]
if self.debug:
print('Reduce to', non_terminal, 'by rule', rule, 'popping', pop_count)
state = self.state()
if not self.is_valid(state, non_terminal):
print('Invalid state or symbol')
return False
action, state = self.table[state][non_terminal]
assert(action == 'GOTO')
self.goto(state)
return True
def goto(self, state):
if self.debug:
print('Goto', state)
self.stack.append(state)
def state(self):
# if len(self.stack) < 1:
# return 0
return self.stack[-1]
def decide(self, token):
terminal, value = token
while True:
state = self.state()
if self.debug:
print('Stack:', self.stack)
print('Terminal:', terminal, 'value:', value, 'state:', state)
if self.is_valid(state, terminal): # non-empty entry of the table
action, state_rule = self.table[state][terminal]
# not shifting
else: # empty entry of the table, something wrong!
print('Failed to parse at', 'state:', state, 'terminal:', terminal)
return False, False
if action == 'SHIFT':
if self.debug:
print('Shift')
self.goto(state_rule)
return True, False # shift
elif action == 'REDUCE':
ok = self.reduce(state_rule)
if not ok:
print('Reduce failed')
return False, False
elif action == 'ACCEPT':
return True, True
else: # neither SHIFT nor REDUCE on terminal
print('Unknown action')
return False, False
def parse(self, infile):
for token in lexer.lex(infile):
if self.debug:
print('-' * 40)
ok, accepted = self.decide(token)
if not ok:
return False
ok, accepted = self.decide((None, None)) # terminal = None, value = None
if not ok:
return False
if not accepted:
print('Not accepted after parse finished')
return accepted
with open(sys.argv[1], 'r') as infile:
parser_debug, lexer_debug = False, False
if 'PARSER_DEBUG' in os.environ:
parser_debug = (os.environ['PARSER_DEBUG'] == '1')
if 'LEXER_DEBUG' in os.environ:
lexer_debug = (os.environ['LEXER_DEBUG'] == '1')
lexer = Lexer(debug=lexer_debug)
parser = Parser(lexer, debug=parser_debug)
print('Accepted:', parser.parse(infile))