Mercurial > lcfOS
comparison ide/compiler/parser.py @ 1:92df07bc2081
Initial import of compiler
author | windel |
---|---|
date | Sun, 18 Sep 2011 19:00:29 +0200 |
parents | |
children | 0d5ef85b8698 |
comparison
equal
deleted
inserted
replaced
0:1a4faf9ef1ea | 1:92df07bc2081 |
---|---|
1 """ | |
2 This module parses source code into an abstract syntax tree (AST) | |
3 """ | |
4 | |
5 import shelve | |
6 from .symboltable import SymbolTable | |
7 from .nodes import * | |
8 from .errors import CompilerException, Error | |
9 from .modules import loadModule | |
10 from .display import printNode | |
11 from .builtin import * | |
12 from . import assembler | |
13 | |
14 class Parser: | |
15 def __init__(self, tokens): | |
16 """ provide the parser with the tokens iterator from the lexer. """ | |
17 self.tokens = tokens | |
18 self.NextToken() | |
19 | |
20 def Error(self, msg): | |
21 raise CompilerException(msg, self.token.row, self.token.col) | |
22 | |
23 # Lexer helpers: | |
24 def Consume(self, typ=''): | |
25 if self.token.typ == typ or typ == '': | |
26 v = self.token.val | |
27 self.NextToken() | |
28 return v | |
29 else: | |
30 self.Error('Excected: "{0}", got "{1}"'.format(typ, self.token)) | |
31 | |
32 def hasConsumed(self, typ): | |
33 if self.token.typ == typ: | |
34 self.Consume(typ) | |
35 return True | |
36 return False | |
37 | |
38 def NextToken(self): | |
39 self.token = self.tokens.__next__() | |
40 | |
41 def setLocation(self): | |
42 pass | |
43 def attachLocation(self, node): | |
44 node.row, node.col = self.token.row, self.token.col | |
45 return node | |
46 """ | |
47 Recursive descent parser functions: | |
48 A set of mutual recursive functions. | |
49 Starting symbol is the Module. | |
50 """ | |
51 | |
52 def parseModule(self): | |
53 self.imports = [] | |
54 self.Consume('module') | |
55 modname = self.Consume('ID') | |
56 self.Consume(';') | |
57 mod = Module(modname) | |
58 | |
59 # Construct a symbol table for this program | |
60 mod.symtable = SymbolTable() | |
61 # Add built in types and functions: | |
62 for x in [real, integer, boolean, char, chr_func]: | |
63 mod.symtable.addSymbol(x) | |
64 | |
65 self.cst = mod.symtable | |
66 self.parseImportList() | |
67 | |
68 self.parseDeclarationSequence() | |
69 # Procedures only allowed in this scope | |
70 self.parseProcedureDeclarations() | |
71 | |
72 if self.hasConsumed('begin'): | |
73 mod.initcode = self.parseStatementSequence() | |
74 else: | |
75 mod.initcode = EmptyStatement() | |
76 | |
77 self.Consume('end') | |
78 endname = self.Consume('ID') | |
79 if endname != modname: | |
80 self.Error('end denoter must be module name') | |
81 self.Consume('.') | |
82 | |
83 mod.imports = self.imports | |
84 return mod | |
85 | |
86 # Import part | |
87 def parseImportList(self): | |
88 if self.hasConsumed('import'): | |
89 self.parseImport() | |
90 while self.hasConsumed(','): | |
91 self.parseImport() | |
92 self.Consume(';') | |
93 | |
94 def parseImport(self): | |
95 modname = self.Consume('ID') | |
96 mod = loadModule(modname) | |
97 self.cst.addSymbol(mod) | |
98 | |
99 # Helper to parse an identifier defenitions | |
100 def parseIdentDef(self): | |
101 name = self.Consume('ID') | |
102 ispublic = self.hasConsumed('*') | |
103 return (name, ispublic) | |
104 | |
105 def parseIdentList(self): | |
106 ids = [ self.parseIdentDef() ] | |
107 while self.hasConsumed(','): | |
108 ids.append( self.parseIdentDef() ) | |
109 return ids | |
110 | |
111 def parseQualIdent(self): | |
112 """ Parse a qualified identifier """ | |
113 name = self.Consume('ID') | |
114 if self.cst.has(Module, name): | |
115 modname = name | |
116 mod = self.cst.get(Module, modname) | |
117 self.Consume('.') | |
118 name = self.Consume('ID') | |
119 # Try to find existing imported symbol: | |
120 for imp in self.imports: | |
121 if imp.modname == modname and imp.name == name: | |
122 return imp | |
123 # Try to find the symbol in the modules exports: | |
124 for sym in mod.exports: | |
125 if sym.name == name: | |
126 impsym = ImportedSymbol(modname, name) | |
127 impsym.typ = sym.typ | |
128 impsym.signature = mod.signature | |
129 self.imports.append(impsym) | |
130 return impsym | |
131 self.Error("Cannot find symbol {0}".format(name)) | |
132 else: | |
133 return self.cst.getSymbol(name) | |
134 | |
135 # Helper to parse a designator | |
136 def parseDesignator(self): | |
137 """ A designator designates an object. | |
138 The base location in memory is denoted by the qualified identifier | |
139 The actual address depends on the selector. | |
140 """ | |
141 obj = self.parseQualIdent() | |
142 typ = obj.typ | |
143 selectors = [] | |
144 while self.token.typ in ['.', '[', '^']: | |
145 if self.hasConsumed('.'): | |
146 field = self.Consume('ID') | |
147 if typ is PointerType: | |
148 selectors.append(Deref()) | |
149 typ = typ.pointedType | |
150 if not type(typ) is RecordType: | |
151 self.Error("field reference, type not record but {0}".format(typ)) | |
152 typ = typ.fields[field] | |
153 selectors.append(Field(field)) | |
154 elif self.hasConsumed('['): | |
155 indexes = self.parseExpressionList() | |
156 self.Consume(']') | |
157 for idx in indexes: | |
158 if not type(typ) is ArrayType: | |
159 self.Error('Cannot index non array type') | |
160 if not isType(idx.typ, integer): | |
161 self.Error('Only integer expressions can be used as an index') | |
162 selectors.append(Index(idx, typ)) | |
163 typ = typ.elementType | |
164 elif self.hasConsumed('^'): | |
165 selectors.append(Deref()) | |
166 typ = typ.pointedType | |
167 return Designator(obj, selectors, typ) | |
168 | |
169 # Declaration sequence | |
170 def parseDeclarationSequence(self): | |
171 """ 1. constants, 2. types, 3. variables """ | |
172 self.parseConstantDeclarations() | |
173 self.parseTypeDeclarations() | |
174 self.parseVariableDeclarations() | |
175 | |
176 # Constants | |
177 def evalExpression(self, expr): | |
178 if type(expr) is Binop: | |
179 a = self.evalExpression(expr.a) | |
180 b = self.evalExpression(expr.b) | |
181 if expr.op == '+': | |
182 return a + b | |
183 elif expr.op == '-': | |
184 return a - b | |
185 elif expr.op == '*': | |
186 return a * b | |
187 elif expr.op == '/': | |
188 return float(a) / float(b) | |
189 elif expr.op == 'mod': | |
190 return int(a % b) | |
191 elif expr.op == 'div': | |
192 return int(a / b) | |
193 elif expr.op == 'or': | |
194 return a or b | |
195 elif expr.op == 'and': | |
196 return a and b | |
197 else: | |
198 self.Error('Cannot evaluate expression with {0}'.format(expr.op)) | |
199 elif type(expr) is Constant: | |
200 return expr.value | |
201 elif type(expr) is Designator: | |
202 if type(expr.obj) is Constant: | |
203 return self.evalExpression(expr.obj) | |
204 else: | |
205 self.Error('Cannot evaluate designated object {0}'.format(expr.obj)) | |
206 elif type(expr) is Unop: | |
207 a = self.evalExpression(expr.a) | |
208 if expr.op == 'not': | |
209 return not a | |
210 elif expr.op == '-': | |
211 return -a | |
212 else: | |
213 self.Error('Unimplemented unary operation {0}'.format(expr.op)) | |
214 else: | |
215 self.Error('Cannot evaluate expression {0}'.format(expr)) | |
216 | |
217 def parseConstExpression(self): | |
218 e = self.parseExpression() | |
219 return self.evalExpression(e), e.typ | |
220 | |
221 def parseConstantDeclarations(self): | |
222 """ Parse const part of a module """ | |
223 if self.hasConsumed('const'): | |
224 while self.token.typ == 'ID': | |
225 name, ispublic = self.parseIdentDef() | |
226 self.Consume('=') | |
227 constvalue, typ = self.parseConstExpression() | |
228 self.Consume(';') | |
229 c = Constant(constvalue, typ, name=name, public=ispublic) | |
230 self.cst.addSymbol(c) | |
231 | |
232 # Type system | |
233 def parseTypeDeclarations(self): | |
234 if self.hasConsumed('type'): | |
235 while self.token.typ == 'ID': | |
236 typename, export = self.parseIdentDef() | |
237 self.Consume('=') | |
238 typ = self.parseStructuredType() | |
239 self.Consume(';') | |
240 t = DefinedType(typename, typ) | |
241 self.cst.addSymbol(t) | |
242 | |
243 def parseType(self): | |
244 if self.token.typ == 'ID': | |
245 typename = self.Consume('ID') | |
246 if self.cst.has(Type, typename): | |
247 typ = self.cst.get(Type, typename) | |
248 while type(typ) is DefinedType: | |
249 typ = typ.typ | |
250 return typ | |
251 else: | |
252 self.Error('Cannot find type {0}'.format(typename)) | |
253 else: | |
254 return self.parseStructuredType() | |
255 | |
256 def parseStructuredType(self): | |
257 if self.hasConsumed('array'): | |
258 dimensions = [] | |
259 dimensions.append( self.parseConstExpression() ) | |
260 while self.hasConsumed(','): | |
261 dimensions.append( self.parseConstExpression() ) | |
262 self.Consume('of') | |
263 arr = self.parseType() | |
264 for dimension, consttyp in reversed(dimensions): | |
265 if not isType(consttyp, integer): | |
266 self.Error('array dimension must be an integer type (not {0})'.format(consttyp)) | |
267 if dimension < 2: | |
268 self.Error('array dimension must be bigger than 1 (not {0})'.format(dimension)) | |
269 arr = ArrayType(dimension, arr) | |
270 return arr | |
271 elif self.hasConsumed('record'): | |
272 fields = {} | |
273 while self.token.typ == 'ID': | |
274 # parse a fieldlist: | |
275 identifiers = self.parseIdentList() | |
276 self.Consume(':') | |
277 typ = self.parseType() | |
278 self.Consume(';') | |
279 for id, public in identifiers: | |
280 if id in fields.keys(): | |
281 self.Error('record field "{0}" multiple defined.'.format(id)) | |
282 fields[id] = typ | |
283 # TODO store this in another way, symbol table? | |
284 self.Consume('end') | |
285 return RecordType(fields) | |
286 elif self.hasConsumed('pointer'): | |
287 self.Consume('to') | |
288 typ = self.parseType() | |
289 return PointerType(typ) | |
290 elif self.hasConsumed('procedure'): | |
291 parameters, returntype = self.parseFormalParameters() | |
292 return ProcedureType(parameters, returntype) | |
293 else: | |
294 self.Error('Unknown structured type "{0}"'.format(self.token.val)) | |
295 | |
296 # Variable declarations: | |
297 def parseVariableDeclarations(self): | |
298 if self.hasConsumed('var'): | |
299 if self.token.typ == 'ID': | |
300 while self.token.typ == 'ID': | |
301 ids = self.parseIdentList() | |
302 self.Consume(':') | |
303 typename = self.parseType() | |
304 self.Consume(';') | |
305 for name, ispublic in ids: | |
306 v = Variable(name, typename, public=ispublic) | |
307 self.cst.addSymbol(v) | |
308 else: | |
309 self.Error('Expected ID, got'+str(self.token)) | |
310 | |
311 # Procedures | |
312 def parseFPsection(self): | |
313 if self.hasConsumed('const'): | |
314 kind = 'const' | |
315 elif self.hasConsumed('var'): | |
316 kind = 'var' | |
317 else: | |
318 kind = 'value' | |
319 names = [ self.Consume('ID') ] | |
320 while self.hasConsumed(','): | |
321 names.append( self.Consume('ID') ) | |
322 self.Consume(':') | |
323 typ = self.parseType() | |
324 parameters = [Parameter(kind, name, typ) | |
325 for name in names] | |
326 return parameters | |
327 | |
328 def parseFormalParameters(self): | |
329 parameters = [] | |
330 self.Consume('(') | |
331 if not self.hasConsumed(')'): | |
332 parameters += self.parseFPsection() | |
333 while self.hasConsumed(';'): | |
334 parameters += self.parseFPsection() | |
335 self.Consume(')') | |
336 if self.hasConsumed(':'): | |
337 returntype = self.parseQualIdent() | |
338 else: | |
339 returntype = void | |
340 return ProcedureType(parameters, returntype) | |
341 | |
342 def parseProcedureDeclarations(self): | |
343 procedures = [] | |
344 while self.token.typ == 'procedure': | |
345 p = self.parseProcedureDeclaration() | |
346 procedures.append(p) | |
347 self.Consume(';') | |
348 return procedures | |
349 | |
350 def parseProcedureDeclaration(self): | |
351 self.Consume('procedure') | |
352 name, ispublic = self.parseIdentDef() | |
353 proctyp = self.parseFormalParameters() | |
354 procsymtable = SymbolTable(parent = self.cst) | |
355 self.cst = procsymtable # Switch symbol table: | |
356 # Add parameters as variables to symbol table: | |
357 for parameter in proctyp.parameters: | |
358 vname = parameter.name | |
359 vtyp = parameter.typ | |
360 if parameter.kind == 'var': | |
361 vtyp = PointerType(vtyp) | |
362 variable = Variable(vname, vtyp, False) | |
363 if parameter.kind == 'const': | |
364 variable.isReadOnly = True | |
365 variable.isParameter = True | |
366 self.cst.addSymbol(variable) | |
367 self.Consume(';') | |
368 self.parseDeclarationSequence() | |
369 # Mark all variables as local: | |
370 for variable in self.cst.getAllLocal(Variable): | |
371 variable.isLocal = True | |
372 | |
373 if self.hasConsumed('begin'): | |
374 block = self.parseStatementSequence() | |
375 if self.hasConsumed('return'): | |
376 returnexpression = self.parseExpression() | |
377 else: | |
378 returnexpression = None | |
379 | |
380 if proctyp.returntype.isType(void): | |
381 if not returnexpression is None: | |
382 self.Error('Void procedure cannot return a value') | |
383 else: | |
384 if returnexpression is None: | |
385 self.Error('Procedure must return a value') | |
386 if not isType(returnexpression.typ, proctyp.returntype): | |
387 self.Error('Returned type {0} does not match function return type {1}'.format(returnexpression.typ, proctyp.returntype)) | |
388 | |
389 self.Consume('end') | |
390 endname = self.Consume('ID') | |
391 if endname != name: | |
392 self.Error('endname should match {0}'.format(name)) | |
393 self.cst = procsymtable.parent # Switch back to parent symbol table | |
394 proc = Procedure(name, proctyp, block, procsymtable, returnexpression) | |
395 self.cst.addSymbol(proc) | |
396 proc.public = ispublic | |
397 return proc | |
398 | |
399 # Statements: | |
400 def parseAssignment(self, lval): | |
401 self.Consume(':=') | |
402 rval = self.parseExpression() | |
403 if isType(lval.typ, real) and isType(rval.typ, integer): | |
404 rval = Unop(rval, 'INTTOREAL', real) | |
405 if type(rval.typ) is NilType: | |
406 if not type(lval.typ) is ProcedureType and not type(lval.typ) is PointerType: | |
407 self.Error('Can assign nil only to pointers or procedure types, not {0}'.format(lval)) | |
408 elif not isType(lval.typ, rval.typ): | |
409 self.Error('Type mismatch {0} != {1}'.format(lval.typ, rval.typ)) | |
410 return Assignment(lval, rval) | |
411 | |
412 def parseExpressionList(self): | |
413 expressions = [ self.parseExpression() ] | |
414 while self.hasConsumed(','): | |
415 expressions.append( self.parseExpression() ) | |
416 return expressions | |
417 | |
418 def parseProcedureCall(self, procedure): | |
419 self.Consume('(') | |
420 if self.token.typ != ')': | |
421 args = self.parseExpressionList() | |
422 else: | |
423 args = [] | |
424 self.Consume(')') | |
425 parameters = procedure.typ.parameters | |
426 if len(args) != len(parameters): | |
427 self.Error("Procedure requires {0} arguments, {1} given".format(len(parameters), len(args))) | |
428 for arg, param in zip(args, parameters): | |
429 if not arg.typ.isType(param.typ): | |
430 print(arg.typ, param.typ) | |
431 self.Error('Mismatch in parameter') | |
432 return ProcedureCall(procedure, args) | |
433 | |
434 def parseIfStatement(self): | |
435 self.Consume('if') | |
436 ifs = [] | |
437 condition = self.parseExpression() | |
438 if not isType(condition.typ, boolean): | |
439 self.Error('condition of if statement must be boolean') | |
440 self.Consume('then') | |
441 truestatement = self.parseStatementSequence() | |
442 ifs.append( (condition, truestatement) ) | |
443 while self.hasConsumed('elsif'): | |
444 condition = self.parseExpression() | |
445 if not isType(condition.typ, boolean): | |
446 self.Error('condition of if statement must be boolean') | |
447 self.Consume('then') | |
448 truestatement = self.parseStatementSequence() | |
449 ifs.append( (condition, truestatement) ) | |
450 if self.hasConsumed('else'): | |
451 statement = self.parseStatementSequence() | |
452 else: | |
453 statement = None | |
454 self.Consume('end') | |
455 for condition, truestatement in reversed(ifs): | |
456 statement = IfStatement(condition, truestatement, statement) | |
457 return statement | |
458 | |
459 def parseCase(self): | |
460 # TODO | |
461 pass | |
462 | |
463 def parseCaseStatement(self): | |
464 self.Consume('case') | |
465 expr = self.parseExpression() | |
466 self.Consume('of') | |
467 self.parseCase() | |
468 while self.hasConsumed('|'): | |
469 self.parseCase() | |
470 self.Consume('end') | |
471 | |
472 def parseWhileStatement(self): | |
473 self.Consume('while') | |
474 condition = self.parseExpression() | |
475 self.Consume('do') | |
476 statements = self.parseStatementSequence() | |
477 if self.hasConsumed('elsif'): | |
478 self.Error('elsif in while not yet implemented') | |
479 self.Consume('end') | |
480 return WhileStatement(condition, statements) | |
481 | |
482 def parseRepeatStatement(self): | |
483 self.Consume('repeat') | |
484 stmt = self.parseStatementSequence() | |
485 self.Consume('until') | |
486 cond = self.parseBoolExpression() | |
487 | |
488 def parseForStatement(self): | |
489 self.Consume('for') | |
490 variable = self.parseDesignator() | |
491 if not variable.typ.isType(integer): | |
492 self.Error('loop variable of for statement must have integer type') | |
493 assert(variable.typ.isType(integer)) | |
494 self.Consume(':=') | |
495 begin = self.parseExpression() | |
496 if not begin.typ.isType(integer): | |
497 self.Error('begin expression of a for statement must have integer type') | |
498 self.Consume('to') | |
499 end = self.parseExpression() | |
500 if not end.typ.isType(integer): | |
501 self.Error('end expression of a for statement must have integer type') | |
502 if self.hasConsumed('by'): | |
503 increment, typ = self.parseConstExpression() | |
504 if not typ.isType(integer): | |
505 self.Error('Increment must be integer') | |
506 else: | |
507 increment = 1 | |
508 assert(type(increment) is int) | |
509 self.Consume('do') | |
510 statements = self.parseStatementSequence() | |
511 self.Consume('end') | |
512 return ForStatement(variable, begin, end, increment, statements) | |
513 | |
514 def parseAsmcode(self): | |
515 def parseOpcode(): | |
516 return self.Consume('ID') | |
517 def parseOperand(): | |
518 if self.hasConsumed('['): | |
519 memref = [] | |
520 memref.append(parseOperand()) | |
521 self.Consume(']') | |
522 return memref | |
523 else: | |
524 if self.token.typ == 'NUMBER': | |
525 return self.Consume('NUMBER') | |
526 else: | |
527 ID = self.Consume('ID') | |
528 if self.cst.has(Variable, ID): | |
529 return self.cst.get(Variable, ID) | |
530 else: | |
531 return ID | |
532 | |
533 def parseOperands(n): | |
534 operands = [] | |
535 if n > 0: | |
536 operands.append( parseOperand() ) | |
537 n = n - 1 | |
538 while n > 0: | |
539 self.Consume(',') | |
540 operands.append(parseOperand()) | |
541 n = n - 1 | |
542 return operands | |
543 self.Consume('asm') | |
544 asmcode = [] | |
545 while self.token.typ != 'end': | |
546 opcode = parseOpcode() | |
547 func, numargs = assembler.opcodes[opcode] | |
548 operands = parseOperands(numargs) | |
549 asmcode.append( (opcode, operands) ) | |
550 #print('opcode', opcode, operands) | |
551 self.Consume('end') | |
552 return AsmCode(asmcode) | |
553 | |
554 def parseStatement(self): | |
555 # Determine statement type based on the pending token: | |
556 if self.token.typ == 'if': | |
557 return self.parseIfStatement() | |
558 elif self.token.typ == 'case': | |
559 return self.parseCaseStatement() | |
560 elif self.token.typ == 'while': | |
561 return self.parseWhileStatement() | |
562 elif self.token.typ == 'repeat': | |
563 return self.parseRepeatStatement() | |
564 elif self.token.typ == 'for': | |
565 return self.parseForStatement() | |
566 elif self.token.typ == 'asm': | |
567 return self.parseAsmcode() | |
568 elif self.token.typ == 'ID': | |
569 # Assignment or procedure call | |
570 designator = self.parseDesignator() | |
571 if self.token.typ == '(' and type(designator.typ) is ProcedureType: | |
572 return self.parseProcedureCall(designator) | |
573 elif self.token.typ == ':=': | |
574 return self.parseAssignment(designator) | |
575 else: | |
576 self.Error('Unknown statement following designator: {0}'.format(self.token)) | |
577 else: | |
578 # TODO: return empty statement??: | |
579 return EmptyStatement() | |
580 self.Error('Unknown statement {0}'.format(self.token)) | |
581 | |
582 def parseStatementSequence(self): | |
583 """ Sequence of statements seperated by ';' """ | |
584 statements = [ self.parseStatement() ] | |
585 while self.hasConsumed(';'): | |
586 statements.append( self.parseStatement() ) | |
587 return StatementSequence( statements ) | |
588 | |
589 # Parsing expressions: | |
590 """ | |
591 grammar of expressions: | |
592 expression = SimpleExpression [ reloperator SimpleExpression ] | |
593 reloperator = '=' | '<=' | '>=' | '<>' | |
594 Simpleexpression = [ '+' | '-' ] term { addoperator term } | |
595 addoperator = '+' | '-' | 'or' | |
596 term = factor { muloperator factor } | |
597 muloperator = '*' | '/' | 'div' | 'mod' | 'and' | |
598 factor = number | nil | true | false | "(" expression ")" | | |
599 designator [ actualparameters ] | 'not' factor | |
600 """ | |
601 def parseExpression(self): | |
602 """ The connector between the boolean and expression domain """ | |
603 expr = self.parseSimpleExpression() | |
604 if self.token.typ in ['>=','<=','<','>','<>','=']: | |
605 relop = self.Consume() | |
606 expr2 = self.parseSimpleExpression() | |
607 # Automatic type convert to reals: | |
608 if isType(expr.typ, real) and isType(expr2.typ, integer): | |
609 expr2 = Unop(expr2, 'INTTOREAL', real) | |
610 if isType(expr2.typ, real) and isType(expr.typ, integer): | |
611 expr = Unop(expr, 'INTTOREAL', real) | |
612 # Type check: | |
613 if not isType(expr.typ, expr2.typ): | |
614 self.Error('Type mismatch in relop') | |
615 if isType(expr.typ, real) and relop in ['<>', '=']: | |
616 self.Error('Cannot check real values for equality') | |
617 | |
618 expr = Relop(expr, relop, expr2, boolean) | |
619 return expr | |
620 | |
621 # Parsing arithmatic expressions: | |
622 def parseTerm(self): | |
623 a = self.parseFactor() | |
624 while self.token.typ in ['*', '/', 'mod', 'div', 'and']: | |
625 op = self.Consume() | |
626 b = self.parseTerm() | |
627 # Type determination and checking: | |
628 if op in ['mod', 'div']: | |
629 if not isType(a.typ, integer): | |
630 self.Error('First operand should be integer, not {0}'.format(a.typ)) | |
631 if not isType(b.typ, integer): | |
632 self.Error('Second operand should be integer, not {0}'.format(b.typ)) | |
633 typ = integer | |
634 elif op == '*': | |
635 if isType(a.typ, integer) and isType(b.typ, integer): | |
636 typ = integer | |
637 elif isType(a.typ, real) or isType(b.typ, real): | |
638 if isType(a.typ, integer): | |
639 # Automatic type cast | |
640 a = Unop(a, 'INTTOREAL', real) | |
641 if isType(b.typ, integer): | |
642 b = Unop(b, 'INTTOREAL', real) | |
643 if not isType(a.typ, real): | |
644 self.Error('first operand must be a real!') | |
645 if not isType(b.typ, real): | |
646 self.Error('second operand must be a real!') | |
647 typ = real | |
648 else: | |
649 self.Error('Unknown operands for multiply: {0}, {1}'.format(a, b)) | |
650 elif op == '/': | |
651 # Division always yields a real result, for integer division use div | |
652 if isType(a.typ, integer): | |
653 # Automatic type cast | |
654 a = Unop(a, 'INTTOREAL', real) | |
655 if isType(b.typ, integer): | |
656 b = Unop(b, 'INTTOREAL', real) | |
657 if not isType(a.typ, real): | |
658 self.Error('first operand must be a real!') | |
659 if not isType(b.typ, real): | |
660 self.Error('second operand must be a real!') | |
661 typ = real | |
662 elif op == 'and': | |
663 if not isType(a.typ, boolean): | |
664 self.Error('First operand of and must be boolean') | |
665 if not isType(b.typ, boolean): | |
666 self.Error('Second operand of and must be boolean') | |
667 typ = boolean | |
668 else: | |
669 self.Error('Unknown operand {0}'.format(op)) | |
670 | |
671 a = Binop(a, op, b, typ) | |
672 return a | |
673 | |
674 def parseFactor(self): | |
675 if self.hasConsumed('('): | |
676 e = self.parseExpression() | |
677 self.Consume(')') | |
678 return e | |
679 elif self.token.typ == 'NUMBER': | |
680 val = self.Consume('NUMBER') | |
681 return Constant(val, integer) | |
682 elif self.token.typ == 'REAL': | |
683 val = self.Consume('REAL') | |
684 return Constant(val, real) | |
685 elif self.token.typ == 'CHAR': | |
686 val = self.Consume('CHAR') | |
687 return Constant(val, char) | |
688 elif self.token.typ == 'STRING': | |
689 txt = self.Consume('STRING') | |
690 return StringConstant(txt) | |
691 elif self.token.typ in ['true', 'false']: | |
692 val = self.Consume() | |
693 val = True if val == 'true' else False | |
694 return Constant(val, boolean) | |
695 elif self.hasConsumed('nil'): | |
696 return Constant(0, NilType()) | |
697 elif self.hasConsumed('not'): | |
698 f = self.parseFactor() | |
699 if not isType(f.typ, boolean): | |
700 self.Error('argument of boolean negation must be boolean type') | |
701 return Unop(f, 'not', boolean) | |
702 elif self.token.typ == 'ID': | |
703 designator = self.parseDesignator() | |
704 # TODO: handle functions different here? | |
705 if self.token.typ == '(' and type(designator.typ) is ProcedureType: | |
706 return self.parseProcedureCall(designator) | |
707 else: | |
708 return designator | |
709 else: | |
710 self.Error('Expected NUMBER, ID or ( expr ), got'+str(self.token)) | |
711 | |
712 def parseSimpleExpression(self): | |
713 """ Arithmatic expression """ | |
714 if self.token.typ in ['+', '-']: | |
715 # Handle the unary minus | |
716 op = self.Consume() | |
717 a = self.parseTerm() | |
718 typ = a.typ | |
719 if not isType(typ,real) and not isType(typ, integer): | |
720 self.Error('Unary minus or plus can be only applied to real or integers') | |
721 if op == '-': | |
722 a = Unop(a, op, typ) | |
723 else: | |
724 a = self.parseTerm() | |
725 while self.token.typ in ['+', '-', 'or']: | |
726 op = self.Consume() | |
727 b = self.parseTerm() | |
728 if op in ['+', '-']: | |
729 if isType(a.typ, real) or isType(b.typ, real): | |
730 typ = real | |
731 if isType(a.typ, integer): | |
732 # Automatic type cast | |
733 a = Unop(a, 'INTTOREAL', real) | |
734 if not isType(a.typ, real): | |
735 self.Error('first operand must be a real!') | |
736 if isType(b.typ, integer): | |
737 b = Unop(b, 'INTTOREAL', real) | |
738 if not isType(b.typ, real): | |
739 self.Error('second operand must be a real!') | |
740 elif isType(a.typ, integer) and isType(b.typ, integer): | |
741 typ = integer | |
742 else: | |
743 self.Error('Invalid types {0} and {1}'.format(a.typ, b.typ)) | |
744 elif op == 'or': | |
745 if not isType(a.typ, boolean): | |
746 self.Error('first operand must be boolean for or operation') | |
747 if not isType(b.typ, boolean): | |
748 self.Error('second operand must be boolean for or operation') | |
749 typ = boolean | |
750 else: | |
751 self.Error('Unknown operand {0}'.format(op)) | |
752 a = Binop(a, op, b, typ) | |
753 return a | |
754 |