1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 12:59:55 +00:00
openmw/components/compiler/controlparser.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

293 lines
8.8 KiB
C++
Raw Normal View History

2010-06-30 17:58:25 +00:00
#include "controlparser.hpp"
#include <algorithm>
#include <iterator>
2010-07-01 08:42:49 +00:00
#include <stdexcept>
2010-06-30 17:58:25 +00:00
#include "errorhandler.hpp"
2010-06-30 17:58:25 +00:00
#include "generator.hpp"
#include "scanner.hpp"
#include "skipparser.hpp"
2010-06-30 17:58:25 +00:00
namespace Compiler
{
2010-07-01 08:47:29 +00:00
bool ControlParser::parseIfBody(int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (keyword == Scanner::K_endif || keyword == Scanner::K_elseif || keyword == Scanner::K_else)
{
std::pair<Codes, Codes> entry;
2010-08-22 10:47:56 +00:00
if (mState != IfElseBodyState)
2010-07-01 08:47:29 +00:00
mExprParser.append(entry.first);
std::copy(mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter(entry.second));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
mIfCode.push_back(entry);
mCodeBlock.clear();
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
if (keyword == Scanner::K_endif)
{
// store code for if-cascade
Codes codes;
2010-08-22 10:47:56 +00:00
for (auto iter(mIfCode.rbegin()); iter != mIfCode.rend(); ++iter)
2010-07-01 08:47:29 +00:00
{
Codes block;
if (iter != mIfCode.rbegin())
2021-05-02 06:43:44 +00:00
Generator::jump(iter->second, static_cast<int>(codes.size() + 1));
2010-07-01 08:47:29 +00:00
if (!iter->first.empty())
{
// if or elseif
std::copy(iter->first.begin(), iter->first.end(), std::back_inserter(block));
2021-05-02 06:43:44 +00:00
Generator::jumpOnZero(block, static_cast<int>(iter->second.size() + 1));
2010-07-01 08:47:29 +00:00
}
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::copy(iter->second.begin(), iter->second.end(), std::back_inserter(block));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::swap(codes, block);
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::copy(block.begin(), block.end(), std::back_inserter(codes));
}
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::copy(codes.begin(), codes.end(), std::back_inserter(mCode));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
mIfCode.clear();
mState = IfEndifState;
}
else if (keyword == Scanner::K_elseif)
{
mExprParser.reset();
scanner.scan(mExprParser);
2010-08-22 10:47:56 +00:00
mState = IfElseifEndState;
2010-07-01 08:47:29 +00:00
}
else if (keyword == Scanner::K_else)
{
mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that
2010-08-22 10:47:56 +00:00
}
2010-07-01 08:47:29 +00:00
return true;
}
else if (keyword == Scanner::K_if || keyword == Scanner::K_while)
{
// nested
ControlParser parser(getErrorHandler(), getContext(), mLocals, mLiterals);
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
if (parser.parseKeyword(keyword, loc, scanner))
2010-08-22 10:47:56 +00:00
scanner.scan(parser);
parser.appendCode(mCodeBlock);
2010-07-01 08:47:29 +00:00
return true;
}
else
{
mLineParser.reset();
if (mLineParser.parseKeyword(keyword, loc, scanner))
2010-08-22 10:47:56 +00:00
scanner.scan(mLineParser);
return true;
}
2010-07-01 08:47:29 +00:00
}
bool ControlParser::parseWhileBody(int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (keyword == Scanner::K_endwhile)
{
Codes loop;
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
Codes expr;
mExprParser.append(expr);
2010-08-22 10:47:56 +00:00
2014-02-11 12:31:04 +00:00
Generator::jump(loop, -static_cast<int>(mCodeBlock.size() + expr.size()));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::copy(expr.begin(), expr.end(), std::back_inserter(mCode));
Codes skip;
2010-08-22 10:47:56 +00:00
2021-05-02 06:43:44 +00:00
Generator::jumpOnZero(skip, static_cast<int>(mCodeBlock.size() + loop.size() + 1));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::copy(skip.begin(), skip.end(), std::back_inserter(mCode));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
std::copy(mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter(mCode));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
Codes loop2;
2010-08-22 10:47:56 +00:00
2014-02-11 12:31:04 +00:00
Generator::jump(loop2, -static_cast<int>(mCodeBlock.size() + expr.size() + skip.size()));
2010-07-01 08:47:29 +00:00
if (loop.size() != loop2.size())
2019-03-28 21:59:26 +00:00
throw std::logic_error("Internal compiler error: failed to generate a while loop");
2010-07-01 08:47:29 +00:00
std::copy(loop2.begin(), loop2.end(), std::back_inserter(mCode));
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
mState = WhileEndwhileState;
2010-08-22 10:47:56 +00:00
return true;
2010-07-01 08:47:29 +00:00
}
else if (keyword == Scanner::K_if || keyword == Scanner::K_while)
{
// nested
ControlParser parser(getErrorHandler(), getContext(), mLocals, mLiterals);
2010-08-22 10:47:56 +00:00
2010-07-01 08:47:29 +00:00
if (parser.parseKeyword(keyword, loc, scanner))
2010-08-22 10:47:56 +00:00
scanner.scan(parser);
parser.appendCode(mCodeBlock);
2010-07-01 08:47:29 +00:00
return true;
}
else
{
mLineParser.reset();
if (mLineParser.parseKeyword(keyword, loc, scanner))
2010-08-22 10:47:56 +00:00
scanner.scan(mLineParser);
return true;
}
2010-07-01 08:47:29 +00:00
}
2014-02-14 11:23:00 +00:00
ControlParser::ControlParser(ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals)
2010-06-30 17:58:25 +00:00
: Parser(errorHandler, context)
, mLocals(locals)
, mLiterals(literals)
, mLineParser(errorHandler, context, locals, literals, mCodeBlock)
, mExprParser(errorHandler, context, locals, literals)
, mState(StartState)
{
}
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
void ControlParser::appendCode(std::vector<Interpreter::Type_Code>& code) const
{
std::copy(mCode.begin(), mCode.end(), std::back_inserter(code));
}
2010-08-22 10:47:56 +00:00
bool ControlParser::parseName(const std::string& name, const TokenLoc& loc, Scanner& scanner)
{
if (mState == IfBodyState || mState == IfElseifBodyState || mState == IfElseBodyState
|| mState == WhileBodyState)
{
scanner.putbackName(name, loc);
mLineParser.reset();
scanner.scan(mLineParser);
return true;
}
else if (mState == IfElseJunkState)
{
2019-03-28 21:59:26 +00:00
getErrorHandler().warning("Extra text after else", loc);
SkipParser skip(getErrorHandler(), getContext());
scanner.scan(skip);
mState = IfElseBodyState;
return true;
}
return Parser::parseName(name, loc, scanner);
}
2010-06-30 17:58:25 +00:00
bool ControlParser::parseKeyword(int keyword, const TokenLoc& loc, Scanner& scanner)
{
if (mState == StartState)
{
if (keyword == Scanner::K_if || keyword == Scanner::K_elseif)
2010-06-30 17:58:25 +00:00
{
if (keyword == Scanner::K_elseif)
getErrorHandler().warning("elseif without matching if", loc);
2010-06-30 17:58:25 +00:00
mExprParser.reset();
scanner.scan(mExprParser);
mState = IfEndState;
return true;
}
2010-07-01 08:42:49 +00:00
else if (keyword == Scanner::K_while)
{
mExprParser.reset();
scanner.scan(mExprParser);
mState = WhileEndState;
2010-08-22 10:47:56 +00:00
return true;
2010-07-01 08:42:49 +00:00
}
2010-06-30 17:58:25 +00:00
}
else if (mState == IfBodyState || mState == IfElseifBodyState || mState == IfElseBodyState)
2010-06-30 17:58:25 +00:00
{
2010-07-01 08:47:29 +00:00
if (parseIfBody(keyword, loc, scanner))
2010-08-22 10:47:56 +00:00
return true;
2010-06-30 17:58:25 +00:00
}
2010-07-01 08:42:49 +00:00
else if (mState == WhileBodyState)
{
2010-07-01 08:47:29 +00:00
if (parseWhileBody(keyword, loc, scanner))
2010-07-01 08:42:49 +00:00
return true;
}
else if (mState == IfElseJunkState)
{
2019-03-28 21:59:26 +00:00
getErrorHandler().warning("Extra text after else", loc);
SkipParser skip(getErrorHandler(), getContext());
scanner.scan(skip);
mState = IfElseBodyState;
return true;
}
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
return Parser::parseKeyword(keyword, loc, scanner);
}
bool ControlParser::parseSpecial(int code, const TokenLoc& loc, Scanner& scanner)
{
if (code == Scanner::S_newline)
{
switch (mState)
{
case IfEndState:
mState = IfBodyState;
return true;
case IfElseifEndState:
mState = IfElseifBodyState;
return true;
case IfElseEndState:
mState = IfElseBodyState;
return true;
case IfElseJunkState:
mState = IfElseBodyState;
2010-07-01 08:42:49 +00:00
return true;
2022-09-22 18:26:05 +00:00
2010-07-01 08:42:49 +00:00
case WhileEndState:
mState = WhileBodyState;
2010-06-30 17:58:25 +00:00
return true;
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
case IfBodyState:
case IfElseifBodyState:
case IfElseBodyState:
2010-07-01 08:42:49 +00:00
case WhileBodyState:
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
return true; // empty line
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
case IfEndifState:
2010-07-01 08:42:49 +00:00
case WhileEndwhileState:
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
return false;
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
default:;
}
}
else if (mState == IfElseJunkState)
{
2019-03-28 21:59:26 +00:00
getErrorHandler().warning("Extra text after else", loc);
SkipParser skip(getErrorHandler(), getContext());
scanner.scan(skip);
mState = IfElseBodyState;
return true;
2010-06-30 17:58:25 +00:00
}
2010-08-22 10:47:56 +00:00
2010-06-30 17:58:25 +00:00
return Parser::parseSpecial(code, loc, scanner);
}
void ControlParser::reset()
{
mCode.clear();
mCodeBlock.clear();
mIfCode.clear();
mState = StartState;
2010-08-22 10:47:56 +00:00
Parser::reset();
2010-06-30 17:58:25 +00:00
}
}