X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Floader%2FParser.cpp;h=3f5f3446955ab8d78005912ad1d31df432c658e8;hb=a67f7e662c85b2b8d46f26a3c6e018b2df6eb318;hp=d6abcc39561e4b70f8fce0ced7ce880580701ad0;hpb=322be5954c0f8df6a9e3aaeb2456783a814d52c3;p=l2e.git diff --git a/src/loader/Parser.cpp b/src/loader/Parser.cpp index d6abcc3..3f5f344 100644 --- a/src/loader/Parser.cpp +++ b/src/loader/Parser.cpp @@ -1,12 +1,7 @@ -/* - * Parser.cpp - * - * Created on: Aug 26, 2012 - * Author: holy - */ - #include "Parser.h" +#include "utility.h" + #include #include @@ -15,11 +10,14 @@ using std::ifstream; using std::string; using std::vector; +typedef loader::Tokenizer::Token Token; + namespace loader { -Parser::Parser(const char *file, ParsedSource &product) +Parser::Parser(const string &file, ParsedSource &product) : file(file) -, in(file) +, dirname(Dirname(file)) +, in(this->file.c_str()) , tok(in) , product(product) { if (!in) { @@ -34,15 +32,15 @@ void Parser::Parse() { } void Parser::ParseStatement() { - Tokenizer::Token t(GetToken()); + Token t(GetToken()); switch (t.type) { - case Tokenizer::Token::KEYWORD_EXPORT: + case Token::KEYWORD_EXPORT: ParseExportDirective(); break; - case Tokenizer::Token::KEYWORD_INCLUDE: + case Token::KEYWORD_INCLUDE: ParseIncludeDirective(); break; - case Tokenizer::Token::TYPE_NAME: + case Token::TYPE_NAME: tok.Putback(t); { Declaration *decl(ProbeDefinition()); @@ -54,15 +52,15 @@ void Parser::ParseStatement() { } } -Tokenizer::Token Parser::GetToken() try { +Token Parser::GetToken() try { return tok.GetNext(); } catch (Tokenizer::LexerError &e) { throw Error(file, e.Line(), e.what()); } void Parser::ParseExportDirective() { - Tokenizer::Token t(GetToken()); - if (t.type != Tokenizer::Token::IDENTIFIER) { + Token t(GetToken()); + if (t.type != Token::IDENTIFIER) { tok.Putback(t); Declaration *decl(ProbeDefinition()); product.ExportDeclaration(decl); @@ -72,9 +70,9 @@ void Parser::ParseExportDirective() { } void Parser::ParseIncludeDirective() { - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::STRING); - Parser sub(t.str.c_str(), product); // TODO: resolve path name + Token t(GetToken()); + AssertTokenType(t.type, Token::STRING); + Parser sub(CatPath(dirname, t.str), product); sub.Parse(); } @@ -82,50 +80,73 @@ Declaration *Parser::ProbeDefinition() { string typeName(ParseTypeName()); string identifier(ParseIdentifier()); - Tokenizer::Token t(GetToken()); - tok.Putback(t); - if (BeginOfPropertyList(t)) { - auto_ptr propertyList(ParsePropertyList()); - auto_ptr dfn(new Definition(typeName, identifier)); - dfn->SetValue(propertyList.release()); - product.AddDefinition(dfn.get()); - return dfn.release(); - } else if (BeginningOfLiteral(t)) { - auto_ptr literal(ParseLiteral()); - auto_ptr dfn(new Definition(typeName, identifier)); - dfn->SetValue(literal.release()); - product.AddDefinition(dfn.get()); - return dfn.release(); - } else { - return new Declaration(typeName, identifier); + if (tok.HasMore()) { + Token t(GetToken()); + tok.Putback(t); + if (BeginOfPropertyList(t)) { + auto_ptr propertyList(ParsePropertyList()); + auto_ptr dfn(new Definition(typeName, identifier)); + dfn->SetValue(propertyList.release()); + product.AddDefinition(dfn.get()); + return dfn.release(); + } else if (BeginningOfPrimitiveLiteral(t)) { + auto_ptr literal(ParseLiteral()); + auto_ptr dfn(new Definition(typeName, identifier)); + dfn->SetValue(literal.release()); + product.AddDefinition(dfn.get()); + return dfn.release(); + } + } + return new Declaration(typeName, identifier); +} + +bool Parser::BeginningOfLiteral(const Token &t) const { + switch (t.type) { + case Token::CHEVRON_OPEN: + case Token::COLON: + case Token::BRACKET_OPEN: + case Token::PARENTHESIS_OPEN: + case Token::NUMBER: + case Token::SCRIPT_BEGIN: + case Token::STRING: + case Token::KEYWORD_FALSE: + case Token::KEYWORD_TRUE: + case Token::TYPE_NAME: + return true; + default: + return false; } } -bool Parser::BeginningOfLiteral(const Tokenizer::Token &t) const { +bool Parser::BeginningOfPrimitiveLiteral(const Token &t) const { switch (t.type) { - case Tokenizer::Token::CHEVRON_OPEN: - case Tokenizer::Token::BRACKET_OPEN: - case Tokenizer::Token::PARENTHESIS_OPEN: - case Tokenizer::Token::NUMBER: - case Tokenizer::Token::STRING: - case Tokenizer::Token::KEYWORD_FALSE: - case Tokenizer::Token::KEYWORD_TRUE: - case Tokenizer::Token::TYPE_NAME: + case Token::CHEVRON_OPEN: + case Token::COLON: + case Token::BRACKET_OPEN: + case Token::PARENTHESIS_OPEN: + case Token::NUMBER: + case Token::STRING: + case Token::KEYWORD_FALSE: + case Token::KEYWORD_TRUE: return true; default: return false; } } -bool Parser::BeginOfPropertyList(const Tokenizer::Token &t) const { - return t.type == Tokenizer::Token::ANGLE_BRACKET_OPEN; +bool Parser::BeginOfPropertyList(const Token &t) const { + return t.type == Token::ANGLE_BRACKET_OPEN; +} + +bool Parser::BeginningOfScriptLiteral(const Token &t) const { + return t.type == Token::SCRIPT_BEGIN; } Definition *Parser::ParseDefinition() { string typeName(ParseTypeName()); string identifier(ParseIdentifier()); - Tokenizer::Token t(GetToken()); + Token t(GetToken()); tok.Putback(t); if (BeginOfPropertyList(t)) { PropertyList *propertyList(ParsePropertyList()); @@ -143,35 +164,35 @@ Definition *Parser::ParseDefinition() { } string Parser::ParseIdentifier() { - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::IDENTIFIER); + Token t(GetToken()); + AssertTokenType(t.type, Token::IDENTIFIER); return t.str; } string Parser::ParseTypeName() { - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::TYPE_NAME); + Token t(GetToken()); + AssertTokenType(t.type, Token::TYPE_NAME); return t.str; } PropertyList *Parser::ParsePropertyList() { - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::ANGLE_BRACKET_OPEN); + Token t(GetToken()); + AssertTokenType(t.type, Token::ANGLE_BRACKET_OPEN); auto_ptr props(new PropertyList); - while (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE) { - Tokenizer::Token name(GetToken()); - AssertTokenType(name.type, Tokenizer::Token::IDENTIFIER); + while (t.type != Token::ANGLE_BRACKET_CLOSE) { + Token name(GetToken()); + AssertTokenType(name.type, Token::IDENTIFIER); t = GetToken(); - AssertTokenType(t.type, Tokenizer::Token::COLON); + AssertTokenType(t.type, Token::COLON); Value *value(ParseValue()); props->SetProperty(name.str, value); t = GetToken(); - if (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) { + if (t.type != Token::ANGLE_BRACKET_CLOSE && t.type != Token::COMMA) { throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }"); } } @@ -180,8 +201,8 @@ PropertyList *Parser::ParsePropertyList() { } Value *Parser::ParseValue() { - Tokenizer::Token t(GetToken()); - if (t.type == Tokenizer::Token::IDENTIFIER) { + Token t(GetToken()); + if (t.type == Token::IDENTIFIER) { return new Value(t.str); } else if (BeginningOfLiteral(t)) { tok.Putback(t); @@ -193,28 +214,35 @@ Value *Parser::ParseValue() { } Literal *Parser::ParseLiteral() { - Tokenizer::Token t(GetToken()); - if (t.type == Tokenizer::Token::TYPE_NAME) { + Token t(GetToken()); + if (t.type == Token::TYPE_NAME) { PropertyList *props(ParsePropertyList()); return new Literal(t.str, props); - } else if (BeginningOfLiteral(t)) { + } else if (BeginningOfScriptLiteral(t)) { + tok.Putback(t); + return ParseScript(); + } else if (BeginningOfPrimitiveLiteral(t)) { switch (t.type) { - case Tokenizer::Token::CHEVRON_OPEN: + case Token::CHEVRON_OPEN: tok.Putback(t); return ParseVector(); - case Tokenizer::Token::BRACKET_OPEN: + case Token::COLON: + t = GetToken(); + AssertTokenType(t.type, Token::STRING); + return new Literal(dirname, t.str); + case Token::BRACKET_OPEN: tok.Putback(t); return ParseArray(); - case Tokenizer::Token::PARENTHESIS_OPEN: + case Token::PARENTHESIS_OPEN: tok.Putback(t); return ParseColor(); - case Tokenizer::Token::NUMBER: + case Token::NUMBER: return new Literal(t.number); - case Tokenizer::Token::STRING: + case Token::STRING: return new Literal(t.str); - case Tokenizer::Token::KEYWORD_FALSE: + case Token::KEYWORD_FALSE: return new Literal(false); - case Tokenizer::Token::KEYWORD_TRUE: + case Token::KEYWORD_TRUE: return new Literal(true); default: throw std::logic_error("literal switch reached impossible default branch oO"); @@ -225,32 +253,49 @@ Literal *Parser::ParseLiteral() { } Literal *Parser::ParseArray() { - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::BRACKET_OPEN); + Token t(GetToken()); + AssertTokenType(t.type, Token::BRACKET_OPEN); - Tokenizer::Token probe(GetToken()); - tok.Putback(probe); + Token probe(GetToken()); - if (probe.type == Tokenizer::Token::ANGLE_BRACKET_OPEN) { - vector values; - while (t.type != Tokenizer::Token::BRACKET_CLOSE) { - PropertyList *value(ParsePropertyList()); - values.push_back(value); - - t = GetToken(); - if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) { - throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); + if (probe.type == Token::TYPE_NAME) { + t = GetToken(); + tok.Putback(t); + if (t.type == Token::ANGLE_BRACKET_OPEN) { + vector values; + while (t.type != Token::BRACKET_CLOSE) { + PropertyList *value(ParsePropertyList()); + values.push_back(value); + + t = GetToken(); + if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); + } + } + return new Literal(probe.str, values); + } else { + vector values; + while (t.type != Token::BRACKET_CLOSE) { + string value(ParseIdentifier()); + values.push_back(value); + + t = GetToken(); + if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) { + throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); + } } + return new Literal(probe.str, values); } - return new Literal(values); } else { + tok.Putback(probe); + vector values; - while (t.type != Tokenizer::Token::BRACKET_CLOSE) { + while (t.type != Token::BRACKET_CLOSE) { Value *value(ParseValue()); values.push_back(value); t = GetToken(); - if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) { + if (t.type != Token::BRACKET_CLOSE && t.type != Token::COMMA) { throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]"); } } @@ -260,33 +305,33 @@ Literal *Parser::ParseArray() { Literal *Parser::ParseColor() { string msg("error parsing color"); - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_OPEN, msg); + Token t(GetToken()); + AssertTokenType(t.type, Token::PARENTHESIS_OPEN, msg); - Tokenizer::Token red(GetToken()); - AssertTokenType(red.type, Tokenizer::Token::NUMBER, "error parsing red component of color"); + Token red(GetToken()); + AssertTokenType(red.type, Token::NUMBER, "error parsing red component of color"); t = GetToken(); - AssertTokenType(t.type, Tokenizer::Token::COMMA, msg); + AssertTokenType(t.type, Token::COMMA, msg); - Tokenizer::Token green(GetToken()); - AssertTokenType(green.type, Tokenizer::Token::NUMBER, "error parsing green component of color"); + Token green(GetToken()); + AssertTokenType(green.type, Token::NUMBER, "error parsing green component of color"); t = GetToken(); - AssertTokenType(t.type, Tokenizer::Token::COMMA, msg); + AssertTokenType(t.type, Token::COMMA, msg); - Tokenizer::Token blue(GetToken()); - AssertTokenType(blue.type, Tokenizer::Token::NUMBER, "error parsing blue component of color"); + Token blue(GetToken()); + AssertTokenType(blue.type, Token::NUMBER, "error parsing blue component of color"); t = GetToken(); - if (t.type == Tokenizer::Token::BRACKET_CLOSE) { + if (t.type == Token::PARENTHESIS_CLOSE) { return new Literal(red.number, green.number, blue.number); - } else if (t.type != Tokenizer::Token::COMMA) { - Tokenizer::Token alpha(GetToken()); - AssertTokenType(alpha.type, Tokenizer::Token::NUMBER, "error parsing alpha component of color"); + } else if (t.type != Token::COMMA) { + Token alpha(GetToken()); + AssertTokenType(alpha.type, Token::NUMBER, "error parsing alpha component of color"); t = GetToken(); - AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_CLOSE, msg); + AssertTokenType(t.type, Token::PARENTHESIS_CLOSE, msg); return new Literal(red.number, green.number, blue.number, alpha.number); } else { @@ -296,31 +341,83 @@ Literal *Parser::ParseColor() { Literal *Parser::ParseVector() { std::string msg("error parsing vector"); - Tokenizer::Token t(GetToken()); - AssertTokenType(t.type, Tokenizer::Token::CHEVRON_OPEN, msg); + Token t(GetToken()); + AssertTokenType(t.type, Token::CHEVRON_OPEN, msg); - Tokenizer::Token x(GetToken()); - AssertTokenType(x.type, Tokenizer::Token::NUMBER, "error parsing x component of vector"); + Token x(GetToken()); + AssertTokenType(x.type, Token::NUMBER, "error parsing x component of vector"); t = GetToken(); - AssertTokenType(t.type, Tokenizer::Token::COMMA, msg); + AssertTokenType(t.type, Token::COMMA, msg); - Tokenizer::Token y(GetToken()); - AssertTokenType(y.type, Tokenizer::Token::NUMBER, "error parsing y component of vector"); + Token y(GetToken()); + AssertTokenType(y.type, Token::NUMBER, "error parsing y component of vector"); t = GetToken(); - AssertTokenType(t.type, Tokenizer::Token::CHEVRON_CLOSE, msg); + AssertTokenType(t.type, Token::CHEVRON_CLOSE, msg); return new Literal(x.number, y.number); } -void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected) { +Literal *Parser::ParseScript() { + std::string msg("error parsing script"); + Token t(GetToken()); + AssertTokenType(t.type, Token::SCRIPT_BEGIN, msg); + + t = GetToken(); + vector script; + try { + while (t.type != Token::SCRIPT_END) { + if (BeginningOfPrimitiveLiteral(t)) { + tok.Putback(t); + script.push_back(new ScriptToken(ParseLiteral())); + } else { + switch (t.type) { + case Token::COMMAND: { + Token t2(GetToken()); + AssertTokenType(t2.type, Token::IDENTIFIER, msg); + script.push_back(new ScriptToken(t2.str, ScriptToken::COMMAND)); + break; + } + case Token::IDENTIFIER: { + Token t2(GetToken()); + if (t2.type == Token::COLON) { + script.push_back(new ScriptToken(t.str, ScriptToken::LABEL)); + } else { + tok.Putback(t2); + script.push_back(new ScriptToken(t.str, ScriptToken::IDENTIFIER)); + } + break; + } + case Token::REGISTER: { + Token t2(GetToken()); + AssertTokenType(t2.type, Token::IDENTIFIER, msg); + script.push_back(new ScriptToken(t2.str, ScriptToken::REGISTER)); + break; + } + default: + throw Error(file, tok.Line(), string("unexpected token in script: ") + TokenTypeToString(t.type)); + } + } + t = GetToken(); + } + } catch (...) { + for (vector::const_iterator i(script.begin()), end(script.end()); i != end; ++i) { + delete *i; + } + throw; + } + return new Literal(script); +} + + +void Parser::AssertTokenType(Token::Type actual, Token::Type expected) { if (expected != actual) { throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected)); } } -void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const string &msg) { +void Parser::AssertTokenType(Token::Type actual, Token::Type expected, const string &msg) { if (expected != actual) { throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected)); }