Mercurial > projects > dang
annotate parser/Parser.d @ 22:e331e4e816e4
now handling structs to some extend
author | johnsen@johnsen-laptop |
---|---|
date | Fri, 18 Apr 2008 23:45:45 +0200 |
parents | 0fb2d13dce37 |
children | 69464d465284 |
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; | |
22 | 78 case Tok.Struct: |
79 Token iden = lexer.next; | |
80 switch(iden.type) | |
81 { | |
82 case Tok.Identifier: | |
83 Identifier identifier = new Identifier(iden); | |
84 return new StructDecl (identifier, parseStruct()); | |
85 default: | |
86 throw new Error("Expected struct identifier, but got "~iden.getType, | |
87 iden.location); | |
88 } | |
1 | 89 case Tok.EOF: |
90 return null; | |
91 default: | |
92 char[] c = t.getType; | |
93 error("Unexpexted token "~c~" at line "~Integer.toString(__LINE__)); | |
94 } | |
95 } | |
96 | |
22 | 97 VarDecl[] parseStruct() |
98 { | |
99 VarDecl[] varDecls; | |
100 require(Tok.OpenBrace); | |
101 while(lexer.peek.type != Tok.CloseBrace) | |
102 { | |
103 varDecls ~= cast(VarDecl)parseDecl; | |
104 } | |
105 | |
106 require(Tok.CloseBrace); | |
107 return varDecls; | |
108 } | |
109 | |
1 | 110 Stmt parseStatement() |
111 { | |
112 Token t = lexer.peek; | |
113 | |
114 switch(t.type) | |
115 { | |
116 case Tok.Return: | |
117 lexer.next; | |
118 auto ret = new ReturnStmt(); | |
119 ret.exp = parseExpression(); | |
120 require(Tok.Seperator); | |
121 return ret; | |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
122 |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
123 case Tok.If: |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
124 lexer.next; |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
125 require(Tok.OpenParentheses); |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
126 auto condition = parseExpression(); |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
127 require(Tok.CloseParentheses); |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
128 |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
129 auto then_body = parseBlockOrSingleStmt(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
130 |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
131 Stmt[] else_body; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
132 if (lexer.peek.type == Tok.Else) |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
133 { |
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
134 lexer.next; |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
135 else_body = parseBlockOrSingleStmt(); |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
136 } |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
137 |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
138 return new IfStmt(condition, then_body, else_body); |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
139 |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
140 case Tok.While: |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
141 lexer.next; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
142 require(Tok.OpenParentheses); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
143 auto condition = parseExpression(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
144 require(Tok.CloseParentheses); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
145 return new WhileStmt(condition, parseBlockOrSingleStmt()); |
5
2c5a8f4c254a
Added very simple if support.
Anders Halager <halager@gmail.com>
parents:
1
diff
changeset
|
146 |
1 | 147 case Tok.Identifier: |
148 Token n = lexer.peek(1); | |
149 switch(n.type) | |
150 { | |
151 case Tok.Assign: | |
152 lexer.next; | |
153 lexer.next; | |
154 auto stmt = new ExpStmt(new AssignExp(new Identifier(t), parseExpression())); | |
155 require(Tok.Seperator); | |
156 return stmt; | |
157 break; | |
22 | 158 case Tok.Identifier: |
159 auto decl = new DeclStmt(parseDecl()); | |
160 return decl; | |
1 | 161 |
162 default: | |
163 auto e = new ExpStmt(parseExpression()); | |
164 require(Tok.Seperator); | |
165 return e; | |
166 | |
167 } | |
168 break; | |
169 | |
170 default: | |
171 auto decl = new DeclStmt(parseDecl()); | |
172 //require(Tok.Seperator); | |
173 return decl; | |
174 } | |
175 return new Stmt(); | |
176 } | |
177 | |
178 FuncDecl parseFunc(Identifier type, Identifier identifier) | |
179 { | |
180 VarDecl[] funcArgs = parseFuncArgs(); | |
181 | |
182 lexer.next; // Remove the "{" | |
183 | |
184 Stmt[] statements; | |
185 | |
186 while(lexer.peek.type != Tok.CloseBrace) | |
187 statements ~= parseStatement(); | |
188 | |
189 lexer.next; // Remove "}" | |
190 | |
191 return new FuncDecl(type, identifier, funcArgs, statements); | |
192 } | |
193 | |
194 VarDecl[] parseFuncArgs() | |
195 { | |
196 lexer.next; // Remove the "(" token. | |
197 | |
198 VarDecl[] funcArgs; | |
199 | |
200 while(lexer.peek.type != Tok.CloseParentheses) | |
201 { | |
21
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
202 auto t = parseType; |
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
203 auto i = parseIdentifier; |
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
204 funcArgs ~= new VarDecl(t, i); |
1 | 205 |
206 if(lexer.peek.type == Tok.Comma) | |
207 lexer.next; | |
208 } | |
209 | |
210 lexer.next; // Remove the ")" | |
211 | |
212 return funcArgs; | |
213 } | |
214 | |
215 Identifier parseIdentifier() | |
216 { | |
217 Token identifier = lexer.next; | |
218 | |
219 switch(identifier.type) | |
220 { | |
221 case Tok.Identifier: | |
222 return new Identifier(identifier); | |
223 break; | |
224 default: | |
21
0fb2d13dce37
Now working with gdc also (gdc use reverse paremeter validating on function calls)
johnsen@johnsen-laptop
parents:
12
diff
changeset
|
225 throw new Error("Unexpexted token in Identifier parsing. Got "~identifier.getType, identifier.location); |
1 | 226 } |
227 } | |
228 | |
229 Identifier parseType() | |
230 { | |
231 Token type = lexer.next; | |
232 | |
233 switch(type.type) | |
234 { | |
235 case Tok.Byte, Tok.Ubyte, | |
236 Tok.Short, Tok.Ushort, | |
237 Tok.Int, Tok.Uint, | |
238 Tok.Long, Tok.Ulong, | |
239 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
|
240 Tok.Bool, |
1 | 241 Tok.Identifier: |
242 return new Identifier(type); | |
243 break; | |
244 default: | |
245 char[] c = type.getType; | |
246 error("Unexpexted token in Type parsing. Got "~c); | |
247 } | |
248 } | |
249 | |
250 // -- Expression parsing -- // | |
251 private: | |
252 Exp parseExpression(int p = 0) | |
253 { | |
254 auto exp = P(); | |
255 Token next = lexer.peek(); | |
256 BinOp* op = null; | |
257 while ((op = binary(next.type)) != null && op.prec >= p) | |
258 { | |
259 lexer.next(); | |
260 int q = op.leftAssoc? 1 + op.prec : op.prec; | |
261 auto exp2 = parseExpression(q); | |
262 exp = new BinaryExp(op.operator, exp, exp2); | |
263 next = lexer.peek(); | |
264 } | |
265 | |
266 return exp; | |
267 } | |
268 | |
269 Exp P() | |
270 { | |
271 Token next = lexer.next(); | |
272 if (auto op = unary(next.type)) | |
273 return new NegateExp(parseExpression(op.prec)); | |
274 else if (next.type == Tok.OpenParentheses) | |
275 { | |
276 auto e = parseExpression(0); | |
277 require(Tok.CloseParentheses); | |
278 return e; | |
279 } | |
280 else if (next.type == Tok.Identifier) | |
281 { | |
282 switch(lexer.peek.type) | |
283 { | |
284 case Tok.OpenParentheses: | |
285 lexer.next; | |
286 Exp[] args; | |
287 while(lexer.peek.type != Tok.CloseParentheses) | |
288 { | |
289 if(lexer.peek.type == Tok.Comma) | |
290 { | |
291 lexer.next; | |
292 } | |
293 args ~= parseExpression(); | |
294 } | |
295 | |
296 lexer.next(); | |
297 return new CallExp(new Identifier(next), args); | |
298 | |
299 default: | |
300 return new Identifier(next); | |
301 } | |
302 } | |
303 else if (next.type == Tok.Integer) | |
304 return new IntegerLit(next); | |
305 | |
306 Stdout.formatln("{}", next.getType); | |
307 assert(0, "Should not happen"); | |
308 } | |
309 | |
11
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
310 private Stmt[] parseBlockOrSingleStmt() |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
311 { |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
312 Stmt[] stmts; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
313 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
|
314 { |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
315 lexer.next; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
316 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
|
317 stmts ~= parseStatement(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
318 lexer.next; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
319 } |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
320 else |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
321 stmts ~= parseStatement(); |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
322 |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
323 return stmts; |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
324 } |
642c6a998fd9
Support for while statements and fixed scope for if
Anders Halager <halager@gmail.com>
parents:
10
diff
changeset
|
325 |
1 | 326 struct UnOp |
327 { | |
328 Tok tokenType; | |
329 int prec; | |
330 } | |
331 | |
332 static UnOp[] _unary = [{Tok.Sub, 4}]; | |
333 UnOp* unary(Tok t) | |
334 { | |
335 foreach (ref op; _unary) | |
336 if (op.tokenType == t) | |
337 return &op; | |
338 return null; | |
339 } | |
340 | |
341 struct BinOp | |
342 { | |
343 Tok tokenType; | |
344 int prec; | |
345 bool leftAssoc; | |
346 BinaryExp.Operator operator; | |
347 } | |
348 | |
349 static BinOp[] _binary = | |
350 [ | |
10
2f493057cf17
Some support for the rest of the boolean operators
Anders Halager <halager@gmail.com>
parents:
7
diff
changeset
|
351 {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
|
352 {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
|
353 {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
|
354 {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
|
355 {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
|
356 {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
|
357 |
7
2ce5209f1954
Starting to work on bool support, for now == works
Anders Halager <halager@gmail.com>
parents:
5
diff
changeset
|
358 {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
|
359 {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
|
360 |
7
2ce5209f1954
Starting to work on bool support, for now == works
Anders Halager <halager@gmail.com>
parents:
5
diff
changeset
|
361 {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
|
362 {Tok.Div, 5, true, BinaryExp.Operator.Div} |
1 | 363 ]; |
364 BinOp* binary(Tok t) | |
365 { | |
366 foreach (ref op; _binary) | |
367 if (op.tokenType == t) | |
368 return &op; | |
369 return null; | |
370 } | |
371 | |
372 private: | |
373 | |
374 void require(Tok t) | |
375 { | |
376 if (lexer.peek().type != t) | |
377 error("Unexpexted token: Got '"~lexer.peek.getType~"' Expected '"~typeToString[t]~"'"); | |
378 lexer.next(); | |
379 } | |
380 | |
381 void error(char[] errMsg) | |
382 { | |
383 throw new Exception("Parser error: " ~errMsg); | |
384 } | |
385 | |
386 Lexer lexer; | |
387 } |