comparison python/ks/parser.py @ 146:91af0e40f868

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