forked from teamnwah/openmw-tes3coop
added if control structure
This commit is contained in:
parent
73f9436ed9
commit
69342f320d
9 changed files with 366 additions and 3 deletions
165
components/compiler/controlparser.cpp
Normal file
165
components/compiler/controlparser.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
|
||||
#include "controlparser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "generator.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||
mLineParser (errorHandler, context, locals, literals, mCodeBlock),
|
||||
mExprParser (errorHandler, context, locals, literals),
|
||||
mState (StartState)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ControlParser::appendCode (std::vector<Interpreter::Type_Code>& code) const
|
||||
{
|
||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||
}
|
||||
|
||||
bool ControlParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==StartState)
|
||||
{
|
||||
if (keyword==Scanner::K_if)
|
||||
{
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
mState = IfEndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
|
||||
{
|
||||
if (keyword==Scanner::K_endif || keyword==Scanner::K_elseif ||
|
||||
keyword==Scanner::K_else)
|
||||
{
|
||||
std::pair<Codes, Codes> entry;
|
||||
|
||||
if (mState!=IfElseBodyState)
|
||||
mExprParser.append (entry.first);
|
||||
|
||||
std::copy (mCodeBlock.begin(), mCodeBlock.end(),
|
||||
std::back_inserter (entry.second));
|
||||
|
||||
mIfCode.push_back (entry);
|
||||
|
||||
mCodeBlock.clear();
|
||||
|
||||
if (keyword==Scanner::K_endif)
|
||||
{
|
||||
// store code for if-cascade
|
||||
Codes codes;
|
||||
|
||||
for (IfCodes::reverse_iterator iter (mIfCode.rbegin());
|
||||
iter!=mIfCode.rend(); ++iter)
|
||||
{
|
||||
Codes block;
|
||||
|
||||
if (iter!=mIfCode.rbegin())
|
||||
Generator::jump (iter->second, codes.size()+1);
|
||||
|
||||
if (!iter->first.empty())
|
||||
{
|
||||
// if or elseif
|
||||
std::copy (iter->first.begin(), iter->first.end(),
|
||||
std::back_inserter (block));
|
||||
Generator::jumpOnZero (block, iter->second.size()+1);
|
||||
}
|
||||
|
||||
std::copy (iter->second.begin(), iter->second.end(),
|
||||
std::back_inserter (block));
|
||||
|
||||
std::swap (codes, block);
|
||||
|
||||
std::copy (block.begin(), block.end(), std::back_inserter (codes));
|
||||
}
|
||||
|
||||
std::copy (codes.begin(), codes.end(), std::back_inserter (mCode));
|
||||
|
||||
mIfCode.clear();
|
||||
mState = IfEndifState;
|
||||
}
|
||||
else if (keyword==Scanner::K_elseif)
|
||||
{
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
mState = IfElseifEndState;
|
||||
}
|
||||
else if (keyword==Scanner::K_else)
|
||||
{
|
||||
mState = IfElseEndState;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_if || keyword==Scanner::K_while)
|
||||
{
|
||||
// nested
|
||||
ControlParser parser (getErrorHandler(), getContext(), mLocals, mLiterals);
|
||||
|
||||
if (parser.parseKeyword (keyword, loc, scanner))
|
||||
scanner.scan (parser);
|
||||
|
||||
parser.appendCode (mCodeBlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mLineParser.reset();
|
||||
if (mLineParser.parseKeyword (keyword, loc, scanner))
|
||||
scanner.scan (mLineParser);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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 IfBodyState:
|
||||
case IfElseifBodyState:
|
||||
case IfElseBodyState:
|
||||
return true; // empty line
|
||||
|
||||
case IfEndifState:
|
||||
|
||||
return false;
|
||||
|
||||
default: ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void ControlParser::reset()
|
||||
{
|
||||
mCode.clear();
|
||||
mCodeBlock.clear();
|
||||
mIfCode.clear();
|
||||
mState = StartState;
|
||||
}
|
||||
}
|
||||
|
64
components/compiler/controlparser.hpp
Normal file
64
components/compiler/controlparser.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef COMPILER_CONTROLPARSER_H_INCLUDED
|
||||
#define COMPILER_CONTROLPARSER_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "exprparser.hpp"
|
||||
#include "lineparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
class Literals;
|
||||
|
||||
// Control structure parser
|
||||
|
||||
class ControlParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
StartState,
|
||||
IfState, IfEndState, IfBodyState,
|
||||
IfElseifEndState, IfElseifBodyState,
|
||||
IfElseEndState, IfElseBodyState,
|
||||
IfEndifState
|
||||
};
|
||||
|
||||
typedef std::vector<Interpreter::Type_Code> Codes;
|
||||
typedef std::vector<std::pair<Codes, Codes> > IfCodes;
|
||||
|
||||
Locals& mLocals;
|
||||
Literals& mLiterals;
|
||||
Codes mCode;
|
||||
Codes mCodeBlock;
|
||||
IfCodes mIfCode; // condition, body
|
||||
LineParser mLineParser;
|
||||
ExprParser mExprParser;
|
||||
State mState;
|
||||
|
||||
public:
|
||||
|
||||
ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals);
|
||||
|
||||
void appendCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||
///< store generated code in \æ code.
|
||||
|
||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a keyword token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -175,6 +175,26 @@ namespace
|
|||
{
|
||||
code.push_back (segment5 (23));
|
||||
}
|
||||
|
||||
void opJumpForward (Compiler::Generator::CodeContainer& code, int offset)
|
||||
{
|
||||
code.push_back (segment0 (1, offset));
|
||||
}
|
||||
|
||||
void opJumpBackward (Compiler::Generator::CodeContainer& code, int offset)
|
||||
{
|
||||
code.push_back (segment0 (2, offset));
|
||||
}
|
||||
|
||||
void opSkipOnZero (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (24));
|
||||
}
|
||||
|
||||
void opSkipOnNonZero (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (25));
|
||||
}
|
||||
}
|
||||
|
||||
namespace Compiler
|
||||
|
@ -389,6 +409,36 @@ namespace Compiler
|
|||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void jump (CodeContainer& code, int offset)
|
||||
{
|
||||
if (offset>0)
|
||||
opJumpForward (code, offset);
|
||||
else if (offset<0)
|
||||
opJumpBackward (code, offset);
|
||||
else
|
||||
throw std::logic_error ("inifite loop");
|
||||
}
|
||||
|
||||
void jumpOnZero (CodeContainer& code, int offset)
|
||||
{
|
||||
opSkipOnNonZero (code);
|
||||
|
||||
if (offset<0)
|
||||
--offset; // compensate for skip instruction
|
||||
|
||||
jump (code, offset);
|
||||
}
|
||||
|
||||
void jumpOnNonZero (CodeContainer& code, int offset)
|
||||
{
|
||||
opSkipOnZero (code);
|
||||
|
||||
if (offset<0)
|
||||
--offset; // compensate for skip instruction
|
||||
|
||||
jump (code, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,12 @@ namespace Compiler
|
|||
int buttons);
|
||||
|
||||
void fetchLocal (CodeContainer& code, char localType, int localIndex);
|
||||
|
||||
void jump (CodeContainer& code, int offset);
|
||||
|
||||
void jumpOnZero (CodeContainer& code, int offset);
|
||||
|
||||
void jumpOnNonZero (CodeContainer& code, int offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Compiler
|
|||
Locals& locals, bool end)
|
||||
: Parser (errorHandler, context), mOutput (locals),
|
||||
mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()),
|
||||
mControlParser (errorHandler, context, locals, mOutput.getLiterals()),
|
||||
mEnd (end)
|
||||
{}
|
||||
|
||||
|
@ -29,6 +30,17 @@ namespace Compiler
|
|||
|
||||
bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (keyword==Scanner::K_while || keyword==Scanner::K_if)
|
||||
{
|
||||
mControlParser.reset();
|
||||
if (mControlParser.parseKeyword (keyword, loc, scanner))
|
||||
scanner.scan (mControlParser);
|
||||
|
||||
mControlParser.appendCode (mOutput.getCode());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyword==Scanner::K_end && mEnd)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "parser.hpp"
|
||||
#include "lineparser.hpp"
|
||||
#include "controlparser.hpp"
|
||||
#include "output.hpp"
|
||||
|
||||
namespace Compiler
|
||||
|
@ -16,6 +17,7 @@ namespace Compiler
|
|||
{
|
||||
Output mOutput;
|
||||
LineParser mLineParser;
|
||||
ControlParser mControlParser;
|
||||
bool mEnd;
|
||||
|
||||
public:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef INTERPRETER_CONTROLOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_CONTROLOPCODES_H_INCLUDED
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
|
||||
|
@ -15,6 +17,60 @@ namespace Interpreter
|
|||
runtime.setPC (-1);
|
||||
}
|
||||
};
|
||||
|
||||
class OpSkipZero : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Data data = runtime[0];
|
||||
runtime.pop();
|
||||
|
||||
if (data==0)
|
||||
runtime.setPC (runtime.getPC()+1);
|
||||
}
|
||||
};
|
||||
|
||||
class OpSkipNonZero : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Data data = runtime[0];
|
||||
runtime.pop();
|
||||
|
||||
if (data!=0)
|
||||
runtime.setPC (runtime.getPC()+1);
|
||||
}
|
||||
};
|
||||
|
||||
class OpJumpForward : public Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
if (arg0==0)
|
||||
throw std::logic_error ("inifite loop");
|
||||
|
||||
runtime.setPC (runtime.getPC()+arg0-1);
|
||||
}
|
||||
};
|
||||
|
||||
class OpJumpBackward : public Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
if (arg0==0)
|
||||
throw std::logic_error ("inifite loop");
|
||||
|
||||
runtime.setPC (runtime.getPC()-arg0-1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,8 +30,10 @@ A: argument 0
|
|||
B: argument 1
|
||||
|
||||
Segment 0:
|
||||
op 0: push A
|
||||
opcodes 1-31 unused
|
||||
op 0: push arg0
|
||||
op 1: move pv ahead by arg0
|
||||
op 2: move pv back by arg0
|
||||
opcodes 3-31 unused
|
||||
opcodes 32-63 reserved for extensions
|
||||
|
||||
Segment 1:
|
||||
|
@ -80,6 +82,8 @@ op 20: return
|
|||
op 21: replace stack[0] with local short stack[0]
|
||||
op 22: replace stack[0] with local long stack[0]
|
||||
op 23: replace stack[0] with local float stack[0]
|
||||
opcodes 24-33554431 unused
|
||||
op 24: skip next instruction if stack[0]==0; pop
|
||||
op 25: skip next instruction if stack[0]!=0; pop
|
||||
opcodes 26-33554431 unused
|
||||
opcodes 33554432-67108863 reserved for extensions
|
||||
|
||||
|
|
|
@ -44,6 +44,10 @@ namespace Interpreter
|
|||
|
||||
// control structures
|
||||
interpreter.installSegment5 (20, new OpReturn);
|
||||
interpreter.installSegment5 (24, new OpSkipZero);
|
||||
interpreter.installSegment5 (25, new OpSkipNonZero);
|
||||
interpreter.installSegment0 (1, new OpJumpForward);
|
||||
interpreter.installSegment0 (2, new OpJumpBackward);
|
||||
|
||||
// misc
|
||||
interpreter.installSegment3 (0, new OpMessageBox);
|
||||
|
|
Loading…
Reference in a new issue