#include "lineparser.hpp" #include #include #include #include "context.hpp" #include "declarationparser.hpp" #include "errorhandler.hpp" #include "extensions.hpp" #include "generator.hpp" #include "locals.hpp" #include "scanner.hpp" #include "skipparser.hpp" namespace Compiler { void LineParser::parseExpression(Scanner& scanner, const TokenLoc& loc) { mExprParser.reset(); if (!mExplicit.empty()) { mExprParser.parseName(mExplicit, loc, scanner); if (mState == MemberState) mExprParser.parseSpecial(Scanner::S_member, loc, scanner); else mExprParser.parseSpecial(Scanner::S_ref, loc, scanner); } scanner.scan(mExprParser); char type = mExprParser.append(mCode); mState = EndState; switch (type) { case 'l': Generator::report(mCode, mLiterals, "%d"); break; case 'f': Generator::report(mCode, mLiterals, "%f"); break; default: throw std::runtime_error("Unknown expression result type"); } } LineParser::LineParser(ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, std::vector& code, bool allowExpression) : Parser(errorHandler, context) , mLocals(locals) , mLiterals(literals) , mCode(code) , mState(BeginState) , mReferenceMember(false) , mButtons(0) , mType(0) , mExprParser(errorHandler, context, locals, literals) , mAllowExpression(allowExpression) { } bool LineParser::parseInt(int value, const TokenLoc& loc, Scanner& scanner) { if (mAllowExpression && mState == BeginState) { scanner.putbackInt(value, loc); parseExpression(scanner, loc); return true; } else if (mState == SetState) { // Allow ints to be used as variable names return parseName(loc.mLiteral, loc, scanner); } return Parser::parseInt(value, loc, scanner); } bool LineParser::parseFloat(float value, const TokenLoc& loc, Scanner& scanner) { if (mAllowExpression && mState == BeginState) { scanner.putbackFloat(value, loc); parseExpression(scanner, loc); return true; } return Parser::parseFloat(value, loc, scanner); } bool LineParser::parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner) { if (mState == SetState) { std::string name2 = Misc::StringUtils::lowerCase(name); mName = name2; // local variable? char type = mLocals.getType(name2); if (type != ' ') { mType = type; mState = SetLocalVarState; return true; } type = getContext().getGlobalType(name2); if (type != ' ') { mType = type; mState = SetGlobalVarState; return true; } mState = SetPotentialMemberVarState; return true; } if (mState == SetMemberVarState) { mMemberName = Misc::StringUtils::lowerCase(name); std::pair type = getContext().getMemberType(mMemberName, ESM::RefId::stringRefId(mName)); if (type.first != ' ') { mState = SetMemberVarState2; mType = type.first; mReferenceMember = type.second; return true; } getErrorHandler().error("Unknown variable", loc); SkipParser skip(getErrorHandler(), getContext()); scanner.scan(skip); return false; } if (mState == MessageState) { GetArgumentsFromMessageFormat processor; processor.process(name); std::string arguments = processor.getArguments(); if (!arguments.empty()) { mExprParser.reset(); mExprParser.parseArguments(arguments, scanner, mCode, -1, true); } mName = name; mButtons = 0; mState = MessageButtonState; return true; } if (mState == MessageButtonState) { Generator::pushString(mCode, mLiterals, name); mState = MessageButtonState; ++mButtons; return true; } if (mState == BeginState && getContext().isId(ESM::RefId::stringRefId(name))) { mState = PotentialExplicitState; mExplicit = Misc::StringUtils::lowerCase(name); return true; } if (mState == BeginState && mAllowExpression) { std::string name2 = Misc::StringUtils::lowerCase(name); char type = mLocals.getType(name2); if (type != ' ') { scanner.putbackName(name, loc); parseExpression(scanner, loc); return true; } type = getContext().getGlobalType(name2); if (type != ' ') { scanner.putbackName(name, loc); parseExpression(scanner, loc); return true; } } return Parser::parseName(name, loc, scanner); } bool LineParser::parseKeyword(int keyword, const TokenLoc& loc, Scanner& scanner) { if (mState == MessageState) { if (const Extensions* extensions = getContext().getExtensions()) { std::string argumentType; // ignored bool hasExplicit = false; // ignored if (extensions->isInstruction(keyword, argumentType, hasExplicit)) { // pretend this is not a keyword std::string name = loc.mLiteral; if (name.size() >= 2 && name[0] == '"' && name[name.size() - 1] == '"') name = name.substr(1, name.size() - 2); return parseName(name, loc, scanner); } } } if (mState == SetMemberVarState) { mMemberName = loc.mLiteral; std::pair type = getContext().getMemberType(mMemberName, ESM::RefId::stringRefId(mName)); if (type.first != ' ') { mState = SetMemberVarState2; mType = type.first; mReferenceMember = type.second; return true; } } if (mState == SetPotentialMemberVarState && keyword == Scanner::K_to) { getErrorHandler().warning("Unknown variable", loc); SkipParser skip(getErrorHandler(), getContext()); scanner.scan(skip); return false; } if (mState == SetState) { // allow keywords to be used as variable names when assigning a value to a variable. return parseName(loc.mLiteral, loc, scanner); } if (mState == BeginState || mState == ExplicitState) { // check for custom extensions if (const Extensions* extensions = getContext().getExtensions()) { std::string argumentType; bool hasExplicit = mState == ExplicitState; if (extensions->isInstruction(keyword, argumentType, hasExplicit)) { if (!hasExplicit && mState == ExplicitState) { getErrorHandler().warning("Stray explicit reference", loc); mExplicit.clear(); } std::vector code; int optionals = mExprParser.parseArguments(argumentType, scanner, code, keyword); mCode.insert(mCode.end(), code.begin(), code.end()); extensions->generateInstructionCode(keyword, mCode, mLiterals, mExplicit, optionals); SkipParser skip(getErrorHandler(), getContext(), true); scanner.scan(skip); mState = EndState; return true; } char returnType; if (extensions->isFunction(keyword, returnType, argumentType, hasExplicit)) { if (!hasExplicit && mState == ExplicitState) { getErrorHandler().warning("Stray explicit reference", loc); mExplicit.clear(); } if (mAllowExpression) { scanner.putbackKeyword(keyword, loc); parseExpression(scanner, loc); } else { std::vector code; int optionals = mExprParser.parseArguments(argumentType, scanner, code, keyword); mCode.insert(mCode.end(), code.begin(), code.end()); extensions->generateFunctionCode(keyword, mCode, mLiterals, mExplicit, optionals); SkipParser skip(getErrorHandler(), getContext(), true); scanner.scan(skip); } mState = EndState; return true; } } } if (mState == ExplicitState) { // drop stray explicit reference getErrorHandler().warning("Stray explicit reference", loc); mState = BeginState; mExplicit.clear(); } if (mState == BeginState) { switch (keyword) { case Scanner::K_short: case Scanner::K_long: case Scanner::K_float: { if (!getContext().canDeclareLocals()) { getErrorHandler().error("Local variables cannot be declared in this context", loc); SkipParser skip(getErrorHandler(), getContext()); scanner.scan(skip); return true; } DeclarationParser declaration(getErrorHandler(), getContext(), mLocals); if (declaration.parseKeyword(keyword, loc, scanner)) scanner.scan(declaration); return false; } case Scanner::K_set: mState = SetState; return true; case Scanner::K_messagebox: mState = MessageState; scanner.enableStrictKeywords(); return true; case Scanner::K_return: Generator::exit(mCode); mState = EndState; return true; case Scanner::K_else: getErrorHandler().warning("Stray else", loc); mState = EndState; return true; case Scanner::K_endif: getErrorHandler().warning("Stray endif", loc); mState = EndState; return true; case Scanner::K_begin: getErrorHandler().warning("Stray begin", loc); mState = EndState; return true; } } else if (mState == SetLocalVarState && keyword == Scanner::K_to) { mExprParser.reset(); scanner.scan(mExprParser); std::vector code; char type = mExprParser.append(code); Generator::assignToLocal(mCode, mLocals.getType(mName), mLocals.getIndex(mName), code, type); mState = EndState; return true; } else if (mState == SetGlobalVarState && keyword == Scanner::K_to) { mExprParser.reset(); scanner.scan(mExprParser); std::vector code; char type = mExprParser.append(code); Generator::assignToGlobal(mCode, mLiterals, mType, mName, code, type); mState = EndState; return true; } else if (mState == SetMemberVarState2 && keyword == Scanner::K_to) { mExprParser.reset(); scanner.scan(mExprParser); std::vector code; char type = mExprParser.append(code); Generator::assignToMember(mCode, mLiterals, mType, mMemberName, mName, code, type, !mReferenceMember); mState = EndState; return true; } return Parser::parseKeyword(keyword, loc, scanner); } bool LineParser::parseSpecial(int code, const TokenLoc& loc, Scanner& scanner) { if (mState == EndState && code == Scanner::S_open) { getErrorHandler().warning("Stray '[' or '(' at the end of the line", loc); return true; } if (code == Scanner::S_newline && (mState == EndState || mState == BeginState)) return false; if (code == Scanner::S_ref && mState == SetPotentialMemberVarState) { getErrorHandler().warning("Stray explicit reference", loc); mState = SetState; return true; } if (code == Scanner::S_ref && mState == PotentialExplicitState) { mState = ExplicitState; return true; } if (code == Scanner::S_member && mState == PotentialExplicitState && mAllowExpression) { mState = MemberState; parseExpression(scanner, loc); mState = EndState; return true; } if (code == Scanner::S_newline && mState == MessageButtonState) { Generator::message(mCode, mLiterals, mName, mButtons); return false; } if (code == Scanner::S_member && mState == SetPotentialMemberVarState) { mState = SetMemberVarState; return true; } if (mAllowExpression && mState == BeginState && (code == Scanner::S_open || code == Scanner::S_minus || code == Scanner::S_plus)) { scanner.putbackSpecial(code, loc); parseExpression(scanner, loc); mState = EndState; return true; } return Parser::parseSpecial(code, loc, scanner); } void LineParser::reset() { mState = BeginState; mName.clear(); mExplicit.clear(); } void GetArgumentsFromMessageFormat::visitedPlaceholder( Placeholder placeholder, char /*padding*/, int /*width*/, int /*precision*/, Notation /*notation*/) { switch (placeholder) { case StringPlaceholder: mArguments += 'S'; break; case IntegerPlaceholder: mArguments += 'l'; break; case FloatPlaceholder: mArguments += 'f'; break; default: break; } } }