]> git.localhorst.tv Git - l2e.git/blobdiff - src/loader/Parser.cpp
new language, new compiler
[l2e.git] / src / loader / Parser.cpp
index d6abcc39561e4b70f8fce0ced7ce880580701ad0..25a99b6d2314dbc7f7e6e591e80dee875a040b2e 100644 (file)
@@ -1,25 +1,26 @@
-/*
- * Parser.cpp
- *
- *  Created on: Aug 26, 2012
- *      Author: holy
- */
-
 #include "Parser.h"
 
-#include <auto_ptr.h>
+#include "ParsedSource.h"
+#include "utility.h"
+
 #include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
 
-using std::auto_ptr;
+using std::unique_ptr;
 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 +35,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 +55,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 +73,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 +83,73 @@ Declaration *Parser::ProbeDefinition() {
        string typeName(ParseTypeName());
        string identifier(ParseIdentifier());
 
-       Tokenizer::Token t(GetToken());
-       tok.Putback(t);
-       if (BeginOfPropertyList(t)) {
-               auto_ptr<PropertyList> propertyList(ParsePropertyList());
-               auto_ptr<Definition> dfn(new Definition(typeName, identifier));
-               dfn->SetValue(propertyList.release());
-               product.AddDefinition(dfn.get());
-               return dfn.release();
-       } else if (BeginningOfLiteral(t)) {
-               auto_ptr<Literal> literal(ParseLiteral());
-               auto_ptr<Definition> 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)) {
+                       unique_ptr<PropertyList> propertyList(ParsePropertyList());
+                       unique_ptr<Definition> dfn(new Definition(typeName, identifier));
+                       dfn->SetValue(propertyList.release());
+                       product.AddDefinition(dfn.get());
+                       return dfn.release();
+               } else if (BeginningOfPrimitiveLiteral(t)) {
+                       unique_ptr<Literal> literal(ParseLiteral());
+                       unique_ptr<Definition> 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 +167,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<PropertyList> props(new PropertyList);
+       unique_ptr<PropertyList> 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 +204,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 +217,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 +256,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<PropertyList *> 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<PropertyList *> 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<string> 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<Value *> 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 +308,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 +344,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<ScriptToken *> 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<ScriptToken *>::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));
        }