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) {
262 vector<PropertyList *> values;
263 while (t.type != Token::BRACKET_CLOSE) {
264 PropertyList *value(ParsePropertyList());
265 values.push_back(value);
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 ]");
272 return new Literal(probe.str, values);
276 vector<Value *> values;
277 while (t.type != Token::BRACKET_CLOSE) {
278 Value *value(ParseValue());
279 values.push_back(value);
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 ]");
286 return new Literal(values);
290 Literal *Parser::ParseColor() {
291 string msg("error parsing color");
293 AssertTokenType(t.type, Token::PARENTHESIS_OPEN, msg);
295 Token red(GetToken());
296 AssertTokenType(red.type, Token::NUMBER, "error parsing red component of color");
299 AssertTokenType(t.type, Token::COMMA, msg);
301 Token green(GetToken());
302 AssertTokenType(green.type, Token::NUMBER, "error parsing green component of color");
305 AssertTokenType(t.type, Token::COMMA, msg);
307 Token blue(GetToken());
308 AssertTokenType(blue.type, Token::NUMBER, "error parsing blue component of color");
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");
318 AssertTokenType(t.type, Token::PARENTHESIS_CLOSE, msg);
320 return new Literal(red.number, green.number, blue.number, alpha.number);
322 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
326 Literal *Parser::ParseVector() {
327 std::string msg("error parsing vector");
329 AssertTokenType(t.type, Token::CHEVRON_OPEN, msg);
332 AssertTokenType(x.type, Token::NUMBER, "error parsing x component of vector");
335 AssertTokenType(t.type, Token::COMMA, msg);
338 AssertTokenType(y.type, Token::NUMBER, "error parsing y component of vector");
341 AssertTokenType(t.type, Token::CHEVRON_CLOSE, msg);
343 return new Literal(x.number, y.number);
346 Literal *Parser::ParseScript() {
347 std::string msg("error parsing script");
349 AssertTokenType(t.type, Token::SCRIPT_BEGIN, msg);
352 vector<ScriptToken *> script;
354 while (t.type != Token::SCRIPT_END) {
355 if (BeginningOfPrimitiveLiteral(t)) {
357 script.push_back(new ScriptToken(ParseLiteral()));
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));
366 case Token::IDENTIFIER: {
367 Token t2(GetToken());
368 if (t2.type == Token::COLON) {
369 script.push_back(new ScriptToken(t.str, ScriptToken::LABEL));
372 script.push_back(new ScriptToken(t.str, ScriptToken::IDENTIFIER));
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));
383 throw Error(file, tok.Line(), string("unexpected token in script: ") + TokenTypeToString(t.type));
389 for (vector<ScriptToken *>::const_iterator i(script.begin()), end(script.end()); i != end; ++i) {
394 return new Literal(script);
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));
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));