3 #include "ParsedSource.h"
16 typedef loader::Tokenizer::Token Token;
20 Parser::Parser(const string &file, ParsedSource &product)
22 , dirname(Dirname(file))
23 , in(this->file.c_str())
27 throw Error(file, 0, "unable to read file");
31 void Parser::Parse() {
32 while (tok.HasMore()) {
37 void Parser::ParseStatement() {
40 case Token::KEYWORD_EXPORT:
41 ParseExportDirective();
43 case Token::KEYWORD_INCLUDE:
44 ParseIncludeDirective();
46 case Token::TYPE_NAME:
49 Declaration *decl(ProbeDefinition());
50 product.AddDeclaration(decl);
54 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type));
58 Token Parser::GetToken() try {
60 } catch (Tokenizer::LexerError &e) {
61 throw Error(file, e.Line(), e.what());
64 void Parser::ParseExportDirective() {
66 if (t.type != Token::IDENTIFIER) {
68 Declaration *decl(ProbeDefinition());
69 product.ExportDeclaration(decl);
71 product.ExportIdentifier(t.str);
75 void Parser::ParseIncludeDirective() {
77 AssertTokenType(t.type, Token::STRING);
78 Parser sub(CatPath(dirname, t.str), product);
82 Declaration *Parser::ProbeDefinition() {
83 string typeName(ParseTypeName());
84 string identifier(ParseIdentifier());
89 if (BeginOfPropertyList(t)) {
90 auto_ptr<PropertyList> propertyList(ParsePropertyList());
91 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
92 dfn->SetValue(propertyList.release());
93 product.AddDefinition(dfn.get());
95 } else if (BeginningOfPrimitiveLiteral(t)) {
96 auto_ptr<Literal> literal(ParseLiteral());
97 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
98 dfn->SetValue(literal.release());
99 product.AddDefinition(dfn.get());
100 return dfn.release();
103 return new Declaration(typeName, identifier);
106 bool Parser::BeginningOfLiteral(const Token &t) const {
108 case Token::CHEVRON_OPEN:
110 case Token::BRACKET_OPEN:
111 case Token::PARENTHESIS_OPEN:
113 case Token::SCRIPT_BEGIN:
115 case Token::KEYWORD_FALSE:
116 case Token::KEYWORD_TRUE:
117 case Token::TYPE_NAME:
124 bool Parser::BeginningOfPrimitiveLiteral(const Token &t) const {
126 case Token::CHEVRON_OPEN:
128 case Token::BRACKET_OPEN:
129 case Token::PARENTHESIS_OPEN:
132 case Token::KEYWORD_FALSE:
133 case Token::KEYWORD_TRUE:
140 bool Parser::BeginOfPropertyList(const Token &t) const {
141 return t.type == Token::ANGLE_BRACKET_OPEN;
144 bool Parser::BeginningOfScriptLiteral(const Token &t) const {
145 return t.type == Token::SCRIPT_BEGIN;
148 Definition *Parser::ParseDefinition() {
149 string typeName(ParseTypeName());
150 string identifier(ParseIdentifier());
154 if (BeginOfPropertyList(t)) {
155 PropertyList *propertyList(ParsePropertyList());
156 Definition *dfn(new Definition(typeName, identifier));
157 dfn->SetValue(propertyList);
159 } else if (BeginningOfLiteral(t)) {
160 Literal *literal(ParseLiteral());
161 Definition *dfn(new Definition(typeName, identifier));
162 dfn->SetValue(literal);
165 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
169 string Parser::ParseIdentifier() {
171 AssertTokenType(t.type, Token::IDENTIFIER);
175 string Parser::ParseTypeName() {
177 AssertTokenType(t.type, Token::TYPE_NAME);
181 PropertyList *Parser::ParsePropertyList() {
183 AssertTokenType(t.type, Token::ANGLE_BRACKET_OPEN);
185 auto_ptr<PropertyList> props(new PropertyList);
187 while (t.type != Token::ANGLE_BRACKET_CLOSE) {
188 Token name(GetToken());
189 AssertTokenType(name.type, Token::IDENTIFIER);
192 AssertTokenType(t.type, Token::COLON);
194 Value *value(ParseValue());
195 props->SetProperty(name.str, value);
198 if (t.type != Token::ANGLE_BRACKET_CLOSE && t.type != Token::COMMA) {
199 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }");
203 return props.release();
206 Value *Parser::ParseValue() {
208 if (t.type == Token::IDENTIFIER) {
209 return new Value(t.str);
210 } else if (BeginningOfLiteral(t)) {
212 Literal *literal(ParseLiteral());
213 return new Value(literal);
215 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
219 Literal *Parser::ParseLiteral() {
221 if (t.type == Token::TYPE_NAME) {
222 PropertyList *props(ParsePropertyList());
223 return new Literal(t.str, props);
224 } else if (BeginningOfScriptLiteral(t)) {
226 return ParseScript();
227 } else if (BeginningOfPrimitiveLiteral(t)) {
229 case Token::CHEVRON_OPEN:
231 return ParseVector();
234 AssertTokenType(t.type, Token::STRING);
235 return new Literal(dirname, t.str);
236 case Token::BRACKET_OPEN:
239 case Token::PARENTHESIS_OPEN:
243 return new Literal(t.number);
245 return new Literal(t.str);
246 case Token::KEYWORD_FALSE:
247 return new Literal(false);
248 case Token::KEYWORD_TRUE:
249 return new Literal(true);
251 throw std::logic_error("literal switch reached impossible default branch oO");
254 throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
258 Literal *Parser::ParseArray() {
260 AssertTokenType(t.type, Token::BRACKET_OPEN);
262 Token probe(GetToken());
264 if (probe.type == Token::TYPE_NAME) {
267 if (t.type == Token::ANGLE_BRACKET_OPEN) {
268 vector<PropertyList *> values;
269 while (t.type != Token::BRACKET_CLOSE) {
270 PropertyList *value(ParsePropertyList());
271 values.push_back(value);
274 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
275 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
278 return new Literal(probe.str, values);
280 vector<string> values;
281 while (t.type != Token::BRACKET_CLOSE) {
282 string value(ParseIdentifier());
283 values.push_back(value);
286 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
287 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
290 return new Literal(probe.str, values);
295 vector<Value *> values;
296 while (t.type != Token::BRACKET_CLOSE) {
297 Value *value(ParseValue());
298 values.push_back(value);
301 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
302 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
305 return new Literal(values);
309 Literal *Parser::ParseColor() {
310 string msg("error parsing color");
312 AssertTokenType(t.type, Token::PARENTHESIS_OPEN, msg);
314 Token red(GetToken());
315 AssertTokenType(red.type, Token::NUMBER, "error parsing red component of color");
318 AssertTokenType(t.type, Token::COMMA, msg);
320 Token green(GetToken());
321 AssertTokenType(green.type, Token::NUMBER, "error parsing green component of color");
324 AssertTokenType(t.type, Token::COMMA, msg);
326 Token blue(GetToken());
327 AssertTokenType(blue.type, Token::NUMBER, "error parsing blue component of color");
330 if (t.type == Token::PARENTHESIS_CLOSE) {
331 return new Literal(red.number, green.number, blue.number);
332 } else if (t.type != Token::COMMA) {
333 Token alpha(GetToken());
334 AssertTokenType(alpha.type, Token::NUMBER, "error parsing alpha component of color");
337 AssertTokenType(t.type, Token::PARENTHESIS_CLOSE, msg);
339 return new Literal(red.number, green.number, blue.number, alpha.number);
341 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
345 Literal *Parser::ParseVector() {
346 std::string msg("error parsing vector");
348 AssertTokenType(t.type, Token::CHEVRON_OPEN, msg);
351 AssertTokenType(x.type, Token::NUMBER, "error parsing x component of vector");
354 AssertTokenType(t.type, Token::COMMA, msg);
357 AssertTokenType(y.type, Token::NUMBER, "error parsing y component of vector");
360 AssertTokenType(t.type, Token::CHEVRON_CLOSE, msg);
362 return new Literal(x.number, y.number);
365 Literal *Parser::ParseScript() {
366 std::string msg("error parsing script");
368 AssertTokenType(t.type, Token::SCRIPT_BEGIN, msg);
371 vector<ScriptToken *> script;
373 while (t.type != Token::SCRIPT_END) {
374 if (BeginningOfPrimitiveLiteral(t)) {
376 script.push_back(new ScriptToken(ParseLiteral()));
379 case Token::COMMAND: {
380 Token t2(GetToken());
381 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
382 script.push_back(new ScriptToken(t2.str, ScriptToken::COMMAND));
385 case Token::IDENTIFIER: {
386 Token t2(GetToken());
387 if (t2.type == Token::COLON) {
388 script.push_back(new ScriptToken(t.str, ScriptToken::LABEL));
391 script.push_back(new ScriptToken(t.str, ScriptToken::IDENTIFIER));
395 case Token::REGISTER: {
396 Token t2(GetToken());
397 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
398 script.push_back(new ScriptToken(t2.str, ScriptToken::REGISTER));
402 throw Error(file, tok.Line(), string("unexpected token in script: ") + TokenTypeToString(t.type));
408 for (vector<ScriptToken *>::const_iterator i(script.begin()), end(script.end()); i != end; ++i) {
413 return new Literal(script);
417 void Parser::AssertTokenType(Token::Type actual, Token::Type expected) {
418 if (expected != actual) {
419 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
423 void Parser::AssertTokenType(Token::Type actual, Token::Type expected, const string &msg) {
424 if (expected != actual) {
425 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));