comparison python/c3/parser.py @ 148:e5263f74b287

Added c3 language frontend initial parser
author Windel Bouwman
date Fri, 01 Mar 2013 10:24:01 +0100
parents
children 74241ca312cc
comparison
equal deleted inserted replaced
147:4e79484a9d47 148:e5263f74b287
1 from . import astnodes, lexer, semantics
2 from ppci.errors import CompilerException, SourceLocation
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 def getTokenPrecedence(typ):
10 if typ in binopPrecs:
11 return binopPrecs[typ]
12 return -1
13
14 class Parser:
15 """ Parses sourcecode into an abstract syntax tree (AST) """
16 def __init__(self, sema, diag):
17 self.sema = sema
18 self.diag = diag
19 def parseSource(self, source):
20 self.initLex(source)
21 try:
22 self.parsePackage()
23 except CompilerException as e:
24 self.diag.diag(e)
25 def Error(self, msg):
26 raise CompilerException(msg, self.token.loc)
27 def skipToSemiCol(self):
28 while not (self.Peak == ';' or self.Peak == 'END'):
29 self.NextToken()
30 # Lexer helpers:
31 def Consume(self, typ):
32 if self.Peak == typ:
33 return self.NextToken()
34 else:
35 self.Error('Excected: "{0}", got "{1}"'.format(typ, self.Peak))
36 @property
37 def Peak(self):
38 return self.token.typ
39 @property
40 def PeakPrec(self):
41 return getTokenPrecedence(self.Peak)
42 def hasConsumed(self, typ):
43 if self.Peak == typ:
44 self.Consume(typ)
45 return True
46 return False
47 def NextToken(self):
48 t = self.token
49 if t.typ != 'END':
50 self.token = self.tokens.__next__()
51 return t
52 def initLex(self, source):
53 self.tokens = lexer.tokenize(source) # Lexical stage
54 self.token = self.tokens.__next__()
55
56 def parsePackage(self):
57 self.Consume('package')
58 name = self.Consume('ID')
59 self.Consume(';')
60 self.sema.handlePackage(name.val, name.loc)
61 # TODO: parse uses
62 while self.Peak != 'END':
63 self.parseTopLevel()
64 self.Consume('END')
65
66 def parseTopLevel(self):
67 is_public = self.hasConsumed('public')
68 if self.Peak == 'function':
69 self.parseFunctionDefinition(is_public)
70 elif self.Peak == 'var':
71 self.parseVarDef(is_public)
72
73 def parseDesignator(self):
74 """ A designator designates an object """
75 name = self.Consume('ID')
76 return name
77
78 # Type system
79 def parseType(self):
80 d = self.parseDesignator()
81 return d
82
83 # Variable declarations:
84 def parseVarDef(self, is_public):
85 self.Consume('var')
86 typ = self.parseType()
87 ID = self.Consume('ID')
88 self.Consume(';')
89 v = Variable(i.name, typename, public=is_public)
90 self.curScope.add(v)
91
92 # Procedures
93 def parseFunctionDefinition(self, is_pub):
94 self.Consume('function')
95 returntype = self.parseType()
96 procname = self.Consume('ID')
97 self.Consume('(')
98 parameters = []
99 if not self.hasConsumed(')'):
100 typ = self.parseType()
101 name = self.Consume('ID')
102 parameters.append(astnodes.Parameter(name, typ))
103 while self.hasConsumed(','):
104 typ = self.parseType()
105 name = self.Consume('ID')
106 parameters.append(astnodes.Parameter(name, typ))
107 self.Consume(')')
108 proctyp = astnodes.FunctionType(parameters, returntype)
109 body = self.parseCompoundStatement()
110 return astnodes.Procedure(procname, proctyp, body)
111
112 # Statements:
113 def parseAssignment(self, lval):
114 self.Consume('=')
115 rval = self.parseExpression()
116 return astnodes.Assignment(lval, rval)
117
118 def parseProcedureCall(self, procedure):
119 self.Consume('(')
120 args = []
121 if not self.hasConsumed(')'):
122 args.append(self.parseExpression())
123 while self.hasConsumed(','):
124 args.append(self.parseExpression())
125 self.Consume(')')
126 return ProcedureCall(procedure, args)
127
128 def parseLocal(self, t):
129 name = self.Consume('ID')
130 if self.hasConsumed('='):
131 ival = self.parseExpression()
132 else:
133 ival = None
134 self.sema.actOnLocal(t, name, ival)
135 def parseLocalDeclaration(self):
136 self.Consume('var')
137 t = self.parseType()
138 self.parseLocal(t)
139 while self.hasConsumed(','):
140 self.parseLocal(t)
141
142 def parseIfStatement(self):
143 self.Consume('if')
144 self.Consume('(')
145 condition = self.parseExpression()
146 self.Consume(')')
147 truestatement = self.parseStatement()
148 if self.hasConsumed('else'):
149 els = self.parseStatement()
150 return astnodes.IfStatement(condition, truestatement, els)
151 return astnodes.IfStatement(condition, truestatement)
152
153 def parseWhileStatement(self):
154 self.Consume('while')
155 self.Consume('(')
156 condition = self.parseExpression()
157 self.Consume(')')
158 statements = self.parseStatement()
159 def parseReturnStatement(self):
160 self.Consume('return')
161 expr = self.parseExpression()
162
163 def parseCompoundStatement(self):
164 self.Consume('{')
165 statements = [self.parseStatement()]
166 while self.hasConsumed(';'):
167 statements.append(self.parseStatement())
168 self.Consume('}')
169 return astnodes.CompoundStatement(statements)
170
171 def parseStatement(self):
172 # Determine statement type based on the pending token:
173 if self.Peak == 'if':
174 return self.parseIfStatement()
175 elif self.Peak == 'while':
176 return self.parseWhileStatement()
177 elif self.Peak == '{':
178 return self.parseCompoundStatement()
179 elif self.Peak == 'var':
180 return self.parseLocalDeclaration()
181 elif self.Peak == 'return':
182 return self.parseReturnStatement()
183 elif self.Peak == 'ID':
184 # Assignment or procedure call
185 designator = self.parseDesignator()
186 if self.Peak == '(':
187 return self.parseProcedureCall(designator)
188 elif self.Peak == '=':
189 return self.parseAssignment(designator)
190 self.Error('Unable to determine statement')
191
192 # Parsing expressions:
193 def parseExpression(self):
194 return self.parseBinopRhs(self.parsePrimary(), 0)
195 def parsePrimary(self):
196 if self.hasConsumed('('):
197 e = self.parseExpression()
198 self.Consume(')')
199 return e
200 elif self.Peak == 'NUMBER':
201 val = self.Consume('NUMBER')
202 return astnodes.Constant(val, val)
203 elif self.Peak == 'ID':
204 d = self.parseDesignator()
205 return d
206 self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak))
207
208 def parseBinopRhs(self, lhs, min_prec):
209 while self.PeakPrec >= min_prec:
210 op_prec = self.PeakPrec
211 op = self.Consume(self.Peak)
212 rhs = self.parsePrimary()
213 while self.PeakPrec > op_prec:
214 rhs = self.parseBinopRhs(rhs, self.PeakPrec)
215 lhs = astnodes.Binop(lhs, op, rhs)
216 return lhs
217