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