Mercurial > projects > dang
annotate parser/Parser.d @ 21:0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
author | johnsen@johnsen-laptop |
---|---|
date | Fri, 18 Apr 2008 21:39:17 +0200 |
parents | 6282db07115f |
children | e331e4e816e4 |
rev | line source |
---|---|
1 | 1 module parser.Parser; |
2 | |
3 import lexer.Lexer, | |
4 lexer.Token; | |
5 | |
6 import ast.Exp, | |
7 ast.Stmt, | |
8 ast.Decl; | |
9 | |
21
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
10 import misc.Error; |
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
11 |
1 | 12 import tango.io.Stdout, |
13 Integer = tango.text.convert.Integer; | |
14 | |
15 class Parser | |
16 { | |
17 | |
18 public: | |
19 Decl[] parse(Lexer lexer) | |
20 { | |
21 this.lexer = lexer; | |
22 | |
23 | |
24 Decl[] declarations; | |
25 | |
26 while(lexer.peek.type != Tok.EOF) | |
27 { | |
28 declarations ~= parseDecl; | |
29 } | |
30 | |
31 return declarations; | |
32 } | |
33 | |
34 Decl parseDecl() | |
35 { | |
36 Token t = lexer.next; | |
37 | |
38 switch(t.type) | |
39 { | |
40 case Tok.Byte, Tok.Ubyte, | |
41 Tok.Short, Tok.Ushort, | |
42 Tok.Int, Tok.Uint, | |
43 Tok.Long, Tok.Ulong, | |
44 Tok.Float, Tok.Double, | |
12
6282db07115f
Added some ekstra tests, and allowed bool as a type
Anders Halager <halager@gmail.com>
parents:
11
diff
changeset
|
45 Tok.Bool, |
1 | 46 Tok.Identifier: |
47 Identifier type = new Identifier(t); | |
48 | |
49 Token iden = lexer.next; | |
21
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
50 |
1 | 51 switch(iden.type) |
52 { | |
53 case Tok.Identifier: | |
54 Identifier identifier = new Identifier(iden); | |
55 Token p = lexer.peek(); | |
56 switch(p.type) | |
57 { | |
58 case Tok.OpenParentheses: | |
59 return parseFunc(type, identifier); | |
60 case Tok.Seperator: | |
61 require(Tok.Seperator); | |
62 return new VarDecl(type, identifier, null); | |
63 case Tok.Assign: | |
64 lexer.next(); | |
65 auto exp = parseExpression(); | |
66 require(Tok.Seperator); | |
67 return new VarDecl(type, identifier, exp); | |
68 default: | |
69 char[] c = t.getType; | |
70 error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__)); | |
71 } | |
72 break; | |
73 default: | |
74 char[] c = t.getType; | |
75 error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__)); | |
76 } | |
77 break; | |
78 | |
79 case Tok.EOF: | |
80 return null; | |
81 default: | |
82 char[] c = t.getType; | |
83 error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__)); | |
84 } | |
85 } | |
86 | |
87 Stmt parseStatement() | |
88 { | |
89 Token t = lexer.peek; | |
90 | |
91 switch(t.type) | |
92 { | |
93 case Tok.Return: | |
94 lexer.next; | |
95 auto ret = new ReturnStmt(); | |
96 ret.exp = parseExpression(); | |
97 require(Tok.Seperator); | |
98 return ret; | |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
99 |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
100 case Tok.If: |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
101 lexer.next; |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
102 require(Tok.OpenParentheses); |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
103 auto condition = parseExpression(); |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
104 require(Tok.CloseParentheses); |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
105 |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
106 auto then_body = parseBlockOrSingleStmt(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
107 |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
108 Stmt[] else_body; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
109 if (lexer.peek.type == Tok.Else) |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
110 { |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
111 lexer.next; |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
112 else_body = parseBlockOrSingleStmt(); |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
113 } |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
114 |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
115 return new IfStmt(condition, then_body, else_body); |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
116 |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
117 case Tok.While: |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
118 lexer.next; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
119 require(Tok.OpenParentheses); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
120 auto condition = parseExpression(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
121 require(Tok.CloseParentheses); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
122 return new WhileStmt(condition, parseBlockOrSingleStmt()); |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
123 |
1 | 124 case Tok.Identifier: |
125 Token n = lexer.peek(1); | |
126 switch(n.type) | |
127 { | |
128 case Tok.Assign: | |
129 lexer.next; | |
130 lexer.next; | |
131 auto stmt = new ExpStmt(new AssignExp(new Identifier(t), parseExpression())); | |
132 require(Tok.Seperator); | |
133 return stmt; | |
134 break; | |
135 | |
136 default: | |
137 auto e = new ExpStmt(parseExpression()); | |
138 require(Tok.Seperator); | |
139 return e; | |
140 | |
141 } | |
142 break; | |
143 | |
144 default: | |
145 auto decl = new DeclStmt(parseDecl()); | |
146 //require(Tok.Seperator); | |
147 return decl; | |
148 } | |
149 return new Stmt(); | |
150 } | |
151 | |
152 FuncDecl parseFunc(Identifier type, Identifier identifier) | |
153 { | |
154 VarDecl[] funcArgs = parseFuncArgs(); | |
155 | |
156 lexer.next; // Remove the "{" | |
157 | |
158 Stmt[] statements; | |
159 | |
160 while(lexer.peek.type != Tok.CloseBrace) | |
161 statements ~= parseStatement(); | |
162 | |
163 lexer.next; // Remove "}" | |
164 | |
165 return new FuncDecl(type, identifier, funcArgs, statements); | |
166 } | |
167 | |
168 VarDecl[] parseFuncArgs() | |
169 { | |
170 lexer.next; // Remove the "(" token. | |
171 | |
172 VarDecl[] funcArgs; | |
173 | |
174 while(lexer.peek.type != Tok.CloseParentheses) | |
175 { | |
21
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
176 auto t = parseType; |
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
177 auto i = parseIdentifier; |
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
178 funcArgs ~= new VarDecl(t, i); |
1 | 179 |
180 if(lexer.peek.type == Tok.Comma) | |
181 lexer.next; | |
182 } | |
183 | |
184 lexer.next; // Remove the ")" | |
185 | |
186 return funcArgs; | |
187 } | |
188 | |
189 Identifier parseIdentifier() | |
190 { | |
191 Token identifier = lexer.next; | |
192 | |
193 switch(identifier.type) | |
194 { | |
195 case Tok.Identifier: | |
196 return new Identifier(identifier); | |
197 break; | |
198 default: | |
21
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
199 throw new Error("Unexpexted token in Identifier parsing. Got "~identifier.getType, identifier.location); |
1 | 200 } |
201 } | |
202 | |
203 Identifier parseType() | |
204 { | |
205 Token type = lexer.next; | |
206 | |
207 switch(type.type) | |
208 { | |
209 case Tok.Byte, Tok.Ubyte, | |
210 Tok.Short, Tok.Ushort, | |
211 Tok.Int, Tok.Uint, | |
212 Tok.Long, Tok.Ulong, | |
213 Tok.Float, Tok.Double, | |
12
6282db07115f
Added some ekstra tests, and allowed bool as a type
Anders Halager <halager@gmail.com>
parents:
11
diff
changeset
|
214 Tok.Bool, |
1 | 215 Tok.Identifier: |
216 return new Identifier(type); | |
217 break; | |
218 default: | |
219 char[] c = type.getType; | |
220 error("Unexpexted token in Type parsing. Got "~c); | |
221 } | |
222 } | |
223 | |
224 // -- Expression parsing -- // | |
225 private: | |
226 Exp parseExpression(int p = 0) | |
227 { | |
228 auto exp = P(); | |
229 Token next = lexer.peek(); | |
230 BinOp* op = null; | |
231 while ((op = binary(next.type)) != null && op.prec >= p) | |
232 { | |
233 lexer.next(); | |
234 int q = op.leftAssoc? 1 + op.prec : op.prec; | |
235 auto exp2 = parseExpression(q); | |
236 exp = new BinaryExp(op.operator, exp, exp2); | |
237 next = lexer.peek(); | |
238 } | |
239 | |
240 return exp; | |
241 } | |
242 | |
243 Exp P() | |
244 { | |
245 Token next = lexer.next(); | |
246 if (auto op = unary(next.type)) | |
247 return new NegateExp(parseExpression(op.prec)); | |
248 else if (next.type == Tok.OpenParentheses) | |
249 { | |
250 auto e = parseExpression(0); | |
251 require(Tok.CloseParentheses); | |
252 return e; | |
253 } | |
254 else if (next.type == Tok.Identifier) | |
255 { | |
256 switch(lexer.peek.type) | |
257 { | |
258 case Tok.OpenParentheses: | |
259 lexer.next; | |
260 Exp[] args; | |
261 while(lexer.peek.type != Tok.CloseParentheses) | |
262 { | |
263 if(lexer.peek.type == Tok.Comma) | |
264 { | |
265 lexer.next; | |
266 } | |
267 args ~= parseExpression(); | |
268 } | |
269 | |
270 lexer.next(); | |
271 return new CallExp(new Identifier(next), args); | |
272 | |
273 default: | |
274 return new Identifier(next); | |
275 } | |
276 } | |
277 else if (next.type == Tok.Integer) | |
278 return new IntegerLit(next); | |
279 | |
280 Stdout.formatln("{}", next.getType); | |
281 assert(0, "Should not happen"); | |
282 } | |
283 | |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
284 private Stmt[] parseBlockOrSingleStmt() |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
285 { |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
286 Stmt[] stmts; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
287 if (lexer.peek.type == Tok.OpenBrace) |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
288 { |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
289 lexer.next; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
290 while(lexer.peek.type != Tok.CloseBrace) |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
291 stmts ~= parseStatement(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
292 lexer.next; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
293 } |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
294 else |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
295 stmts ~= parseStatement(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
296 |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
297 return stmts; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
298 } |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
299 |
1 | 300 struct UnOp |
301 { | |
302 Tok tokenType; | |
303 int prec; | |
304 } | |
305 | |
306 static UnOp[] _unary = [{Tok.Sub, 4}]; | |
307 UnOp* unary(Tok t) | |
308 { | |
309 foreach (ref op; _unary) | |
310 if (op.tokenType == t) | |
311 return &op; | |
312 return null; | |
313 } | |
314 | |
315 struct BinOp | |
316 { | |
317 Tok tokenType; | |
318 int prec; | |
319 bool leftAssoc; | |
320 BinaryExp.Operator operator; | |
321 } | |
322 | |
323 static BinOp[] _binary = | |
324 [ | |
10
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
325 {Tok.Eq, 2, true, BinaryExp.Operator.Eq}, |
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
326 {Tok.Ne, 2, true, BinaryExp.Operator.Ne}, |
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
327 {Tok.Lt, 2, true, BinaryExp.Operator.Lt}, |
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
328 {Tok.Le, 2, true, BinaryExp.Operator.Le}, |
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
329 {Tok.Gt, 2, true, BinaryExp.Operator.Gt}, |
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
330 {Tok.Ge, 2, true, BinaryExp.Operator.Ge}, |
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
331 |
7
2ce5209f1954
Starting to work on bool support, for now == works
Anders Halager <halager@gmail.com>
parents:
5
diff
changeset
|
332 {Tok.Add, 3, true, BinaryExp.Operator.Add}, |
2ce5209f1954
Starting to work on bool support, for now == works
Anders Halager <halager@gmail.com>
parents:
5
diff
changeset
|
333 {Tok.Sub, 3, true, BinaryExp.Operator.Sub}, |
10
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
334 |
7
2ce5209f1954
Starting to work on bool support, for now == works
Anders Halager <halager@gmail.com>
parents:
5
diff
changeset
|
335 {Tok.Mul, 5, true, BinaryExp.Operator.Mul}, |
2ce5209f1954
Starting to work on bool support, for now == works
Anders Halager <halager@gmail.com>
parents:
5
diff
changeset
|
336 {Tok.Div, 5, true, BinaryExp.Operator.Div} |
1 | 337 ]; |
338 BinOp* binary(Tok t) | |
339 { | |
340 foreach (ref op; _binary) | |
341 if (op.tokenType == t) | |
342 return &op; | |
343 return null; | |
344 } | |
345 | |
346 private: | |
347 | |
348 void require(Tok t) | |
349 { | |
350 if (lexer.peek().type != t) | |
351 error("Unexpexted token: Got '"~lexer.peek.getType~"' Expected '"~typeToString[t]~"'"); | |
352 lexer.next(); | |
353 } | |
354 | |
355 void error(char[] errMsg) | |
356 { | |
357 throw new Exception("Parser error: " ~errMsg); | |
358 } | |
359 | |
360 Lexer lexer; | |
361 } |