Merge branch 'mwscript'

Conflicts:
	CMakeLists.txt
actorid
Marc Zinnschlag 15 years ago
commit 1ad9b234f0

@ -105,12 +105,23 @@ set(MISC_HEADER
components/misc/fileops.hpp components/misc/fileops.hpp
components/misc/slice_array.hpp components/misc/slice_array.hpp
components/misc/stringops.hpp) components/misc/stringops.hpp)
source_group(misc FILES ${MISC} ${MISC_HEADER}) source_group(misc FILES ${MISC} ${MISC_HEADER})
file(GLOB COMPILER components/compiler/*.cpp)
file(GLOB COMPILER_HEADER components/compiler/*.hpp)
source_group(compiler FILES ${COMPILER} ${COMPILER_HEADER})
file(GLOB INTERPRETER components/interpreter/*.cpp)
file(GLOB INTERPRETER_HEADER components/interpreter/*.hpp)
source_group(interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER})
set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC}) set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC} ${COMPILER}
${INTERPRETER})
set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER} set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER}
${ESM_HEADER} ${OGRE_HEADER} ${INPUT_HEADER} ${MISC_HEADER}) ${ESM_HEADER} ${OGRE_HEADER} ${INPUT_HEADER} ${MISC_HEADER} ${COMPILER_HEADER}
${INTERPRETER_HEADER})
# source directory: libs # source directory: libs
set(MANGLE_VFS libs/mangle/vfs/servers/ogre_vfs.cpp) set(MANGLE_VFS libs/mangle/vfs/servers/ogre_vfs.cpp)
@ -203,3 +214,22 @@ if (APPLE)
MACOSX_BUNDLE_BUNDLE_NAME "OpenMW" MACOSX_BUNDLE_BUNDLE_NAME "OpenMW"
) )
endif (APPLE) endif (APPLE)
# Tools
option(BUILD_MWCOMPILER "build standalone Morrowind script compiler" ON)
if (BUILD_MWCOMPILER)
set(TOOLS_MWCOMPILER ${COMPILER} apps/mwcompiler/main.cpp apps/mwcompiler/context.cpp
apps/mwcompiler/context.hpp)
add_executable(mwcompiler ${TOOLS_MWCOMPILER})
endif()
option(BUILD_MWINTERPRETER "build standalone Morrowind script code interpreter" ON)
if (BUILD_MWINTERPRETER)
set(TOOLS_MWINTERPRETER ${INTERPRETER} apps/mwinterpreter/main.cpp
apps/mwinterpreter/context.cpp apps/mwinterpreter/context.hpp)
add_executable(mwinterpreter ${TOOLS_MWINTERPRETER})
endif()

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

@ -131,6 +131,35 @@ namespace ESMS
} }
} }
}; };
template <typename X>
struct ScriptListT : RecList
{
typedef std::map<std::string,X> MapType;
MapType list;
// Load one object of this type
void load(ESMReader &esm, const std::string &id)
{
X ref;
ref.load (esm);
std::string realId = ref.data.name.toString();
std::swap (list[realId], ref);
}
// Find the given object ID, or return NULL if not found.
const X* find(const std::string &id) const
{
if(list.find(id) == list.end())
return NULL;
return &list.find(id)->second;
}
int getSize() { return list.size(); }
};
/* We need special lists for: /* We need special lists for:

@ -73,7 +73,7 @@ namespace ESMS
//RecListT<Land> lands; //RecListT<Land> lands;
//RecListT<LandTexture> landTexts; //RecListT<LandTexture> landTexts;
//RecListT<MagicEffect> magicEffects; //RecListT<MagicEffect> magicEffects;
//RecListT<Script> scripts; ScriptListT<Script> scripts;
//RecListT<Skill> skills; //RecListT<Skill> skills;
//RecListT<PathGrid> pathgrids; //RecListT<PathGrid> pathgrids;
@ -130,7 +130,7 @@ namespace ESMS
recLists[REC_RACE] = &races; recLists[REC_RACE] = &races;
recLists[REC_REGN] = &regions; recLists[REC_REGN] = &regions;
recLists[REC_REPA] = &repairs; recLists[REC_REPA] = &repairs;
//recLists[REC_SCPT] = &scripts; recLists[REC_SCPT] = &scripts;
//recLists[REC_SKIL] = &skills; //recLists[REC_SKIL] = &skills;
recLists[REC_SNDG] = &soundGens; recLists[REC_SNDG] = &soundGens;
recLists[REC_SOUN] = &sounds; recLists[REC_SOUN] = &sounds;

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