#include "fileparser.hpp" #include "scanner.hpp" #include "tokenloc.hpp" namespace Compiler { FileParser::FileParser(ErrorHandler& errorHandler, Context& context) : Parser(errorHandler, context) , mScriptParser(errorHandler, context, mLocals, true) , mState(BeginState) { } std::string FileParser::getName() const { return mName; } void FileParser::getCode(std::vector& code) const { mScriptParser.getCode(code); } 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 (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 (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) { // Ignore any junk special characters if (mState == BeginState) { if (code != Scanner::S_newline) reportWarning("Stray special character before begin statement", loc); return true; } if (code == Scanner::S_newline) { 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(); } }