added if control structure

actorid
Marc Zinnschlag 15 years ago
parent 73f9436ed9
commit 69342f320d

@ -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;
}
}

@ -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…
Cancel
Save