You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/compiler/fileparser.cpp

133 lines
3.8 KiB
C++

#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();
}
}