Mercurial > lcfOS
diff ide/compiler/parser.py @ 4:0d5ef85b8698
Improved link between ast viewer and code edit
author | windel-eee |
---|---|
date | Wed, 21 Sep 2011 19:05:18 +0200 |
parents | 92df07bc2081 |
children | 818f80afa78b |
line wrap: on
line diff
--- a/ide/compiler/parser.py Sun Sep 18 21:21:54 2011 +0200 +++ b/ide/compiler/parser.py Wed Sep 21 19:05:18 2011 +0200 @@ -37,20 +37,23 @@ def NextToken(self): self.token = self.tokens.__next__() + self.location = (self.token.row, self.token.col) - def setLocation(self): - pass - def attachLocation(self, node): - node.row, node.col = self.token.row, self.token.col - return node + # Helpers to find location of the error in the code: + def setLocation(self, obj, location): + obj.location = location + return obj + def getLocation(self): + return self.location + """ Recursive descent parser functions: A set of mutual recursive functions. Starting symbol is the Module. """ - def parseModule(self): self.imports = [] + loc = self.getLocation() self.Consume('module') modname = self.Consume('ID') self.Consume(';') @@ -81,7 +84,7 @@ self.Consume('.') mod.imports = self.imports - return mod + return self.setLocation(mod, loc) # Import part def parseImportList(self): @@ -92,15 +95,21 @@ self.Consume(';') def parseImport(self): + loc = self.getLocation() modname = self.Consume('ID') mod = loadModule(modname) + self.setLocation(mod, loc) self.cst.addSymbol(mod) # Helper to parse an identifier defenitions def parseIdentDef(self): + loc = self.getLocation() name = self.Consume('ID') ispublic = self.hasConsumed('*') - return (name, ispublic) + # Make a node of this thing: + i = Id(name) + i.ispublic = ispublic + return self.setLocation(i, loc) def parseIdentList(self): ids = [ self.parseIdentDef() ] @@ -138,6 +147,7 @@ The base location in memory is denoted by the qualified identifier The actual address depends on the selector. """ + loc = self.getLocation() obj = self.parseQualIdent() typ = obj.typ selectors = [] @@ -164,7 +174,7 @@ elif self.hasConsumed('^'): selectors.append(Deref()) typ = typ.pointedType - return Designator(obj, selectors, typ) + return self.setLocation(Designator(obj, selectors, typ), loc) # Declaration sequence def parseDeclarationSequence(self): @@ -222,11 +232,12 @@ """ Parse const part of a module """ if self.hasConsumed('const'): while self.token.typ == 'ID': - name, ispublic = self.parseIdentDef() + i = self.parseIdentDef() self.Consume('=') constvalue, typ = self.parseConstExpression() self.Consume(';') - c = Constant(constvalue, typ, name=name, public=ispublic) + c = Constant(constvalue, typ, name=i.name, public=i.ispublic) + self.setLocation(c, i.location) self.cst.addSymbol(c) # Type system @@ -276,10 +287,10 @@ self.Consume(':') typ = self.parseType() self.Consume(';') - for id, public in identifiers: - if id in fields.keys(): - self.Error('record field "{0}" multiple defined.'.format(id)) - fields[id] = typ + for i in identifiers: + if i.name in fields.keys(): + self.Error('record field "{0}" multiple defined.'.format(i.name)) + fields[i.name] = typ # TODO store this in another way, symbol table? self.Consume('end') return RecordType(fields) @@ -302,8 +313,9 @@ self.Consume(':') typename = self.parseType() self.Consume(';') - for name, ispublic in ids: - v = Variable(name, typename, public=ispublic) + for i in ids: + v = Variable(i.name, typename, public=i.ispublic) + self.setLocation(v, i.location) self.cst.addSymbol(v) else: self.Error('Expected ID, got'+str(self.token)) @@ -349,7 +361,8 @@ def parseProcedureDeclaration(self): self.Consume('procedure') - name, ispublic = self.parseIdentDef() + i = self.parseIdentDef() + procname = i.name proctyp = self.parseFormalParameters() procsymtable = SymbolTable(parent = self.cst) self.cst = procsymtable # Switch symbol table: @@ -388,16 +401,17 @@ self.Consume('end') endname = self.Consume('ID') - if endname != name: + if endname != procname: self.Error('endname should match {0}'.format(name)) self.cst = procsymtable.parent # Switch back to parent symbol table - proc = Procedure(name, proctyp, block, procsymtable, returnexpression) + proc = Procedure(procname, proctyp, block, procsymtable, returnexpression) self.cst.addSymbol(proc) - proc.public = ispublic + proc.public = i.ispublic return proc # Statements: def parseAssignment(self, lval): + loc = self.getLocation() self.Consume(':=') rval = self.parseExpression() if isType(lval.typ, real) and isType(rval.typ, integer): @@ -407,7 +421,7 @@ self.Error('Can assign nil only to pointers or procedure types, not {0}'.format(lval)) elif not isType(lval.typ, rval.typ): self.Error('Type mismatch {0} != {1}'.format(lval.typ, rval.typ)) - return Assignment(lval, rval) + return self.setLocation(Assignment(lval, rval), loc) def parseExpressionList(self): expressions = [ self.parseExpression() ] @@ -432,6 +446,7 @@ return ProcedureCall(procedure, args) def parseIfStatement(self): + loc = self.getLocation() self.Consume('if') ifs = [] condition = self.parseExpression() @@ -454,7 +469,7 @@ self.Consume('end') for condition, truestatement in reversed(ifs): statement = IfStatement(condition, truestatement, statement) - return statement + return self.setLocation(statement, loc) def parseCase(self): # TODO @@ -470,6 +485,7 @@ self.Consume('end') def parseWhileStatement(self): + loc = self.getLocation() self.Consume('while') condition = self.parseExpression() self.Consume('do') @@ -477,7 +493,7 @@ if self.hasConsumed('elsif'): self.Error('elsif in while not yet implemented') self.Consume('end') - return WhileStatement(condition, statements) + return self.setLocation(WhileStatement(condition, statements), loc) def parseRepeatStatement(self): self.Consume('repeat') @@ -486,6 +502,7 @@ cond = self.parseBoolExpression() def parseForStatement(self): + loc = self.getLocation() self.Consume('for') variable = self.parseDesignator() if not variable.typ.isType(integer): @@ -509,9 +526,10 @@ self.Consume('do') statements = self.parseStatementSequence() self.Consume('end') - return ForStatement(variable, begin, end, increment, statements) + return self.setLocation(ForStatement(variable, begin, end, increment, statements), loc) def parseAsmcode(self): + # TODO: move this to seperate file def parseOpcode(): return self.Consume('ID') def parseOperand(): @@ -622,6 +640,7 @@ def parseTerm(self): a = self.parseFactor() while self.token.typ in ['*', '/', 'mod', 'div', 'and']: + loc = self.getLocation() op = self.Consume() b = self.parseTerm() # Type determination and checking: @@ -668,7 +687,7 @@ else: self.Error('Unknown operand {0}'.format(op)) - a = Binop(a, op, b, typ) + a = self.setLocation(Binop(a, op, b, typ), loc) return a def parseFactor(self): @@ -677,11 +696,13 @@ self.Consume(')') return e elif self.token.typ == 'NUMBER': - val = self.Consume('NUMBER') - return Constant(val, integer) + loc = self.getLocation() + val = self.Consume('NUMBER') + return self.setLocation(Constant(val, integer), loc) elif self.token.typ == 'REAL': - val = self.Consume('REAL') - return Constant(val, real) + loc = self.getLocation() + val = self.Consume('REAL') + return self.setLocation(Constant(val, real), loc) elif self.token.typ == 'CHAR': val = self.Consume('CHAR') return Constant(val, char) @@ -723,6 +744,7 @@ else: a = self.parseTerm() while self.token.typ in ['+', '-', 'or']: + loc = self.getLocation() op = self.Consume() b = self.parseTerm() if op in ['+', '-']: @@ -749,6 +771,6 @@ typ = boolean else: self.Error('Unknown operand {0}'.format(op)) - a = Binop(a, op, b, typ) + a = self.setLocation(Binop(a, op, b, typ), loc) return a