4 * Created on: Aug 26, 2012
20 typedef loader::Tokenizer::Token Token;
24 Parser::Parser(const string &file, ParsedSource &product)
26 , dirname(Dirname(file))
27 , in(this->file.c_str())
31 throw Error(file, 0, "unable to read file");
35 void Parser::Parse() {
36 while (tok.HasMore()) {
41 void Parser::ParseStatement() {
44 case Token::KEYWORD_EXPORT:
45 ParseExportDirective();
47 case Token::KEYWORD_INCLUDE:
48 ParseIncludeDirective();
50 case Token::TYPE_NAME:
53 Declaration *decl(ProbeDefinition());
54 product.AddDeclaration(decl);
58 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type));
62 Token Parser::GetToken() try {
64 } catch (Tokenizer::LexerError &e) {
65 throw Error(file, e.Line(), e.what());
68 void Parser::ParseExportDirective() {
70 if (t.type != Token::IDENTIFIER) {
72 Declaration *decl(ProbeDefinition());
73 product.ExportDeclaration(decl);
75 product.ExportIdentifier(t.str);
79 void Parser::ParseIncludeDirective() {
81 AssertTokenType(t.type, Token::STRING);
82 Parser sub(CatPath(dirname, t.str), product);
86 Declaration *Parser::ProbeDefinition() {
87 string typeName(ParseTypeName());
88 string identifier(ParseIdentifier());
93 if (BeginOfPropertyList(t)) {
94 auto_ptr<PropertyList> propertyList(ParsePropertyList());
95 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
96 dfn->SetValue(propertyList.release());
97 product.AddDefinition(dfn.get());
99 } else if (BeginningOfPrimitiveLiteral(t)) {
100 auto_ptr<Literal> literal(ParseLiteral());
101 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
102 dfn->SetValue(literal.release());
103 product.AddDefinition(dfn.get());
104 return dfn.release();
107 return new Declaration(typeName, identifier);
110 bool Parser::BeginningOfLiteral(const Token &t) const {
112 case Token::CHEVRON_OPEN:
114 case Token::BRACKET_OPEN:
115 case Token::PARENTHESIS_OPEN:
117 case Token::SCRIPT_BEGIN:
119 case Token::KEYWORD_FALSE:
120 case Token::KEYWORD_TRUE:
121 case Token::TYPE_NAME:
128 bool Parser::BeginningOfPrimitiveLiteral(const Token &t) const {
130 case Token::CHEVRON_OPEN:
132 case Token::BRACKET_OPEN:
133 case Token::PARENTHESIS_OPEN:
136 case Token::KEYWORD_FALSE:
137 case Token::KEYWORD_TRUE:
144 bool Parser::BeginOfPropertyList(const Token &t) const {
145 return t.type == Token::ANGLE_BRACKET_OPEN;
148 bool Parser::BeginningOfScriptLiteral(const Token &t) const {
149 return t.type == Token::SCRIPT_BEGIN;
152 Definition *Parser::ParseDefinition() {
153 string typeName(ParseTypeName());
154 string identifier(ParseIdentifier());
158 if (BeginOfPropertyList(t)) {
159 PropertyList *propertyList(ParsePropertyList());
160 Definition *dfn(new Definition(typeName, identifier));
161 dfn->SetValue(propertyList);
163 } else if (BeginningOfLiteral(t)) {
164 Literal *literal(ParseLiteral());
165 Definition *dfn(new Definition(typeName, identifier));
166 dfn->SetValue(literal);
169 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
173 string Parser::ParseIdentifier() {
175 AssertTokenType(t.type, Token::IDENTIFIER);
179 string Parser::ParseTypeName() {
181 AssertTokenType(t.type, Token::TYPE_NAME);
185 PropertyList *Parser::ParsePropertyList() {
187 AssertTokenType(t.type, Token::ANGLE_BRACKET_OPEN);
189 auto_ptr<PropertyList> props(new PropertyList);
191 while (t.type != Token::ANGLE_BRACKET_CLOSE) {
192 Token name(GetToken());
193 AssertTokenType(name.type, Token::IDENTIFIER);
196 AssertTokenType(t.type, Token::COLON);
198 Value *value(ParseValue());
199 props->SetProperty(name.str, value);
202 if (t.type != Token::ANGLE_BRACKET_CLOSE && t.type != Token::COMMA) {
203 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }");
207 return props.release();
210 Value *Parser::ParseValue() {
212 if (t.type == Token::IDENTIFIER) {
213 return new Value(t.str);
214 } else if (BeginningOfLiteral(t)) {
216 Literal *literal(ParseLiteral());
217 return new Value(literal);
219 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
223 Literal *Parser::ParseLiteral() {
225 if (t.type == Token::TYPE_NAME) {
226 PropertyList *props(ParsePropertyList());
227 return new Literal(t.str, props);
228 } else if (BeginningOfScriptLiteral(t)) {
230 return ParseScript();
231 } else if (BeginningOfPrimitiveLiteral(t)) {
233 case Token::CHEVRON_OPEN:
235 return ParseVector();
238 AssertTokenType(t.type, Token::STRING);
239 return new Literal(dirname, t.str);
240 case Token::BRACKET_OPEN:
243 case Token::PARENTHESIS_OPEN:
247 return new Literal(t.number);
249 return new Literal(t.str);
250 case Token::KEYWORD_FALSE:
251 return new Literal(false);
252 case Token::KEYWORD_TRUE:
253 return new Literal(true);
255 throw std::logic_error("literal switch reached impossible default branch oO");
258 throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
262 Literal *Parser::ParseArray() {
264 AssertTokenType(t.type, Token::BRACKET_OPEN);
266 Token probe(GetToken());
268 if (probe.type == Token::TYPE_NAME) {
269 vector<PropertyList *> values;
270 while (t.type != Token::BRACKET_CLOSE) {
271 PropertyList *value(ParsePropertyList());
272 values.push_back(value);
275 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
276 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
279 return new Literal(probe.str, values);
283 vector<Value *> values;
284 while (t.type != Token::BRACKET_CLOSE) {
285 Value *value(ParseValue());
286 values.push_back(value);
289 if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) {
290 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
293 return new Literal(values);
297 Literal *Parser::ParseColor() {
298 string msg("error parsing color");
300 AssertTokenType(t.type, Token::PARENTHESIS_OPEN, msg);
302 Token red(GetToken());
303 AssertTokenType(red.type, Token::NUMBER, "error parsing red component of color");
306 AssertTokenType(t.type, Token::COMMA, msg);
308 Token green(GetToken());
309 AssertTokenType(green.type, Token::NUMBER, "error parsing green component of color");
312 AssertTokenType(t.type, Token::COMMA, msg);
314 Token blue(GetToken());
315 AssertTokenType(blue.type, Token::NUMBER, "error parsing blue component of color");
318 if (t.type == Token::PARENTHESIS_CLOSE) {
319 return new Literal(red.number, green.number, blue.number);
320 } else if (t.type != Token::COMMA) {
321 Token alpha(GetToken());
322 AssertTokenType(alpha.type, Token::NUMBER, "error parsing alpha component of color");
325 AssertTokenType(t.type, Token::PARENTHESIS_CLOSE, msg);
327 return new Literal(red.number, green.number, blue.number, alpha.number);
329 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
333 Literal *Parser::ParseVector() {
334 std::string msg("error parsing vector");
336 AssertTokenType(t.type, Token::CHEVRON_OPEN, msg);
339 AssertTokenType(x.type, Token::NUMBER, "error parsing x component of vector");
342 AssertTokenType(t.type, Token::COMMA, msg);
345 AssertTokenType(y.type, Token::NUMBER, "error parsing y component of vector");
348 AssertTokenType(t.type, Token::CHEVRON_CLOSE, msg);
350 return new Literal(x.number, y.number);
353 Literal *Parser::ParseScript() {
354 std::string msg("error parsing script");
356 AssertTokenType(t.type, Token::SCRIPT_BEGIN, msg);
359 vector<ScriptToken *> script;
361 while (t.type != Token::SCRIPT_END) {
362 if (BeginningOfPrimitiveLiteral(t)) {
364 script.push_back(new ScriptToken(ParseLiteral()));
367 case Token::COMMAND: {
368 Token t2(GetToken());
369 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
370 script.push_back(new ScriptToken(t2.str, ScriptToken::COMMAND));
373 case Token::IDENTIFIER: {
374 Token t2(GetToken());
375 if (t2.type == Token::COLON) {
376 script.push_back(new ScriptToken(t.str, ScriptToken::LABEL));
379 script.push_back(new ScriptToken(t.str, ScriptToken::IDENTIFIER));
383 case Token::REGISTER: {
384 Token t2(GetToken());
385 AssertTokenType(t2.type, Token::IDENTIFIER, msg);
386 script.push_back(new ScriptToken(t2.str, ScriptToken::REGISTER));
390 throw Error(file, tok.Line(), string("unexpected token in script: ") + TokenTypeToString(t.type));
396 for (vector<ScriptToken *>::const_iterator i(script.begin()), end(script.end()); i != end; ++i) {
401 return new Literal(script);
405 void Parser::AssertTokenType(Token::Type actual, Token::Type expected) {
406 if (expected != actual) {
407 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
411 void Parser::AssertTokenType(Token::Type actual, Token::Type expected, const string &msg) {
412 if (expected != actual) {
413 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));