-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathParser.py
More file actions
151 lines (129 loc) · 5.65 KB
/
Copy pathParser.py
File metadata and controls
151 lines (129 loc) · 5.65 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import pandas as pd
from tabulate import tabulate
from Lexer import Lexer
from IC import ICVar, getICVar
from Utils import checkFile, Stack
TOKEN_HEADERS = ["LINE", "LEXEME", "TOKEN ID", "TOKEN"]
STACK_HEADERS = ["INPUT", "STACK", "ACTION"]
IC_HEADERS = ["OPERATOR", "ARG1", "ARG2", "RESULT"]
# Parser class to parse the langwej program
class Parser():
def __init__(self, tokenPath, stackPath, ICPath):
self.pt = pd.read_csv("parse_table.csv")
self.actions = list(self.pt.columns[:45])
self.goto = list(self.pt.columns[45:])
self.stack = Stack([0, ("$", "END")])
self.ICStack = Stack([ICVar("$")])
self.tokenTable = []
self.stackTable = []
self.ICTable = []
self.tokenPath = tokenPath
self.stackPath = stackPath
self.ICPath = ICPath
self.parsable = None
with open("langwej.cfg", "r") as f:
self.rules = [x.strip() for x in f.read().split("\n") if len(x.strip()) > 0]
def tokenize(self, filepath):
checkFile(filepath)
lexer = Lexer(filepath)
nextToken = lexer.getNextToken()
while nextToken is not None:
self.tokenTable.append(nextToken)
nextToken = lexer.getNextToken()
with open(self.tokenPath, "w") as f:
f.write(tabulate(self.tokenTable, headers=TOKEN_HEADERS))
def parse(self, filepath, parseOnly=False):
checkFile(filepath)
lexer = Lexer(filepath)
nextToken = lexer.getNextToken()
self.tokenTable.append(nextToken)
while True:
# import pdb; pdb.set_trace()
if nextToken is not None:
lineNum, lexeme, _, token = nextToken
else:
_, lexeme, _, token = ("_", "$", "_", "END")
if token in self.actions:
next = (token, lexeme)
else:
next = (lexeme, lexeme)
cell = self.pt.loc[self.stack.top()][next[0]]
if cell[0] == "e":
self.parsable = False
if cell == "e0":
print(f"[SYNTAX ERROR: {lineNum}]: Unexpected closing parenthesis ')'")
nextToken = lexer.getNextToken()
if nextToken is not None:
self.tokenTable.append(nextToken)
elif cell == "e1":
print(f"[SYNTAX ERROR: {lineNum}]: Unexpected closing braces '}}'")
nextToken = lexer.getNextToken()
if nextToken is not None:
self.tokenTable.append(nextToken)
elif cell == "ee":
print(f"[SYNTAX ERROR: {lineNum}]: PANIK MODE INITIATED")
nextToken = lexer.getNextToken()
while nextToken is not None:
self.tokenTable.append(nextToken)
if nextToken[1] in [';','}']:
break
nextToken = lexer.getNextToken()
if nextToken is None:
break
while self.stack.top() != 0 and self.pt.loc[self.stack.top()][nextToken[0]] != "e":
self.stack.pop()
self.stack.pop()
if self.stack.top() == 0:
nextToken = lexer.getNextToken()
if nextToken is not None:
self.tokenTable.append(nextToken)
else:
raise Exception("Invalid error")
elif cell == "acc":
if self.parsable is None:
self.parsable = True
break
elif cell[0] == "s":
self.stackTable.append((next, self.stack.getStack(), f"SHIFT {int(float(cell[1:]))}"))
self.shift(int(float(cell[1:])), next)
nextToken = lexer.getNextToken()
if nextToken is not None:
self.tokenTable.append(nextToken)
elif cell[0] == "r":
self.stackTable.append((next, self.stack.getStack(), f"REDUCE {int(float(cell[1:]))}"))
self.reduce(int(float(cell[1:])), parseOnly)
else:
raise Exception("Invalid stack")
with open(self.tokenPath, "w") as f:
f.write(tabulate(self.tokenTable, headers=TOKEN_HEADERS))
with open(self.stackPath, "w") as f:
f.write(tabulate(self.stackTable, headers=STACK_HEADERS))
f.write(f"\n\nValid: {self.parsable}")
if not parseOnly:
self.ICTable = self.ICStack.top().code
with open(self.ICPath, "w") as f:
if not self.parsable:
f.write("Note: Syntax errors were found. Intermediate code maybe unreliable.\n\n")
f.write(tabulate(self.ICTable, headers=IC_HEADERS))
return self.parsable
def shift(self, index, next):
self.stack.push(next)
self.ICStack.push(ICVar(next[1]))
self.stack.push(index)
def reduce(self, index, parseOnly):
rule = self.rules[index].split(" ")
if index == 1 or index == 4:
popCount = 0
else:
popCount = len(rule[2:])
for _ in range(2*popCount):
self.stack.pop()
if not parseOnly:
popped = []
for _ in range(popCount):
popped.insert(0, self.ICStack.pop())
goto = self.stack.top()
self.stack.push((rule[0], rule[0]))
if not parseOnly:
self.ICStack.push(getICVar(index, popped))
self.stack.push(int(float(self.pt.loc[goto][rule[0]])))