1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
#include "fileparser.hpp"
#include <components/misc/strings/algorithm.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)
{
}
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();
}
}
|