13 typedef loader::Tokenizer::Token Token;
17 Parser::Parser(const string &file, ParsedSource &product)
19 , dirname(Dirname(file))
20 , in(this->file.c_str())
24 throw Error(file, 0, "unable to read file");
28 void Parser::Parse() {
29 while (tok.HasMore()) {
34 void Parser::ParseStatement() {
37 case Token::KEYWORD_EXPORT:
38 ParseExportDirective();
40 case Token::KEYWORD_INCLUDE:
41 ParseIncludeDirective();
43 case Token::TYPE_NAME:
46 Declaration *decl(ProbeDefinition());
47 product.AddDeclaration(decl);
51 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type));
55 Token Parser::GetToken() try {
57 } catch (Tokenizer::LexerError &e) {
58 throw Error(file, e.Line(), e.what());
61 void Parser::ParseExportDirective() {
63 if (t.type != Token::IDENTIFIER) {
65 Declaration *decl(ProbeDefinition());
66 product.ExportDeclaration(decl);
68 product.ExportIdentifier(t.str);
72 void Parser::ParseIncludeDirective() {
74 AssertTokenType(t.type, Token::STRING);
75 Parser sub(CatPath(dirname, t.str), product);
79 Declaration *Parser::ProbeDefinition() {
80 string typeName(ParseTypeName());
81 string identifier(ParseIdentifier());
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());
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());
100 return new Declaration(typeName, identifier);
103 bool Parser::BeginningOfLiteral(const Token &t) const {
105 case Token::CHEVRON_OPEN:
107 case Token::BRACKET_OPEN:
108 case Token::PARENTHESIS_OPEN:
110 case Token::SCRIPT_BEGIN:
112 case Token::KEYWORD_FALSE:
113 case Token::KEYWORD_TRUE:
114 case Token::TYPE_NAME:
121 bool Parser::BeginningOfPrimitiveLiteral(const Token &t) const {
123 case Token::CHEVRON_OPEN:
125 case Token::BRACKET_OPEN:
126 case Token::PARENTHESIS_OPEN:
129 case Token::KEYWORD_FALSE:
130 case Token::KEYWORD_TRUE:
137 bool Parser::BeginOfPropertyList(const Token &t) const {
138 return t.type == Token::ANGLE_BRACKET_OPEN;
141 bool Parser::BeginningOfScriptLiteral(const Token &t) const {
142 return t.type == Token::SCRIPT_BEGIN;
145 Definition *Parser::ParseDefinition() {
146 string typeName(ParseTypeName());
147 string identifier(ParseIdentifier());
151 if (BeginOfPropertyList(t)) {
152 PropertyList *propertyList(ParsePropertyList());
153 Definition *dfn(new Definition(typeName, identifier));
154 dfn->SetValue(propertyList);
156 } else if (BeginningOfLiteral(t)) {
157 Literal *literal(ParseLiteral());
158 Definition *dfn(new Definition(typeName, identifier));
159 dfn->SetValue(literal);
162 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
166 string Parser::ParseIdentifier() {
168 AssertTokenType(t.type, Token::IDENTIFIER);
172 string Parser::ParseTypeName() {
174 AssertTokenType(t.type, Token::TYPE_NAME);
178 PropertyList *Parser::ParsePropertyList() {
180 AssertTokenType(t.type, Token::ANGLE_BRACKET_OPEN);
182 auto_ptr<PropertyList> props(new PropertyList);
184 while (t.type != Token::ANGLE_BRACKET_CLOSE) {
185 Token name(GetToken());
186 AssertTokenType(name.type, Token::IDENTIFIER);
189 AssertTokenType(t.type, Token::COLON);
191 Value *value(ParseValue());
192 props->SetProperty(name.str, value);
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 }");
200 return props.release();
203 Value *Parser::ParseValue() {
205 if (t.type == Token::IDENTIFIER) {
206 return new Value(t.str);
207 } else if (BeginningOfLiteral(t)) {
209 Literal *literal(ParseLiteral());
210 return new Value(literal);
212 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
216 Literal *Parser::ParseLiteral() {
218 if (t.type == Token::TYPE_NAME) {
219 PropertyList *props(ParsePropertyList());
220 return new Literal(t.str, props);
221 } else if (BeginningOfScriptLiteral(t)) {
223 return ParseScript();
224 } else if (BeginningOfPrimitiveLiteral(t)) {
226 case Token::CHEVRON_OPEN:
228 return ParseVector();
231 AssertTokenType(t.type, Token::STRING);
232 return new Literal(dirname, t.str);
233 case Token::BRACKET_OPEN:
236 case Token::PARENTHESIS_OPEN:
240 return new Literal(t.number);
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);
248 throw std::logic_error("literal switch reached impossible default branch oO");
251 throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
255 Literal *Parser::ParseArray() {
257 AssertTokenType(t.type, Token::BRACKET_OPEN);
259 Token probe(GetToken());
261 if (probe.type == Token::TYPE_NAME) {
264 if (t.type == Token::ANGLE_BRACKET_OPEN) {
265 vector<PropertyList *> values;
266 while (t.type != Token::BRACKET_CLOSE) {
267 PropertyList *value(ParsePropertyList());
268 values.push_back(value);
271 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
272 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
275 return new Literal(probe.str, values);
277 vector<string> values;
278 while (t.type != Token::BRACKET_CLOSE) {
279 string value(ParseIdentifier());
280 values.push_back(value);
283 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
284 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
287 return new Literal(probe.str, values);
292 vector<Value *> values;
293 while (t.type != Token::BRACKET_CLOSE) {
294 Value *value(ParseValue());
295 values.push_back(value);
298 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
299 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
302 return new Literal(values);
306 Literal *Parser::ParseColor() {
307 string msg("error parsing color");
309 AssertTokenType(t.type, Token::PARENTHESIS_OPEN, msg);
311 Token red(GetToken());
312 AssertTokenType(red.type, Token::NUMBER, "error parsing red component of color");
315 AssertTokenType(t.type, Token::COMMA, msg);
317 Token green(GetToken());
318 AssertTokenType(green.type, Token::NUMBER, "error parsing green component of color");
321 AssertTokenType(t.type, Token::COMMA, msg);
323 Token blue(GetToken());
324 AssertTokenType(blue.type, Token::NUMBER, "error parsing blue component of color");
327 if (t.type == Token::PARENTHESIS_CLOSE) {
328 return new Literal(red.number, green.number, blue.number);
329 } else if (t.type != Token::COMMA) {
330 Token alpha(GetToken());
331 AssertTokenType(alpha.type, Token::NUMBER, "error parsing alpha component of color");
334 AssertTokenType(t.type, Token::PARENTHESIS_CLOSE, msg);
336 return new Literal(red.number, green.number, blue.number, alpha.number);
338 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
342 Literal *Parser::ParseVector() {
343 std::string msg("error parsing vector");
345 AssertTokenType(t.type, Token::CHEVRON_OPEN, msg);
348 AssertTokenType(x.type, Token::NUMBER, "error parsing x component of vector");
351 AssertTokenType(t.type, Token::COMMA, msg);
354 AssertTokenType(y.type, Token::NUMBER, "error parsing y component of vector");
357 AssertTokenType(t.type, Token::CHEVRON_CLOSE, msg);
359 return new Literal(x.number, y.number);
362 Literal *Parser::ParseScript() {
363 std::string msg("error parsing script");
365 AssertTokenType(t.type, Token::SCRIPT_BEGIN, msg);
368 vector<ScriptToken *> script;
370 while (t.type != Token::SCRIPT_END) {
371 if (BeginningOfPrimitiveLiteral(t)) {
373 script.push_back(new ScriptToken(ParseLiteral()));
376 case Token::COMMAND: {
377 Token t2(GetToken());
378 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
379 script.push_back(new ScriptToken(t2.str, ScriptToken::COMMAND));
382 case Token::IDENTIFIER: {
383 Token t2(GetToken());
384 if (t2.type == Token::COLON) {
385 script.push_back(new ScriptToken(t.str, ScriptToken::LABEL));
388 script.push_back(new ScriptToken(t.str, ScriptToken::IDENTIFIER));
392 case Token::REGISTER: {
393 Token t2(GetToken());
394 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
395 script.push_back(new ScriptToken(t2.str, ScriptToken::REGISTER));
399 throw Error(file, tok.Line(), string("unexpected token in script: ") + TokenTypeToString(t.type));
405 for (vector<ScriptToken *>::const_iterator i(script.begin()), end(script.end()); i != end; ++i) {
410 return new Literal(script);
414 void Parser::AssertTokenType(Token::Type actual, Token::Type expected) {
415 if (expected != actual) {
416 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
420 void Parser::AssertTokenType(Token::Type actual, Token::Type expected, const string &msg) {
421 if (expected != actual) {
422 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));