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