]> git.localhorst.tv Git - l2e.git/blob - src/loader/Parser.cpp
removed stupid file headers that eclipse put in
[l2e.git] / src / loader / Parser.cpp
1 #include "Parser.h"
2
3 #include "utility.h"
4
5 #include <auto_ptr.h>
6 #include <fstream>
7
8 using std::auto_ptr;
9 using std::ifstream;
10 using std::string;
11 using std::vector;
12
13 typedef loader::Tokenizer::Token Token;
14
15 namespace loader {
16
17 Parser::Parser(const string &file, ParsedSource &product)
18 : file(file)
19 , dirname(Dirname(file))
20 , in(this->file.c_str())
21 , tok(in)
22 , product(product) {
23         if (!in) {
24                 throw Error(file, 0, "unable to read file");
25         }
26 }
27
28 void Parser::Parse() {
29         while (tok.HasMore()) {
30                 ParseStatement();
31         }
32 }
33
34 void Parser::ParseStatement() {
35         Token t(GetToken());
36         switch (t.type) {
37                 case Token::KEYWORD_EXPORT:
38                         ParseExportDirective();
39                         break;
40                 case Token::KEYWORD_INCLUDE:
41                         ParseIncludeDirective();
42                         break;
43                 case Token::TYPE_NAME:
44                         tok.Putback(t);
45                         {
46                                 Declaration *decl(ProbeDefinition());
47                                 product.AddDeclaration(decl);
48                         }
49                         break;
50                 default:
51                         throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type));
52         }
53 }
54
55 Token Parser::GetToken() try {
56         return tok.GetNext();
57 } catch (Tokenizer::LexerError &e) {
58         throw Error(file, e.Line(), e.what());
59 }
60
61 void Parser::ParseExportDirective() {
62         Token t(GetToken());
63         if (t.type != Token::IDENTIFIER) {
64                 tok.Putback(t);
65                 Declaration *decl(ProbeDefinition());
66                 product.ExportDeclaration(decl);
67         } else {
68                 product.ExportIdentifier(t.str);
69         }
70 }
71
72 void Parser::ParseIncludeDirective() {
73         Token t(GetToken());
74         AssertTokenType(t.type, Token::STRING);
75         Parser sub(CatPath(dirname, t.str), product);
76         sub.Parse();
77 }
78
79 Declaration *Parser::ProbeDefinition() {
80         string typeName(ParseTypeName());
81         string identifier(ParseIdentifier());
82
83         if (tok.HasMore()) {
84                 Token t(GetToken());
85                 tok.Putback(t);
86                 if (BeginOfPropertyList(t)) {
87                         auto_ptr<PropertyList> propertyList(ParsePropertyList());
88                         auto_ptr<Definition> dfn(new Definition(typeName, identifier));
89                         dfn->SetValue(propertyList.release());
90                         product.AddDefinition(dfn.get());
91                         return dfn.release();
92                 } else if (BeginningOfPrimitiveLiteral(t)) {
93                         auto_ptr<Literal> literal(ParseLiteral());
94                         auto_ptr<Definition> dfn(new Definition(typeName, identifier));
95                         dfn->SetValue(literal.release());
96                         product.AddDefinition(dfn.get());
97                         return dfn.release();
98                 }
99         }
100         return new Declaration(typeName, identifier);
101 }
102
103 bool Parser::BeginningOfLiteral(const Token &t) const {
104         switch (t.type) {
105                 case Token::CHEVRON_OPEN:
106                 case Token::COLON:
107                 case Token::BRACKET_OPEN:
108                 case Token::PARENTHESIS_OPEN:
109                 case Token::NUMBER:
110                 case Token::SCRIPT_BEGIN:
111                 case Token::STRING:
112                 case Token::KEYWORD_FALSE:
113                 case Token::KEYWORD_TRUE:
114                 case Token::TYPE_NAME:
115                         return true;
116                 default:
117                         return false;
118         }
119 }
120
121 bool Parser::BeginningOfPrimitiveLiteral(const Token &t) const {
122         switch (t.type) {
123                 case Token::CHEVRON_OPEN:
124                 case Token::COLON:
125                 case Token::BRACKET_OPEN:
126                 case Token::PARENTHESIS_OPEN:
127                 case Token::NUMBER:
128                 case Token::STRING:
129                 case Token::KEYWORD_FALSE:
130                 case Token::KEYWORD_TRUE:
131                         return true;
132                 default:
133                         return false;
134         }
135 }
136
137 bool Parser::BeginOfPropertyList(const Token &t) const {
138         return t.type == Token::ANGLE_BRACKET_OPEN;
139 }
140
141 bool Parser::BeginningOfScriptLiteral(const Token &t) const {
142         return t.type == Token::SCRIPT_BEGIN;
143 }
144
145 Definition *Parser::ParseDefinition() {
146         string typeName(ParseTypeName());
147         string identifier(ParseIdentifier());
148
149         Token t(GetToken());
150         tok.Putback(t);
151         if (BeginOfPropertyList(t)) {
152                 PropertyList *propertyList(ParsePropertyList());
153                 Definition *dfn(new Definition(typeName, identifier));
154                 dfn->SetValue(propertyList);
155                 return dfn;
156         } else if (BeginningOfLiteral(t)) {
157                 Literal *literal(ParseLiteral());
158                 Definition *dfn(new Definition(typeName, identifier));
159                 dfn->SetValue(literal);
160                 return dfn;
161         } else {
162                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
163         }
164 }
165
166 string Parser::ParseIdentifier() {
167         Token t(GetToken());
168         AssertTokenType(t.type, Token::IDENTIFIER);
169         return t.str;
170 }
171
172 string Parser::ParseTypeName() {
173         Token t(GetToken());
174         AssertTokenType(t.type, Token::TYPE_NAME);
175         return t.str;
176 }
177
178 PropertyList *Parser::ParsePropertyList() {
179         Token t(GetToken());
180         AssertTokenType(t.type, Token::ANGLE_BRACKET_OPEN);
181
182         auto_ptr<PropertyList> props(new PropertyList);
183
184         while (t.type != Token::ANGLE_BRACKET_CLOSE) {
185                 Token name(GetToken());
186                 AssertTokenType(name.type, Token::IDENTIFIER);
187
188                 t = GetToken();
189                 AssertTokenType(t.type, Token::COLON);
190
191                 Value *value(ParseValue());
192                 props->SetProperty(name.str, value);
193
194                 t = GetToken();
195                 if (t.type != Token::ANGLE_BRACKET_CLOSE && t.type != Token::COMMA) {
196                         throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }");
197                 }
198         }
199
200         return props.release();
201 }
202
203 Value *Parser::ParseValue() {
204         Token t(GetToken());
205         if (t.type == Token::IDENTIFIER) {
206                 return new Value(t.str);
207         } else if (BeginningOfLiteral(t)) {
208                 tok.Putback(t);
209                 Literal *literal(ParseLiteral());
210                 return new Value(literal);
211         } else {
212                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
213         }
214 }
215
216 Literal *Parser::ParseLiteral() {
217         Token t(GetToken());
218         if (t.type == Token::TYPE_NAME) {
219                 PropertyList *props(ParsePropertyList());
220                 return new Literal(t.str, props);
221         } else if (BeginningOfScriptLiteral(t)) {
222                 tok.Putback(t);
223                 return ParseScript();
224         } else if (BeginningOfPrimitiveLiteral(t)) {
225                 switch (t.type) {
226                         case Token::CHEVRON_OPEN:
227                                 tok.Putback(t);
228                                 return ParseVector();
229                         case Token::COLON:
230                                 t = GetToken();
231                                 AssertTokenType(t.type, Token::STRING);
232                                 return new Literal(dirname, t.str);
233                         case Token::BRACKET_OPEN:
234                                 tok.Putback(t);
235                                 return ParseArray();
236                         case Token::PARENTHESIS_OPEN:
237                                 tok.Putback(t);
238                                 return ParseColor();
239                         case Token::NUMBER:
240                                 return new Literal(t.number);
241                         case Token::STRING:
242                                 return new Literal(t.str);
243                         case Token::KEYWORD_FALSE:
244                                 return new Literal(false);
245                         case Token::KEYWORD_TRUE:
246                                 return new Literal(true);
247                         default:
248                                 throw std::logic_error("literal switch reached impossible default branch oO");
249                 }
250         } else {
251                 throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
252         }
253 }
254
255 Literal *Parser::ParseArray() {
256         Token t(GetToken());
257         AssertTokenType(t.type, Token::BRACKET_OPEN);
258
259         Token probe(GetToken());
260
261         if (probe.type == Token::TYPE_NAME) {
262                 vector<PropertyList *> values;
263                 while (t.type != Token::BRACKET_CLOSE) {
264                         PropertyList *value(ParsePropertyList());
265                         values.push_back(value);
266
267                         t = GetToken();
268                         if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
269                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
270                         }
271                 }
272                 return new Literal(probe.str, values);
273         } else {
274                 tok.Putback(probe);
275
276                 vector<Value *> values;
277                 while (t.type != Token::BRACKET_CLOSE) {
278                         Value *value(ParseValue());
279                         values.push_back(value);
280
281                         t = GetToken();
282                         if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
283                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
284                         }
285                 }
286                 return new Literal(values);
287         }
288 }
289
290 Literal *Parser::ParseColor() {
291         string msg("error parsing color");
292         Token t(GetToken());
293         AssertTokenType(t.type, Token::PARENTHESIS_OPEN, msg);
294
295         Token red(GetToken());
296         AssertTokenType(red.type, Token::NUMBER, "error parsing red component of color");
297
298         t = GetToken();
299         AssertTokenType(t.type, Token::COMMA, msg);
300
301         Token green(GetToken());
302         AssertTokenType(green.type, Token::NUMBER, "error parsing green component of color");
303
304         t = GetToken();
305         AssertTokenType(t.type, Token::COMMA, msg);
306
307         Token blue(GetToken());
308         AssertTokenType(blue.type, Token::NUMBER, "error parsing blue component of color");
309
310         t = GetToken();
311         if (t.type == Token::PARENTHESIS_CLOSE) {
312                 return new Literal(red.number, green.number, blue.number);
313         } else if (t.type != Token::COMMA) {
314                 Token alpha(GetToken());
315                 AssertTokenType(alpha.type, Token::NUMBER, "error parsing alpha component of color");
316
317                 t = GetToken();
318                 AssertTokenType(t.type, Token::PARENTHESIS_CLOSE, msg);
319
320                 return new Literal(red.number, green.number, blue.number, alpha.number);
321         } else {
322                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
323         }
324 }
325
326 Literal *Parser::ParseVector() {
327         std::string msg("error parsing vector");
328         Token t(GetToken());
329         AssertTokenType(t.type, Token::CHEVRON_OPEN, msg);
330
331         Token x(GetToken());
332         AssertTokenType(x.type, Token::NUMBER, "error parsing x component of vector");
333
334         t = GetToken();
335         AssertTokenType(t.type, Token::COMMA, msg);
336
337         Token y(GetToken());
338         AssertTokenType(y.type, Token::NUMBER, "error parsing y component of vector");
339
340         t = GetToken();
341         AssertTokenType(t.type, Token::CHEVRON_CLOSE, msg);
342
343         return new Literal(x.number, y.number);
344 }
345
346 Literal *Parser::ParseScript() {
347         std::string msg("error parsing script");
348         Token t(GetToken());
349         AssertTokenType(t.type, Token::SCRIPT_BEGIN, msg);
350
351         t = GetToken();
352         vector<ScriptToken *> script;
353         try {
354                 while (t.type != Token::SCRIPT_END) {
355                         if (BeginningOfPrimitiveLiteral(t)) {
356                                 tok.Putback(t);
357                                 script.push_back(new ScriptToken(ParseLiteral()));
358                         } else {
359                                 switch (t.type) {
360                                         case Token::COMMAND: {
361                                                 Token t2(GetToken());
362                                                 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
363                                                 script.push_back(new ScriptToken(t2.str, ScriptToken::COMMAND));
364                                                 break;
365                                         }
366                                         case Token::IDENTIFIER: {
367                                                 Token t2(GetToken());
368                                                 if (t2.type == Token::COLON) {
369                                                         script.push_back(new ScriptToken(t.str, ScriptToken::LABEL));
370                                                 } else {
371                                                         tok.Putback(t2);
372                                                         script.push_back(new ScriptToken(t.str, ScriptToken::IDENTIFIER));
373                                                 }
374                                                 break;
375                                         }
376                                         case Token::REGISTER: {
377                                                 Token t2(GetToken());
378                                                 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
379                                                 script.push_back(new ScriptToken(t2.str, ScriptToken::REGISTER));
380                                                 break;
381                                         }
382                                         default:
383                                                 throw Error(file, tok.Line(), string("unexpected token in script: ") + TokenTypeToString(t.type));
384                                 }
385                         }
386                         t = GetToken();
387                 }
388         } catch (...) {
389                 for (vector<ScriptToken *>::const_iterator i(script.begin()), end(script.end()); i != end; ++i) {
390                         delete *i;
391                 }
392                 throw;
393         }
394         return new Literal(script);
395 }
396
397
398 void Parser::AssertTokenType(Token::Type actual, Token::Type expected) {
399         if (expected != actual) {
400                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
401         }
402 }
403
404 void Parser::AssertTokenType(Token::Type actual, Token::Type expected, const string &msg) {
405         if (expected != actual) {
406                 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
407         }
408 }
409
410 }