213
|
1 from . import astnodes, lexer
|
152
|
2 from ppci import CompilerError
|
148
|
3
|
|
4 # binop precedence for expressions:
|
|
5 binopPrecs = {'or': 5, 'and': 10, \
|
|
6 '<': 20, '>': 20, '==': 20, '<=': 20, '>=': 20, '!=': 20, \
|
|
7 '+': 30, '-': 30, '*': 40, '/': 40 }
|
|
8
|
|
9 class Parser:
|
213
|
10 """ Parses sourcecode into an abstract syntax tree (AST) """
|
|
11 def __init__(self, diag):
|
|
12 self.diag = diag
|
|
13
|
|
14 def parseSource(self, source):
|
148
|
15 self.initLex(source)
|
|
16 try:
|
|
17 self.parsePackage()
|
213
|
18 return self.mod
|
152
|
19 except CompilerError as e:
|
|
20 self.diag.addDiag(e)
|
213
|
21 def Error(self, msg):
|
152
|
22 raise CompilerError(msg, self.token.loc)
|
213
|
23 # Lexer helpers:
|
|
24 def Consume(self, typ):
|
148
|
25 if self.Peak == typ:
|
|
26 return self.NextToken()
|
|
27 else:
|
|
28 self.Error('Excected: "{0}", got "{1}"'.format(typ, self.Peak))
|
213
|
29 @property
|
|
30 def Peak(self):
|
148
|
31 return self.token.typ
|
213
|
32 @property
|
|
33 def PeakPrec(self):
|
149
|
34 if self.Peak in binopPrecs:
|
|
35 return binopPrecs[self.Peak]
|
|
36 return -1
|
213
|
37 def hasConsumed(self, typ):
|
148
|
38 if self.Peak == typ:
|
|
39 self.Consume(typ)
|
|
40 return True
|
|
41 return False
|
213
|
42
|
|
43 def NextToken(self):
|
219
|
44 t = self.token
|
|
45 if t.typ != 'END':
|
|
46 self.token = self.tokens.__next__()
|
|
47 return t
|
213
|
48
|
|
49 def initLex(self, source):
|
219
|
50 self.tokens = lexer.tokenize(source) # Lexical stage
|
|
51 self.token = self.tokens.__next__()
|
215
|
52 def addDeclaration(self, decl):
|
|
53 self.currentPart.declarations.append(decl)
|
213
|
54
|
|
55 def parseUses(self):
|
|
56 pass
|
|
57
|
|
58 def parsePackage(self):
|
148
|
59 self.Consume('package')
|
|
60 name = self.Consume('ID')
|
|
61 self.Consume(';')
|
213
|
62 self.mod = astnodes.Package(name.val, name.loc)
|
215
|
63 self.currentPart = self.mod
|
213
|
64 self.parseUses()
|
148
|
65 # TODO: parse uses
|
|
66 while self.Peak != 'END':
|
|
67 self.parseTopLevel()
|
|
68 self.Consume('END')
|
|
69
|
213
|
70 def parseTopLevel(self):
|
148
|
71 if self.Peak == 'function':
|
213
|
72 self.parseFunctionDef()
|
148
|
73 elif self.Peak == 'var':
|
149
|
74 self.parseVarDef()
|
163
|
75 elif self.Peak == 'const':
|
|
76 self.parseConstDef()
|
213
|
77 elif self.Peak == 'type':
|
|
78 self.parseTypeDef()
|
149
|
79 else:
|
213
|
80 self.Error('Expected function, var, const or type')
|
148
|
81
|
213
|
82 def parseDesignator(self):
|
148
|
83 """ A designator designates an object """
|
|
84 name = self.Consume('ID')
|
213
|
85 d = astnodes.Designator(name.val, name.loc)
|
148
|
86 return d
|
|
87
|
213
|
88 # Type system
|
|
89 def parseTypeSpec(self):
|
|
90 # For now, do simple type spec, just parse an ID:
|
219
|
91 #return self.parseDesignator()
|
213
|
92 if self.Peak == 'struct':
|
|
93 self.Consume('struct')
|
|
94 self.Consume('{')
|
|
95 mems = []
|
|
96 while self.Peak != '}':
|
|
97 mem_t = self.parseTypeSpec()
|
|
98 mem_n = self.Consume('ID')
|
|
99 mems.append((mem_t, mem_n))
|
|
100 while self.hasConsumed(','):
|
|
101 mem_n = self.Consume('ID')
|
|
102 mems.append((mem_t, mem_n))
|
|
103 self.Consume(';')
|
|
104 self.Consume('}')
|
|
105 theT = astnodes.StructureType(mems)
|
|
106 else:
|
|
107 theT = self.parseDesignator()
|
|
108 # Check for pointer suffix:
|
|
109 while self.hasConsumed('*'):
|
|
110 theT = astnodes.PointerType(theT)
|
|
111 return theT
|
|
112
|
|
113 def parseTypeDef(self):
|
|
114 self.Consume('type')
|
|
115 newtype = self.parseTypeSpec()
|
|
116 typename = self.Consume('ID')
|
|
117 # TODO: action here :)
|
|
118 self.Consume(';')
|
|
119 return astnodes.DefinedType(typename, newtype)
|
|
120
|
|
121 # Variable declarations:
|
|
122 def parseVarDef(self):
|
148
|
123 self.Consume('var')
|
213
|
124 t = self.parseTypeSpec()
|
149
|
125 def parseVar():
|
|
126 name = self.Consume('ID')
|
213
|
127 v = astnodes.Variable(name.val, t)
|
|
128 v.loc = name.loc
|
149
|
129 if self.hasConsumed('='):
|
213
|
130 v.ival = self.parseExpression()
|
215
|
131 self.addDeclaration(v)
|
149
|
132 parseVar()
|
|
133 while self.hasConsumed(','):
|
|
134 parseVar()
|
157
|
135 self.Consume(';')
|
148
|
136
|
213
|
137 def parseConstDef(self):
|
163
|
138 self.Consume('const')
|
213
|
139 t = self.parseTypeSpec()
|
163
|
140 def parseConst():
|
|
141 name = self.Consume('ID')
|
|
142 self.Consume('=')
|
|
143 val = self.parseExpression()
|
213
|
144 c = astnodes.Constant(name.val, t, val)
|
|
145 c.loc = name.loc
|
163
|
146 parseConst()
|
|
147 while self.hasConsumed(','):
|
|
148 parseConst()
|
|
149 self.Consume(';')
|
|
150
|
213
|
151 # Procedures
|
|
152 def parseFunctionDef(self):
|
|
153 loc = self.Consume('function').loc
|
|
154 returntype = self.parseTypeSpec()
|
|
155 fname = self.Consume('ID').val
|
|
156 f = astnodes.Function(fname, loc)
|
215
|
157 self.addDeclaration(f)
|
|
158 savePart = self.currentPart
|
|
159 self.currentPart = f
|
148
|
160 self.Consume('(')
|
|
161 parameters = []
|
|
162 if not self.hasConsumed(')'):
|
150
|
163 def parseParameter():
|
213
|
164 typ = self.parseTypeSpec()
|
148
|
165 name = self.Consume('ID')
|
213
|
166 param = astnodes.Variable(name.val, typ)
|
|
167 param.loc = name.loc
|
215
|
168 self.addDeclaration(param)
|
213
|
169 parameters.append(param)
|
150
|
170 parseParameter()
|
|
171 while self.hasConsumed(','):
|
|
172 parseParameter()
|
148
|
173 self.Consume(')')
|
215
|
174 paramtypes = [p.typ for p in parameters]
|
|
175 f.typ = astnodes.FunctionType(paramtypes, returntype)
|
|
176 f.body = self.parseCompoundStatement()
|
|
177 self.currentPart = savePart
|
148
|
178
|
213
|
179 # Statements:
|
|
180 def parseAssignment(self, lval):
|
|
181 lval = astnodes.VariableUse(lval, lval.loc)
|
164
|
182 loc = self.Consume('=').loc
|
148
|
183 rval = self.parseExpression()
|
157
|
184 self.Consume(';')
|
213
|
185 return astnodes.Assignment(lval, rval, loc)
|
148
|
186
|
213
|
187 def parseCall(self, func):
|
148
|
188 self.Consume('(')
|
|
189 args = []
|
|
190 if not self.hasConsumed(')'):
|
|
191 args.append(self.parseExpression())
|
|
192 while self.hasConsumed(','):
|
|
193 args.append(self.parseExpression())
|
|
194 self.Consume(')')
|
213
|
195 return astnodes.FunctionCall(func, args, func.loc)
|
148
|
196
|
213
|
197 def parseIfStatement(self):
|
165
|
198 loc = self.Consume('if').loc
|
148
|
199 self.Consume('(')
|
|
200 condition = self.parseExpression()
|
|
201 self.Consume(')')
|
149
|
202 yes = self.parseCompoundStatement()
|
148
|
203 if self.hasConsumed('else'):
|
149
|
204 no = self.parseCompoundStatement()
|
165
|
205 else:
|
|
206 no = astnodes.EmptyStatement()
|
213
|
207 return astnodes.IfStatement(condition, yes, no, loc)
|
148
|
208
|
213
|
209 def parseWhileStatement(self):
|
|
210 loc = self.Consume('while').loc
|
148
|
211 self.Consume('(')
|
|
212 condition = self.parseExpression()
|
|
213 self.Consume(')')
|
149
|
214 statements = self.parseCompoundStatement()
|
213
|
215 return astnodes.WhileStatement(condition, statements, loc)
|
149
|
216
|
213
|
217 def parseReturnStatement(self):
|
148
|
218 self.Consume('return')
|
|
219 expr = self.parseExpression()
|
157
|
220 self.Consume(';')
|
149
|
221 return astnodes.ReturnStatement(expr)
|
148
|
222
|
213
|
223 def parseCompoundStatement(self):
|
149
|
224 self.Consume('{')
|
157
|
225 statements = []
|
|
226 while not self.hasConsumed('}'):
|
166
|
227 s = self.parseStatement()
|
|
228 if not type(s) is astnodes.EmptyStatement:
|
|
229 statements.append(s)
|
149
|
230 return astnodes.CompoundStatement(statements)
|
148
|
231
|
213
|
232 def parseStatement(self):
|
148
|
233 # Determine statement type based on the pending token:
|
|
234 if self.Peak == 'if':
|
|
235 return self.parseIfStatement()
|
|
236 elif self.Peak == 'while':
|
|
237 return self.parseWhileStatement()
|
|
238 elif self.Peak == '{':
|
|
239 return self.parseCompoundStatement()
|
158
|
240 elif self.hasConsumed(';'):
|
155
|
241 return astnodes.EmptyStatement()
|
148
|
242 elif self.Peak == 'var':
|
158
|
243 self.parseVarDef()
|
|
244 return astnodes.EmptyStatement()
|
148
|
245 elif self.Peak == 'return':
|
|
246 return self.parseReturnStatement()
|
213
|
247 else:
|
148
|
248 designator = self.parseDesignator()
|
|
249 if self.Peak == '(':
|
213
|
250 return self.parseCall(designator)
|
148
|
251 elif self.Peak == '=':
|
|
252 return self.parseAssignment(designator)
|
213
|
253 else:
|
|
254 self.Error('Unable to determine statement')
|
148
|
255
|
213
|
256 # Parsing expressions:
|
|
257 def parseExpression(self):
|
148
|
258 return self.parseBinopRhs(self.parsePrimary(), 0)
|
213
|
259
|
|
260 def parsePrimary(self):
|
148
|
261 if self.hasConsumed('('):
|
|
262 e = self.parseExpression()
|
|
263 self.Consume(')')
|
|
264 return e
|
|
265 elif self.Peak == 'NUMBER':
|
|
266 val = self.Consume('NUMBER')
|
213
|
267 return astnodes.Literal(val.val, val.loc)
|
163
|
268 elif self.Peak == 'REAL':
|
|
269 val = self.Consume('REAL')
|
213
|
270 return astnodes.Literal(val.val, val.loc)
|
166
|
271 elif self.Peak == 'true':
|
|
272 val = self.Consume('true')
|
213
|
273 return astnodes.Literal(True, val.loc)
|
166
|
274 elif self.Peak == 'false':
|
|
275 val = self.Consume('false')
|
213
|
276 return astnodes.Literal(False, val.loc)
|
148
|
277 elif self.Peak == 'ID':
|
|
278 d = self.parseDesignator()
|
155
|
279 if self.Peak == '(':
|
213
|
280 return self.parseCall(d)
|
155
|
281 else:
|
213
|
282 return astnodes.VariableUse(d, d.loc)
|
148
|
283 self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak))
|
|
284
|
213
|
285 def parseBinopRhs(self, lhs, min_prec):
|
148
|
286 while self.PeakPrec >= min_prec:
|
|
287 op_prec = self.PeakPrec
|
|
288 op = self.Consume(self.Peak)
|
|
289 rhs = self.parsePrimary()
|
|
290 while self.PeakPrec > op_prec:
|
|
291 rhs = self.parseBinopRhs(rhs, self.PeakPrec)
|
213
|
292 lhs = astnodes.Binop(lhs, op.typ, rhs, op.loc)
|
148
|
293 return lhs
|
|
294
|