mirror of https://github.com/OpenMW/openmw.git
Merge upstream
commit
056194baa2
@ -0,0 +1,11 @@
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace SACompiler
|
||||
{
|
||||
bool Context::canDeclareLocals() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
#ifndef MWCOMPILER_CONTEXT_H_INCLUDED
|
||||
#define MWCOMPILER_CONTEXT_H_INCLUDED
|
||||
|
||||
#include <components/compiler/context.hpp>
|
||||
|
||||
namespace SACompiler
|
||||
{
|
||||
class Context : public Compiler::Context
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool canDeclareLocals() const;
|
||||
///< Is the compiler allowed to declare local variables?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,78 @@
|
||||
// Stand-alone MW-script compiler
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
#include <components/compiler/streamerrorhandler.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
#include <components/compiler/fileparser.hpp>
|
||||
#include <components/compiler/exception.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
SACompiler::Context context;
|
||||
Compiler::StreamErrorHandler errorHandler (std::cout);
|
||||
Compiler::FileParser parser (errorHandler, context);
|
||||
|
||||
std::string filename = argc>1 ? argv[1] : "test.mwscript";
|
||||
|
||||
try
|
||||
{
|
||||
std::ifstream file (filename.c_str());
|
||||
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cout << "can't open script file: " << filename << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Compiler::Scanner scanner (errorHandler, file);
|
||||
|
||||
scanner.scan (parser);
|
||||
}
|
||||
catch (const Compiler::SourceException&)
|
||||
{
|
||||
// ignore exception (problem has already been reported to the user)
|
||||
}
|
||||
|
||||
if (errorHandler.countErrors() || errorHandler.countWarnings())
|
||||
{
|
||||
std::cout
|
||||
<< errorHandler.countErrors() << " error(s), "
|
||||
<< errorHandler.countWarnings() << " warning(s)" << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (errorHandler.isGood())
|
||||
{
|
||||
std::vector<Interpreter::Type_Code> code;
|
||||
parser.getCode (code);
|
||||
|
||||
std::ofstream codeFile ((filename + ".code").c_str());
|
||||
|
||||
codeFile.write (reinterpret_cast<const char *> (&code[0]),
|
||||
code.size()*sizeof (Interpreter::Type_Code));
|
||||
|
||||
std::ofstream localFile ((filename + ".locals").c_str());
|
||||
|
||||
parser.getLocals().write (localFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cout << "\nERROR: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
namespace SAInterpreter
|
||||
{
|
||||
Context::Context (const std::string& filename)
|
||||
{
|
||||
std::ifstream file (filename.c_str());
|
||||
|
||||
if (!file.is_open())
|
||||
throw std::runtime_error ("can't open locals file: " + filename);
|
||||
|
||||
std::size_t shortSize, longSize, floatSize;
|
||||
|
||||
file >> shortSize >> longSize >> floatSize;
|
||||
|
||||
mShorts.resize (shortSize, 0);
|
||||
mLongs.resize (longSize, 0);
|
||||
mFloats.resize (floatSize, 0.0);
|
||||
|
||||
std::size_t size = shortSize + longSize + floatSize;
|
||||
|
||||
mNames.resize (size);
|
||||
|
||||
for (std::size_t i=0; i<size; ++i)
|
||||
file >> mNames[i];
|
||||
}
|
||||
|
||||
int Context::getLocalShort (int index) const
|
||||
{
|
||||
assert (index>=0);
|
||||
return mShorts.at (index);
|
||||
}
|
||||
|
||||
int Context::getLocalLong (int index) const
|
||||
{
|
||||
assert (index>=0);
|
||||
return mLongs.at (index);
|
||||
}
|
||||
|
||||
float Context::getLocalFloat (int index) const
|
||||
{
|
||||
assert (index>=0);
|
||||
return mFloats.at (index);
|
||||
}
|
||||
|
||||
void Context::setLocalShort (int index, int value)
|
||||
{
|
||||
assert (index>=0);
|
||||
mShorts.at (index) = value;
|
||||
}
|
||||
|
||||
void Context::setLocalLong (int index, int value)
|
||||
{
|
||||
assert (index>=0);
|
||||
mLongs.at (index) = value;
|
||||
}
|
||||
|
||||
void Context::setLocalFloat (int index, float value)
|
||||
{
|
||||
assert (index>=0);
|
||||
mFloats.at (index) = value;
|
||||
}
|
||||
|
||||
void Context::messageBox (const std::string& message,
|
||||
const std::vector<std::string>& buttons)
|
||||
{
|
||||
std::cout << "message box: " << message << std::endl;
|
||||
for (std::size_t i=0; i<buttons.size(); ++i)
|
||||
std::cout << " button " << i << ": " << buttons[i] << std::endl;
|
||||
}
|
||||
|
||||
void Context::report()
|
||||
{
|
||||
std::size_t i = 0;
|
||||
|
||||
std::cout << "local shorts:" << std::endl;
|
||||
|
||||
for (std::vector<Interpreter::Type_Short>::const_iterator iter (mShorts.begin());
|
||||
iter!=mShorts.end(); ++iter)
|
||||
std::cout << mNames[i++] << ": " << *iter << std::endl;
|
||||
|
||||
std::cout << "local longs:" << std::endl;
|
||||
|
||||
for (std::vector<Interpreter::Type_Integer>::const_iterator iter (mLongs.begin());
|
||||
iter!=mLongs.end(); ++iter)
|
||||
std::cout << mNames[i++] << ": " << *iter << std::endl;
|
||||
|
||||
std::cout << "local floats:" << std::endl;
|
||||
|
||||
for (std::vector<Interpreter::Type_Float>::const_iterator iter (mFloats.begin());
|
||||
iter!=mFloats.end(); ++iter)
|
||||
std::cout << mNames[i++] << ": " << *iter << std::endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
#ifndef SAINTERPRETER_CONTEXT_H_INCLUDED
|
||||
#define SAINTERPRETER_CONTEXT_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/context.hpp>
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
namespace SAInterpreter
|
||||
{
|
||||
class Context : public Interpreter::Context
|
||||
{
|
||||
std::vector<Interpreter::Type_Short> mShorts;
|
||||
std::vector<Interpreter::Type_Integer> mLongs;
|
||||
std::vector<Interpreter::Type_Float> mFloats;
|
||||
std::vector<std::string> mNames;
|
||||
|
||||
public:
|
||||
|
||||
Context (const std::string& filename);
|
||||
///< Create context from file
|
||||
/// \note A context for an integreted interpreter will typically not
|
||||
/// configure at construction, but will offer a separate function.
|
||||
|
||||
virtual int getLocalShort (int index) const;
|
||||
|
||||
virtual int getLocalLong (int index) const;
|
||||
|
||||
virtual float getLocalFloat (int index) const;
|
||||
|
||||
virtual void setLocalShort (int index, int value);
|
||||
|
||||
virtual void setLocalLong (int index, int value);
|
||||
|
||||
virtual void setLocalFloat (int index, float value);
|
||||
|
||||
virtual void messageBox (const std::string& message,
|
||||
const std::vector<std::string>& buttons);
|
||||
|
||||
void report();
|
||||
///< Write state to std::cout
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,57 @@
|
||||
// Stand-alone MW-script code interpreter
|
||||
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/interpreter.hpp>
|
||||
#include <components/interpreter/context.hpp>
|
||||
#include <components/interpreter/types.hpp>
|
||||
#include <components/interpreter/installopcodes.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string filename = argc>1 ? argv[1] : "test.mwscript";
|
||||
|
||||
std::string localfilename = filename + ".locals";
|
||||
|
||||
SAInterpreter::Context context (localfilename);
|
||||
Interpreter::Interpreter interpreter (context);
|
||||
Interpreter::installOpcodes (interpreter);
|
||||
|
||||
std::string codefilename = filename + ".code";
|
||||
|
||||
std::ifstream codefile (codefilename.c_str());
|
||||
|
||||
if (!codefile.is_open())
|
||||
{
|
||||
std::cout << "can't open code file: " << codefilename << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<Interpreter::Type_Code> code (4);
|
||||
|
||||
codefile.read (reinterpret_cast<char *> (&code[0]), 4 * sizeof (Interpreter::Type_Code));
|
||||
|
||||
unsigned int size = code[0] + code[1] + code[2] + code[3];
|
||||
|
||||
code.resize (4+size);
|
||||
|
||||
codefile.read (reinterpret_cast<char *> (&code[4]), size * sizeof (Interpreter::Type_Code));
|
||||
|
||||
interpreter.run (&code[0], size+4);
|
||||
|
||||
context.report();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cout << "\nERROR: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
#ifndef COMPILER_CONTEXT_H_INCLUDED
|
||||
#define COMPILER_CONTEXT_H_INCLUDED
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Context() {}
|
||||
|
||||
virtual bool canDeclareLocals() const = 0;
|
||||
///< Is the compiler allowed to declare local variables?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,250 @@
|
||||
|
||||
#include "controlparser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "generator.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
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;
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
bool ControlParser::parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (keyword==Scanner::K_endwhile)
|
||||
{
|
||||
Codes loop;
|
||||
|
||||
Codes expr;
|
||||
mExprParser.append (expr);
|
||||
|
||||
Generator::jump (loop, -mCodeBlock.size()-expr.size());
|
||||
|
||||
std::copy (expr.begin(), expr.end(), std::back_inserter (mCode));
|
||||
|
||||
Codes skip;
|
||||
|
||||
Generator::jumpOnZero (skip, mCodeBlock.size()+loop.size()+1);
|
||||
|
||||
std::copy (skip.begin(), skip.end(), std::back_inserter (mCode));
|
||||
|
||||
std::copy (mCodeBlock.begin(), mCodeBlock.end(), std::back_inserter (mCode));
|
||||
|
||||
Codes loop2;
|
||||
|
||||
Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size());
|
||||
|
||||
if (loop.size()!=loop2.size())
|
||||
throw std::logic_error (
|
||||
"internal compiler error: failed to generate a while loop");
|
||||
|
||||
std::copy (loop2.begin(), loop2.end(), std::back_inserter (mCode));
|
||||
|
||||
mState = WhileEndwhileState;
|
||||
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 false;
|
||||
}
|
||||
|
||||
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 (keyword==Scanner::K_while)
|
||||
{
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
mState = WhileEndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState)
|
||||
{
|
||||
if (parseIfBody (keyword, loc, scanner))
|
||||
return true;
|
||||
}
|
||||
else if (mState==WhileBodyState)
|
||||
{
|
||||
if ( parseWhileBody (keyword, loc, scanner))
|
||||
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 WhileEndState: mState = WhileBodyState; return true;
|
||||
|
||||
case IfBodyState:
|
||||
case IfElseifBodyState:
|
||||
case IfElseBodyState:
|
||||
case WhileBodyState:
|
||||
|
||||
return true; // empty line
|
||||
|
||||
case IfEndifState:
|
||||
case WhileEndwhileState:
|
||||
|
||||
return false;
|
||||
|
||||
default: ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void ControlParser::reset()
|
||||
{
|
||||
mCode.clear();
|
||||
mCodeBlock.clear();
|
||||
mIfCode.clear();
|
||||
mState = StartState;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
#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,
|
||||
IfEndState, IfBodyState,
|
||||
IfElseifEndState, IfElseifBodyState,
|
||||
IfElseEndState, IfElseBodyState,
|
||||
IfEndifState,
|
||||
WhileEndState, WhileBodyState,
|
||||
WhileEndwhileState
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
bool parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
|
||||
bool parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
|
||||
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
|
||||
|
@ -0,0 +1,65 @@
|
||||
|
||||
#include "errorhandler.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
// constructor
|
||||
|
||||
ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0) {}
|
||||
|
||||
// destructor
|
||||
|
||||
ErrorHandler::~ErrorHandler() {}
|
||||
|
||||
// Was compiling successful?
|
||||
|
||||
bool ErrorHandler::isGood() const
|
||||
{
|
||||
return mErrors==0;
|
||||
}
|
||||
|
||||
// Return number of errors
|
||||
|
||||
int ErrorHandler::countErrors() const
|
||||
{
|
||||
return mErrors;
|
||||
}
|
||||
|
||||
// Return number of warnings
|
||||
|
||||
int ErrorHandler::countWarnings() const
|
||||
{
|
||||
return mWarnings;
|
||||
}
|
||||
|
||||
// Generate a warning message.
|
||||
|
||||
void ErrorHandler::warning (const std::string& message, const TokenLoc& loc)
|
||||
{
|
||||
++mWarnings;
|
||||
report (message, loc, WarningMessage);
|
||||
}
|
||||
|
||||
// Generate an error message.
|
||||
|
||||
void ErrorHandler::error (const std::string& message, const TokenLoc& loc)
|
||||
{
|
||||
++mErrors;
|
||||
report (message, loc, ErrorMessage);
|
||||
}
|
||||
|
||||
// Generate an error message for an unexpected EOF.
|
||||
|
||||
void ErrorHandler::endOfFile()
|
||||
{
|
||||
++mErrors;
|
||||
report ("unexpected end of file", ErrorMessage);
|
||||
}
|
||||
|
||||
// Remove all previous error/warning events
|
||||
|
||||
void ErrorHandler::reset()
|
||||
{
|
||||
mErrors = mWarnings = 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
|
||||
#ifndef COMPILER_ERRORHANDLER_H_INCLUDED
|
||||
#define COMPILER_ERRORHANDLER_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
struct TokenLoc;
|
||||
|
||||
/// \brief Error handling
|
||||
///
|
||||
/// This class collects errors and provides an interface for reporting them to the user.
|
||||
|
||||
class ErrorHandler
|
||||
{
|
||||
int mWarnings;
|
||||
int mErrors;
|
||||
|
||||
protected:
|
||||
|
||||
enum Type
|
||||
{
|
||||
WarningMessage, ErrorMessage
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// mutators
|
||||
|
||||
virtual void report (const std::string& message, const TokenLoc& loc, Type type) = 0;
|
||||
///< Report error to the user.
|
||||
|
||||
virtual void report (const std::string& message, Type type) = 0;
|
||||
///< Report a file related error
|
||||
|
||||
public:
|
||||
|
||||
ErrorHandler();
|
||||
///< constructor
|
||||
|
||||
virtual ~ErrorHandler();
|
||||
///< destructor
|
||||
|
||||
bool isGood() const;
|
||||
///< Was compiling successful?
|
||||
|
||||
int countErrors() const;
|
||||
///< Return number of errors
|
||||
|
||||
int countWarnings() const;
|
||||
///< Return number of warnings
|
||||
|
||||
void warning (const std::string& message, const TokenLoc& loc);
|
||||
///< Generate a warning message.
|
||||
|
||||
void error (const std::string& message, const TokenLoc& loc);
|
||||
///< Generate an error message.
|
||||
|
||||
void endOfFile();
|
||||
///< Generate an error message for an unexpected EOF.
|
||||
|
||||
virtual void reset();
|
||||
///< Remove all previous error/warning events
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,32 @@
|
||||
#ifndef COMPILER_EXCEPTION_H_INCLUDED
|
||||
#define COMPILER_EXCEPTION_H_INCLUDED
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// \brief Exception: Error while parsing the source
|
||||
|
||||
class SourceException : public std::exception
|
||||
{
|
||||
virtual const char *what() const throw() { return "compile error";}
|
||||
///< Return error message
|
||||
};
|
||||
|
||||
/// \brief Exception: File error
|
||||
|
||||
class FileException : public SourceException
|
||||
{
|
||||
virtual const char *what() const throw() { return "can't read file"; }
|
||||
///< Return error message
|
||||
};
|
||||
|
||||
/// \brief Exception: EOF condition encountered
|
||||
|
||||
class EOFException : public SourceException
|
||||
{ virtual const char *what() const throw() { return "end of file"; }
|
||||
///< Return error message
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,481 @@
|
||||
|
||||
#include "exprparser.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
|
||||
#include "generator.hpp"
|
||||
#include "scanner.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "locals.hpp"
|
||||
#include "stringparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
int ExprParser::getPriority (char op) const
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case '(':
|
||||
|
||||
return 0;
|
||||
|
||||
case 'e': // ==
|
||||
case 'n': // !=
|
||||
case 'l': // <
|
||||
case 'L': // <=
|
||||
case 'g': // <
|
||||
case 'G': // >=
|
||||
|
||||
return 1;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
|
||||
return 2;
|
||||
|
||||
case '*':
|
||||
case '/':
|
||||
|
||||
return 3;
|
||||
|
||||
case 'm':
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char ExprParser::getOperandType (int Index) const
|
||||
{
|
||||
assert (!mOperands.empty());
|
||||
assert (Index>=0);
|
||||
assert (Index<static_cast<int> (mOperands.size()));
|
||||
return mOperands[mOperands.size()-1-Index];
|
||||
}
|
||||
|
||||
char ExprParser::getOperator() const
|
||||
{
|
||||
assert (!mOperators.empty());
|
||||
return mOperators[mOperators.size()-1];
|
||||
}
|
||||
|
||||
bool ExprParser::isOpen() const
|
||||
{
|
||||
return std::find (mOperators.begin(), mOperators.end(), '(')!=mOperators.end();
|
||||
}
|
||||
|
||||
void ExprParser::popOperator()
|
||||
{
|
||||
assert (!mOperators.empty());
|
||||
mOperators.resize (mOperators.size()-1);
|
||||
}
|
||||
|
||||
void ExprParser::popOperand()
|
||||
{
|
||||
assert (!mOperands.empty());
|
||||
mOperands.resize (mOperands.size()-1);
|
||||
}
|
||||
|
||||
void ExprParser::replaceBinaryOperands()
|
||||
{
|
||||
char t1 = getOperandType (1);
|
||||
char t2 = getOperandType();
|
||||
|
||||
popOperand();
|
||||
popOperand();
|
||||
|
||||
if (t1==t2)
|
||||
mOperands.push_back (t1);
|
||||
else if (t1=='f' || t2=='f')
|
||||
mOperands.push_back ('f');
|
||||
else
|
||||
std::logic_error ("failed to determine result operand type");
|
||||
}
|
||||
|
||||
void ExprParser::pop()
|
||||
{
|
||||
char op = getOperator();
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case 'm':
|
||||
|
||||
Generator::negate (mCode, getOperandType());
|
||||
popOperator();
|
||||
break;
|
||||
|
||||
case '+':
|
||||
|
||||
Generator::add (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case '-':
|
||||
|
||||
Generator::sub (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case '*':
|
||||
|
||||
Generator::mul (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case '/':
|
||||
|
||||
Generator::div (mCode, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
replaceBinaryOperands();
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'n':
|
||||
case 'l':
|
||||
case 'L':
|
||||
case 'g':
|
||||
case 'G':
|
||||
|
||||
Generator::compare (mCode, op, getOperandType (1), getOperandType());
|
||||
popOperator();
|
||||
popOperand();
|
||||
popOperand();
|
||||
mOperands.push_back ('l');
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::logic_error ("unknown operator");
|
||||
}
|
||||
}
|
||||
|
||||
void ExprParser::pushIntegerLiteral (int value)
|
||||
{
|
||||
mNextOperand = false;
|
||||
mOperands.push_back ('l');
|
||||
Generator::pushInt (mCode, mLiterals, value);
|
||||
}
|
||||
|
||||
void ExprParser::pushFloatLiteral (float value)
|
||||
{
|
||||
mNextOperand = false;
|
||||
mOperands.push_back ('f');
|
||||
Generator::pushFloat (mCode, mLiterals, value);
|
||||
}
|
||||
|
||||
void ExprParser::pushBinaryOperator (char c)
|
||||
{
|
||||
while (!mOperators.empty() && getPriority (getOperator())>=getPriority (c))
|
||||
pop();
|
||||
|
||||
mOperators.push_back (c);
|
||||
mNextOperand = true;
|
||||
}
|
||||
|
||||
void ExprParser::close()
|
||||
{
|
||||
while (getOperator()!='(')
|
||||
pop();
|
||||
|
||||
popOperator();
|
||||
}
|
||||
|
||||
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
|
||||
{
|
||||
parseArguments (arguments, scanner, mCode);
|
||||
}
|
||||
|
||||
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals, bool argument)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||
mNextOperand (true), mFirst (true), mArgument (argument)
|
||||
{}
|
||||
|
||||
bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
pushIntegerLiteral (value);
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no comma was used between arguments
|
||||
scanner.putbackInt (value, loc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExprParser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
pushFloatLiteral (value);
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no comma was used between arguments
|
||||
scanner.putbackFloat (value, loc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExprParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
char type = mLocals.getType (name);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
Generator::fetchLocal (mCode, type, mLocals.getIndex (name));
|
||||
mNextOperand = false;
|
||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no comma was used between arguments
|
||||
scanner.putbackName (name, loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
if (keyword==Scanner::K_getsquareroot)
|
||||
{
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("f", scanner);
|
||||
|
||||
Generator::squareRoot (mCode);
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no comma was used between arguments
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
bool ExprParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_comma)
|
||||
{
|
||||
mTokenLoc = loc;
|
||||
|
||||
if (mFirst)
|
||||
{
|
||||
// leading comma
|
||||
mFirst = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// end marker
|
||||
scanner.putbackSpecial (code, loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
mFirst = false;
|
||||
|
||||
if (code==Scanner::S_newline)
|
||||
{
|
||||
// end marker
|
||||
mTokenLoc = loc;
|
||||
scanner.putbackSpecial (code, loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_minus && mNextOperand)
|
||||
{
|
||||
// unary
|
||||
mOperators.push_back ('m');
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_open)
|
||||
{
|
||||
if (mNextOperand)
|
||||
{
|
||||
mOperators.push_back ('(');
|
||||
mTokenLoc = loc;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no comma was used between arguments
|
||||
scanner.putbackKeyword (code, loc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (code==Scanner::S_close && !mNextOperand)
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
|
||||
mTokenLoc = loc;
|
||||
scanner.putbackSpecial (code, loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mNextOperand)
|
||||
{
|
||||
mTokenLoc = loc;
|
||||
char c = 0; // comparison
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case Scanner::S_plus: pushBinaryOperator ('+'); return true;
|
||||
case Scanner::S_minus: pushBinaryOperator ('-'); return true;
|
||||
case Scanner::S_mult: pushBinaryOperator ('*'); return true;
|
||||
case Scanner::S_div: pushBinaryOperator ('/'); return true;
|
||||
case Scanner::S_cmpEQ: c = 'e'; break;
|
||||
case Scanner::S_cmpNE: c = 'n'; break;
|
||||
case Scanner::S_cmpLT: c = 'l'; break;
|
||||
case Scanner::S_cmpLE: c = 'L'; break;
|
||||
case Scanner::S_cmpGT: c = 'g'; break;
|
||||
case Scanner::S_cmpGE: c = 'G'; break;
|
||||
}
|
||||
|
||||
if (c)
|
||||
{
|
||||
if (mArgument && !isOpen())
|
||||
{
|
||||
// expression ends here
|
||||
// Thank you Morrowind for this rotten syntax :(
|
||||
scanner.putbackSpecial (code, loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
pushBinaryOperator (c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void ExprParser::reset()
|
||||
{
|
||||
mOperands.clear();
|
||||
mOperators.clear();
|
||||
mNextOperand = true;
|
||||
mCode.clear();
|
||||
mFirst = true;
|
||||
}
|
||||
|
||||
char ExprParser::append (std::vector<Interpreter::Type_Code>& code)
|
||||
{
|
||||
if (mOperands.empty() && mOperators.empty())
|
||||
{
|
||||
getErrorHandler().error ("missing expression", mTokenLoc);
|
||||
return 'l';
|
||||
}
|
||||
|
||||
if (mNextOperand || mOperands.empty())
|
||||
{
|
||||
getErrorHandler().error ("syntax error in expression", mTokenLoc);
|
||||
return 'l';
|
||||
}
|
||||
|
||||
while (!mOperators.empty())
|
||||
pop();
|
||||
|
||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||
|
||||
assert (mOperands.size()==1);
|
||||
return mOperands[0];
|
||||
}
|
||||
|
||||
void ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
|
||||
std::vector<Interpreter::Type_Code>& code, bool invert)
|
||||
{
|
||||
ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true);
|
||||
StringParser stringParser (getErrorHandler(), getContext(), mLiterals);
|
||||
|
||||
std::stack<std::vector<Interpreter::Type_Code> > stack;
|
||||
|
||||
for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end();
|
||||
++iter)
|
||||
{
|
||||
if (*iter=='S')
|
||||
{
|
||||
stringParser.reset();
|
||||
scanner.scan (stringParser);
|
||||
|
||||
if (invert)
|
||||
{
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
stringParser.append (tmp);
|
||||
|
||||
stack.push (tmp);
|
||||
}
|
||||
else
|
||||
stringParser.append (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.reset();
|
||||
scanner.scan (parser);
|
||||
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
|
||||
char type = parser.append (tmp);
|
||||
|
||||
if (type!=*iter)
|
||||
Generator::convert (tmp, type, *iter);
|
||||
|
||||
if (invert)
|
||||
stack.push (tmp);
|
||||
else
|
||||
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
||||
}
|
||||
}
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
std::vector<Interpreter::Type_Code>& tmp = stack.top();
|
||||
|
||||
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
#ifndef COMPILER_EXPRPARSER_H_INCLUDED
|
||||
#define COMPILER_EXPRPARSER_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "tokenloc.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
class Literals;
|
||||
|
||||
class ExprParser : public Parser
|
||||
{
|
||||
Locals& mLocals;
|
||||
Literals& mLiterals;
|
||||
std::vector<char> mOperands;
|
||||
std::vector<char> mOperators;
|
||||
bool mNextOperand;
|
||||
TokenLoc mTokenLoc;
|
||||
std::vector<Interpreter::Type_Code> mCode;
|
||||
bool mFirst;
|
||||
bool mArgument;
|
||||
|
||||
int getPriority (char op) const;
|
||||
|
||||
char getOperandType (int Index = 0) const;
|
||||
|
||||
char getOperator() const;
|
||||
|
||||
bool isOpen() const;
|
||||
|
||||
void popOperator();
|
||||
|
||||
void popOperand();
|
||||
|
||||
void replaceBinaryOperands();
|
||||
|
||||
void pop();
|
||||
|
||||
void pushIntegerLiteral (int value);
|
||||
|
||||
void pushFloatLiteral (float value);
|
||||
|
||||
void pushBinaryOperator (char c);
|
||||
|
||||
void close();
|
||||
|
||||
void parseArguments (const std::string& arguments, Scanner& scanner);
|
||||
|
||||
public:
|
||||
|
||||
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals, bool argument = false);
|
||||
///< constructor
|
||||
/// \param argument Parser is used to parse function- or instruction-
|
||||
/// arguments (this influences the precedence rules).
|
||||
|
||||
char getType() const;
|
||||
///< Return type of parsed expression ('l' integer, 'f' float)
|
||||
|
||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle an int token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseFloat (float value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a float token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
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.
|
||||
|
||||
char append (std::vector<Interpreter::Type_Code>& code);
|
||||
///< Generate code for parsed expression.
|
||||
/// \return Type ('l': integer, 'f': float)
|
||||
|
||||
void parseArguments (const std::string& arguments, Scanner& scanner,
|
||||
std::vector<Interpreter::Type_Code>& code, bool invert = false);
|
||||
///< Parse sequence of arguments specified by \a arguments.
|
||||
/// \param arguments Each character represents one arguments ('l': integer,
|
||||
/// 'f': float, 'S': string)
|
||||
/// \param invert Store arguments in reverted order.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,103 @@
|
||||
#include "fileparser.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "tokenloc.hpp"
|
||||
#include "scanner.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
FileParser::FileParser (ErrorHandler& errorHandler, Context& context)
|
||||
: Parser (errorHandler, context),
|
||||
mScriptParser (errorHandler, context, mLocals, true),
|
||||
mState (BeginState)
|
||||
{}
|
||||
|
||||
std::string FileParser::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
void FileParser::getCode (std::vector<Interpreter::Type_Code>& code) const
|
||||
{
|
||||
mScriptParser.getCode (code);
|
||||
}
|
||||
|
||||
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 (mName!=name)
|
||||
reportWarning ("Names for script " + mName + " do not match", loc);
|
||||
|
||||
mState = EndCompleteState;
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
bool FileParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
#ifndef COMPILER_FILEPARSER_H_INCLUDED
|
||||
#define COMPILER_FILEPARSER_H_INCLUDED
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "scriptparser.hpp"
|
||||
#include "locals.hpp"
|
||||
#include "literals.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
// Top-level parser, to be used for global scripts, local scripts and targeted scripts
|
||||
|
||||
class FileParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
BeginState, NameState, BeginCompleteState, EndNameState,
|
||||
EndCompleteState
|
||||
};
|
||||
|
||||
ScriptParser mScriptParser;
|
||||
State mState;
|
||||
std::string mName;
|
||||
Locals mLocals;
|
||||
|
||||
public:
|
||||
|
||||
FileParser (ErrorHandler& errorHandler, Context& context);
|
||||
|
||||
std::string getName() const;
|
||||
///< Return script name.
|
||||
|
||||
void getCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||
///< store generated code in \æ code.
|
||||
|
||||
const Locals& getLocals() const;
|
||||
///< get local variable declarations.
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
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?
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,552 @@
|
||||
|
||||
#include "generator.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "literals.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
Interpreter::Type_Code segment0 (unsigned int c, unsigned int arg0)
|
||||
{
|
||||
assert (c<64);
|
||||
return (c<<24) | (arg0 & 0xffffff);
|
||||
}
|
||||
|
||||
Interpreter::Type_Code segment1 (unsigned int c, unsigned int arg0, unsigned int arg1)
|
||||
{
|
||||
assert (c<64);
|
||||
return 0x40000000 | (c<<24) | ((arg0 & 0xfff)<<12) | (arg1 & 0xfff);
|
||||
}
|
||||
|
||||
Interpreter::Type_Code segment2 (unsigned int c, unsigned int arg0)
|
||||
{
|
||||
assert (c<1024);
|
||||
return 0x80000000 | (c<<20) | (arg0 & 0xfffff);
|
||||
}
|
||||
|
||||
Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0)
|
||||
{
|
||||
assert (c<1024);
|
||||
return 0xc0000000 | (c<<20) | (arg0 & 0xffff);
|
||||
}
|
||||
|
||||
Interpreter::Type_Code segment4 (unsigned int c, unsigned int arg0, unsigned int arg1)
|
||||
{
|
||||
assert (c<1024);
|
||||
return 0xc4000000 | (c<<16) | ((arg0 & 0xff)<<8) | (arg1 & 0xff);
|
||||
}
|
||||
|
||||
Interpreter::Type_Code segment5 (unsigned int c)
|
||||
{
|
||||
assert (c<67108864);
|
||||
return 0xc8000000 | c;
|
||||
}
|
||||
|
||||
void opPushInt (Compiler::Generator::CodeContainer& code, int value)
|
||||
{
|
||||
code.push_back (segment0 (0, value));
|
||||
}
|
||||
|
||||
void opFetchIntLiteral (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (4));
|
||||
}
|
||||
|
||||
void opFetchFloatLiteral (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (5));
|
||||
}
|
||||
|
||||
void opIntToFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (3));
|
||||
}
|
||||
|
||||
void opFloatToInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (6));
|
||||
}
|
||||
|
||||
void opStoreLocalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (0));
|
||||
}
|
||||
|
||||
void opStoreLocalLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (1));
|
||||
}
|
||||
|
||||
void opStoreLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (2));
|
||||
}
|
||||
|
||||
void opNegateInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (7));
|
||||
}
|
||||
|
||||
void opNegateFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (8));
|
||||
}
|
||||
|
||||
void opAddInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (9));
|
||||
}
|
||||
|
||||
void opAddFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (10));
|
||||
}
|
||||
|
||||
void opSubInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (11));
|
||||
}
|
||||
|
||||
void opSubFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (12));
|
||||
}
|
||||
|
||||
void opMulInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (13));
|
||||
}
|
||||
|
||||
void opMulFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (14));
|
||||
}
|
||||
|
||||
void opDivInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (15));
|
||||
}
|
||||
|
||||
void opDivFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (16));
|
||||
}
|
||||
|
||||
void opIntToFloat1 (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (17));
|
||||
}
|
||||
|
||||
void opFloatToInt1 (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (18));
|
||||
}
|
||||
|
||||
void opSquareRoot (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (19));
|
||||
}
|
||||
|
||||
void opReturn (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (20));
|
||||
}
|
||||
|
||||
void opMessageBox (Compiler::Generator::CodeContainer& code, int buttons)
|
||||
{
|
||||
code.push_back (segment3 (0, buttons));
|
||||
}
|
||||
|
||||
void opFetchLocalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (21));
|
||||
}
|
||||
|
||||
void opFetchLocalLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (22));
|
||||
}
|
||||
|
||||
void opFetchLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void opEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (26));
|
||||
}
|
||||
|
||||
void opNonEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (27));
|
||||
}
|
||||
|
||||
void opLessThanInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (28));
|
||||
}
|
||||
|
||||
void opLessOrEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (29));
|
||||
}
|
||||
|
||||
void opGreaterThanInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (30));
|
||||
}
|
||||
|
||||
void opGreaterOrEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (31));
|
||||
}
|
||||
|
||||
void opEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (32));
|
||||
}
|
||||
|
||||
void opNonEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (33));
|
||||
}
|
||||
|
||||
void opLessThanFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (34));
|
||||
}
|
||||
|
||||
void opLessOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (35));
|
||||
}
|
||||
|
||||
void opGreaterThanFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (36));
|
||||
}
|
||||
|
||||
void opGreaterOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (segment5 (37));
|
||||
}
|
||||
}
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
namespace Generator
|
||||
{
|
||||
void pushInt (CodeContainer& code, Literals& literals, int value)
|
||||
{
|
||||
int index = literals.addInteger (value);
|
||||
opPushInt (code, index);
|
||||
opFetchIntLiteral (code);
|
||||
}
|
||||
|
||||
void pushFloat (CodeContainer& code, Literals& literals, float value)
|
||||
{
|
||||
int index = literals.addFloat (value);
|
||||
opPushInt (code, index);
|
||||
opFetchFloatLiteral (code);
|
||||
}
|
||||
|
||||
void pushString (CodeContainer& code, Literals& literals, const std::string& value)
|
||||
{
|
||||
int index = literals.addString (value);
|
||||
opPushInt (code, index);
|
||||
}
|
||||
|
||||
void assignToLocal (CodeContainer& code, char localType,
|
||||
int localIndex, const CodeContainer& value, char valueType)
|
||||
{
|
||||
opPushInt (code, localIndex);
|
||||
|
||||
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
||||
|
||||
if (localType!=valueType)
|
||||
{
|
||||
if (localType=='f' && valueType=='l')
|
||||
{
|
||||
opIntToFloat (code);
|
||||
}
|
||||
else if ((localType=='l' || localType=='s') && valueType=='f')
|
||||
{
|
||||
opFloatToInt (code);
|
||||
}
|
||||
}
|
||||
|
||||
switch (localType)
|
||||
{
|
||||
case 'f':
|
||||
|
||||
opStoreLocalFloat (code);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opStoreLocalShort (code);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opStoreLocalLong (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void negate (CodeContainer& code, char valueType)
|
||||
{
|
||||
switch (valueType)
|
||||
{
|
||||
case 'l':
|
||||
|
||||
opNegateInt (code);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
|
||||
opNegateFloat (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void add (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opAddInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opAddFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void sub (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opSubInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opSubFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void mul (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opMulInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opMulFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void div (CodeContainer& code, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
opDivInt (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
opDivFloat (code);
|
||||
}
|
||||
}
|
||||
|
||||
void convert (CodeContainer& code, char fromType, char toType)
|
||||
{
|
||||
if (fromType!=toType)
|
||||
{
|
||||
if (fromType=='f' && toType=='l')
|
||||
opFloatToInt (code);
|
||||
else if (fromType=='l' && toType=='f')
|
||||
opIntToFloat (code);
|
||||
else
|
||||
throw std::logic_error ("illegal type conversion");
|
||||
}
|
||||
}
|
||||
|
||||
void squareRoot (CodeContainer& code)
|
||||
{
|
||||
opSquareRoot (code);
|
||||
}
|
||||
|
||||
void exit (CodeContainer& code)
|
||||
{
|
||||
opReturn (code);
|
||||
}
|
||||
|
||||
void message (CodeContainer& code, Literals& literals, const std::string& message,
|
||||
int buttons)
|
||||
{
|
||||
assert (buttons==0);
|
||||
|
||||
int index = literals.addString (message);
|
||||
|
||||
opPushInt (code, index);
|
||||
opMessageBox (code, buttons);
|
||||
}
|
||||
|
||||
void fetchLocal (CodeContainer& code, char localType, int localIndex)
|
||||
{
|
||||
opPushInt (code, localIndex);
|
||||
|
||||
switch (localType)
|
||||
{
|
||||
case 'f':
|
||||
|
||||
opFetchLocalFloat (code);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opFetchLocalShort (code);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opFetchLocalLong (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void compare (CodeContainer& code, char op, char valueType1, char valueType2)
|
||||
{
|
||||
if (valueType1=='l' && valueType2=='l')
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case 'e': opEqualInt (code); break;
|
||||
case 'n': opNonEqualInt (code); break;
|
||||
case 'l': opLessThanInt (code); break;
|
||||
case 'L': opLessOrEqualInt (code); break;
|
||||
case 'g': opGreaterThanInt (code); break;
|
||||
case 'G': opGreaterOrEqualInt (code); break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (valueType1=='l')
|
||||
opIntToFloat1 (code);
|
||||
|
||||
if (valueType2=='l')
|
||||
opIntToFloat (code);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case 'e': opEqualFloat (code); break;
|
||||
case 'n': opNonEqualFloat (code); break;
|
||||
case 'l': opLessThanFloat (code); break;
|
||||
case 'L': opLessOrEqualFloat (code); break;
|
||||
case 'g': opGreaterThanFloat (code); break;
|
||||
case 'G': opGreaterOrEqualFloat (code); break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
#ifndef COMPILER_GENERATOR_H_INCLUDED
|
||||
#define COMPILER_GENERATOR_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Literals;
|
||||
|
||||
namespace Generator
|
||||
{
|
||||
typedef std::vector<Interpreter::Type_Code> CodeContainer;
|
||||
|
||||
void pushInt (CodeContainer& code, Literals& literals, int value);
|
||||
|
||||
void pushFloat (CodeContainer& code, Literals& literals, float value);
|
||||
|
||||
void pushString (CodeContainer& code, Literals& literals, const std::string& value);
|
||||
|
||||
void assignToLocal (CodeContainer& code, char localType,
|
||||
int localIndex, const CodeContainer& value, char valueType);
|
||||
|
||||
void negate (CodeContainer& code, char valueType);
|
||||
|
||||
void add (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void sub (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void mul (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void div (CodeContainer& code, char valueType1, char valueType2);
|
||||
|
||||
void convert (CodeContainer& code, char fromType, char toType);
|
||||
|
||||
void squareRoot (CodeContainer& code);
|
||||
|
||||
void exit (CodeContainer& code);
|
||||
|
||||
void message (CodeContainer& code, Literals& literals, const std::string& message,
|
||||
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);
|
||||
|
||||
void compare (CodeContainer& code, char op, char valueType1, char valueType2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,177 @@
|
||||
|
||||
#include "lineparser.hpp"
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "context.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "skipparser.hpp"
|
||||
#include "locals.hpp"
|
||||
#include "generator.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
LineParser::LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals, std::vector<Interpreter::Type_Code>& code)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code),
|
||||
mState (BeginState), mExprParser (errorHandler, context, locals, literals)
|
||||
{}
|
||||
|
||||
bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
return Parser::parseInt (value, loc, scanner);
|
||||
}
|
||||
|
||||
bool LineParser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
return Parser::parseFloat (value, loc, scanner);
|
||||
}
|
||||
|
||||
bool LineParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==ShortState || mState==LongState || mState==FloatState)
|
||||
{
|
||||
if (!getContext().canDeclareLocals())
|
||||
{
|
||||
getErrorHandler().error ("local variables can't be declared in this context", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name2 = toLower (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
getErrorHandler().error ("can't re-declare local variable", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return false;
|
||||
}
|
||||
|
||||
mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'),
|
||||
name2);
|
||||
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==SetState)
|
||||
{
|
||||
// local variable?
|
||||
std::string name2 = toLower (name);
|
||||
char type = mLocals.getType (name2);
|
||||
if (type!=' ')
|
||||
{
|
||||
mName = name2;
|
||||
mState = SetLocalVarState;
|
||||
return true;
|
||||
}
|
||||
|
||||
getErrorHandler().error ("unknown variable", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mState==MessageState || mState==MessageCommaState)
|
||||
{
|
||||
std::string arguments;
|
||||
|
||||
for (std::size_t i=0; i<name.size(); ++i)
|
||||
{
|
||||
if (name[i]=='%')
|
||||
{
|
||||
++i;
|
||||
if (i<name.size())
|
||||
{
|
||||
if (name[i]=='G' || name[i]=='g')
|
||||
{
|
||||
arguments += "l";
|
||||
}
|
||||
else if (name[i]=='S' || name[i]=='s')
|
||||
{
|
||||
arguments += 'S';
|
||||
}
|
||||
else if (name[i]=='.' || name[i]=='f')
|
||||
{
|
||||
arguments += 'f';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!arguments.empty())
|
||||
{
|
||||
mExprParser.reset();
|
||||
mExprParser.parseArguments (arguments, scanner, mCode, true);
|
||||
}
|
||||
|
||||
Generator::message (mCode, mLiterals, name, 0);
|
||||
mState = EndState;
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==BeginState)
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case Scanner::K_short: mState = ShortState; return true;
|
||||
case Scanner::K_long: mState = LongState; return true;
|
||||
case Scanner::K_float: mState = FloatState; return true;
|
||||
case Scanner::K_set: mState = SetState; return true;
|
||||
case Scanner::K_messagebox: mState = MessageState; return true;
|
||||
|
||||
case Scanner::K_return:
|
||||
|
||||
Generator::exit (mCode);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==SetLocalVarState && keyword==Scanner::K_to)
|
||||
{
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
std::vector<Interpreter::Type_Code> code;
|
||||
char type = mExprParser.append (code);
|
||||
|
||||
Generator::assignToLocal (mCode, mLocals.getType (mName),
|
||||
mLocals.getIndex (mName), code, type);
|
||||
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline && mState==EndState)
|
||||
return false;
|
||||
|
||||
if (code==Scanner::S_comma && mState==MessageState)
|
||||
{
|
||||
mState = MessageCommaState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void LineParser::reset()
|
||||
{
|
||||
mState = BeginState;
|
||||
mName.clear();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
#ifndef COMPILER_LINEPARSER_H_INCLUDED
|
||||
#define COMPILER_LINEPARSER_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "exprparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
class Literals;
|
||||
|
||||
/// \brief Line parser, to be used in console scripts and as part of ScriptParser
|
||||
|
||||
class LineParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
BeginState,
|
||||
ShortState, LongState, FloatState,
|
||||
SetState, SetLocalVarState,
|
||||
MessageState, MessageCommaState,
|
||||
EndState
|
||||
};
|
||||
|
||||
Locals& mLocals;
|
||||
Literals& mLiterals;
|
||||
std::vector<Interpreter::Type_Code>& mCode;
|
||||
State mState;
|
||||
std::string mName;
|
||||
ExprParser mExprParser;
|
||||
|
||||
public:
|
||||
|
||||
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals, std::vector<Interpreter::Type_Code>& code);
|
||||
|
||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle an int token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseFloat (float value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a float token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
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
|
@ -0,0 +1,94 @@
|
||||
|
||||
#include "literals.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
int Literals::getIntegerSize() const
|
||||
{
|
||||
return mIntegers.size() * sizeof (Interpreter::Type_Integer);
|
||||
}
|
||||
|
||||
int Literals::getFloatSize() const
|
||||
{
|
||||
return mFloats.size() * sizeof (Interpreter::Type_Float);
|
||||
}
|
||||
|
||||
int Literals::getStringSize() const
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (mStrings.begin());
|
||||
iter!=mStrings.end(); ++iter)
|
||||
size += static_cast<int> (iter->size()) + 1;
|
||||
|
||||
if (size % 4) // padding
|
||||
size += 4 - size % 4;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void Literals::append (std::vector<Interpreter::Type_Code>& code) const
|
||||
{
|
||||
for (std::vector<Interpreter::Type_Integer>::const_iterator iter (mIntegers.begin());
|
||||
iter!=mIntegers.end(); ++iter)
|
||||
code.push_back (*reinterpret_cast<const Interpreter::Type_Code *> (&*iter));
|
||||
|
||||
for (std::vector<Interpreter::Type_Float>::const_iterator iter (mFloats.begin());
|
||||
iter!=mFloats.end(); ++iter)
|
||||
code.push_back (*reinterpret_cast<const Interpreter::Type_Code *> (&*iter));
|
||||
|
||||
int stringBlockSize = getStringSize();
|
||||
int size = static_cast<int> (code.size());
|
||||
|
||||
code.resize (size+stringBlockSize/4);
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (mStrings.begin());
|
||||
iter!=mStrings.end(); ++iter)
|
||||
{
|
||||
int stringSize = iter->size()+1;
|
||||
|
||||
std::copy (iter->c_str(), iter->c_str()+stringSize,
|
||||
reinterpret_cast<char *> (&code[size]) + offset);
|
||||
offset += stringSize;
|
||||
}
|
||||
}
|
||||
|
||||
int Literals::addInteger (Interpreter::Type_Integer value)
|
||||
{
|
||||
int index = static_cast<int> (mIntegers.size());
|
||||
|
||||
mIntegers.push_back (value);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int Literals::addFloat (Interpreter::Type_Float value)
|
||||
{
|
||||
int index = static_cast<int> (mFloats.size());
|
||||
|
||||
mFloats.push_back (value);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int Literals::addString (const std::string& value)
|
||||
{
|
||||
int index = static_cast<int> (mStrings.size());
|
||||
|
||||
mStrings.push_back (value);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void Literals::clear()
|
||||
{
|
||||
mIntegers.clear();
|
||||
mFloats.clear();
|
||||
mStrings.clear();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
#ifndef COMPILER_LITERALS_H_INCLUDED
|
||||
#define COMPILER_LITERALS_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// \brief Literal values.
|
||||
|
||||
class Literals
|
||||
{
|
||||
std::vector<Interpreter::Type_Integer> mIntegers;
|
||||
std::vector<Interpreter::Type_Float> mFloats;
|
||||
std::vector<std::string> mStrings;
|
||||
|
||||
public:
|
||||
|
||||
int getIntegerSize() const;
|
||||
///< Return size of integer block (in bytes).
|
||||
|
||||
int getFloatSize() const;
|
||||
///< Return size of float block (in bytes).
|
||||
|
||||
int getStringSize() const;
|
||||
///< Return size of string block (in bytes).
|
||||
|
||||
void append (std::vector<Interpreter::Type_Code>& code) const;
|
||||
///< Apepnd literal blocks to code.
|
||||
/// \note code blocks will be padded for 32-bit alignment.
|
||||
|
||||
int addInteger (Interpreter::Type_Integer value);
|
||||
///< add integer liternal and return index.
|
||||
|
||||
int addFloat (Interpreter::Type_Float value);
|
||||
///< add float literal and return value.
|
||||
|
||||
int addString (const std::string& value);
|
||||
///< add string literal and return value.
|
||||
|
||||
void clear();
|
||||
///< remove all literals.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,110 @@
|
||||
|
||||
#include "locals.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
const std::vector<std::string>& Locals::get (char type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 's': return mShorts;
|
||||
case 'l': return mLongs;
|
||||
case 'f': return mFloats;
|
||||
}
|
||||
|
||||
throw std::logic_error ("unknown variable type");
|
||||
}
|
||||
|
||||
int Locals::searchIndex (char type, const std::string& name) const
|
||||
{
|
||||
const std::vector<std::string>& collection = get (type);
|
||||
|
||||
std::vector<std::string>::const_iterator iter =
|
||||
std::find (collection.begin(), collection.end(), name);
|
||||
|
||||
if (iter==collection.end())
|
||||
return -1;
|
||||
|
||||
return iter-collection.begin();
|
||||
}
|
||||
|
||||
bool Locals::search (char type, const std::string& name) const
|
||||
{
|
||||
return searchIndex (type, name)!=-1;
|
||||
}
|
||||
|
||||
std::vector<std::string>& Locals::get (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 's': return mShorts;
|
||||
case 'l': return mLongs;
|
||||
case 'f': return mFloats;
|
||||
}
|
||||
|
||||
throw std::logic_error ("unknown variable type");
|
||||
}
|
||||
|
||||
char Locals::getType (const std::string& name) const
|
||||
{
|
||||
if (search ('s', name))
|
||||
return 's';
|
||||
|
||||
if (search ('l', name))
|
||||
return 'l';
|
||||
|
||||
if (search ('f', name))
|
||||
return 'f';
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
int Locals::getIndex (const std::string& name) const
|
||||
{
|
||||
int index = searchIndex ('s', name);
|
||||
|
||||
if (index!=-1)
|
||||
return index;
|
||||
|
||||
index = searchIndex ('l', name);
|
||||
|
||||
if (index!=-1)
|
||||
return index;
|
||||
|
||||
return searchIndex ('f', name);
|
||||
}
|
||||
|
||||
void Locals::write (std::ostream& localFile) const
|
||||
{
|
||||
localFile
|
||||
<< get ('s').size() << ' '
|
||||
<< get ('l').size() << ' '
|
||||
<< get ('f').size() << std::endl;
|
||||
|
||||
std::copy (get ('s').begin(), get ('s').end(),
|
||||
std::ostream_iterator<std::string> (localFile, " "));
|
||||
std::copy (get ('l').begin(), get ('l').end(),
|
||||
std::ostream_iterator<std::string> (localFile, " "));
|
||||
std::copy (get ('f').begin(), get ('f').end(),
|
||||
std::ostream_iterator<std::string> (localFile, " "));
|
||||
}
|
||||
|
||||
void Locals::declare (char type, const std::string& name)
|
||||
{
|
||||
get (type).push_back (name);
|
||||
}
|
||||
|
||||
void Locals::clear()
|
||||
{
|
||||
get ('s').clear();
|
||||
get ('l').clear();
|
||||
get ('f').clear();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
#ifndef COMPILER_LOCALS_H_INCLUDED
|
||||
#define COMPILER_LOCALS_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// \brief Local variable declarations
|
||||
|
||||
class Locals
|
||||
{
|
||||
std::vector<std::string> mShorts;
|
||||
std::vector<std::string> mLongs;
|
||||
std::vector<std::string> mFloats;
|
||||
|
||||
const std::vector<std::string>& get (char type) const;
|
||||
|
||||
int searchIndex (char type, const std::string& name) const;
|
||||
|
||||
bool search (char type, const std::string& name) const;
|
||||
|
||||
std::vector<std::string>& get (char type);
|
||||
|
||||
public:
|
||||
|
||||
char getType (const std::string& name) const;
|
||||
///< 's': short, 'l': long, 'f': float, ' ': does not exist.
|
||||
|
||||
int getIndex (const std::string& name) const;
|
||||
///< return index for local variable \a name (-1: does not exist).
|
||||
|
||||
void write (std::ostream& localFile) const;
|
||||
///< write declarations to file.
|
||||
|
||||
void declare (char type, const std::string& name);
|
||||
///< declares a variable.
|
||||
|
||||
void clear();
|
||||
///< remove all declarations.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,74 @@
|
||||
|
||||
#include "output.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "locals.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
Output::Output (Locals& locals) : mLocals (locals) {}
|
||||
|
||||
void Output::getCode (std::vector<Interpreter::Type_Code>& code) const
|
||||
{
|
||||
code.clear();
|
||||
|
||||
// header
|
||||
code.push_back (static_cast<Interpreter::Type_Code> (mCode.size()));
|
||||
|
||||
assert (mLiterals.getIntegerSize()%4==0);
|
||||
code.push_back (static_cast<Interpreter::Type_Code> (mLiterals.getIntegerSize()/4));
|
||||
|
||||
assert (mLiterals.getFloatSize()%4==0);
|
||||
code.push_back (static_cast<Interpreter::Type_Code> (mLiterals.getFloatSize()/4));
|
||||
|
||||
assert (mLiterals.getStringSize()%4==0);
|
||||
code.push_back (static_cast<Interpreter::Type_Code> (mLiterals.getStringSize()/4));
|
||||
|
||||
// code
|
||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||
|
||||
// literals
|
||||
mLiterals.append (code);
|
||||
}
|
||||
|
||||
const Literals& Output::getLiterals() const
|
||||
{
|
||||
return mLiterals;
|
||||
}
|
||||
|
||||
const std::vector<Interpreter::Type_Code>& Output::getCode() const
|
||||
{
|
||||
return mCode;
|
||||
}
|
||||
|
||||
const Locals& Output::getLocals() const
|
||||
{
|
||||
return mLocals;
|
||||
}
|
||||
|
||||
Literals& Output::getLiterals()
|
||||
{
|
||||
return mLiterals;
|
||||
}
|
||||
|
||||
std::vector<Interpreter::Type_Code>& Output::getCode()
|
||||
{
|
||||
return mCode;
|
||||
}
|
||||
|
||||
Locals& Output::getLocals()
|
||||
{
|
||||
return mLocals;
|
||||
}
|
||||
|
||||
void Output::clear()
|
||||
{
|
||||
mLiterals.clear();
|
||||
mCode.clear();
|
||||
mLocals.clear();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
#ifndef COMPILER_OUTPUT_H_INCLUDED
|
||||
#define COMPILER_OUTPUT_H_INCLUDED
|
||||
|
||||
#include "literals.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
|
||||
class Output
|
||||
{
|
||||
Literals mLiterals;
|
||||
std::vector<Interpreter::Type_Code> mCode;
|
||||
Locals& mLocals;
|
||||
|
||||
public:
|
||||
|
||||
Output (Locals& locals);
|
||||
|
||||
void getCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||
///< store generated code in \æ code.
|
||||
|
||||
const Literals& getLiterals() const;
|
||||
|
||||
const Locals& getLocals() const;
|
||||
|
||||
const std::vector<Interpreter::Type_Code>& getCode() const;
|
||||
|
||||
Literals& getLiterals();
|
||||
|
||||
std::vector<Interpreter::Type_Code>& getCode();
|
||||
|
||||
Locals& getLocals();
|
||||
|
||||
void clear();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,139 @@
|
||||
|
||||
#include "parser.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
#include "errorhandler.hpp"
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
// Report the error and throw an exception.
|
||||
|
||||
void Parser::reportSeriousError (const std::string& message, const TokenLoc& loc)
|
||||
{
|
||||
mErrorHandler.error (message, loc);
|
||||
throw SourceException();
|
||||
}
|
||||
|
||||
// Report the error
|
||||
|
||||
void Parser::reportError (const std::string& message, const TokenLoc& loc)
|
||||
{
|
||||
mErrorHandler.error (message, loc);
|
||||
}
|
||||
|
||||
// Report the warning without throwing an exception.
|
||||
|
||||
void Parser::reportWarning (const std::string& message, const TokenLoc& loc)
|
||||
{
|
||||
mErrorHandler.warning (message, loc);
|
||||
}
|
||||
|
||||
// Report an unexpected EOF condition.
|
||||
|
||||
void Parser::reportEOF()
|
||||
{
|
||||
mErrorHandler.endOfFile();
|
||||
throw EOFException();
|
||||
}
|
||||
|
||||
// Return error handler
|
||||
|
||||
ErrorHandler& Parser::getErrorHandler()
|
||||
{
|
||||
return mErrorHandler;
|
||||
}
|
||||
|
||||
// Return context
|
||||
|
||||
Context& Parser::getContext()
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
std::string Parser::toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
Parser::Parser (ErrorHandler& errorHandler, Context& context)
|
||||
: mErrorHandler (errorHandler), mContext (context)
|
||||
{}
|
||||
|
||||
// destructor
|
||||
|
||||
Parser::~Parser() {}
|
||||
|
||||
// Handle an int token.
|
||||
// \return fetch another token?
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
bool Parser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
reportSeriousError ("Unexpected numeric value", loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle a float token.
|
||||
// \return fetch another token?
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
bool Parser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
reportSeriousError ("Unexpected floating point value", loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle a name token.
|
||||
// \return fetch another token?
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
bool Parser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
reportSeriousError ("Unexpected name", loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle a keyword token.
|
||||
// \return fetch another token?
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
bool Parser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
reportSeriousError ("Unexpected keyword", loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle a special character token.
|
||||
// \return fetch another token?
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
bool Parser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
reportSeriousError ("Unexpected special token", loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle an EOF token.
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
void Parser::parseEOF (Scanner& scanner)
|
||||
{
|
||||
reportEOF();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
#ifndef COMPILER_PARSER_H_INCLUDED
|
||||
#define COMPILER_PARSER_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Scanner;
|
||||
struct TokenLoc;
|
||||
class ErrorHandler;
|
||||
class Context;
|
||||
|
||||
/// \brief Parser base class
|
||||
///
|
||||
/// This class defines a callback-parser.
|
||||
|
||||
class Parser
|
||||
{
|
||||
ErrorHandler& mErrorHandler;
|
||||
Context& mContext;
|
||||
|
||||
protected:
|
||||
|
||||
void reportSeriousError (const std::string& message, const TokenLoc& loc);
|
||||
///< Report the error and throw a exception.
|
||||
|
||||
void reportError (const std::string& message, const TokenLoc& loc);
|
||||
///< Report the error
|
||||
|
||||
void reportWarning (const std::string& message, const TokenLoc& loc);
|
||||
///< Report the warning without throwing an exception.
|
||||
|
||||
void reportEOF();
|
||||
///< Report an unexpected EOF condition.
|
||||
|
||||
ErrorHandler& getErrorHandler();
|
||||
///< Return error handler
|
||||
|
||||
Context& getContext();
|
||||
///< Return context
|
||||
|
||||
static std::string toLower (const std::string& name);
|
||||
|
||||
public:
|
||||
|
||||
Parser (ErrorHandler& errorHandler, Context& context);
|
||||
///< constructor
|
||||
|
||||
virtual ~Parser();
|
||||
///< destructor
|
||||
|
||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle an int token.
|
||||
/// \return fetch another token?
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
|
||||
virtual bool parseFloat (float value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a float token.
|
||||
/// \return fetch another token?
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
|
||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a keyword token.
|
||||
/// \return fetch another token?
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
|
||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,492 @@
|
||||
|
||||
#include "scanner.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
bool Scanner::get (char& c)
|
||||
{
|
||||
mStream.get (c);
|
||||
|
||||
if (!mStream.good())
|
||||
return false;
|
||||
|
||||
mPrevLoc =mLoc;
|
||||
|
||||
if (c=='\n')
|
||||
{
|
||||
mLoc.mColumn = 0;
|
||||
++mLoc.mLine;
|
||||
mLoc.mLiteral.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
++mLoc.mColumn;
|
||||
mLoc.mLiteral += c;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Scanner::putback (char c)
|
||||
{
|
||||
mStream.putback (c);
|
||||
mLoc = mPrevLoc;
|
||||
}
|
||||
|
||||
bool Scanner::scanToken (Parser& parser)
|
||||
{
|
||||
switch (mPutback)
|
||||
{
|
||||
case Putback_Special:
|
||||
|
||||
mPutback = Putback_None;
|
||||
return parser.parseSpecial (mPutbackCode, mPutbackLoc, *this);
|
||||
|
||||
case Putback_Integer:
|
||||
|
||||
mPutback = Putback_None;
|
||||
return parser.parseInt (mPutbackInteger, mPutbackLoc, *this);
|
||||
|
||||
case Putback_Float:
|
||||
|
||||
mPutback = Putback_None;
|
||||
return parser.parseFloat (mPutbackFloat, mPutbackLoc, *this);
|
||||
|
||||
case Putback_Name:
|
||||
|
||||
mPutback = Putback_None;
|
||||
return parser.parseName (mPutbackName, mPutbackLoc, *this);
|
||||
|
||||
case Putback_Keyword:
|
||||
|
||||
mPutback = Putback_None;
|
||||
return parser.parseKeyword (mPutbackCode, mPutbackLoc, *this);
|
||||
|
||||
case Putback_None:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
char c;
|
||||
|
||||
if (!get (c))
|
||||
{
|
||||
parser.parseEOF (*this);
|
||||
return false;
|
||||
}
|
||||
else if (c==';')
|
||||
{
|
||||
while (get (c))
|
||||
{
|
||||
if (c=='\n')
|
||||
{
|
||||
putback (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (isWhitespace (c))
|
||||
{
|
||||
mLoc.mLiteral.clear();
|
||||
return true;
|
||||
}
|
||||
else if (std::isdigit (c))
|
||||
{
|
||||
bool cont = false;
|
||||
|
||||
if (scanInt (c, parser, cont))
|
||||
{
|
||||
mLoc.mLiteral.clear();
|
||||
return cont;
|
||||
}
|
||||
}
|
||||
else if (std::isalpha (c) || c=='_' || c=='"')
|
||||
{
|
||||
bool cont = false;
|
||||
|
||||
if (scanName (c, parser, cont))
|
||||
{
|
||||
mLoc.mLiteral.clear();
|
||||
return cont;
|
||||
}
|
||||
}
|
||||
else if (c==13) // linux compatibility hack
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool cont = false;
|
||||
|
||||
if (scanSpecial (c, parser, cont))
|
||||
{
|
||||
mLoc.mLiteral.clear();
|
||||
return cont;
|
||||
}
|
||||
}
|
||||
|
||||
TokenLoc loc (mLoc);
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
mErrorHandler.error ("syntax error", loc);
|
||||
throw SourceException();
|
||||
}
|
||||
|
||||
bool Scanner::scanInt (char c, Parser& parser, bool& cont)
|
||||
{
|
||||
std::string value;
|
||||
|
||||
value += c;
|
||||
bool empty = false;
|
||||
|
||||
bool error = false;
|
||||
|
||||
while (get (c))
|
||||
{
|
||||
if (std::isdigit (c))
|
||||
{
|
||||
value += c;
|
||||
empty = false;
|
||||
}
|
||||
else if (std::isalpha (c) || c=='_')
|
||||
error = true;
|
||||
else if (c=='.' && !error)
|
||||
{
|
||||
return scanFloat (value, parser, cont);
|
||||
}
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty || error)
|
||||
return false;
|
||||
|
||||
TokenLoc loc (mLoc);
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
std::istringstream stream (value);
|
||||
|
||||
int intValue = 0;
|
||||
stream >> intValue;
|
||||
|
||||
cont = parser.parseInt (intValue, loc, *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scanner::scanFloat (const std::string& intValue, Parser& parser, bool& cont)
|
||||
{
|
||||
std::string value = intValue + ".";
|
||||
|
||||
char c;
|
||||
|
||||
bool empty = intValue.empty() || intValue=="-";
|
||||
bool error = false;
|
||||
|
||||
while (get (c))
|
||||
{
|
||||
if (std::isdigit (c))
|
||||
{
|
||||
value += c;
|
||||
empty = false;
|
||||
}
|
||||
else if (std::isalpha (c) || c=='_')
|
||||
error = true;
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty || error)
|
||||
return false;
|
||||
|
||||
TokenLoc loc (mLoc);
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
std::istringstream stream (value);
|
||||
|
||||
float floatValue = 0;
|
||||
stream >> floatValue;
|
||||
|
||||
cont = parser.parseFloat (floatValue, loc, *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scanner::scanName (char c, Parser& parser, bool& cont)
|
||||
{
|
||||
static const char *keywords[] =
|
||||
{
|
||||
"begin", "end",
|
||||
"short", "long", "float",
|
||||
"if", "endif", "else", "elseif",
|
||||
"while", "endwhile",
|
||||
"return",
|
||||
"messagebox",
|
||||
"set", "to",
|
||||
"getsquareroot",
|
||||
0
|
||||
};
|
||||
|
||||
std::string name;
|
||||
|
||||
if (!scanName (c, name))
|
||||
return false;
|
||||
|
||||
TokenLoc loc (mLoc);
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"')
|
||||
{
|
||||
name = name.substr (1, name.size()-2);
|
||||
cont = parser.parseName (name, loc, *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
std::string lowerCase;
|
||||
lowerCase.reserve (name.size());
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
for (; keywords[i]; ++i)
|
||||
if (lowerCase==keywords[i])
|
||||
break;
|
||||
|
||||
cont =
|
||||
keywords[i] ? parser.parseKeyword (i, loc, *this) : parser.parseName (name, loc, *this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scanner::scanName (char c, std::string& name)
|
||||
{
|
||||
bool first = false;
|
||||
bool error = false;
|
||||
|
||||
name.clear();
|
||||
|
||||
putback (c);
|
||||
|
||||
while (get (c))
|
||||
{
|
||||
if (!name.empty() && name[0]=='"')
|
||||
{
|
||||
if (c=='"')
|
||||
{
|
||||
name += c;
|
||||
break;
|
||||
}
|
||||
else if (c=='\\')
|
||||
{
|
||||
if (!get (c))
|
||||
{
|
||||
mErrorHandler.error ("incomplete escape sequence", mLoc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (c=='\n')
|
||||
{
|
||||
mErrorHandler.error ("incomplete string or name", mLoc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!(c=='"' && name.empty()))
|
||||
{
|
||||
if (!(std::isalpha (c) || std::isdigit (c) || c=='_'))
|
||||
{
|
||||
putback (c);
|
||||
break;
|
||||
}
|
||||
|
||||
if (first && std::isdigit (c))
|
||||
error = true;
|
||||
}
|
||||
|
||||
name += c;
|
||||
first = false;
|
||||
}
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
bool Scanner::scanSpecial (char c, Parser& parser, bool& cont)
|
||||
{
|
||||
int special = -1;
|
||||
|
||||
if (c=='\n')
|
||||
special = S_newline;
|
||||
else if (c=='(')
|
||||
special = S_open;
|
||||
else if (c==')')
|
||||
special = S_close;
|
||||
else if (c=='=')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='=')
|
||||
special = S_cmpEQ;
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (c=='!')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='=')
|
||||
special = S_cmpNE;
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (c=='-')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='>')
|
||||
special = S_ref;
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
special = S_minus;
|
||||
}
|
||||
}
|
||||
else
|
||||
special = S_minus;
|
||||
}
|
||||
else if (c=='<')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='=')
|
||||
special = S_cmpLE;
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
special = S_cmpLT;
|
||||
}
|
||||
}
|
||||
else
|
||||
special = S_cmpLT;
|
||||
}
|
||||
else if (c=='>')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='=')
|
||||
special = S_cmpGE;
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
special = S_cmpGT;
|
||||
}
|
||||
}
|
||||
else
|
||||
special = S_cmpGT;
|
||||
}
|
||||
else if (c==',')
|
||||
special = S_comma;
|
||||
else if (c=='+')
|
||||
special = S_plus;
|
||||
else if (c=='*')
|
||||
special = S_mult;
|
||||
else if (c=='/')
|
||||
special = S_div;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (special==S_newline)
|
||||
mLoc.mLiteral = "<newline>";
|
||||
|
||||
TokenLoc loc (mLoc);
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
cont = parser.parseSpecial (special, loc, *this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scanner::isWhitespace (char c)
|
||||
{
|
||||
return c==' ' || c=='\t';
|
||||
}
|
||||
|
||||
// constructor
|
||||
|
||||
Scanner::Scanner (ErrorHandler& errorHandler, std::istream& inputStream)
|
||||
: mErrorHandler (errorHandler), mStream (inputStream), mPutback (Putback_None)
|
||||
{
|
||||
}
|
||||
|
||||
void Scanner::scan (Parser& parser)
|
||||
{
|
||||
while (scanToken (parser));
|
||||
}
|
||||
|
||||
void Scanner::putbackSpecial (int code, const TokenLoc& loc)
|
||||
{
|
||||
mPutback = Putback_Special;
|
||||
mPutbackCode = code;
|
||||
mPutbackLoc = loc;
|
||||
}
|
||||
|
||||
void Scanner::putbackInt (int value, const TokenLoc& loc)
|
||||
{
|
||||
mPutback = Putback_Integer;
|
||||
mPutbackInteger = value;
|
||||
mPutbackLoc = loc;
|
||||
}
|
||||
|
||||
void Scanner::putbackFloat (float value, const TokenLoc& loc)
|
||||
{
|
||||
mPutback = Putback_Float;
|
||||
mPutbackFloat = value;
|
||||
mPutbackLoc = loc;
|
||||
}
|
||||
|
||||
void Scanner::putbackName (const std::string& name, const TokenLoc& loc)
|
||||
{
|
||||
mPutback = Putback_Name;
|
||||
mPutbackName = name;
|
||||
mPutbackLoc = loc;
|
||||
}
|
||||
|
||||
void Scanner::putbackKeyword (int keyword, const TokenLoc& loc)
|
||||
{
|
||||
mPutback = Putback_Keyword;
|
||||
mPutbackCode = keyword;
|
||||
mPutbackLoc = loc;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,113 @@
|
||||
#ifndef COMPILER_SCANNER_H_INCLUDED
|
||||
#define COMPILER_SCANNER_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
#include "tokenloc.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class ErrorHandler;
|
||||
class Parser;
|
||||
|
||||
/// \brief Scanner
|
||||
///
|
||||
/// This class translate a char-stream to a token stream (delivered via
|
||||
/// parser-callbacks).
|
||||
|
||||
class Scanner
|
||||
{
|
||||
enum putback_type
|
||||
{
|
||||
Putback_None, Putback_Special, Putback_Integer, Putback_Float,
|
||||
Putback_Name, Putback_Keyword
|
||||
};
|
||||
|
||||
ErrorHandler& mErrorHandler;
|
||||
TokenLoc mLoc;
|
||||
TokenLoc mPrevLoc;
|
||||
std::istream& mStream;
|
||||
putback_type mPutback;
|
||||
int mPutbackCode;
|
||||
int mPutbackInteger;
|
||||
float mPutbackFloat;
|
||||
std::string mPutbackName;
|
||||
TokenLoc mPutbackLoc;
|
||||
|
||||
public:
|
||||
|
||||
enum keyword
|
||||
{
|
||||
K_begin, K_end,
|
||||
K_short, K_long, K_float,
|
||||
K_if, K_endif, K_else, K_elseif,
|
||||
K_while, K_endwhile,
|
||||
K_return,
|
||||
K_messagebox,
|
||||
K_set, K_to,
|
||||
K_getsquareroot
|
||||
};
|
||||
|
||||
enum special
|
||||
{
|
||||
S_newline,
|
||||
S_open, S_close,
|
||||
S_cmpEQ, S_cmpNE, S_cmpLT, S_cmpLE, S_cmpGT, S_cmpGE,
|
||||
S_plus, S_minus, S_mult, S_div,
|
||||
S_comma,
|
||||
S_ref
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// not implemented
|
||||
|
||||
Scanner (const Scanner&);
|
||||
Scanner& operator= (const Scanner&);
|
||||
|
||||
bool get (char& c);
|
||||
|
||||
void putback (char c);
|
||||
|
||||
bool scanToken (Parser& parser);
|
||||
|
||||
bool scanInt (char c, Parser& parser, bool& cont);
|
||||
|
||||
bool scanFloat (const std::string& intValue, Parser& parser, bool& cont);
|
||||
|
||||
bool scanName (char c, Parser& parser, bool& cont);
|
||||
|
||||
bool scanName (char c, std::string& name);
|
||||
|
||||
bool scanSpecial (char c, Parser& parser, bool& cont);
|
||||
|
||||
static bool isWhitespace (char c);
|
||||
|
||||
public:
|
||||
|
||||
Scanner (ErrorHandler& errorHandler, std::istream& inputStream);
|
||||
///< constructor
|
||||
|
||||
void scan (Parser& parser);
|
||||
///< Scan a token and deliver it to the parser.
|
||||
|
||||
void putbackSpecial (int code, const TokenLoc& loc);
|
||||
///< put back a special token
|
||||
|
||||
void putbackInt (int value, const TokenLoc& loc);
|
||||
///< put back an integer token
|
||||
|
||||
void putbackFloat (float value, const TokenLoc& loc);
|
||||
///< put back a float token
|
||||
|
||||
void putbackName (const std::string& name, const TokenLoc& loc);
|
||||
///< put back a name toekn
|
||||
|
||||
void putbackKeyword (int keyword, const TokenLoc& loc);
|
||||
///< put back a keyword token
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,80 @@
|
||||
|
||||
#include "scriptparser.hpp"
|
||||
|
||||
#include "scanner.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context,
|
||||
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)
|
||||
{}
|
||||
|
||||
void ScriptParser::getCode (std::vector<Interpreter::Type_Code>& code) const
|
||||
{
|
||||
mOutput.getCode (code);
|
||||
}
|
||||
|
||||
bool ScriptParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
mLineParser.reset();
|
||||
if (mLineParser.parseName (name, loc, scanner))
|
||||
scanner.scan (mLineParser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mLineParser.reset();
|
||||
if (mLineParser.parseKeyword (keyword, loc, scanner))
|
||||
scanner.scan (mLineParser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline) // empty line
|
||||
return true;
|
||||
|
||||
mLineParser.reset();
|
||||
if (mLineParser.parseSpecial (code, loc, scanner))
|
||||
scanner.scan (mLineParser);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptParser::parseEOF (Scanner& scanner)
|
||||
{
|
||||
if (mEnd)
|
||||
Parser::parseEOF (scanner);
|
||||
}
|
||||
|
||||
void ScriptParser::reset()
|
||||
{
|
||||
mLineParser.reset();
|
||||
mOutput.clear();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
#ifndef COMPILER_SCRIPTPARSER_H_INCLUDED
|
||||
#define COMPILER_SCRIPTPARSER_H_INCLUDED
|
||||
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "lineparser.hpp"
|
||||
#include "controlparser.hpp"
|
||||
#include "output.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
|
||||
// Script parser, to be used in dialogue scripts and as part of FileParser
|
||||
|
||||
class ScriptParser : public Parser
|
||||
{
|
||||
Output mOutput;
|
||||
LineParser mLineParser;
|
||||
ControlParser mControlParser;
|
||||
bool mEnd;
|
||||
|
||||
public:
|
||||
|
||||
/// \param end of script is marked by end keyword.
|
||||
ScriptParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
bool end = false);
|
||||
|
||||
void getCode (std::vector<Interpreter::Type_Code>& code) const;
|
||||
///< store generated code in \æ code.
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
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?
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,41 @@
|
||||
|
||||
#include "skipparser.hpp"
|
||||
|
||||
#include "scanner.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
SkipParser::SkipParser (ErrorHandler& errorHandler, Context& context)
|
||||
: Parser (errorHandler, context)
|
||||
{}
|
||||
|
||||
bool SkipParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkipParser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkipParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkipParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkipParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
#ifndef COMPILER_SKIPPARSER_H_INCLUDED
|
||||
#define COMPILER_SKIPPARSER_H_INCLUDED
|
||||
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
// \brief Skip parser for skipping a line
|
||||
//
|
||||
// This parser is mainly intended for skipping the rest of a faulty line.
|
||||
|
||||
class SkipParser : public Parser
|
||||
{
|
||||
public:
|
||||
|
||||
SkipParser (ErrorHandler& errorHandler, Context& context);
|
||||
|
||||
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle an int token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseFloat (float value, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a float token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
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?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,38 @@
|
||||
|
||||
#include "streamerrorhandler.hpp"
|
||||
|
||||
#include "tokenloc.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
// Report error to the user.
|
||||
|
||||
void StreamErrorHandler::report (const std::string& message, const TokenLoc& loc,
|
||||
Type type)
|
||||
{
|
||||
if (type==ErrorMessage)
|
||||
mStream << "error ";
|
||||
else
|
||||
mStream << "warning ";
|
||||
|
||||
mStream
|
||||
<< "line " << loc.mLine << ", column " << loc.mColumn
|
||||
<< " (" << loc.mLiteral << ")" << std::endl
|
||||
<< " " << message << std::endl;
|
||||
}
|
||||
|
||||
// Report a file related error
|
||||
|
||||
void StreamErrorHandler::report (const std::string& message, Type type)
|
||||
{
|
||||
if (type==ErrorMessage)
|
||||
mStream << "error ";
|
||||
else
|
||||
mStream << "warning ";
|
||||
|
||||
mStream
|
||||
<< "file:" << std::endl
|
||||
<< " " << message << std::endl;
|
||||
}
|
||||
|
||||
StreamErrorHandler::StreamErrorHandler (std::ostream& ErrorStream) : mStream (ErrorStream) {}}
|
@ -0,0 +1,37 @@
|
||||
|
||||
#ifndef COMPILER_STREAMERRORHANDLER_H_INCLUDED
|
||||
#define COMPILER_STREAMERRORHANDLER_H_INCLUDED
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "errorhandler.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// \brief Error handler implementation: Write errors into stream
|
||||
|
||||
class StreamErrorHandler : public ErrorHandler
|
||||
{
|
||||
std::ostream& mStream;
|
||||
|
||||
// not implemented
|
||||
|
||||
StreamErrorHandler (const StreamErrorHandler&);
|
||||
StreamErrorHandler& operator= (const StreamErrorHandler&);
|
||||
|
||||
virtual void report (const std::string& message, const TokenLoc& loc, Type type);
|
||||
///< Report error to the user.
|
||||
|
||||
virtual void report (const std::string& message, Type type);
|
||||
///< Report a file related error
|
||||
|
||||
public:
|
||||
|
||||
// constructors
|
||||
|
||||
StreamErrorHandler (std::ostream& ErrorStream);
|
||||
///< constructor
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,52 @@
|
||||
|
||||
#include "stringparser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "generator.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
|
||||
: Parser (errorHandler, context), mLiterals (literals), mState (StartState)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool StringParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==StartState || mState==CommaState)
|
||||
{
|
||||
Generator::pushString (mCode, mLiterals, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
bool StringParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_comma && mState==StartState)
|
||||
{
|
||||
mState = CommaState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void StringParser::append (std::vector<Interpreter::Type_Code>& code)
|
||||
{
|
||||
std::copy (mCode.begin(), mCode.end(), std::back_inserter (code));
|
||||
}
|
||||
|
||||
void StringParser::reset()
|
||||
{
|
||||
mState = StartState;
|
||||
mCode.clear();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
#ifndef COMPILER_STRINGPARSER_H_INCLUDED
|
||||
#define COMPILER_STRINGPARSER_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Literals;
|
||||
|
||||
class StringParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
StartState, CommaState
|
||||
};
|
||||
|
||||
Literals& mLiterals;
|
||||
State mState;
|
||||
std::vector<Interpreter::Type_Code> mCode;
|
||||
|
||||
public:
|
||||
|
||||
StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals);
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name 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 append (std::vector<Interpreter::Type_Code>& code);
|
||||
///< Append code for parsed string.
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,20 @@
|
||||
#ifndef COMPILER_TOKENLOC_H_INCLUDED
|
||||
#define COMPILER_TOKENLOC_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// \brief Location of a token in a source file
|
||||
|
||||
struct TokenLoc
|
||||
{
|
||||
int mColumn;
|
||||
int mLine;
|
||||
std::string mLiteral;
|
||||
|
||||
TokenLoc() : mColumn (0), mLine (0), mLiteral ("") {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TOKENLOC_H_INCLUDED
|
@ -0,0 +1,31 @@
|
||||
#ifndef INTERPRETER_CONTEXT_H_INCLUDED
|
||||
#define INTERPRETER_CONTEXT_H_INCLUDED
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Context() {}
|
||||
|
||||
virtual int getLocalShort (int index) const = 0;
|
||||
|
||||
virtual int getLocalLong (int index) const = 0;
|
||||
|
||||
virtual float getLocalFloat (int index) const = 0;
|
||||
|
||||
virtual void setLocalShort (int index, int value) = 0;
|
||||
|
||||
virtual void setLocalLong (int index, int value) = 0;
|
||||
|
||||
virtual void setLocalFloat (int index, float value) = 0;
|
||||
|
||||
virtual void messageBox (const std::string& message,
|
||||
const std::vector<std::string>& buttons) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -0,0 +1,76 @@
|
||||
#ifndef INTERPRETER_CONTROLOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_CONTROLOPCODES_H_INCLUDED
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class OpReturn : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
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
|
@ -0,0 +1,101 @@
|
||||
Note: a word is considered to be 32 bit long.
|
||||
|
||||
Header (4 words):
|
||||
word: number of words in code block
|
||||
word: number of words in integer literal block
|
||||
word: number of words in float literal block
|
||||
word: number of words in string literal block
|
||||
|
||||
Body (variable length):
|
||||
code block
|
||||
integer literal block (contains a collection of 1 word long integers)
|
||||
float literal block (contains a collection of 1 word long floating point numbers)
|
||||
string literal block (contains a collection of strings of variable length, word-padded)
|
||||
|
||||
Code bit-patterns:
|
||||
|
||||
3322222222221111111111
|
||||
10987654321098765432109876543210
|
||||
00ccccccAAAAAAAAAAAAAAAAAAAAAAAA segment 0: 64 opcodes, 1 24-bit argument
|
||||
01ccccccAAAAAAAAAAAABBBBBBBBBBBB segment 1: 64 opcodes, 2 12-bit arguments
|
||||
10ccccccccccAAAAAAAAAAAAAAAAAAAA segment 2: 1024 opcodes, 1 20-bit argument
|
||||
110000ccccccccccAAAAAAAAAAAAAAAA segment 3: 1024 opcodes, 1 16-bit argument
|
||||
110001ccccccccccAAAAAAAABBBBBBBB segment 4: 1024 opcodes, 2 8-bit arguments
|
||||
110010cccccccccccccccccccccccccc segment 5: 67108864 opcodes, no arguments
|
||||
other bit-patterns reserved
|
||||
|
||||
legent:
|
||||
c: code
|
||||
A: argument 0
|
||||
B: argument 1
|
||||
|
||||
Segment 0:
|
||||
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:
|
||||
opcodes 0-31 unused
|
||||
opcodes 32-63 reserved for extensions
|
||||
|
||||
Segment 2:
|
||||
opcodes 0-511 unused
|
||||
opcodes 512-1023 reserved for extensions
|
||||
|
||||
Segment 3:
|
||||
op 0: show message box with message string literal index in stack[0];
|
||||
buttons (if any) in stack[arg0]..stack[1];
|
||||
additional arguments (if any) in stack[arg0+n]..stack[arg0+1];
|
||||
n is determined according to the message string
|
||||
all arguments are removed from stack
|
||||
opcodes 1-511 unused
|
||||
opcodes 512-1023 reserved for extensions
|
||||
|
||||
Segment 4:
|
||||
opcodes 0-511 unused
|
||||
opcodes 512-1023 reserved for extensions
|
||||
|
||||
Segment 5:
|
||||
op 0: store stack[0] in local short stack[1] and pop twice
|
||||
op 1: store stack[0] in local long stack[1] and pop twice
|
||||
op 2: store stack[0] in local float stack[1] and pop twice
|
||||
op 3: convert stack[0] from integer to float
|
||||
op 4: replace stack[0] with integer literal index stack[0]
|
||||
op 5: replace stack[0] with float literal index stack[0]
|
||||
op 6: convert stack[0] from float to integer
|
||||
op 7: invert sign of int value stack[0]
|
||||
op 8: invert sign of float value stack[0]
|
||||
op 9: add (integer) stack[0] to stack[1], pop twice, push result
|
||||
op 10: add (float) stack[0] to stack[1], pop twice, push result
|
||||
op 11: sub (integer) stack[1] from stack[0], pop twice, push result
|
||||
op 12: sub (float) stack[1] from stack[0], pop twice, push result
|
||||
op 13: mul (integer) stack[0] with stack[1], pop twice, push result
|
||||
op 14: mul (float) stack[0] with stack[1], pop twice, push result
|
||||
op 15: div (integer) stack[1] by stack[0], pop twice, push result
|
||||
op 16: div (float) stack[1] by stack[0], pop twice, push result
|
||||
op 17: convert stack[1] from integer to float
|
||||
op 18: convert stack[1] from float to integer
|
||||
op 19: take square root of stack[0] (float)
|
||||
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]
|
||||
op 24: skip next instruction if stack[0]==0; pop
|
||||
op 25: skip next instruction if stack[0]!=0; pop
|
||||
op 26: compare (intger) stack[1] with stack[0]; pop twice; push 1 if equal, 0 else
|
||||
op 27: compare (intger) stack[1] with stack[0]; pop twice; push 1 if no equal, 0 else
|
||||
op 28: compare (intger) stack[1] with stack[0]; pop twice; push 1 if lesser than, 0 else
|
||||
op 29: compare (intger) stack[1] with stack[0]; pop twice; push 1 if lesser or equal, 0 else
|
||||
op 30: compare (intger) stack[1] with stack[0]; pop twice; push 1 if greater than, 0 else
|
||||
op 31: compare (intger) stack[1] with stack[0]; pop twice; push 1 if greater or equal, 0 else
|
||||
op 32: compare (float) stack[1] with stack[0]; pop twice; push 1 if equal, 0 else
|
||||
op 33: compare (float) stack[1] with stack[0]; pop twice; push 1 if no equal, 0 else
|
||||
op 34: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser than, 0 else
|
||||
op 35: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser or equal, 0 else
|
||||
op 36: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater than, 0 else
|
||||
op 37: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater or equal, 0 else
|
||||
opcodes 38-33554431 unused
|
||||
opcodes 33554432-67108863 reserved for extensions
|
||||
|
@ -0,0 +1,93 @@
|
||||
#ifndef INTERPRETER_GENERICOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_GENERICOPCODES_H_INCLUDED
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class OpPushInt : public Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
runtime.push (arg0);
|
||||
}
|
||||
};
|
||||
|
||||
class OpIntToFloat : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer data = *reinterpret_cast<Type_Integer *> (&runtime[0]);
|
||||
Type_Float floatValue = static_cast<Type_Float> (data);
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&floatValue);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFloatToInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Float data = *reinterpret_cast<Type_Float *> (&runtime[0]);
|
||||
Type_Integer integerValue = static_cast<Type_Integer> (data);
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&integerValue);
|
||||
}
|
||||
};
|
||||
|
||||
class OpNegateInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer data = *reinterpret_cast<Type_Integer *> (&runtime[0]);
|
||||
data = -data;
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&data);
|
||||
}
|
||||
};
|
||||
|
||||
class OpNegateFloat : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Float data = *reinterpret_cast<Type_Float *> (&runtime[0]);
|
||||
data = -data;
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&data);
|
||||
}
|
||||
};
|
||||
|
||||
class OpIntToFloat1 : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Integer data = *reinterpret_cast<Type_Integer *> (&runtime[1]);
|
||||
Type_Float floatValue = static_cast<Type_Float> (data);
|
||||
runtime[1] = *reinterpret_cast<Type_Data *> (&floatValue);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFloatToInt1 : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Float data = *reinterpret_cast<Type_Float *> (&runtime[1]);
|
||||
Type_Integer integerValue = static_cast<Type_Integer> (data);
|
||||
runtime[1] = *reinterpret_cast<Type_Data *> (&integerValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,83 @@
|
||||
|
||||
#include "installopcodes.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "interpreter.hpp"
|
||||
#include "genericopcodes.hpp"
|
||||
#include "localopcodes.hpp"
|
||||
#include "mathopcodes.hpp"
|
||||
#include "controlopcodes.hpp"
|
||||
#include "miscopcodes.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
void installOpcodes (Interpreter& interpreter)
|
||||
{
|
||||
// generic
|
||||
interpreter.installSegment0 (0, new OpPushInt);
|
||||
interpreter.installSegment5 (3, new OpIntToFloat);
|
||||
interpreter.installSegment5 (6, new OpFloatToInt);
|
||||
interpreter.installSegment5 (7, new OpNegateInt);
|
||||
interpreter.installSegment5 (8, new OpNegateFloat);
|
||||
interpreter.installSegment5 (17, new OpIntToFloat1);
|
||||
interpreter.installSegment5 (18, new OpFloatToInt1);
|
||||
|
||||
// local variables & literals
|
||||
interpreter.installSegment5 (0, new OpStoreLocalShort);
|
||||
interpreter.installSegment5 (1, new OpStoreLocalLong);
|
||||
interpreter.installSegment5 (2, new OpStoreLocalFloat);
|
||||
interpreter.installSegment5 (4, new OpFetchIntLiteral);
|
||||
interpreter.installSegment5 (5, new OpFetchFloatLiteral);
|
||||
interpreter.installSegment5 (21, new OpFetchLocalShort);
|
||||
interpreter.installSegment5 (22, new OpFetchLocalLong);
|
||||
interpreter.installSegment5 (23, new OpFetchLocalFloat);
|
||||
|
||||
// math
|
||||
interpreter.installSegment5 (9, new OpAddInt<Type_Integer>);
|
||||
interpreter.installSegment5 (10, new OpAddInt<Type_Float>);
|
||||
interpreter.installSegment5 (11, new OpSubInt<Type_Integer>);
|
||||
interpreter.installSegment5 (12, new OpSubInt<Type_Float>);
|
||||
interpreter.installSegment5 (13, new OpMulInt<Type_Integer>);
|
||||
interpreter.installSegment5 (14, new OpMulInt<Type_Float>);
|
||||
interpreter.installSegment5 (15, new OpDivInt<Type_Integer>);
|
||||
interpreter.installSegment5 (16, new OpDivInt<Type_Float>);
|
||||
interpreter.installSegment5 (19, new OpSquareRoot);
|
||||
interpreter.installSegment5 (26,
|
||||
new OpCompare<Type_Integer, std::equal_to<Type_Integer> >);
|
||||
interpreter.installSegment5 (27,
|
||||
new OpCompare<Type_Integer, std::not_equal_to<Type_Integer> >);
|
||||
interpreter.installSegment5 (28,
|
||||
new OpCompare<Type_Integer, std::less<Type_Integer> >);
|
||||
interpreter.installSegment5 (29,
|
||||
new OpCompare<Type_Integer, std::less_equal<Type_Integer> >);
|
||||
interpreter.installSegment5 (30,
|
||||
new OpCompare<Type_Integer, std::greater<Type_Integer> >);
|
||||
interpreter.installSegment5 (31,
|
||||
new OpCompare<Type_Integer, std::greater_equal<Type_Integer> >);
|
||||
|
||||
interpreter.installSegment5 (32,
|
||||
new OpCompare<Type_Float, std::equal_to<Type_Float> >);
|
||||
interpreter.installSegment5 (33,
|
||||
new OpCompare<Type_Float, std::not_equal_to<Type_Float> >);
|
||||
interpreter.installSegment5 (34,
|
||||
new OpCompare<Type_Float, std::less<Type_Float> >);
|
||||
interpreter.installSegment5 (35,
|
||||
new OpCompare<Type_Float, std::less_equal<Type_Float> >);
|
||||
interpreter.installSegment5 (36,
|
||||
new OpCompare<Type_Float, std::greater<Type_Float> >);
|
||||
interpreter.installSegment5 (37,
|
||||
new OpCompare<Type_Float, std::greater_equal<Type_Float> >);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
#ifndef INTERPRETER_INSTALLOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_INSTALLOPCODES_H_INCLUDED
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Interpreter;
|
||||
|
||||
void installOpcodes (Interpreter& interpreter);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,217 @@
|
||||
|
||||
#include "interpreter.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "opcodes.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
void Interpreter::execute (Type_Code code)
|
||||
{
|
||||
unsigned int segSpec = code>>30;
|
||||
|
||||
switch (segSpec)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int opcode = code>>24;
|
||||
unsigned int arg0 = code & 0xffffff;
|
||||
|
||||
std::map<int, Opcode1 *>::iterator iter = mSegment0.find (opcode);
|
||||
|
||||
if (iter==mSegment0.end())
|
||||
abortUnknownCode (0, opcode);
|
||||
|
||||
iter->second->execute (mRuntime, arg0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
int opcode = (code>>24) & 0x3f;
|
||||
unsigned int arg0 = (code>>16) & 0xfff;
|
||||
unsigned int arg1 = code & 0xfff;
|
||||
|
||||
std::map<int, Opcode2 *>::iterator iter = mSegment1.find (opcode);
|
||||
|
||||
if (iter==mSegment1.end())
|
||||
abortUnknownCode (1, opcode);
|
||||
|
||||
iter->second->execute (mRuntime, arg0, arg1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
int opcode = (code>>20) & 0x3ff;
|
||||
unsigned int arg0 = code & 0xfffff;
|
||||
|
||||
std::map<int, Opcode1 *>::iterator iter = mSegment2.find (opcode);
|
||||
|
||||
if (iter==mSegment2.end())
|
||||
abortUnknownCode (2, opcode);
|
||||
|
||||
iter->second->execute (mRuntime, arg0);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
segSpec = code>>26;
|
||||
|
||||
switch (segSpec)
|
||||
{
|
||||
case 0x30:
|
||||
{
|
||||
int opcode = (code>>16) & 0x3ff;
|
||||
unsigned int arg0 = code & 0xffff;
|
||||
|
||||
std::map<int, Opcode1 *>::iterator iter = mSegment3.find (opcode);
|
||||
|
||||
if (iter==mSegment3.end())
|
||||
abortUnknownCode (3, opcode);
|
||||
|
||||
iter->second->execute (mRuntime, arg0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x31:
|
||||
{
|
||||
int opcode = (code>>16) & 0x3ff;
|
||||
unsigned int arg0 = (code>>8) & 0xff;
|
||||
unsigned int arg1 = code & 0xff;
|
||||
|
||||
std::map<int, Opcode2 *>::iterator iter = mSegment4.find (opcode);
|
||||
|
||||
if (iter==mSegment4.end())
|
||||
abortUnknownCode (4, opcode);
|
||||
|
||||
iter->second->execute (mRuntime, arg0, arg1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x32:
|
||||
{
|
||||
int opcode = code & 0x3ffffff;
|
||||
|
||||
std::map<int, Opcode0 *>::iterator iter = mSegment5.find (opcode);
|
||||
|
||||
if (iter==mSegment5.end())
|
||||
abortUnknownCode (5, opcode);
|
||||
|
||||
iter->second->execute (mRuntime);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
abortUnknownSegment (code);
|
||||
}
|
||||
|
||||
void Interpreter::abortUnknownCode (int segment, int opcode)
|
||||
{
|
||||
std::ostringstream error;
|
||||
|
||||
error << "unknown opcode " << opcode << " in segment " << segment;
|
||||
|
||||
throw std::runtime_error (error.str());
|
||||
}
|
||||
|
||||
void Interpreter::abortUnknownSegment (Type_Code code)
|
||||
{
|
||||
std::ostringstream error;
|
||||
|
||||
error << "opcode outside of the allocated segment range: " << code;
|
||||
|
||||
throw std::runtime_error (error.str());
|
||||
}
|
||||
|
||||
Interpreter::Interpreter (Context& context)
|
||||
: mRuntime (context)
|
||||
{}
|
||||
|
||||
Interpreter::~Interpreter()
|
||||
{
|
||||
for (std::map<int, Opcode1 *>::iterator iter (mSegment0.begin());
|
||||
iter!=mSegment0.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
for (std::map<int, Opcode2 *>::iterator iter (mSegment1.begin());
|
||||
iter!=mSegment1.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
for (std::map<int, Opcode1 *>::iterator iter (mSegment2.begin());
|
||||
iter!=mSegment2.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
for (std::map<int, Opcode1 *>::iterator iter (mSegment3.begin());
|
||||
iter!=mSegment3.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
for (std::map<int, Opcode2 *>::iterator iter (mSegment4.begin());
|
||||
iter!=mSegment4.end(); ++iter)
|
||||
delete iter->second;
|
||||
|
||||
for (std::map<int, Opcode0 *>::iterator iter (mSegment5.begin());
|
||||
iter!=mSegment5.end(); ++iter)
|
||||
delete iter->second;
|
||||
}
|
||||
|
||||
void Interpreter::installSegment0 (int code, Opcode1 *opcode)
|
||||
{
|
||||
mSegment0.insert (std::make_pair (code, opcode));
|
||||
}
|
||||
|
||||
void Interpreter::installSegment1 (int code, Opcode2 *opcode)
|
||||
{
|
||||
mSegment1.insert (std::make_pair (code, opcode));
|
||||
}
|
||||
|
||||
void Interpreter::installSegment2 (int code, Opcode1 *opcode)
|
||||
{
|
||||
mSegment2.insert (std::make_pair (code, opcode));
|
||||
}
|
||||
|
||||
void Interpreter::installSegment3 (int code, Opcode1 *opcode)
|
||||
{
|
||||
mSegment3.insert (std::make_pair (code, opcode));
|
||||
}
|
||||
|
||||
void Interpreter::installSegment4 (int code, Opcode2 *opcode)
|
||||
{
|
||||
mSegment4.insert (std::make_pair (code, opcode));
|
||||
}
|
||||
|
||||
void Interpreter::installSegment5 (int code, Opcode0 *opcode)
|
||||
{
|
||||
mSegment5.insert (std::make_pair (code, opcode));
|
||||
}
|
||||
|
||||
void Interpreter::run (const Type_Code *code, int codeSize)
|
||||
{
|
||||
assert (codeSize>=4);
|
||||
|
||||
mRuntime.configure (code, codeSize);
|
||||
|
||||
int opcodes = static_cast<int> (code[0]);
|
||||
|
||||
const Type_Code *codeBlock = code + 4;
|
||||
|
||||
while (mRuntime.getPC()>=0 && mRuntime.getPC()<opcodes)
|
||||
{
|
||||
Type_Code code = codeBlock[mRuntime.getPC()];
|
||||
mRuntime.setPC (mRuntime.getPC()+1);
|
||||
execute (code);
|
||||
}
|
||||
|
||||
mRuntime.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
#ifndef INTERPRETER_INTERPRETER_H_INCLUDED
|
||||
#define INTERPRETER_INTERPRETER_H_INCLUDED
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "runtime.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Opcode0;
|
||||
class Opcode1;
|
||||
class Opcode2;
|
||||
|
||||
class Interpreter
|
||||
{
|
||||
Runtime mRuntime;
|
||||
std::map<int, Opcode1 *> mSegment0;
|
||||
std::map<int, Opcode2 *> mSegment1;
|
||||
std::map<int, Opcode1 *> mSegment2;
|
||||
std::map<int, Opcode1 *> mSegment3;
|
||||
std::map<int, Opcode2 *> mSegment4;
|
||||
std::map<int, Opcode0 *> mSegment5;
|
||||
|
||||
// not implemented
|
||||
Interpreter (const Interpreter&);
|
||||
Interpreter& operator= (const Interpreter&);
|
||||
|
||||
void execute (Type_Code code);
|
||||
|
||||
void abortUnknownCode (int segment, int opcode);
|
||||
|
||||
void abortUnknownSegment (Type_Code code);
|
||||
|
||||
public:
|
||||
|
||||
Interpreter (Context& context);
|
||||
|
||||
~Interpreter();
|
||||
|
||||
void installSegment0 (int code, Opcode1 *opcode);
|
||||
///< ownership of \a opcode is transferred to *this.
|
||||
|
||||
void installSegment1 (int code, Opcode2 *opcode);
|
||||
///< ownership of \a opcode is transferred to *this.
|
||||
|
||||
void installSegment2 (int code, Opcode1 *opcode);
|
||||
///< ownership of \a opcode is transferred to *this.
|
||||
|
||||
void installSegment3 (int code, Opcode1 *opcode);
|
||||
///< ownership of \a opcode is transferred to *this.
|
||||
|
||||
void installSegment4 (int code, Opcode2 *opcode);
|
||||
///< ownership of \a opcode is transferred to *this.
|
||||
|
||||
void installSegment5 (int code, Opcode0 *opcode);
|
||||
///< ownership of \a opcode is transferred to *this.
|
||||
|
||||
void run (const Type_Code *code, int codeSize);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,118 @@
|
||||
#ifndef INTERPRETER_LOCALOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_LOCALOPCODES_H_INCLUDED
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class OpStoreLocalShort : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Data data = runtime[0];
|
||||
int index = runtime[1];
|
||||
|
||||
runtime.getContext().setLocalShort (index, *reinterpret_cast<int *> (&data));
|
||||
|
||||
runtime.pop();
|
||||
runtime.pop();
|
||||
}
|
||||
};
|
||||
|
||||
class OpStoreLocalLong : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Data data = runtime[0];
|
||||
int index = runtime[1];
|
||||
|
||||
runtime.getContext().setLocalLong (index, *reinterpret_cast<int *> (&data));
|
||||
|
||||
runtime.pop();
|
||||
runtime.pop();
|
||||
}
|
||||
};
|
||||
|
||||
class OpStoreLocalFloat : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Data data = runtime[0];
|
||||
int index = runtime[1];
|
||||
|
||||
runtime.getContext().setLocalFloat (index, *reinterpret_cast<float *> (&data));
|
||||
|
||||
runtime.pop();
|
||||
runtime.pop();
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchIntLiteral : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
int intValue = runtime.getIntegerLiteral (runtime[0]);
|
||||
runtime[0] = intValue;
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchFloatLiteral : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
float floatValue = runtime.getFloatLiteral (runtime[0]);
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&floatValue);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchLocalShort : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
int index = runtime[0];
|
||||
int value = runtime.getContext().getLocalShort (index);
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&value);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchLocalLong : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
int index = runtime[0];
|
||||
int value = runtime.getContext().getLocalLong (index);
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&value);
|
||||
}
|
||||
};
|
||||
|
||||
class OpFetchLocalFloat : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
int index = runtime[0];
|
||||
float value = runtime.getContext().getLocalFloat (index);
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,126 @@
|
||||
#ifndef INTERPRETER_MATHOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_MATHOPCODES_H_INCLUDED
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
template<typename T>
|
||||
class OpAddInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
+
|
||||
*reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OpSubInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
-
|
||||
*reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OpMulInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
*
|
||||
*reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class OpDivInt : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
T left = *reinterpret_cast<T *> (&runtime[0]);
|
||||
|
||||
if (left==0)
|
||||
throw std::runtime_error ("division by zero");
|
||||
|
||||
T result =
|
||||
*reinterpret_cast<T *> (&runtime[1])
|
||||
/
|
||||
left;
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
|
||||
class OpSquareRoot : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
Type_Float value = *reinterpret_cast<Type_Float *> (&runtime[0]);
|
||||
|
||||
if (value<0)
|
||||
throw std::runtime_error (
|
||||
"square root of negative number (we aren't that imaginary)");
|
||||
|
||||
value = std::sqrt (value);
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename C>
|
||||
class OpCompare : public Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime)
|
||||
{
|
||||
int result = C() (
|
||||
*reinterpret_cast<T *> (&runtime[1]),
|
||||
*reinterpret_cast<T *> (&runtime[0]));
|
||||
|
||||
runtime.pop();
|
||||
|
||||
runtime[0] = *reinterpret_cast<Type_Data *> (&result);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,93 @@
|
||||
#ifndef INTERPRETER_MISCOPCODES_H_INCLUDED
|
||||
#define INTERPRETER_MISCOPCODES_H_INCLUDED
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "runtime.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class OpMessageBox : public Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
if (arg0!=0)
|
||||
throw std::logic_error ("message box buttons not implemented yet");
|
||||
|
||||
// message
|
||||
int index = runtime[0];
|
||||
runtime.pop();
|
||||
std::string message = runtime.getStringLiteral (index);
|
||||
|
||||
// additional parameters
|
||||
std::string formattedMessage;
|
||||
|
||||
for (std::size_t i=0; i<message.size(); ++i)
|
||||
{
|
||||
char c = message[i];
|
||||
|
||||
if (c!='%')
|
||||
formattedMessage += c;
|
||||
else
|
||||
{
|
||||
++i;
|
||||
if (i<message.size())
|
||||
{
|
||||
c = message[i];
|
||||
|
||||
if (c=='S' || c=='s')
|
||||
{
|
||||
int index = runtime[0];
|
||||
runtime.pop();
|
||||
formattedMessage += runtime.getStringLiteral (index);
|
||||
}
|
||||
else if (c=='g' || c=='G')
|
||||
{
|
||||
int value = *reinterpret_cast<const int *> (&runtime[0]);
|
||||
runtime.pop();
|
||||
|
||||
std::ostringstream out;
|
||||
out << value;
|
||||
formattedMessage += out.str();
|
||||
}
|
||||
else if (c=='f' || c=='F' || c=='.')
|
||||
{
|
||||
while (c!='f' && i<message.size())
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
float value = *reinterpret_cast<const float *> (&runtime[0]);
|
||||
runtime.pop();
|
||||
|
||||
std::ostringstream out;
|
||||
out << value;
|
||||
formattedMessage += out.str();
|
||||
}
|
||||
else if (c=='%')
|
||||
formattedMessage += "%";
|
||||
else
|
||||
{
|
||||
formattedMessage += "%";
|
||||
formattedMessage += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// buttons (not implemented)
|
||||
std::vector<std::string> buttons;
|
||||
|
||||
runtime.getContext().messageBox (formattedMessage, buttons);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,40 @@
|
||||
#ifndef INTERPRETER_OPCODES_H_INCLUDED
|
||||
#define INTERPRETER_OPCODES_H_INCLUDED
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Runtime;
|
||||
|
||||
/// opcode for 0 arguments
|
||||
class Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime) = 0;
|
||||
|
||||
virtual ~Opcode0() {}
|
||||
};
|
||||
|
||||
/// opcode for 1 argument
|
||||
class Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime, unsigned int arg0) = 0;
|
||||
|
||||
virtual ~Opcode1() {}
|
||||
};
|
||||
|
||||
/// opcode for 2 arguments
|
||||
class Opcode2
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Runtime& runtime, unsigned int arg1, unsigned int arg2) = 0;
|
||||
|
||||
virtual ~Opcode2() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,97 @@
|
||||
|
||||
#include "runtime.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
Runtime::Runtime (Context& context) : mContext (context), mCode (0), mPC (0) {}
|
||||
|
||||
int Runtime::getPC() const
|
||||
{
|
||||
return mPC;
|
||||
}
|
||||
|
||||
int Runtime::getIntegerLiteral (int index) const
|
||||
{
|
||||
assert (index>=0 && index<static_cast<int> (mCode[1]));
|
||||
|
||||
const Type_Code *literalBlock = mCode + 4 + mCode[0];
|
||||
|
||||
return *reinterpret_cast<const int *> (&literalBlock[index]);
|
||||
}
|
||||
|
||||
float Runtime::getFloatLiteral (int index) const
|
||||
{
|
||||
assert (index>=0 && index<static_cast<int> (mCode[2]));
|
||||
|
||||
const Type_Code *literalBlock = mCode + 4 + mCode[0] + mCode[1];
|
||||
|
||||
return *reinterpret_cast<const float *> (&literalBlock[index]);
|
||||
}
|
||||
|
||||
std::string Runtime::getStringLiteral (int index) const
|
||||
{
|
||||
assert (index>=0 && index<static_cast<int> (mCode[3]));
|
||||
|
||||
const char *literalBlock =
|
||||
reinterpret_cast<const char *> (mCode + 4 + mCode[0] + mCode[1] + mCode[2]);
|
||||
|
||||
for (; index; --index)
|
||||
{
|
||||
literalBlock += std::strlen (literalBlock) + 1;
|
||||
}
|
||||
|
||||
return literalBlock;
|
||||
}
|
||||
|
||||
void Runtime::configure (const Interpreter::Type_Code *code, int codeSize)
|
||||
{
|
||||
clear();
|
||||
|
||||
mCode = code;
|
||||
mCodeSize = codeSize;
|
||||
mPC = 0;
|
||||
}
|
||||
|
||||
void Runtime::clear()
|
||||
{
|
||||
mCode = 0;
|
||||
mCodeSize = 0;
|
||||
mStack.clear();
|
||||
}
|
||||
|
||||
void Runtime::setPC (int PC)
|
||||
{
|
||||
mPC = PC;
|
||||
}
|
||||
|
||||
void Runtime::push (Type_Data data)
|
||||
{
|
||||
mStack.push_back (data);
|
||||
}
|
||||
|
||||
void Runtime::pop()
|
||||
{
|
||||
if (mStack.empty())
|
||||
throw std::runtime_error ("stack underflow");
|
||||
|
||||
mStack.resize (mStack.size()-1);
|
||||
}
|
||||
|
||||
Type_Data& Runtime::operator[] (int Index)
|
||||
{
|
||||
if (Index<0 || Index>=static_cast<int> (mStack.size()))
|
||||
throw std::runtime_error ("stack index out of range");
|
||||
|
||||
return mStack[mStack.size()-Index-1];
|
||||
}
|
||||
|
||||
Context& Runtime::getContext()
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
#ifndef INTERPRETER_RUNTIME_H_INCLUDED
|
||||
#define INTERPRETER_RUNTIME_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Context;
|
||||
|
||||
/// Runtime data and engine interface
|
||||
|
||||
class Runtime
|
||||
{
|
||||
Context& mContext;
|
||||
const Type_Code *mCode;
|
||||
int mCodeSize;
|
||||
int mPC;
|
||||
std::vector<Type_Data> mStack;
|
||||
|
||||
public:
|
||||
|
||||
Runtime (Context& context);
|
||||
|
||||
int getPC() const;
|
||||
///< return program counter.
|
||||
|
||||
int getIntegerLiteral (int index) const;
|
||||
|
||||
float getFloatLiteral (int index) const;
|
||||
|
||||
std::string getStringLiteral (int index) const;
|
||||
|
||||
void configure (const Type_Code *code, int codeSize);
|
||||
///< \a context and \a code must exist as least until either configure, clear or
|
||||
/// the destructor is called. \a codeSize is given in 32-bit words.
|
||||
|
||||
void clear();
|
||||
|
||||
void setPC (int PC);
|
||||
///< set program counter.
|
||||
|
||||
void push (Type_Data data);
|
||||
///< push data on stack
|
||||
|
||||
void pop();
|
||||
///< pop stack
|
||||
|
||||
Type_Data& operator[] (int Index);
|
||||
///< Access stack member, counted from the top.
|
||||
|
||||
Context& getContext();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,18 @@
|
||||
#ifndef INTERPRETER_TYPES_H_INCLUDED
|
||||
#define INTERPRETER_TYPES_H_INCLUDED
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
typedef unsigned int Type_Code; // 32 bit
|
||||
|
||||
typedef unsigned int Type_Data; // 32 bit
|
||||
|
||||
typedef short Type_Short; // 16 bit
|
||||
|
||||
typedef int Type_Integer; // 32 bit
|
||||
|
||||
typedef float Type_Float; // 32 bit
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue