#include "fileparser.hpp" #include #include "scanner.hpp" #include "tokenloc.hpp" namespace Compiler { FileParser::FileParser(ErrorHandler& errorHandler, Context& context) : Parser(errorHandler, context) , mScriptParser(errorHandler, context, mLocals, true) , mState(BeginState) { } Interpreter::Program FileParser::getProgram() const { return mScriptParser.getProgram(); } const Locals& FileParser::getLocals() const { return mLocals; } bool FileParser::parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner) { if (mState == NameState) { mName = name; mState = BeginCompleteState; return true; } if (mState == EndNameState) { // optional repeated name after end statement if (!Misc::StringUtils::ciEqual(mName, name)) reportWarning("Names for script " + mName + " do not match", loc); mState = EndCompleteState; return false; // we are stopping here, because there might be more garbage on the end line, // that we must ignore. // /// \todo allow this workaround to be disabled for newer scripts } if (mState == BeginCompleteState) { reportWarning("Stray string (" + name + ") after begin statement", loc); return true; } return Parser::parseName(name, loc, scanner); } bool FileParser::parseKeyword(int keyword, const TokenLoc& loc, Scanner& scanner) { if (mState == BeginState && keyword == Scanner::K_begin) { mState = NameState; scanner.enableTolerantNames(); /// \todo disable return true; } if (mState == NameState) { // keywords can be used as script names too. Thank you Morrowind for another // syntactic perversity :( mName = loc.mLiteral; mState = BeginCompleteState; return true; } if (mState == EndNameState) { // optional repeated name after end statement if (!Misc::StringUtils::ciEqual(mName, loc.mLiteral)) reportWarning("Names for script " + mName + " do not match", loc); mState = EndCompleteState; return false; // we are stopping here, because there might be more garbage on the end line, // that we must ignore. // /// \todo allow this workaround to be disabled for newer scripts } return Parser::parseKeyword(keyword, loc, scanner); } bool FileParser::parseSpecial(int code, const TokenLoc& loc, Scanner& scanner) { if (code == Scanner::S_newline) { if (mState == BeginState) return true; if (mState == BeginCompleteState) { // parse the script body mScriptParser.reset(); scanner.scan(mScriptParser); mState = EndNameState; return true; } if (mState == EndCompleteState || mState == EndNameState) { // we are done here -> ignore the rest of the script return false; } } return Parser::parseSpecial(code, loc, scanner); } void FileParser::parseEOF(Scanner& scanner) { if (mState != EndNameState && mState != EndCompleteState) Parser::parseEOF(scanner); } void FileParser::reset() { mState = BeginState; mName.clear(); mScriptParser.reset(); Parser::reset(); } }