mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-30 05:47:57 +03:00
Imported Upstream version 0.26.0
This commit is contained in:
commit
9a2b6c69b6
1398 changed files with 212217 additions and 0 deletions
44
components/compiler/context.hpp
Normal file
44
components/compiler/context.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef COMPILER_CONTEXT_H_INCLUDED
|
||||
#define COMPILER_CONTEXT_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Extensions;
|
||||
|
||||
class Context
|
||||
{
|
||||
const Extensions *mExtensions;
|
||||
|
||||
public:
|
||||
|
||||
Context() : mExtensions (0) {}
|
||||
|
||||
virtual ~Context() {}
|
||||
|
||||
virtual bool canDeclareLocals() const = 0;
|
||||
///< Is the compiler allowed to declare local variables?
|
||||
|
||||
void setExtensions (const Extensions *extensions = 0)
|
||||
{
|
||||
mExtensions = extensions;
|
||||
}
|
||||
|
||||
const Extensions *getExtensions() const
|
||||
{
|
||||
return mExtensions;
|
||||
}
|
||||
|
||||
virtual char getGlobalType (const std::string& name) const = 0;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const = 0;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual bool isId (const std::string& name) const = 0;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
260
components/compiler/controlparser.cpp
Normal file
260
components/compiler/controlparser.cpp
Normal file
|
@ -0,0 +1,260 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
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, -static_cast<int> (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, -static_cast<int> (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;
|
||||
}
|
||||
}
|
||||
|
||||
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::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState ||
|
||||
mState==WhileBodyState)
|
||||
{
|
||||
scanner.putbackName (name, loc);
|
||||
mLineParser.reset();
|
||||
scanner.scan (mLineParser);
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
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;
|
||||
Parser::reset();
|
||||
}
|
||||
}
|
74
components/compiler/controlparser.hpp
Normal file
74
components/compiler/controlparser.hpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#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 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
|
65
components/compiler/errorhandler.cpp
Normal file
65
components/compiler/errorhandler.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
68
components/compiler/errorhandler.hpp
Normal file
68
components/compiler/errorhandler.hpp
Normal file
|
@ -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
|
39
components/compiler/exception.hpp
Normal file
39
components/compiler/exception.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#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
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char *what() const throw() { return "compile error";}
|
||||
///< Return error message
|
||||
};
|
||||
|
||||
/// \brief Exception: File error
|
||||
|
||||
class FileException : public SourceException
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char *what() const throw() { return "can't read file"; }
|
||||
///< Return error message
|
||||
};
|
||||
|
||||
/// \brief Exception: EOF condition encountered
|
||||
|
||||
class EOFException : public SourceException
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char *what() const throw() { return "end of file"; }
|
||||
///< Return error message
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
756
components/compiler/exprparser.cpp
Normal file
756
components/compiler/exprparser.cpp
Normal file
|
@ -0,0 +1,756 @@
|
|||
|
||||
#include "exprparser.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <iterator>
|
||||
|
||||
#include "generator.hpp"
|
||||
#include "scanner.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "locals.hpp"
|
||||
#include "stringparser.hpp"
|
||||
#include "extensions.hpp"
|
||||
#include "context.hpp"
|
||||
#include <components/misc/stringops.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();
|
||||
}
|
||||
|
||||
int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner)
|
||||
{
|
||||
return parseArguments (arguments, scanner, mCode);
|
||||
}
|
||||
|
||||
bool ExprParser::handleMemberAccess (const std::string& name)
|
||||
{
|
||||
mMemberOp = false;
|
||||
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
std::string id = Misc::StringUtils::lowerCase (mExplicit);
|
||||
|
||||
char type = getContext().getMemberType (name2, id);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
Generator::fetchMember (mCode, mLiterals, type, name2, id);
|
||||
mNextOperand = false;
|
||||
mExplicit.clear();
|
||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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), mRefOp (false), mMemberOp (false)
|
||||
{}
|
||||
|
||||
bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (!mExplicit.empty())
|
||||
return Parser::parseInt (value, loc, scanner);
|
||||
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
start();
|
||||
|
||||
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)
|
||||
{
|
||||
if (!mExplicit.empty())
|
||||
return Parser::parseFloat (value, loc, scanner);
|
||||
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
start();
|
||||
|
||||
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)
|
||||
{
|
||||
if (!mExplicit.empty())
|
||||
{
|
||||
if (mMemberOp && handleMemberAccess (name))
|
||||
return true;
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
mFirst = false;
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
start();
|
||||
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
Generator::fetchLocal (mCode, type, mLocals.getIndex (name2));
|
||||
mNextOperand = false;
|
||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||
return true;
|
||||
}
|
||||
|
||||
type = getContext().getGlobalType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
Generator::fetchGlobal (mCode, mLiterals, type, name2);
|
||||
mNextOperand = false;
|
||||
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mExplicit.empty() && getContext().isId (name2))
|
||||
{
|
||||
mExplicit = name2;
|
||||
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 (!mExplicit.empty())
|
||||
{
|
||||
if (mRefOp && mNextOperand)
|
||||
{
|
||||
if (keyword==Scanner::K_getdisabled)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::getDisabled (mCode, mLiterals, mExplicit);
|
||||
mOperands.push_back ('l');
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getdistance)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::getDistance (mCode, mLiterals, mExplicit);
|
||||
mOperands.push_back ('f');
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for custom extensions
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
char returnType;
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, true))
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
int optionals = parseArguments (argumentType, scanner);
|
||||
|
||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit,
|
||||
optionals);
|
||||
mOperands.push_back (returnType);
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
if (mNextOperand)
|
||||
{
|
||||
if (keyword==Scanner::K_getsquareroot)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("f", scanner);
|
||||
|
||||
Generator::squareRoot (mCode);
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_menumode)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::menuMode (mCode);
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_random)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("l", scanner);
|
||||
|
||||
Generator::random (mCode);
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_scriptrunning)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::scriptRunning (mCode);
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getdistance)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
parseArguments ("c", scanner);
|
||||
|
||||
Generator::getDistance (mCode, mLiterals, "");
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getsecondspassed)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::getSecondsPassed (mCode);
|
||||
mOperands.push_back ('f');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else if (keyword==Scanner::K_getdisabled)
|
||||
{
|
||||
start();
|
||||
|
||||
mTokenLoc = loc;
|
||||
|
||||
Generator::getDisabled (mCode, mLiterals, "");
|
||||
mOperands.push_back ('l');
|
||||
|
||||
mNextOperand = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// check for custom extensions
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
start();
|
||||
|
||||
char returnType;
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType, false))
|
||||
{
|
||||
mTokenLoc = loc;
|
||||
int optionals = parseArguments (argumentType, scanner);
|
||||
|
||||
extensions->generateFunctionCode (keyword, mCode, mLiterals, "", optionals);
|
||||
mOperands.push_back (returnType);
|
||||
|
||||
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 (!mExplicit.empty())
|
||||
{
|
||||
if (!mRefOp && code==Scanner::S_ref)
|
||||
{
|
||||
mRefOp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mMemberOp && code==Scanner::S_member)
|
||||
{
|
||||
mMemberOp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, 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: c = '+'; break;
|
||||
case Scanner::S_minus: c = '-'; break;
|
||||
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;
|
||||
mExplicit.clear();
|
||||
mRefOp = false;
|
||||
mMemberOp = false;
|
||||
Parser::reset();
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner,
|
||||
std::vector<Interpreter::Type_Code>& code, bool invert)
|
||||
{
|
||||
bool optional = false;
|
||||
int optionalCount = 0;
|
||||
|
||||
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=='/')
|
||||
{
|
||||
optional = true;
|
||||
}
|
||||
else if (*iter=='S' || *iter=='c')
|
||||
{
|
||||
stringParser.reset();
|
||||
|
||||
if (optional)
|
||||
stringParser.setOptional (true);
|
||||
|
||||
if (*iter=='c') stringParser.smashCase();
|
||||
scanner.scan (stringParser);
|
||||
|
||||
if (optional && stringParser.isEmpty())
|
||||
break;
|
||||
|
||||
if (invert)
|
||||
{
|
||||
std::vector<Interpreter::Type_Code> tmp;
|
||||
stringParser.append (tmp);
|
||||
|
||||
stack.push (tmp);
|
||||
}
|
||||
else
|
||||
stringParser.append (code);
|
||||
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.reset();
|
||||
|
||||
if (optional)
|
||||
parser.setOptional (true);
|
||||
|
||||
scanner.scan (parser);
|
||||
|
||||
if (optional && parser.isEmpty())
|
||||
break;
|
||||
|
||||
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));
|
||||
|
||||
if (optional)
|
||||
++optionalCount;
|
||||
}
|
||||
}
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
std::vector<Interpreter::Type_Code>& tmp = stack.top();
|
||||
|
||||
std::copy (tmp.begin(), tmp.end(), std::back_inserter (code));
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
return optionalCount;
|
||||
}
|
||||
}
|
109
components/compiler/exprparser.hpp
Normal file
109
components/compiler/exprparser.hpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
#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;
|
||||
std::string mExplicit;
|
||||
bool mRefOp;
|
||||
bool mMemberOp;
|
||||
|
||||
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();
|
||||
|
||||
int parseArguments (const std::string& arguments, Scanner& scanner);
|
||||
|
||||
bool handleMemberAccess (const std::string& name);
|
||||
|
||||
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)
|
||||
|
||||
int 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, 'c': string (case smashed), '/': following arguments are
|
||||
/// optional)
|
||||
/// \param invert Store arguments in reverted order.
|
||||
/// \return number of optional arguments
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
217
components/compiler/extensions.cpp
Normal file
217
components/compiler/extensions.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
|
||||
#include "extensions.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "generator.hpp"
|
||||
#include "literals.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
Extensions::Extensions() : mNextKeywordIndex (-1) {}
|
||||
|
||||
int Extensions::searchKeyword (const std::string& keyword) const
|
||||
{
|
||||
std::map<std::string, int>::const_iterator iter = mKeywords.find (keyword);
|
||||
|
||||
if (iter==mKeywords.end())
|
||||
return 0;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||
bool explicitReference) const
|
||||
{
|
||||
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
||||
|
||||
if (iter==mFunctions.end())
|
||||
return false;
|
||||
|
||||
if (explicitReference && iter->second.mCodeExplicit==-1)
|
||||
return false;
|
||||
|
||||
returnType = iter->second.mReturn;
|
||||
argumentType = iter->second.mArguments;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Extensions::isInstruction (int keyword, std::string& argumentType,
|
||||
bool explicitReference) const
|
||||
{
|
||||
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
||||
|
||||
if (iter==mInstructions.end())
|
||||
return false;
|
||||
|
||||
if (explicitReference && iter->second.mCodeExplicit==-1)
|
||||
return false;
|
||||
|
||||
argumentType = iter->second.mArguments;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Extensions::registerFunction (const std::string& keyword, char returnType,
|
||||
const std::string& argumentType, int code, int codeExplicit)
|
||||
{
|
||||
Function function;
|
||||
|
||||
if (argumentType.find ('/')==std::string::npos)
|
||||
{
|
||||
function.mSegment = 5;
|
||||
assert (code>=33554432 && code<=67108863);
|
||||
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
|
||||
}
|
||||
else
|
||||
{
|
||||
function.mSegment = 3;
|
||||
assert (code>=0x20000 && code<=0x2ffff);
|
||||
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
|
||||
}
|
||||
|
||||
int keywordIndex = mNextKeywordIndex--;
|
||||
|
||||
mKeywords.insert (std::make_pair (keyword, keywordIndex));
|
||||
|
||||
function.mReturn = returnType;
|
||||
function.mArguments = argumentType;
|
||||
function.mCode = code;
|
||||
function.mCodeExplicit = codeExplicit;
|
||||
|
||||
mFunctions.insert (std::make_pair (keywordIndex, function));
|
||||
}
|
||||
|
||||
void Extensions::registerInstruction (const std::string& keyword,
|
||||
const std::string& argumentType, int code, int codeExplicit)
|
||||
{
|
||||
Instruction instruction;
|
||||
|
||||
if (argumentType.find ('/')==std::string::npos)
|
||||
{
|
||||
instruction.mSegment = 5;
|
||||
assert (code>=33554432 && code<=67108863);
|
||||
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
|
||||
}
|
||||
else
|
||||
{
|
||||
instruction.mSegment = 3;
|
||||
assert (code>=0x20000 && code<=0x2ffff);
|
||||
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
|
||||
}
|
||||
|
||||
int keywordIndex = mNextKeywordIndex--;
|
||||
|
||||
mKeywords.insert (std::make_pair (keyword, keywordIndex));
|
||||
|
||||
instruction.mArguments = argumentType;
|
||||
instruction.mCode = code;
|
||||
instruction.mCodeExplicit = codeExplicit;
|
||||
|
||||
mInstructions.insert (std::make_pair (keywordIndex, instruction));
|
||||
}
|
||||
|
||||
void Extensions::generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
||||
Literals& literals, const std::string& id, int optionalArguments) const
|
||||
{
|
||||
assert (optionalArguments>=0);
|
||||
|
||||
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
||||
|
||||
if (iter==mFunctions.end())
|
||||
throw std::logic_error ("unknown custom function keyword");
|
||||
|
||||
if (optionalArguments && iter->second.mSegment!=3)
|
||||
throw std::logic_error ("functions with optional arguments must be placed into segment 3");
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
if (iter->second.mCodeExplicit==-1)
|
||||
throw std::logic_error ("explicit references not supported");
|
||||
|
||||
int index = literals.addString (id);
|
||||
Generator::pushInt (code, literals, index);
|
||||
}
|
||||
|
||||
switch (iter->second.mSegment)
|
||||
{
|
||||
case 3:
|
||||
|
||||
if (optionalArguments>=256)
|
||||
throw std::logic_error ("number of optional arguments is too large for segment 3");
|
||||
|
||||
code.push_back (Generator::segment3 (
|
||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
|
||||
optionalArguments));
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
|
||||
code.push_back (Generator::segment5 (
|
||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::logic_error ("unsupported code segment");
|
||||
}
|
||||
}
|
||||
|
||||
void Extensions::generateInstructionCode (int keyword,
|
||||
std::vector<Interpreter::Type_Code>& code, Literals& literals, const std::string& id,
|
||||
int optionalArguments) const
|
||||
{
|
||||
assert (optionalArguments>=0);
|
||||
|
||||
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
||||
|
||||
if (iter==mInstructions.end())
|
||||
throw std::logic_error ("unknown custom instruction keyword");
|
||||
|
||||
if (optionalArguments && iter->second.mSegment!=3)
|
||||
throw std::logic_error ("instructions with optional arguments must be placed into segment 3");
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
if (iter->second.mCodeExplicit==-1)
|
||||
throw std::logic_error ("explicit references not supported");
|
||||
|
||||
int index = literals.addString (id);
|
||||
Generator::pushInt (code, literals, index);
|
||||
}
|
||||
|
||||
switch (iter->second.mSegment)
|
||||
{
|
||||
case 3:
|
||||
|
||||
if (optionalArguments>=256)
|
||||
throw std::logic_error ("number of optional arguments is too large for segment 3");
|
||||
|
||||
code.push_back (Generator::segment3 (
|
||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
|
||||
optionalArguments));
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
|
||||
code.push_back (Generator::segment5 (
|
||||
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::logic_error ("unsupported code segment");
|
||||
}
|
||||
}
|
||||
|
||||
void Extensions::listKeywords (std::vector<std::string>& keywords) const
|
||||
{
|
||||
for (std::map<std::string, int>::const_iterator iter (mKeywords.begin());
|
||||
iter!=mKeywords.end(); ++iter)
|
||||
keywords.push_back (iter->first);
|
||||
}
|
||||
}
|
87
components/compiler/extensions.hpp
Normal file
87
components/compiler/extensions.hpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#ifndef COMPILER_EXTENSIONS_H_INCLUDED
|
||||
#define COMPILER_EXTENSINOS_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Literals;
|
||||
|
||||
/// \brief Collection of compiler extensions
|
||||
|
||||
class Extensions
|
||||
{
|
||||
struct Function
|
||||
{
|
||||
char mReturn;
|
||||
std::string mArguments;
|
||||
int mCode;
|
||||
int mCodeExplicit;
|
||||
int mSegment;
|
||||
};
|
||||
|
||||
struct Instruction
|
||||
{
|
||||
std::string mArguments;
|
||||
int mCode;
|
||||
int mCodeExplicit;
|
||||
int mSegment;
|
||||
};
|
||||
|
||||
int mNextKeywordIndex;
|
||||
std::map<std::string, int> mKeywords;
|
||||
std::map<int, Function> mFunctions;
|
||||
std::map<int, Instruction> mInstructions;
|
||||
|
||||
public:
|
||||
|
||||
Extensions();
|
||||
|
||||
int searchKeyword (const std::string& keyword) const;
|
||||
///< Return extension keyword code, that is assigned to the string \a keyword.
|
||||
/// - if no match is found 0 is returned.
|
||||
/// - keyword must be all lower case.
|
||||
|
||||
bool isFunction (int keyword, char& returnType, std::string& argumentType,
|
||||
bool explicitReference) const;
|
||||
///< Is this keyword registered with a function? If yes, return return and argument
|
||||
/// types.
|
||||
|
||||
bool isInstruction (int keyword, std::string& argumentType,
|
||||
bool explicitReference) const;
|
||||
///< Is this keyword registered with a function? If yes, return argument types.
|
||||
|
||||
void registerFunction (const std::string& keyword, char returnType,
|
||||
const std::string& argumentType, int code, int codeExplicit = -1);
|
||||
///< Register a custom function
|
||||
/// - keyword must be all lower case.
|
||||
/// - keyword must be unique
|
||||
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
|
||||
/// \note Currently only segment 3 and segment 5 opcodes are supported.
|
||||
|
||||
void registerInstruction (const std::string& keyword,
|
||||
const std::string& argumentType, int code, int codeExplicit = -1);
|
||||
///< Register a custom instruction
|
||||
/// - keyword must be all lower case.
|
||||
/// - keyword must be unique
|
||||
/// - if explicit references are not supported, segment5codeExplicit must be set to -1
|
||||
/// \note Currently only segment 3 and segment 5 opcodes are supported.
|
||||
|
||||
void generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
||||
Literals& literals, const std::string& id, int optionalArguments) const;
|
||||
///< Append code for function to \a code.
|
||||
|
||||
void generateInstructionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
|
||||
Literals& literals, const std::string& id, int optionalArguments) const;
|
||||
///< Append code for function to \a code.
|
||||
|
||||
void listKeywords (std::vector<std::string>& keywords) const;
|
||||
///< Append all known keywords to \æ kaywords.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
467
components/compiler/extensions0.cpp
Normal file
467
components/compiler/extensions0.cpp
Normal file
|
@ -0,0 +1,467 @@
|
|||
#include "extensions0.hpp"
|
||||
|
||||
#include "opcodes.hpp"
|
||||
#include "extensions.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
void registerExtensions (Extensions& extensions, bool consoleOnly)
|
||||
{
|
||||
Ai::registerExtensions (extensions);
|
||||
Animation::registerExtensions (extensions);
|
||||
Cell::registerExtensions (extensions);
|
||||
Container::registerExtensions (extensions);
|
||||
Control::registerExtensions (extensions);
|
||||
Dialogue::registerExtensions (extensions);
|
||||
Gui::registerExtensions (extensions);
|
||||
Misc::registerExtensions (extensions);
|
||||
Sky::registerExtensions (extensions);
|
||||
Sound::registerExtensions (extensions);
|
||||
Stats::registerExtensions (extensions);
|
||||
Transformation::registerExtensions (extensions);
|
||||
|
||||
if (consoleOnly)
|
||||
{
|
||||
Console::registerExtensions (extensions);
|
||||
User::registerExtensions (extensions);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ai
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("aiactivate", "c/l", opcodeAIActivate,
|
||||
opcodeAIActivateExplicit);
|
||||
extensions.registerInstruction ("aitravel", "fff/l", opcodeAiTravel,
|
||||
opcodeAiTravelExplicit);
|
||||
extensions.registerInstruction ("aiescort", "cffff/l", opcodeAiEscort,
|
||||
opcodeAiEscortExplicit);
|
||||
extensions.registerInstruction ("aiescortcell", "ccffff/l", opcodeAiEscortCell,
|
||||
opcodeAiEscortCellExplicit);
|
||||
extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander,
|
||||
opcodeAiWanderExplicit);
|
||||
extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow,
|
||||
opcodeAiFollowExplicit);
|
||||
extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell,
|
||||
opcodeAiFollowCellExplicit);
|
||||
extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone,
|
||||
opcodeGetAiPackageDoneExplicit);
|
||||
extensions.registerFunction ("getcurrentaipackage", 'l', "", opcodeGetCurrentAiPackage,
|
||||
opcodeGetAiPackageDoneExplicit);
|
||||
extensions.registerFunction ("getdetected", 'l', "c", opcodeGetDetected,
|
||||
opcodeGetDetectedExplicit);
|
||||
extensions.registerInstruction ("sethello", "l", opcodeSetHello, opcodeSetHelloExplicit);
|
||||
extensions.registerInstruction ("setfight", "l", opcodeSetFight, opcodeSetFightExplicit);
|
||||
extensions.registerInstruction ("setflee", "l", opcodeSetFlee, opcodeSetFleeExplicit);
|
||||
extensions.registerInstruction ("setalarm", "l", opcodeSetAlarm, opcodeSetAlarmExplicit);
|
||||
extensions.registerInstruction ("modhello", "l", opcodeModHello, opcodeModHelloExplicit);
|
||||
extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit);
|
||||
extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit);
|
||||
extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit);
|
||||
extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
|
||||
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
|
||||
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
|
||||
extensions.registerFunction ("getalarm", 'l', "", opcodeGetAlarm, opcodeGetAlarmExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Animation
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("skipanim", "", opcodeSkipAnim, opcodeSkipAnimExplicit);
|
||||
extensions.registerInstruction ("playgroup", "c/l", opcodePlayAnim, opcodePlayAnimExplicit);
|
||||
extensions.registerInstruction ("loopgroup", "cl/l", opcodeLoopAnim, opcodeLoopAnimExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Cell
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerFunction ("cellchanged", 'l', "", opcodeCellChanged);
|
||||
extensions.registerInstruction ("coc", "S", opcodeCOC);
|
||||
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
|
||||
extensions.registerInstruction ("coe", "ll", opcodeCOE);
|
||||
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
|
||||
extensions.registerInstruction ("setwaterlevel", "f", opcodeSetWaterLevel);
|
||||
extensions.registerInstruction ("modwaterlevel", "f", opcodeModWaterLevel);
|
||||
extensions.registerFunction ("getinterior", 'l', "", opcodeGetInterior);
|
||||
extensions.registerFunction ("getpccell", 'l', "c", opcodeGetPCCell);
|
||||
extensions.registerFunction ("getwaterlevel", 'f', "", opcodeGetWaterLevel);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Console
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Container
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit);
|
||||
extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount,
|
||||
opcodeGetItemCountExplicit);
|
||||
extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem,
|
||||
opcodeRemoveItemExplicit);
|
||||
extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit);
|
||||
extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit);
|
||||
extensions.registerFunction ("hasitemequipped", 'l', "c", opcodeHasItemEquipped, opcodeHasItemEquippedExplicit);
|
||||
extensions.registerFunction ("hassoulgem", 'l', "c", opcodeHasSoulGem, opcodeHasSoulGemExplicit);
|
||||
extensions.registerFunction ("getweapontype", 'l', "", opcodeGetWeaponType, opcodeGetWeaponTypeExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Control
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
std::string enable ("enable");
|
||||
std::string disable ("disable");
|
||||
|
||||
for (int i=0; i<numberOfControls; ++i)
|
||||
{
|
||||
extensions.registerInstruction (enable + controls[i], "", opcodeEnable+i);
|
||||
extensions.registerInstruction (disable + controls[i], "", opcodeDisable+i);
|
||||
extensions.registerFunction (std::string("get") + controls[i] + std::string("disabled"), 'l', "", opcodeGetDisabled+i);
|
||||
}
|
||||
|
||||
extensions.registerInstruction ("togglecollision", "", opcodeToggleCollision);
|
||||
extensions.registerInstruction ("tcl", "", opcodeToggleCollision);
|
||||
|
||||
extensions.registerInstruction ("clearforcerun", "", opcodeClearForceRun,
|
||||
opcodeClearForceRunExplicit);
|
||||
extensions.registerInstruction ("forcerun", "", opcodeForceRun,
|
||||
opcodeForceRunExplicit);
|
||||
|
||||
extensions.registerInstruction ("clearforcesneak", "", opcodeClearForceSneak,
|
||||
opcodeClearForceSneakExplicit);
|
||||
extensions.registerInstruction ("forcesneak", "", opcodeForceSneak,
|
||||
opcodeForceSneakExplicit);
|
||||
extensions.registerFunction ("getpcrunning", 'l', "", opcodeGetPcRunning);
|
||||
extensions.registerFunction ("getpcsneaking", 'l', "", opcodeGetPcSneaking);
|
||||
extensions.registerFunction ("getforcerun", 'l', "", opcodeGetForceRun, opcodeGetForceRunExplicit);
|
||||
extensions.registerFunction ("getforcesneak", 'l', "", opcodeGetForceSneak, opcodeGetForceSneakExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Dialogue
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("journal", "cl", opcodeJournal);
|
||||
extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex);
|
||||
extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex);
|
||||
extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic);
|
||||
extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
|
||||
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting);
|
||||
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting,
|
||||
opcodeForceGreetingExplicit);
|
||||
extensions.registerInstruction("goodbye", "", opcodeGoodbye);
|
||||
extensions.registerInstruction("setreputation", "l", opcodeSetReputation,
|
||||
opcodeSetReputationExplicit);
|
||||
extensions.registerInstruction("modreputation", "l", opcodeModReputation,
|
||||
opcodeModReputationExplicit);
|
||||
extensions.registerFunction("getreputation", 'l', "", opcodeGetReputation,
|
||||
opcodeGetReputationExplicit);
|
||||
extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction,
|
||||
opcodeSameFactionExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("enablebirthmenu", "", opcodeEnableBirthMenu);
|
||||
extensions.registerInstruction ("enableclassmenu", "", opcodeEnableClassMenu);
|
||||
extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu);
|
||||
extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu);
|
||||
extensions.registerInstruction ("enablestatreviewmenu", "",
|
||||
opcodeEnableStatsReviewMenu);
|
||||
|
||||
extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu);
|
||||
extensions.registerInstruction ("enablemagicmenu", "", opcodeEnableMagicMenu);
|
||||
extensions.registerInstruction ("enablemapmenu", "", opcodeEnableMapMenu);
|
||||
extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu);
|
||||
|
||||
extensions.registerInstruction ("enablerest", "", opcodeEnableRest);
|
||||
extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest);
|
||||
|
||||
extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu);
|
||||
|
||||
extensions.registerFunction ("getbuttonpressed", 'l', "", opcodeGetButtonPressed);
|
||||
|
||||
extensions.registerInstruction ("togglefogofwar", "", opcodeToggleFogOfWar);
|
||||
extensions.registerInstruction ("tfow", "", opcodeToggleFogOfWar);
|
||||
|
||||
extensions.registerInstruction ("togglefullhelp", "", opcodeToggleFullHelp);
|
||||
extensions.registerInstruction ("tfh", "", opcodeToggleFullHelp);
|
||||
|
||||
extensions.registerInstruction ("showmap", "S", opcodeShowMap);
|
||||
extensions.registerInstruction ("fillmap", "", opcodeFillMap);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
|
||||
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate);
|
||||
extensions.registerInstruction ("activate", "", opcodeActivate);
|
||||
extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit);
|
||||
extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit);
|
||||
extensions.registerInstruction ("togglecollisionboxes", "", opcodeToggleCollisionBoxes);
|
||||
extensions.registerInstruction ("togglecollisiongrid", "", opcodeToggleCollisionDebug);
|
||||
extensions.registerInstruction ("tcb", "", opcodeToggleCollisionBoxes);
|
||||
extensions.registerInstruction ("tcg", "", opcodeToggleCollisionDebug);
|
||||
extensions.registerInstruction ("twf", "", opcodeToggleWireframe);
|
||||
extensions.registerInstruction ("togglewireframe", "", opcodeToggleWireframe);
|
||||
extensions.registerInstruction ("fadein", "f", opcodeFadeIn);
|
||||
extensions.registerInstruction ("fadeout", "f", opcodeFadeOut);
|
||||
extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo);
|
||||
extensions.registerInstruction ("togglewater", "", opcodeToggleWater);
|
||||
extensions.registerInstruction ("twa", "", opcodeToggleWater);
|
||||
extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid);
|
||||
extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid);
|
||||
extensions.registerInstruction ("dontsaveobject", "", opcodeDontSaveObject);
|
||||
extensions.registerInstruction ("togglevanitymode", "", opcodeToggleVanityMode);
|
||||
extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode);
|
||||
extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep);
|
||||
extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc);
|
||||
extensions.registerInstruction ("playbink", "Sl", opcodePlayBink);
|
||||
extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit);
|
||||
extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit);
|
||||
extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit);
|
||||
extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit);
|
||||
extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit);
|
||||
extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit);
|
||||
extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit);
|
||||
extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit);
|
||||
extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit);
|
||||
extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime);
|
||||
extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit);
|
||||
extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot);
|
||||
extensions.registerInstruction ("fall", "", opcodeFall, opcodeFallExplicit);
|
||||
extensions.registerFunction ("getstandingpc", 'l', "", opcodeGetStandingPc, opcodeGetStandingPcExplicit);
|
||||
extensions.registerFunction ("getstandingactor", 'l', "", opcodeGetStandingActor, opcodeGetStandingActorExplicit);
|
||||
extensions.registerFunction ("getwindspeed", 'f', "", opcodeGetWindSpeed);
|
||||
extensions.registerFunction ("hitonme", 'l', "S", opcodeHitOnMe, opcodeHitOnMeExplicit);
|
||||
extensions.registerInstruction ("disableteleporting", "", opcodeDisableTeleporting);
|
||||
extensions.registerInstruction ("enableteleporting", "", opcodeEnableTeleporting);
|
||||
extensions.registerInstruction ("showvars", "", opcodeShowVars, opcodeShowVarsExplicit);
|
||||
extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Sky
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("togglesky", "", opcodeToggleSky);
|
||||
extensions.registerInstruction ("ts", "", opcodeToggleSky);
|
||||
extensions.registerInstruction ("turnmoonwhite", "", opcodeTurnMoonWhite);
|
||||
extensions.registerInstruction ("turnmoonred", "", opcodeTurnMoonRed);
|
||||
extensions.registerInstruction ("changeweather", "Sl", opcodeChangeWeather);
|
||||
extensions.registerFunction ("getmasserphase", 'l', "", opcodeGetMasserPhase);
|
||||
extensions.registerFunction ("getsecundaphase", 'l', "", opcodeGetSecundaPhase);
|
||||
extensions.registerFunction ("getcurrentweather", 'l', "", opcodeGetCurrentWeather);
|
||||
extensions.registerInstruction ("modregion", "S/llllllllll", opcodeModRegion);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Sound
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("say", "SS", opcodeSay, opcodeSayExplicit);
|
||||
extensions.registerFunction ("saydone", 'l', "", opcodeSayDone, opcodeSayDoneExplicit);
|
||||
extensions.registerInstruction ("streammusic", "S", opcodeStreamMusic);
|
||||
extensions.registerInstruction ("playsound", "c", opcodePlaySound);
|
||||
extensions.registerInstruction ("playsoundvp", "cff", opcodePlaySoundVP);
|
||||
extensions.registerInstruction ("playsound3d", "c", opcodePlaySound3D,
|
||||
opcodePlaySound3DExplicit);
|
||||
extensions.registerInstruction ("playsound3dvp", "cff", opcodePlaySound3DVP,
|
||||
opcodePlaySound3DVPExplicit);
|
||||
extensions.registerInstruction ("playloopsound3d", "c", opcodePlayLoopSound3D,
|
||||
opcodePlayLoopSound3DExplicit);
|
||||
extensions.registerInstruction ("playloopsound3dvp", "cff", opcodePlayLoopSound3DVP,
|
||||
opcodePlayLoopSound3DVPExplicit);
|
||||
extensions.registerInstruction ("stopsound", "c", opcodeStopSound,
|
||||
opcodeStopSoundExplicit);
|
||||
extensions.registerFunction ("getsoundplaying", 'l', "c", opcodeGetSoundPlaying,
|
||||
opcodeGetSoundPlayingExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Stats
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
static const char *attributes[numberOfAttributes] =
|
||||
{
|
||||
"strength", "intelligence", "willpower", "agility", "speed", "endurance",
|
||||
"personality", "luck"
|
||||
};
|
||||
|
||||
static const char *dynamics[numberOfDynamics] =
|
||||
{
|
||||
"health", "magicka", "fatigue"
|
||||
};
|
||||
|
||||
static const char *skills[numberOfSkills] =
|
||||
{
|
||||
"block", "armorer", "mediumarmor", "heavyarmor", "bluntweapon",
|
||||
"longblade", "axe", "spear", "athletics", "enchant", "destruction",
|
||||
"alteration", "illusion", "conjuration", "mysticism",
|
||||
"restoration", "alchemy", "unarmored", "security", "sneak",
|
||||
"acrobatics", "lightarmor", "shortblade", "marksman",
|
||||
"mercantile", "speechcraft", "handtohand"
|
||||
};
|
||||
|
||||
std::string get ("get");
|
||||
std::string set ("set");
|
||||
std::string mod ("mod");
|
||||
std::string modCurrent ("modcurrent");
|
||||
std::string getRatio ("getratio");
|
||||
|
||||
for (int i=0; i<numberOfAttributes; ++i)
|
||||
{
|
||||
extensions.registerFunction (get + attributes[i], 'l', "",
|
||||
opcodeGetAttribute+i, opcodeGetAttributeExplicit+i);
|
||||
|
||||
extensions.registerInstruction (set + attributes[i], "l",
|
||||
opcodeSetAttribute+i, opcodeSetAttributeExplicit+i);
|
||||
|
||||
extensions.registerInstruction (mod + attributes[i], "l",
|
||||
opcodeModAttribute+i, opcodeModAttributeExplicit+i);
|
||||
}
|
||||
|
||||
for (int i=0; i<numberOfDynamics; ++i)
|
||||
{
|
||||
extensions.registerFunction (get + dynamics[i], 'f', "",
|
||||
opcodeGetDynamic+i, opcodeGetDynamicExplicit+i);
|
||||
|
||||
extensions.registerInstruction (set + dynamics[i], "f",
|
||||
opcodeSetDynamic+i, opcodeSetDynamicExplicit+i);
|
||||
|
||||
extensions.registerInstruction (mod + dynamics[i], "f",
|
||||
opcodeModDynamic+i, opcodeModDynamicExplicit+i);
|
||||
|
||||
extensions.registerInstruction (modCurrent + dynamics[i], "f",
|
||||
opcodeModCurrentDynamic+i, opcodeModCurrentDynamicExplicit+i);
|
||||
|
||||
extensions.registerFunction (get + dynamics[i] + getRatio, 'f', "",
|
||||
opcodeGetDynamicGetRatio+i, opcodeGetDynamicGetRatioExplicit+i);
|
||||
}
|
||||
|
||||
for (int i=0; i<numberOfSkills; ++i)
|
||||
{
|
||||
extensions.registerFunction (get + skills[i], 'l', "",
|
||||
opcodeGetSkill+i, opcodeGetSkillExplicit+i);
|
||||
|
||||
extensions.registerInstruction (set + skills[i], "l",
|
||||
opcodeSetSkill+i, opcodeSetSkillExplicit+i);
|
||||
|
||||
extensions.registerInstruction (mod + skills[i], "l",
|
||||
opcodeModSkill+i, opcodeModSkillExplicit+i);
|
||||
}
|
||||
|
||||
extensions.registerFunction ("getpccrimelevel", 'f', "", opcodeGetPCCrimeLevel);
|
||||
extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
|
||||
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);
|
||||
|
||||
extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit);
|
||||
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
|
||||
opcodeRemoveSpellExplicit);
|
||||
extensions.registerFunction ("getspell", 'l', "c", opcodeGetSpell, opcodeGetSpellExplicit);
|
||||
|
||||
extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank);
|
||||
extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank);
|
||||
extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction);
|
||||
extensions.registerInstruction ("moddisposition","l",opcodeModDisposition,
|
||||
opcodeModDispositionExplicit);
|
||||
extensions.registerInstruction ("setdisposition","l",opcodeSetDisposition,
|
||||
opcodeSetDispositionExplicit);
|
||||
extensions.registerFunction ("getdisposition",'l', "",opcodeGetDisposition,
|
||||
opcodeGetDispositionExplicit);
|
||||
extensions.registerFunction("getpcrank",'l',"/S",opcodeGetPCRank,opcodeGetPCRankExplicit);
|
||||
|
||||
extensions.registerInstruction("setlevel", "l", opcodeSetLevel, opcodeSetLevelExplicit);
|
||||
extensions.registerFunction("getlevel", 'l', "", opcodeGetLevel, opcodeGetLevelExplicit);
|
||||
|
||||
extensions.registerFunction ("getdeadcount", 'l', "c", opcodeGetDeadCount);
|
||||
|
||||
extensions.registerFunction ("getpcfacrep", 'l', "/c", opcodeGetPCFacRep, opcodeGetPCFacRepExplicit);
|
||||
extensions.registerInstruction ("setpcfacrep", "l/c", opcodeSetPCFacRep, opcodeSetPCFacRepExplicit);
|
||||
extensions.registerInstruction ("modpcfacrep", "l/c", opcodeModPCFacRep, opcodeModPCFacRepExplicit);
|
||||
|
||||
extensions.registerFunction ("getcommondisease", 'l', "", opcodeGetCommonDisease,
|
||||
opcodeGetCommonDiseaseExplicit);
|
||||
extensions.registerFunction ("getblightdisease", 'l', "", opcodeGetBlightDisease,
|
||||
opcodeGetBlightDiseaseExplicit);
|
||||
|
||||
extensions.registerFunction ("getrace", 'l', "c", opcodeGetRace,
|
||||
opcodeGetRaceExplicit);
|
||||
extensions.registerFunction ("getwerewolfkills", 'f', "", opcodeGetWerewolfKills);
|
||||
extensions.registerFunction ("pcexpelled", 'l', "/S", opcodePcExpelled, opcodePcExpelledExplicit);
|
||||
extensions.registerInstruction ("pcexpell", "/S", opcodePcExpell, opcodePcExpellExplicit);
|
||||
extensions.registerInstruction ("pcclearexpelled", "/S", opcodePcClearExpelled, opcodePcClearExpelledExplicit);
|
||||
extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit);
|
||||
extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit);
|
||||
|
||||
extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath, opcodeOnDeathExplicit);
|
||||
|
||||
extensions.registerFunction ("iswerewolf", 'l', "", opcodeIsWerewolf, opcodeIsWerewolfExplicit);
|
||||
|
||||
extensions.registerInstruction("becomewerewolf", "", opcodeBecomeWerewolf, opcodeBecomeWerewolfExplicit);
|
||||
extensions.registerInstruction("undowerewolf", "", opcodeUndoWerewolf, opcodeUndoWerewolfExplicit);
|
||||
extensions.registerInstruction("setwerewolfacrobatics", "", opcodeSetWerewolfAcrobatics, opcodeSetWerewolfAcrobaticsExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Transformation
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction("setscale","f",opcodeSetScale,opcodeSetScaleExplicit);
|
||||
extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit);
|
||||
extensions.registerInstruction("setangle","cf",opcodeSetAngle,opcodeSetAngleExplicit);
|
||||
extensions.registerFunction("getangle",'f',"c",opcodeGetAngle,opcodeGetAngleExplicit);
|
||||
extensions.registerInstruction("setpos","cf",opcodeSetPos,opcodeSetPosExplicit);
|
||||
extensions.registerFunction("getpos",'f',"c",opcodeGetPos,opcodeGetPosExplicit);
|
||||
extensions.registerFunction("getstartingpos",'f',"c",opcodeGetStartingPos,opcodeGetStartingPosExplicit);
|
||||
extensions.registerInstruction("position","ffff",opcodePosition,opcodePositionExplicit);
|
||||
extensions.registerInstruction("positioncell","ffffc",opcodePositionCell,opcodePositionCellExplicit);
|
||||
extensions.registerInstruction("placeitemcell","ccffff",opcodePlaceItemCell);
|
||||
extensions.registerInstruction("placeitem","cffff",opcodePlaceItem);
|
||||
extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc);
|
||||
extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit);
|
||||
extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit);
|
||||
extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit);
|
||||
extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit);
|
||||
extensions.registerInstruction("setatstart","",opcodeSetAtStart,opcodeSetAtStartExplicit);
|
||||
extensions.registerInstruction("move","cf",opcodeMove,opcodeMoveExplicit);
|
||||
extensions.registerInstruction("moveworld","cf",opcodeMoveWorld,opcodeMoveWorldExplicit);
|
||||
extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit);
|
||||
}
|
||||
}
|
||||
|
||||
namespace User
|
||||
{
|
||||
void registerExtensions (Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("user1", "", opcodeUser1);
|
||||
extensions.registerInstruction ("user2", "", opcodeUser2);
|
||||
extensions.registerInstruction ("user3", "", opcodeUser3, opcodeUser3);
|
||||
extensions.registerInstruction ("user4", "", opcodeUser4, opcodeUser4);
|
||||
}
|
||||
}
|
||||
}
|
81
components/compiler/extensions0.hpp
Normal file
81
components/compiler/extensions0.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef COMPILER_EXTENSIONS0_H
|
||||
#define COMPILER_EXTENSIONS0_H
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Extensions;
|
||||
|
||||
void registerExtensions (Extensions& extensions, bool consoleOnly = false);
|
||||
|
||||
namespace Ai
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Animation
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Cell
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Console
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Container
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Control
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Dialogue
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Sky
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Sound
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Stats
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace Transformation
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
|
||||
namespace User
|
||||
{
|
||||
void registerExtensions (Extensions& extensions);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
134
components/compiler/fileparser.cpp
Normal file
134
components/compiler/fileparser.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#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 false; // we are stopping here, because there might be more garbage on the end line,
|
||||
// that we must ignore.
|
||||
//
|
||||
/// \todo allow this workaround to be disabled for newer scripts
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (mState==NameState)
|
||||
{
|
||||
// keywords can be used as script names too. Thank you Morrowind for another
|
||||
// syntactic perversity :(
|
||||
mName = loc.mLiteral;
|
||||
mState = BeginCompleteState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==EndNameState)
|
||||
{
|
||||
// optional repeated name after end statement
|
||||
if (mName!=loc.mLiteral)
|
||||
reportWarning ("Names for script " + mName + " do not match", loc);
|
||||
|
||||
mState = EndCompleteState;
|
||||
return false; // we are stopping here, because there might be more garbage on the end line,
|
||||
// that we must ignore.
|
||||
//
|
||||
/// \todo allow this workaround to be disabled for newer scripts
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
bool FileParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline)
|
||||
{
|
||||
if (mState==BeginState)
|
||||
{
|
||||
// ignore empty lines
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
Parser::reset();
|
||||
}
|
||||
}
|
60
components/compiler/fileparser.hpp
Normal file
60
components/compiler/fileparser.hpp
Normal file
|
@ -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
|
903
components/compiler/generator.cpp
Normal file
903
components/compiler/generator.cpp
Normal file
|
@ -0,0 +1,903 @@
|
|||
|
||||
#include "generator.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "literals.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
void opPushInt (Compiler::Generator::CodeContainer& code, int value)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment0 (0, value));
|
||||
}
|
||||
|
||||
void opFetchIntLiteral (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (4));
|
||||
}
|
||||
|
||||
void opFetchFloatLiteral (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (5));
|
||||
}
|
||||
|
||||
void opIntToFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (3));
|
||||
}
|
||||
|
||||
void opFloatToInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (6));
|
||||
}
|
||||
|
||||
void opStoreLocalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (0));
|
||||
}
|
||||
|
||||
void opStoreLocalLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (1));
|
||||
}
|
||||
|
||||
void opStoreLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (2));
|
||||
}
|
||||
|
||||
void opNegateInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (7));
|
||||
}
|
||||
|
||||
void opNegateFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (8));
|
||||
}
|
||||
|
||||
void opAddInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (9));
|
||||
}
|
||||
|
||||
void opAddFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (10));
|
||||
}
|
||||
|
||||
void opSubInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (11));
|
||||
}
|
||||
|
||||
void opSubFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (12));
|
||||
}
|
||||
|
||||
void opMulInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (13));
|
||||
}
|
||||
|
||||
void opMulFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (14));
|
||||
}
|
||||
|
||||
void opDivInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (15));
|
||||
}
|
||||
|
||||
void opDivFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (16));
|
||||
}
|
||||
|
||||
void opIntToFloat1 (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (17));
|
||||
}
|
||||
|
||||
void opFloatToInt1 (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (18));
|
||||
}
|
||||
|
||||
void opSquareRoot (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (19));
|
||||
}
|
||||
|
||||
void opReturn (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (20));
|
||||
}
|
||||
|
||||
void opMessageBox (Compiler::Generator::CodeContainer& code, int buttons)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment3 (0, buttons));
|
||||
}
|
||||
|
||||
void opReport (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (58));
|
||||
}
|
||||
|
||||
void opFetchLocalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (21));
|
||||
}
|
||||
|
||||
void opFetchLocalLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (22));
|
||||
}
|
||||
|
||||
void opFetchLocalFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (23));
|
||||
}
|
||||
|
||||
void opJumpForward (Compiler::Generator::CodeContainer& code, int offset)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment0 (1, offset));
|
||||
}
|
||||
|
||||
void opJumpBackward (Compiler::Generator::CodeContainer& code, int offset)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment0 (2, offset));
|
||||
}
|
||||
|
||||
void opSkipOnZero (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (24));
|
||||
}
|
||||
|
||||
void opSkipOnNonZero (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (25));
|
||||
}
|
||||
|
||||
void opEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (26));
|
||||
}
|
||||
|
||||
void opNonEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (27));
|
||||
}
|
||||
|
||||
void opLessThanInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (28));
|
||||
}
|
||||
|
||||
void opLessOrEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (29));
|
||||
}
|
||||
|
||||
void opGreaterThanInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (30));
|
||||
}
|
||||
|
||||
void opGreaterOrEqualInt (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (31));
|
||||
}
|
||||
|
||||
void opEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (32));
|
||||
}
|
||||
|
||||
void opNonEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (33));
|
||||
}
|
||||
|
||||
void opLessThanFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (34));
|
||||
}
|
||||
|
||||
void opLessOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (35));
|
||||
}
|
||||
|
||||
void opGreaterThanFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (36));
|
||||
}
|
||||
|
||||
void opGreaterOrEqualFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (37));
|
||||
}
|
||||
|
||||
void opMenuMode (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (38));
|
||||
}
|
||||
|
||||
void opStoreGlobalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (39));
|
||||
}
|
||||
|
||||
void opStoreGlobalLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (40));
|
||||
}
|
||||
|
||||
void opStoreGlobalFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (41));
|
||||
}
|
||||
|
||||
void opFetchGlobalShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (42));
|
||||
}
|
||||
|
||||
void opFetchGlobalLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (43));
|
||||
}
|
||||
|
||||
void opFetchGlobalFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (44));
|
||||
}
|
||||
|
||||
void opStoreMemberShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (59));
|
||||
}
|
||||
|
||||
void opStoreMemberLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (60));
|
||||
}
|
||||
|
||||
void opStoreMemberFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (61));
|
||||
}
|
||||
|
||||
void opFetchMemberShort (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (62));
|
||||
}
|
||||
|
||||
void opFetchMemberLong (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (63));
|
||||
}
|
||||
|
||||
void opFetchMemberFloat (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (64));
|
||||
}
|
||||
|
||||
void opRandom (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (45));
|
||||
}
|
||||
|
||||
void opScriptRunning (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (46));
|
||||
}
|
||||
|
||||
void opStartScript (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (47));
|
||||
}
|
||||
|
||||
void opStopScript (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (48));
|
||||
}
|
||||
|
||||
void opGetDistance (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (49));
|
||||
}
|
||||
|
||||
void opGetSecondsPassed (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (50));
|
||||
}
|
||||
|
||||
void opEnable (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (51));
|
||||
}
|
||||
|
||||
void opDisable (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (52));
|
||||
}
|
||||
|
||||
void opGetDisabled (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (53));
|
||||
}
|
||||
|
||||
void opEnableExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (54));
|
||||
}
|
||||
|
||||
void opDisableExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (55));
|
||||
}
|
||||
|
||||
void opGetDisabledExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (56));
|
||||
}
|
||||
|
||||
void opGetDistanceExplicit (Compiler::Generator::CodeContainer& code)
|
||||
{
|
||||
code.push_back (Compiler::Generator::segment5 (57));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (buttons>=256)
|
||||
throw std::runtime_error ("A message box can't have more than 255 buttons");
|
||||
|
||||
int index = literals.addString (message);
|
||||
|
||||
opPushInt (code, index);
|
||||
opMessageBox (code, buttons);
|
||||
}
|
||||
|
||||
void report (CodeContainer& code, Literals& literals, const std::string& message)
|
||||
{
|
||||
int index = literals.addString (message);
|
||||
|
||||
opPushInt (code, index);
|
||||
opReport (code);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void menuMode (CodeContainer& code)
|
||||
{
|
||||
opMenuMode (code);
|
||||
}
|
||||
|
||||
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const CodeContainer& value, char valueType)
|
||||
{
|
||||
int index = literals.addString (name);
|
||||
|
||||
opPushInt (code, index);
|
||||
|
||||
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
||||
|
||||
if (localType!=valueType)
|
||||
{
|
||||
if (localType=='f' && (valueType=='l' || valueType=='s'))
|
||||
{
|
||||
opIntToFloat (code);
|
||||
}
|
||||
else if ((localType=='l' || localType=='s') && valueType=='f')
|
||||
{
|
||||
opFloatToInt (code);
|
||||
}
|
||||
}
|
||||
|
||||
switch (localType)
|
||||
{
|
||||
case 'f':
|
||||
|
||||
opStoreGlobalFloat (code);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opStoreGlobalShort (code);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opStoreGlobalLong (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void fetchGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name)
|
||||
{
|
||||
int index = literals.addString (name);
|
||||
|
||||
opPushInt (code, index);
|
||||
|
||||
switch (localType)
|
||||
{
|
||||
case 'f':
|
||||
|
||||
opFetchGlobalFloat (code);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opFetchGlobalShort (code);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opFetchGlobalLong (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void assignToMember (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const std::string& id, const CodeContainer& value, char valueType)
|
||||
{
|
||||
int index = literals.addString (name);
|
||||
|
||||
opPushInt (code, index);
|
||||
|
||||
index = literals.addString (id);
|
||||
|
||||
opPushInt (code, index);
|
||||
|
||||
std::copy (value.begin(), value.end(), std::back_inserter (code));
|
||||
|
||||
if (localType!=valueType)
|
||||
{
|
||||
if (localType=='f' && (valueType=='l' || valueType=='s'))
|
||||
{
|
||||
opIntToFloat (code);
|
||||
}
|
||||
else if ((localType=='l' || localType=='s') && valueType=='f')
|
||||
{
|
||||
opFloatToInt (code);
|
||||
}
|
||||
}
|
||||
|
||||
switch (localType)
|
||||
{
|
||||
case 'f':
|
||||
|
||||
opStoreMemberFloat (code);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opStoreMemberShort (code);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opStoreMemberLong (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void fetchMember (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const std::string& id)
|
||||
{
|
||||
int index = literals.addString (name);
|
||||
|
||||
opPushInt (code, index);
|
||||
|
||||
index = literals.addString (id);
|
||||
|
||||
opPushInt (code, index);
|
||||
|
||||
switch (localType)
|
||||
{
|
||||
case 'f':
|
||||
|
||||
opFetchMemberFloat (code);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
||||
opFetchMemberShort (code);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
|
||||
opFetchMemberLong (code);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
void random (CodeContainer& code)
|
||||
{
|
||||
opRandom (code);
|
||||
}
|
||||
|
||||
void scriptRunning (CodeContainer& code)
|
||||
{
|
||||
opScriptRunning (code);
|
||||
}
|
||||
|
||||
void startScript (CodeContainer& code)
|
||||
{
|
||||
opStartScript (code);
|
||||
}
|
||||
|
||||
void stopScript (CodeContainer& code)
|
||||
{
|
||||
opStopScript (code);
|
||||
}
|
||||
|
||||
void getDistance (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opGetDistance (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opGetDistanceExplicit (code);
|
||||
}
|
||||
}
|
||||
|
||||
void getSecondsPassed (CodeContainer& code)
|
||||
{
|
||||
opGetSecondsPassed (code);
|
||||
}
|
||||
|
||||
void getDisabled (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opGetDisabled (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opGetDisabledExplicit (code);
|
||||
}
|
||||
}
|
||||
|
||||
void enable (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opEnable (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opEnableExplicit (code);
|
||||
}
|
||||
}
|
||||
|
||||
void disable (CodeContainer& code, Literals& literals, const std::string& id)
|
||||
{
|
||||
if (id.empty())
|
||||
{
|
||||
opDisable (code);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = literals.addString (id);
|
||||
opPushInt (code, index);
|
||||
opDisableExplicit (code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
130
components/compiler/generator.hpp
Normal file
130
components/compiler/generator.hpp
Normal file
|
@ -0,0 +1,130 @@
|
|||
#ifndef COMPILER_GENERATOR_H_INCLUDED
|
||||
#define COMPILER_GENERATOR_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include <components/interpreter/types.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Literals;
|
||||
|
||||
namespace Generator
|
||||
{
|
||||
typedef std::vector<Interpreter::Type_Code> CodeContainer;
|
||||
|
||||
inline Interpreter::Type_Code segment0 (unsigned int c, unsigned int arg0)
|
||||
{
|
||||
assert (c<64);
|
||||
return (c<<24) | (arg0 & 0xffffff);
|
||||
}
|
||||
|
||||
inline 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);
|
||||
}
|
||||
|
||||
inline Interpreter::Type_Code segment2 (unsigned int c, unsigned int arg0)
|
||||
{
|
||||
assert (c<1024);
|
||||
return 0x80000000 | (c<<20) | (arg0 & 0xfffff);
|
||||
}
|
||||
|
||||
inline Interpreter::Type_Code segment3 (unsigned int c, unsigned int arg0)
|
||||
{
|
||||
assert (c<262144);
|
||||
return 0xc0000000 | (c<<8) | (arg0 & 0xff);
|
||||
}
|
||||
|
||||
inline 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);
|
||||
}
|
||||
|
||||
inline Interpreter::Type_Code segment5 (unsigned int c)
|
||||
{
|
||||
assert (c<67108864);
|
||||
return 0xc8000000 | c;
|
||||
}
|
||||
|
||||
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 report (CodeContainer& code, Literals& literals, const std::string& message);
|
||||
|
||||
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);
|
||||
|
||||
void menuMode (CodeContainer& code);
|
||||
|
||||
void assignToGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name, const CodeContainer& value, char valueType);
|
||||
|
||||
void fetchGlobal (CodeContainer& code, Literals& literals, char localType,
|
||||
const std::string& name);
|
||||
|
||||
void assignToMember (CodeContainer& code, Literals& literals, char memberType,
|
||||
const std::string& name, const std::string& id, const CodeContainer& value, char valueType);
|
||||
|
||||
void fetchMember (CodeContainer& code, Literals& literals, char memberType,
|
||||
const std::string& name, const std::string& id);
|
||||
|
||||
void random (CodeContainer& code);
|
||||
|
||||
void scriptRunning (CodeContainer& code);
|
||||
|
||||
void startScript (CodeContainer& code);
|
||||
|
||||
void stopScript (CodeContainer& code);
|
||||
|
||||
void getDistance (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void getSecondsPassed (CodeContainer& code);
|
||||
|
||||
void getDisabled (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void enable (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
|
||||
void disable (CodeContainer& code, Literals& literals, const std::string& id);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
451
components/compiler/lineparser.cpp
Normal file
451
components/compiler/lineparser.cpp
Normal file
|
@ -0,0 +1,451 @@
|
|||
|
||||
#include "lineparser.hpp"
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "context.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "skipparser.hpp"
|
||||
#include "locals.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "extensions.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
void LineParser::parseExpression (Scanner& scanner, const TokenLoc& loc)
|
||||
{
|
||||
mExprParser.reset();
|
||||
|
||||
if (!mExplicit.empty())
|
||||
{
|
||||
mExprParser.parseName (mExplicit, loc, scanner);
|
||||
if (mState==MemberState)
|
||||
mExprParser.parseSpecial (Scanner::S_member, loc, scanner);
|
||||
else
|
||||
mExprParser.parseSpecial (Scanner::S_ref, loc, scanner);
|
||||
}
|
||||
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
char type = mExprParser.append (mCode);
|
||||
mState = EndState;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 'l':
|
||||
|
||||
Generator::report (mCode, mLiterals, "%g");
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
|
||||
Generator::report (mCode, mLiterals, "%f");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown expression result type");
|
||||
}
|
||||
}
|
||||
|
||||
LineParser::LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals, std::vector<Interpreter::Type_Code>& code, bool allowExpression)
|
||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code),
|
||||
mState (BeginState), mExprParser (errorHandler, context, locals, literals),
|
||||
mAllowExpression (allowExpression), mButtons(0), mType(0)
|
||||
{}
|
||||
|
||||
bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mAllowExpression && mState==BeginState)
|
||||
{
|
||||
scanner.putbackInt (value, loc);
|
||||
parseExpression (scanner, loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseInt (value, loc, scanner);
|
||||
}
|
||||
|
||||
bool LineParser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mAllowExpression && mState==BeginState)
|
||||
{
|
||||
scanner.putbackFloat (value, loc);
|
||||
parseExpression (scanner, loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
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 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
/// \todo add option to make re-declared local variables an error
|
||||
getErrorHandler().warning ("can't re-declare local variable", loc);
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'),
|
||||
name2);
|
||||
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==SetState)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
mName = name2;
|
||||
|
||||
// local variable?
|
||||
char type = mLocals.getType (name2);
|
||||
if (type!=' ')
|
||||
{
|
||||
mType = type;
|
||||
mState = SetLocalVarState;
|
||||
return true;
|
||||
}
|
||||
|
||||
type = getContext().getGlobalType (name2);
|
||||
if (type!=' ')
|
||||
{
|
||||
mType = type;
|
||||
mState = SetGlobalVarState;
|
||||
return true;
|
||||
}
|
||||
|
||||
mState = SetPotentialMemberVarState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==SetMemberVarState)
|
||||
{
|
||||
mMemberName = name;
|
||||
char type = getContext().getMemberType (mMemberName, mName);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
mState = SetMemberVarState2;
|
||||
mType = type;
|
||||
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);
|
||||
}
|
||||
|
||||
mName = name;
|
||||
mButtons = 0;
|
||||
|
||||
mState = MessageButtonState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==MessageButtonState || mState==MessageButtonCommaState)
|
||||
{
|
||||
Generator::pushString (mCode, mLiterals, name);
|
||||
mState = MessageButtonState;
|
||||
++mButtons;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==BeginState && getContext().isId (name))
|
||||
{
|
||||
mState = PotentialExplicitState;
|
||||
mExplicit = Misc::StringUtils::lowerCase (name);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==BeginState && mAllowExpression)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
scanner.putbackName (name, loc);
|
||||
parseExpression (scanner, loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
type = getContext().getGlobalType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
scanner.putbackName (name, loc);
|
||||
parseExpression (scanner, loc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==BeginState || mState==ExplicitState)
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case Scanner::K_enable:
|
||||
|
||||
Generator::enable (mCode, mLiterals, mExplicit);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_disable:
|
||||
|
||||
Generator::disable (mCode, mLiterals, mExplicit);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for custom extensions
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState))
|
||||
{
|
||||
int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true);
|
||||
|
||||
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mAllowExpression)
|
||||
{
|
||||
if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance)
|
||||
{
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
parseExpression (scanner, loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const Extensions *extensions = getContext().getExtensions())
|
||||
{
|
||||
char returnType;
|
||||
std::string argumentType;
|
||||
|
||||
if (extensions->isFunction (keyword, returnType, argumentType,
|
||||
!mExplicit.empty()))
|
||||
{
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
parseExpression (scanner, loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
case Scanner::K_startscript:
|
||||
|
||||
mExprParser.parseArguments ("c", scanner, mCode, true);
|
||||
Generator::startScript (mCode);
|
||||
mState = EndState;
|
||||
return true;
|
||||
|
||||
case Scanner::K_stopscript:
|
||||
|
||||
mExprParser.parseArguments ("c", scanner, mCode, true);
|
||||
Generator::stopScript (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;
|
||||
}
|
||||
else if (mState==SetGlobalVarState && keyword==Scanner::K_to)
|
||||
{
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
std::vector<Interpreter::Type_Code> code;
|
||||
char type = mExprParser.append (code);
|
||||
|
||||
Generator::assignToGlobal (mCode, mLiterals, mType, mName, code, type);
|
||||
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
else if (mState==SetMemberVarState2 && keyword==Scanner::K_to)
|
||||
{
|
||||
mExprParser.reset();
|
||||
scanner.scan (mExprParser);
|
||||
|
||||
std::vector<Interpreter::Type_Code> code;
|
||||
char type = mExprParser.append (code);
|
||||
|
||||
Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type);
|
||||
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mAllowExpression)
|
||||
{
|
||||
if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode ||
|
||||
keyword==Scanner::K_random || keyword==Scanner::K_scriptrunning ||
|
||||
keyword==Scanner::K_getsecondspassed)
|
||||
{
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
parseExpression (scanner, loc);
|
||||
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 || mState==BeginState))
|
||||
return false;
|
||||
|
||||
if (code==Scanner::S_comma && mState==MessageState)
|
||||
{
|
||||
mState = MessageCommaState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_ref && mState==PotentialExplicitState)
|
||||
{
|
||||
mState = ExplicitState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_member && mState==PotentialExplicitState)
|
||||
{
|
||||
mState = MemberState;
|
||||
parseExpression (scanner, loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_newline && mState==MessageButtonState)
|
||||
{
|
||||
Generator::message (mCode, mLiterals, mName, mButtons);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_comma && mState==MessageButtonState)
|
||||
{
|
||||
mState = MessageButtonCommaState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_member && mState==SetPotentialMemberVarState)
|
||||
{
|
||||
mState = SetMemberVarState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mAllowExpression && mState==BeginState &&
|
||||
(code==Scanner::S_open || code==Scanner::S_minus))
|
||||
{
|
||||
scanner.putbackSpecial (code, loc);
|
||||
parseExpression (scanner, loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void LineParser::reset()
|
||||
{
|
||||
mState = BeginState;
|
||||
mName.clear();
|
||||
mExplicit.clear();
|
||||
}
|
||||
}
|
79
components/compiler/lineparser.hpp
Normal file
79
components/compiler/lineparser.hpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#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, SetGlobalVarState, SetPotentialMemberVarState,
|
||||
SetMemberVarState, SetMemberVarState2,
|
||||
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
|
||||
EndState,
|
||||
PotentialExplicitState, ExplicitState, MemberState
|
||||
};
|
||||
|
||||
Locals& mLocals;
|
||||
Literals& mLiterals;
|
||||
std::vector<Interpreter::Type_Code>& mCode;
|
||||
State mState;
|
||||
std::string mName;
|
||||
std::string mMemberName;
|
||||
int mButtons;
|
||||
std::string mExplicit;
|
||||
char mType;
|
||||
ExprParser mExprParser;
|
||||
bool mAllowExpression;
|
||||
|
||||
void parseExpression (Scanner& scanner, const TokenLoc& loc);
|
||||
|
||||
public:
|
||||
|
||||
LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||
Literals& literals, std::vector<Interpreter::Type_Code>& code,
|
||||
bool allowExpression = false);
|
||||
///< \param allowExpression Allow lines consisting of a naked expression
|
||||
/// (result is send to the messagebox interface)
|
||||
|
||||
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
|
94
components/compiler/literals.cpp
Normal file
94
components/compiler/literals.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
49
components/compiler/literals.hpp
Normal file
49
components/compiler/literals.hpp
Normal file
|
@ -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
|
||||
|
110
components/compiler/locals.cpp
Normal file
110
components/compiler/locals.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
45
components/compiler/locals.hpp
Normal file
45
components/compiler/locals.hpp
Normal file
|
@ -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;
|
||||
|
||||
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).
|
||||
|
||||
const std::vector<std::string>& get (char type) const;
|
||||
|
||||
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
|
6
components/compiler/nullerrorhandler.cpp
Normal file
6
components/compiler/nullerrorhandler.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
#include "nullerrorhandler.hpp"
|
||||
|
||||
void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {}
|
||||
|
||||
void Compiler::NullErrorHandler::report (const std::string& message, Type type) {}
|
21
components/compiler/nullerrorhandler.hpp
Normal file
21
components/compiler/nullerrorhandler.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
|
||||
#ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED
|
||||
#define COMPILER_NULLERRORHANDLER_H_INCLUDED
|
||||
|
||||
#include "errorhandler.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
/// \brief Error handler implementation: Ignore all error messages
|
||||
|
||||
class NullErrorHandler : public ErrorHandler
|
||||
{
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
13
components/compiler/opcodes.cpp
Normal file
13
components/compiler/opcodes.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "opcodes.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
namespace Control
|
||||
{
|
||||
const char *controls[numberOfControls] =
|
||||
{
|
||||
"playercontrols", "playerfighting", "playerjumping", "playerlooking", "playermagic",
|
||||
"playerviewswitch", "vanitymode"
|
||||
};
|
||||
}
|
||||
}
|
416
components/compiler/opcodes.hpp
Normal file
416
components/compiler/opcodes.hpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
#ifndef COMPILER_OPCODES_H
|
||||
#define COMPILER_OPCODES_H
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
namespace Ai
|
||||
{
|
||||
const int opcodeAiTravel = 0x20000;
|
||||
const int opcodeAiTravelExplicit = 0x20001;
|
||||
const int opcodeAiEscort = 0x20002;
|
||||
const int opcodeAiEscortExplicit = 0x20003;
|
||||
const int opcodeGetAiPackageDone = 0x200007c;
|
||||
const int opcodeGetAiPackageDoneExplicit = 0x200007d;
|
||||
const int opcodeGetCurrentAiPackage = 0x20001ef;
|
||||
const int opcodeGetCurrentAiPackageExplicit = 0x20001f0;
|
||||
const int opcodeGetDetected = 0x20001f1;
|
||||
const int opcodeGetDetectedExplicit = 0x20001f2;
|
||||
const int opcodeAiWander = 0x20010;
|
||||
const int opcodeAiWanderExplicit = 0x20011;
|
||||
const int opcodeAIActivate = 0x2001e;
|
||||
const int opcodeAIActivateExplicit = 0x2001f;
|
||||
const int opcodeAiEscortCell = 0x20020;
|
||||
const int opcodeAiEscortCellExplicit = 0x20021;
|
||||
const int opcodeAiFollow = 0x20022;
|
||||
const int opcodeAiFollowExplicit = 0x20023;
|
||||
const int opcodeAiFollowCell = 0x20024;
|
||||
const int opcodeAiFollowCellExplicit = 0x20025;
|
||||
const int opcodeSetHello = 0x200015e;
|
||||
const int opcodeSetHelloExplicit = 0x200015d;
|
||||
const int opcodeSetFight = 0x200015e;
|
||||
const int opcodeSetFightExplicit = 0x200015f;
|
||||
const int opcodeSetFlee = 0x2000160;
|
||||
const int opcodeSetFleeExplicit = 0x2000161;
|
||||
const int opcodeSetAlarm = 0x2000162;
|
||||
const int opcodeSetAlarmExplicit = 0x2000163;
|
||||
const int opcodeModHello = 0x20001b7;
|
||||
const int opcodeModHelloExplicit = 0x20001b8;
|
||||
const int opcodeModFight = 0x20001b9;
|
||||
const int opcodeModFightExplicit = 0x20001ba;
|
||||
const int opcodeModFlee = 0x20001bb;
|
||||
const int opcodeModFleeExplicit = 0x20001bc;
|
||||
const int opcodeModAlarm = 0x20001bd;
|
||||
const int opcodeModAlarmExplicit = 0x20001be;
|
||||
const int opcodeGetHello = 0x20001bf;
|
||||
const int opcodeGetHelloExplicit = 0x20001c0;
|
||||
const int opcodeGetFight = 0x20001c1;
|
||||
const int opcodeGetFightExplicit = 0x20001c2;
|
||||
const int opcodeGetFlee = 0x20001c3;
|
||||
const int opcodeGetFleeExplicit = 0x20001c4;
|
||||
const int opcodeGetAlarm = 0x20001c5;
|
||||
const int opcodeGetAlarmExplicit = 0x20001c6;
|
||||
}
|
||||
|
||||
namespace Animation
|
||||
{
|
||||
const int opcodeSkipAnim = 0x2000138;
|
||||
const int opcodeSkipAnimExplicit = 0x2000139;
|
||||
const int opcodePlayAnim = 0x20006;
|
||||
const int opcodePlayAnimExplicit = 0x20007;
|
||||
const int opcodeLoopAnim = 0x20008;
|
||||
const int opcodeLoopAnimExplicit = 0x20009;
|
||||
}
|
||||
|
||||
namespace Cell
|
||||
{
|
||||
const int opcodeCellChanged = 0x2000000;
|
||||
const int opcodeCOC = 0x2000026;
|
||||
const int opcodeCOE = 0x200008e;
|
||||
const int opcodeGetInterior = 0x2000131;
|
||||
const int opcodeGetPCCell = 0x2000136;
|
||||
const int opcodeGetWaterLevel = 0x2000141;
|
||||
const int opcodeSetWaterLevel = 0x2000142;
|
||||
const int opcodeModWaterLevel = 0x2000143;
|
||||
}
|
||||
|
||||
namespace Console
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace Container
|
||||
{
|
||||
const int opcodeAddItem = 0x2000076;
|
||||
const int opcodeAddItemExplicit = 0x2000077;
|
||||
const int opcodeGetItemCount = 0x2000078;
|
||||
const int opcodeGetItemCountExplicit = 0x2000079;
|
||||
const int opcodeRemoveItem = 0x200007a;
|
||||
const int opcodeRemoveItemExplicit = 0x200007b;
|
||||
const int opcodeEquip = 0x20001b3;
|
||||
const int opcodeEquipExplicit = 0x20001b4;
|
||||
const int opcodeGetArmorType = 0x20001d1;
|
||||
const int opcodeGetArmorTypeExplicit = 0x20001d2;
|
||||
const int opcodeHasItemEquipped = 0x20001d5;
|
||||
const int opcodeHasItemEquippedExplicit = 0x20001d6;
|
||||
const int opcodeHasSoulGem = 0x20001de;
|
||||
const int opcodeHasSoulGemExplicit = 0x20001df;
|
||||
const int opcodeGetWeaponType = 0x20001e0;
|
||||
const int opcodeGetWeaponTypeExplicit = 0x20001e1;
|
||||
}
|
||||
|
||||
namespace Control
|
||||
{
|
||||
const int numberOfControls = 7;
|
||||
|
||||
extern const char *controls[numberOfControls];
|
||||
|
||||
const int opcodeEnable = 0x200007e;
|
||||
const int opcodeDisable = 0x2000085;
|
||||
const int opcodeToggleCollision = 0x2000130;
|
||||
const int opcodeClearForceRun = 0x2000154;
|
||||
const int opcodeClearForceRunExplicit = 0x2000155;
|
||||
const int opcodeForceRun = 0x2000156;
|
||||
const int opcodeForceRunExplicit = 0x2000157;
|
||||
const int opcodeClearForceSneak = 0x2000158;
|
||||
const int opcodeClearForceSneakExplicit = 0x2000159;
|
||||
const int opcodeForceSneak = 0x200015a;
|
||||
const int opcodeForceSneakExplicit = 0x200015b;
|
||||
const int opcodeGetDisabled = 0x2000175;
|
||||
const int opcodeGetPcRunning = 0x20001c9;
|
||||
const int opcodeGetPcSneaking = 0x20001ca;
|
||||
const int opcodeGetForceRun = 0x20001cb;
|
||||
const int opcodeGetForceSneak = 0x20001cc;
|
||||
const int opcodeGetForceRunExplicit = 0x20001cd;
|
||||
const int opcodeGetForceSneakExplicit = 0x20001ce;
|
||||
}
|
||||
|
||||
namespace Dialogue
|
||||
{
|
||||
const int opcodeJournal = 0x2000133;
|
||||
const int opcodeSetJournalIndex = 0x2000134;
|
||||
const int opcodeGetJournalIndex = 0x2000135;
|
||||
const int opcodeAddTopic = 0x200013a;
|
||||
const int opcodeChoice = 0x2000a;
|
||||
const int opcodeForceGreeting = 0x200014f;
|
||||
const int opcodeForceGreetingExplicit = 0x2000150;
|
||||
const int opcodeGoodbye = 0x2000152;
|
||||
const int opcodeSetReputation = 0x20001ad;
|
||||
const int opcodeModReputation = 0x20001ae;
|
||||
const int opcodeSetReputationExplicit = 0x20001af;
|
||||
const int opcodeModReputationExplicit = 0x20001b0;
|
||||
const int opcodeGetReputation = 0x20001b1;
|
||||
const int opcodeGetReputationExplicit = 0x20001b2;
|
||||
const int opcodeSameFaction = 0x20001b5;
|
||||
const int opcodeSameFactionExplicit = 0x20001b6;
|
||||
}
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
const int opcodeEnableBirthMenu = 0x200000e;
|
||||
const int opcodeEnableClassMenu = 0x200000f;
|
||||
const int opcodeEnableNameMenu = 0x2000010;
|
||||
const int opcodeEnableRaceMenu = 0x2000011;
|
||||
const int opcodeEnableStatsReviewMenu = 0x2000012;
|
||||
const int opcodeEnableInventoryMenu = 0x2000013;
|
||||
const int opcodeEnableMagicMenu = 0x2000014;
|
||||
const int opcodeEnableMapMenu = 0x2000015;
|
||||
const int opcodeEnableStatsMenu = 0x2000016;
|
||||
const int opcodeEnableRest = 0x2000017;
|
||||
const int opcodeShowRestMenu = 0x2000018;
|
||||
const int opcodeGetButtonPressed = 0x2000137;
|
||||
const int opcodeToggleFogOfWar = 0x2000145;
|
||||
const int opcodeToggleFullHelp = 0x2000151;
|
||||
const int opcodeShowMap = 0x20001a0;
|
||||
const int opcodeFillMap = 0x20001a1;
|
||||
}
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
const int opcodeXBox = 0x200000c;
|
||||
const int opcodeOnActivate = 0x200000d;
|
||||
const int opcodeActivate = 0x2000075;
|
||||
const int opcodeLock = 0x20004;
|
||||
const int opcodeLockExplicit = 0x20005;
|
||||
const int opcodeUnlock = 0x200008c;
|
||||
const int opcodeUnlockExplicit = 0x200008d;
|
||||
const int opcodeToggleCollisionDebug = 0x2000132;
|
||||
const int opcodeToggleCollisionBoxes = 0x20001ac;
|
||||
const int opcodeToggleWireframe = 0x200013b;
|
||||
const int opcodeFadeIn = 0x200013c;
|
||||
const int opcodeFadeOut = 0x200013d;
|
||||
const int opcodeFadeTo = 0x200013e;
|
||||
const int opcodeToggleWater = 0x2000144;
|
||||
const int opcodeTogglePathgrid = 0x2000146;
|
||||
const int opcodeDontSaveObject = 0x2000153;
|
||||
const int opcodeToggleVanityMode = 0x2000174;
|
||||
const int opcodeGetPcSleep = 0x200019f;
|
||||
const int opcodeWakeUpPc = 0x20001a2;
|
||||
const int opcodeGetLocked = 0x20001c7;
|
||||
const int opcodeGetLockedExplicit = 0x20001c8;
|
||||
const int opcodeGetEffect = 0x20001cf;
|
||||
const int opcodeGetEffectExplicit = 0x20001d0;
|
||||
const int opcodeAddSoulGem = 0x20001f3;
|
||||
const int opcodeAddSoulGemExplicit = 0x20001f4;
|
||||
const int opcodeRemoveSoulGem = 0x20001f5;
|
||||
const int opcodeRemoveSoulGemExplicit = 0x20001f6;
|
||||
const int opcodeDrop = 0x20001f8;
|
||||
const int opcodeDropExplicit = 0x20001f9;
|
||||
const int opcodeDropSoulGem = 0x20001fa;
|
||||
const int opcodeDropSoulGemExplicit = 0x20001fb;
|
||||
const int opcodeGetAttacked = 0x20001d3;
|
||||
const int opcodeGetAttackedExplicit = 0x20001d4;
|
||||
const int opcodeGetWeaponDrawn = 0x20001d7;
|
||||
const int opcodeGetWeaponDrawnExplicit = 0x20001d8;
|
||||
const int opcodeGetSpellEffects = 0x20001db;
|
||||
const int opcodeGetSpellEffectsExplicit = 0x20001dc;
|
||||
const int opcodeGetCurrentTime = 0x20001dd;
|
||||
const int opcodeSetDelete = 0x20001e5;
|
||||
const int opcodeSetDeleteExplicit = 0x20001e6;
|
||||
const int opcodeGetSquareRoot = 0x20001e7;
|
||||
const int opcodeFall = 0x200020a;
|
||||
const int opcodeFallExplicit = 0x200020b;
|
||||
const int opcodeGetStandingPc = 0x200020c;
|
||||
const int opcodeGetStandingPcExplicit = 0x200020d;
|
||||
const int opcodeGetStandingActor = 0x200020e;
|
||||
const int opcodeGetStandingActorExplicit = 0x200020f;
|
||||
const int opcodeGetWindSpeed = 0x2000212;
|
||||
const int opcodePlayBink = 0x20001f7;
|
||||
const int opcodeHitOnMe = 0x2000213;
|
||||
const int opcodeHitOnMeExplicit = 0x2000214;
|
||||
const int opcodeDisableTeleporting = 0x2000215;
|
||||
const int opcodeEnableTeleporting = 0x2000216;
|
||||
const int opcodeShowVars = 0x200021d;
|
||||
const int opcodeShowVarsExplicit = 0x200021e;
|
||||
}
|
||||
|
||||
namespace Sky
|
||||
{
|
||||
const int opcodeToggleSky = 0x2000021;
|
||||
const int opcodeTurnMoonWhite = 0x2000022;
|
||||
const int opcodeTurnMoonRed = 0x2000023;
|
||||
const int opcodeGetMasserPhase = 0x2000024;
|
||||
const int opcodeGetSecundaPhase = 0x2000025;
|
||||
const int opcodeGetCurrentWeather = 0x200013f;
|
||||
const int opcodeChangeWeather = 0x2000140;
|
||||
const int opcodeModRegion = 0x20026;
|
||||
}
|
||||
|
||||
namespace Sound
|
||||
{
|
||||
const int opcodeSay = 0x2000001;
|
||||
const int opcodeSayDone = 0x2000002;
|
||||
const int opcodeStreamMusic = 0x2000003;
|
||||
const int opcodePlaySound = 0x2000004;
|
||||
const int opcodePlaySoundVP = 0x2000005;
|
||||
const int opcodePlaySound3D = 0x2000006;
|
||||
const int opcodePlaySound3DVP = 0x2000007;
|
||||
const int opcodePlayLoopSound3D = 0x2000008;
|
||||
const int opcodePlayLoopSound3DVP = 0x2000009;
|
||||
const int opcodeStopSound = 0x200000a;
|
||||
const int opcodeGetSoundPlaying = 0x200000b;
|
||||
|
||||
const int opcodeSayExplicit = 0x2000019;
|
||||
const int opcodeSayDoneExplicit = 0x200001a;
|
||||
const int opcodePlaySound3DExplicit = 0x200001b;
|
||||
const int opcodePlaySound3DVPExplicit = 0x200001c;
|
||||
const int opcodePlayLoopSound3DExplicit = 0x200001d;
|
||||
const int opcodePlayLoopSound3DVPExplicit = 0x200001e;
|
||||
const int opcodeStopSoundExplicit = 0x200001f;
|
||||
const int opcodeGetSoundPlayingExplicit = 0x2000020;
|
||||
}
|
||||
|
||||
namespace Stats
|
||||
{
|
||||
const int numberOfAttributes = 8;
|
||||
const int numberOfDynamics = 3;
|
||||
const int numberOfSkills = 27;
|
||||
|
||||
const int opcodeGetAttribute = 0x2000027;
|
||||
const int opcodeGetAttributeExplicit = 0x200002f;
|
||||
const int opcodeSetAttribute = 0x2000037;
|
||||
const int opcodeSetAttributeExplicit = 0x200003f;
|
||||
const int opcodeModAttribute = 0x2000047;
|
||||
const int opcodeModAttributeExplicit = 0x200004f;
|
||||
|
||||
const int opcodeGetDynamic = 0x2000057;
|
||||
const int opcodeGetDynamicExplicit = 0x200005a;
|
||||
const int opcodeSetDynamic = 0x200005d;
|
||||
const int opcodeSetDynamicExplicit = 0x2000060;
|
||||
const int opcodeModDynamic = 0x2000063;
|
||||
const int opcodeModDynamicExplicit = 0x2000066;
|
||||
const int opcodeModCurrentDynamic = 0x2000069;
|
||||
const int opcodeModCurrentDynamicExplicit = 0x200006c;
|
||||
const int opcodeGetDynamicGetRatio = 0x200006f;
|
||||
const int opcodeGetDynamicGetRatioExplicit = 0x2000072;
|
||||
|
||||
const int opcodeGetSkill = 0x200008e;
|
||||
const int opcodeGetSkillExplicit = 0x20000a9;
|
||||
const int opcodeSetSkill = 0x20000c4;
|
||||
const int opcodeSetSkillExplicit = 0x20000df;
|
||||
const int opcodeModSkill = 0x20000fa;
|
||||
const int opcodeModSkillExplicit = 0x2000115;
|
||||
|
||||
const int opcodeGetPCCrimeLevel = 0x20001ec;
|
||||
const int opcodeSetPCCrimeLevel = 0x20001ed;
|
||||
const int opcodeModPCCrimeLevel = 0x20001ee;
|
||||
|
||||
const int opcodeAddSpell = 0x2000147;
|
||||
const int opcodeAddSpellExplicit = 0x2000148;
|
||||
const int opcodeRemoveSpell = 0x2000149;
|
||||
const int opcodeRemoveSpellExplicit = 0x200014a;
|
||||
const int opcodeGetSpell = 0x200014b;
|
||||
const int opcodeGetSpellExplicit = 0x200014c;
|
||||
|
||||
const int opcodePCRaiseRank = 0x2000b;
|
||||
const int opcodePCLowerRank = 0x2000c;
|
||||
const int opcodePCJoinFaction = 0x2000d;
|
||||
const int opcodeGetPCRank = 0x2000e;
|
||||
const int opcodeGetPCRankExplicit = 0x2000f;
|
||||
const int opcodeModDisposition = 0x200014d;
|
||||
const int opcodeModDispositionExplicit = 0x200014e;
|
||||
const int opcodeSetDisposition = 0x20001a4;
|
||||
const int opcodeSetDispositionExplicit = 0x20001a5;
|
||||
const int opcodeGetDisposition = 0x20001a6;
|
||||
const int opcodeGetDispositionExplicit = 0x20001a7;
|
||||
|
||||
const int opcodeGetLevel = 0x200018c;
|
||||
const int opcodeGetLevelExplicit = 0x200018d;
|
||||
const int opcodeSetLevel = 0x200018e;
|
||||
const int opcodeSetLevelExplicit = 0x200018f;
|
||||
|
||||
const int opcodeGetDeadCount = 0x20001a3;
|
||||
|
||||
const int opcodeGetPCFacRep = 0x20012;
|
||||
const int opcodeGetPCFacRepExplicit = 0x20013;
|
||||
const int opcodeSetPCFacRep = 0x20014;
|
||||
const int opcodeSetPCFacRepExplicit = 0x20015;
|
||||
const int opcodeModPCFacRep = 0x20016;
|
||||
const int opcodeModPCFacRepExplicit = 0x20017;
|
||||
|
||||
const int opcodeGetCommonDisease = 0x20001a8;
|
||||
const int opcodeGetCommonDiseaseExplicit = 0x20001a9;
|
||||
const int opcodeGetBlightDisease = 0x20001aa;
|
||||
const int opcodeGetBlightDiseaseExplicit = 0x20001ab;
|
||||
|
||||
const int opcodeGetRace = 0x20001d9;
|
||||
const int opcodeGetRaceExplicit = 0x20001da;
|
||||
|
||||
const int opcodePcExpelled = 0x20018;
|
||||
const int opcodePcExpelledExplicit = 0x20019;
|
||||
const int opcodePcExpell = 0x2001a;
|
||||
const int opcodePcExpellExplicit = 0x2001b;
|
||||
const int opcodePcClearExpelled = 0x2001c;
|
||||
const int opcodePcClearExpelledExplicit = 0x2001d;
|
||||
const int opcodeRaiseRank = 0x20001e8;
|
||||
const int opcodeRaiseRankExplicit = 0x20001e9;
|
||||
const int opcodeLowerRank = 0x20001ea;
|
||||
const int opcodeLowerRankExplicit = 0x20001eb;
|
||||
const int opcodeOnDeath = 0x20001fc;
|
||||
const int opcodeOnDeathExplicit = 0x2000205;
|
||||
|
||||
const int opcodeBecomeWerewolf = 0x2000217;
|
||||
const int opcodeBecomeWerewolfExplicit = 0x2000218;
|
||||
const int opcodeUndoWerewolf = 0x2000219;
|
||||
const int opcodeUndoWerewolfExplicit = 0x200021a;
|
||||
const int opcodeSetWerewolfAcrobatics = 0x200021b;
|
||||
const int opcodeSetWerewolfAcrobaticsExplicit = 0x200021c;
|
||||
const int opcodeIsWerewolf = 0x20001fd;
|
||||
const int opcodeIsWerewolfExplicit = 0x20001fe;
|
||||
|
||||
const int opcodeGetWerewolfKills = 0x20001e2;
|
||||
}
|
||||
|
||||
namespace Transformation
|
||||
{
|
||||
const int opcodeSetScale = 0x2000164;
|
||||
const int opcodeSetScaleExplicit = 0x2000165;
|
||||
const int opcodeSetAngle = 0x2000166;
|
||||
const int opcodeSetAngleExplicit = 0x2000167;
|
||||
const int opcodeGetScale = 0x2000168;
|
||||
const int opcodeGetScaleExplicit = 0x2000169;
|
||||
const int opcodeGetAngle = 0x200016a;
|
||||
const int opcodeGetAngleExplicit = 0x200016b;
|
||||
const int opcodeGetPos = 0x2000190;
|
||||
const int opcodeGetPosExplicit = 0x2000191;
|
||||
const int opcodeSetPos = 0x2000192;
|
||||
const int opcodeSetPosExplicit = 0x2000193;
|
||||
const int opcodeGetStartingPos = 0x2000194;
|
||||
const int opcodeGetStartingPosExplicit = 0x2000195;
|
||||
const int opcodeGetStartingAngle = 0x2000210;
|
||||
const int opcodeGetStartingAngleExplicit = 0x2000211;
|
||||
const int opcodePosition = 0x2000196;
|
||||
const int opcodePositionExplicit = 0x2000197;
|
||||
const int opcodePositionCell = 0x2000198;
|
||||
const int opcodePositionCellExplicit = 0x2000199;
|
||||
|
||||
const int opcodePlaceItemCell = 0x200019a;
|
||||
const int opcodePlaceItem = 0x200019b;
|
||||
const int opcodePlaceAtPc = 0x200019c;
|
||||
const int opcodePlaceAtMe = 0x200019d;
|
||||
const int opcodePlaceAtMeExplicit = 0x200019e;
|
||||
const int opcodeModScale = 0x20001e3;
|
||||
const int opcodeModScaleExplicit = 0x20001e4;
|
||||
const int opcodeRotate = 0x20001ff;
|
||||
const int opcodeRotateExplicit = 0x2000200;
|
||||
const int opcodeRotateWorld = 0x2000201;
|
||||
const int opcodeRotateWorldExplicit = 0x2000202;
|
||||
const int opcodeSetAtStart = 0x2000203;
|
||||
const int opcodeSetAtStartExplicit = 0x2000204;
|
||||
const int opcodeMove = 0x2000206;
|
||||
const int opcodeMoveExplicit = 0x2000207;
|
||||
const int opcodeMoveWorld = 0x2000208;
|
||||
const int opcodeMoveWorldExplicit = 0x2000209;
|
||||
}
|
||||
|
||||
namespace User
|
||||
{
|
||||
const int opcodeUser1 = 0x200016c;
|
||||
const int opcodeUser2 = 0x200016d;
|
||||
const int opcodeUser3 = 0x200016e;
|
||||
const int opcodeUser3Explicit = 0x200016f;
|
||||
const int opcodeUser4 = 0x2000170;
|
||||
const int opcodeUser4Explicit = 0x2000171;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
74
components/compiler/output.cpp
Normal file
74
components/compiler/output.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
44
components/compiler/output.hpp
Normal file
44
components/compiler/output.hpp
Normal file
|
@ -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
|
||||
|
185
components/compiler/parser.cpp
Normal file
185
components/compiler/parser.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
|
||||
#include "parser.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "errorhandler.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "scanner.hpp"
|
||||
|
||||
#include <components/misc/stringops.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 = Misc::StringUtils::lowerCase(name);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
Parser::Parser (ErrorHandler& errorHandler, Context& context)
|
||||
: mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true)
|
||||
{}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (!(mOptional && mEmpty))
|
||||
reportSeriousError ("Unexpected numeric value", loc);
|
||||
else
|
||||
scanner.putbackInt (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)
|
||||
{
|
||||
if (!(mOptional && mEmpty))
|
||||
reportSeriousError ("Unexpected floating point value", loc);
|
||||
else
|
||||
scanner.putbackFloat (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)
|
||||
{
|
||||
if (!(mOptional && mEmpty))
|
||||
reportSeriousError ("Unexpected name", loc);
|
||||
else
|
||||
scanner.putbackName (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)
|
||||
{
|
||||
if (!(mOptional && mEmpty))
|
||||
reportSeriousError ("Unexpected keyword", loc);
|
||||
else
|
||||
scanner.putbackKeyword (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)
|
||||
{
|
||||
if (!(mOptional && mEmpty))
|
||||
reportSeriousError ("Unexpected special token", loc);
|
||||
else
|
||||
scanner.putbackSpecial (code, loc);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Parser::parseComment (const std::string& comment, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle an EOF token.
|
||||
//
|
||||
// - Default-implementation: Report an error.
|
||||
|
||||
void Parser::parseEOF (Scanner& scanner)
|
||||
{
|
||||
reportEOF();
|
||||
}
|
||||
|
||||
void Parser::reset()
|
||||
{
|
||||
mOptional = false;
|
||||
mEmpty = true;
|
||||
}
|
||||
|
||||
void Parser::setOptional (bool optional)
|
||||
{
|
||||
mOptional = optional;
|
||||
}
|
||||
|
||||
void Parser::start()
|
||||
{
|
||||
mEmpty = false;
|
||||
}
|
||||
|
||||
bool Parser::isEmpty() const
|
||||
{
|
||||
return mEmpty;
|
||||
}
|
||||
}
|
112
components/compiler/parser.hpp
Normal file
112
components/compiler/parser.hpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
#ifndef COMPILER_PARSER_H_INCLUDED
|
||||
#define COMPILER_PARSER_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Scanner;
|
||||
struct TokenLoc;
|
||||
class ErrorHandler;
|
||||
class Context;
|
||||
|
||||
/// \brief Parser base class
|
||||
///
|
||||
/// This class defines a callback-parser.
|
||||
|
||||
class Parser
|
||||
{
|
||||
ErrorHandler& mErrorHandler;
|
||||
Context& mContext;
|
||||
bool mOptional;
|
||||
bool mEmpty;
|
||||
|
||||
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 bool parseComment (const std::string& comment, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle comment token.
|
||||
/// \return fetch another token?
|
||||
///
|
||||
/// - Default-implementation: ignored (and return true).
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
///
|
||||
/// - Default-implementation: Report an error.
|
||||
|
||||
virtual void reset();
|
||||
///< Reset parser to clean state.
|
||||
|
||||
void setOptional (bool optional);
|
||||
///< Optional mode: If nothign has been parsed yet and an unexpected token is delivered, stop
|
||||
/// parsing without raising an exception (after a reset the parser is in non-optional mode).
|
||||
|
||||
void start();
|
||||
///< Mark parser as non-empty (at least one token has been parser).
|
||||
|
||||
bool isEmpty() const;
|
||||
///< Has anything been parsed?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
564
components/compiler/scanner.cpp
Normal file
564
components/compiler/scanner.cpp
Normal file
|
@ -0,0 +1,564 @@
|
|||
|
||||
#include "scanner.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "extensions.hpp"
|
||||
|
||||
#include <components/misc/stringops.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==';')
|
||||
{
|
||||
std::string comment;
|
||||
|
||||
comment += c;
|
||||
|
||||
while (get (c))
|
||||
{
|
||||
if (c=='\n')
|
||||
{
|
||||
putback (c);
|
||||
break;
|
||||
}
|
||||
else
|
||||
comment += c;
|
||||
}
|
||||
|
||||
TokenLoc loc (mLoc);
|
||||
mLoc.mLiteral.clear();
|
||||
|
||||
return parser.parseComment (comment, loc, *this);
|
||||
}
|
||||
else if (isWhitespace (c))
|
||||
{
|
||||
mLoc.mLiteral.clear();
|
||||
return true;
|
||||
}
|
||||
else if (c==':')
|
||||
{
|
||||
// treat : as a whitespace :(
|
||||
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)
|
||||
{
|
||||
assert(c != '\0');
|
||||
std::string value;
|
||||
value += c;
|
||||
|
||||
bool error = false;
|
||||
|
||||
while (get (c))
|
||||
{
|
||||
if (std::isdigit (c))
|
||||
{
|
||||
value += c;
|
||||
}
|
||||
else if (std::isalpha (c) || c=='_')
|
||||
error = true;
|
||||
else if (c=='.' && !error)
|
||||
{
|
||||
return scanFloat (value, parser, cont);
|
||||
}
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (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;
|
||||
}
|
||||
|
||||
static const char *keywords[] =
|
||||
{
|
||||
"begin", "end",
|
||||
"short", "long", "float",
|
||||
"if", "endif", "else", "elseif",
|
||||
"while", "endwhile",
|
||||
"return",
|
||||
"messagebox",
|
||||
"set", "to",
|
||||
"getsquareroot",
|
||||
"menumode",
|
||||
"random",
|
||||
"startscript", "stopscript", "scriptrunning",
|
||||
"getdistance",
|
||||
"getsecondspassed",
|
||||
"enable", "disable", "getdisabled",
|
||||
0
|
||||
};
|
||||
|
||||
bool Scanner::scanName (char c, Parser& parser, bool& cont)
|
||||
{
|
||||
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 = Misc::StringUtils::lowerCase(name);
|
||||
|
||||
for (; keywords[i]; ++i)
|
||||
if (lowerCase==keywords[i])
|
||||
break;
|
||||
|
||||
if (keywords[i])
|
||||
{
|
||||
cont = parser.parseKeyword (i, loc, *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mExtensions)
|
||||
{
|
||||
if (int keyword = mExtensions->searchKeyword (lowerCase))
|
||||
{
|
||||
cont = parser.parseKeyword (keyword, loc, *this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cont = 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;
|
||||
}
|
||||
// ignoring escape sequences for now, because they are messing up stupid Windows path names.
|
||||
// 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=='_' || c=='`' ||
|
||||
/// \todo add an option to disable the following hack. Also, find out who is
|
||||
/// responsible for allowing it in the first place and meet up with that person in
|
||||
/// a dark alley.
|
||||
(c=='-' && !name.empty() && std::isalpha (mStream.peek()))))
|
||||
{
|
||||
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=='.')
|
||||
{
|
||||
// check, if this starts a float literal
|
||||
if (get (c))
|
||||
{
|
||||
putback (c);
|
||||
|
||||
if (std::isdigit (c))
|
||||
return scanFloat ("", parser, cont);
|
||||
}
|
||||
|
||||
special = S_member;
|
||||
}
|
||||
else if (c=='=')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='=')
|
||||
special = S_cmpEQ;
|
||||
else
|
||||
{
|
||||
special = S_cmpEQ;
|
||||
putback (c);
|
||||
// return false;
|
||||
// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements.
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
if (get (c) && c!='=') // <== is a allowed as an alternative to <= :(
|
||||
putback (c);
|
||||
}
|
||||
else
|
||||
{
|
||||
putback (c);
|
||||
special = S_cmpLT;
|
||||
}
|
||||
}
|
||||
else
|
||||
special = S_cmpLT;
|
||||
}
|
||||
else if (c=='>')
|
||||
{
|
||||
if (get (c))
|
||||
{
|
||||
if (c=='=')
|
||||
{
|
||||
special = S_cmpGE;
|
||||
|
||||
if (get (c) && c!='=') // >== is a allowed as an alternative to >= :(
|
||||
putback (c);
|
||||
}
|
||||
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,
|
||||
const Extensions *extensions)
|
||||
: mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions),
|
||||
mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Scanner::listKeywords (std::vector<std::string>& keywords)
|
||||
{
|
||||
for (int i=0; Compiler::keywords[i]; ++i)
|
||||
keywords.push_back (Compiler::keywords[i]);
|
||||
|
||||
if (mExtensions)
|
||||
mExtensions->listKeywords (keywords);
|
||||
}
|
||||
}
|
126
components/compiler/scanner.hpp
Normal file
126
components/compiler/scanner.hpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
#ifndef COMPILER_SCANNER_H_INCLUDED
|
||||
#define COMPILER_SCANNER_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
||||
#include "tokenloc.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class ErrorHandler;
|
||||
class Parser;
|
||||
class Extensions;
|
||||
|
||||
/// \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;
|
||||
const Extensions *mExtensions;
|
||||
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,
|
||||
K_menumode,
|
||||
K_random,
|
||||
K_startscript, K_stopscript, K_scriptrunning,
|
||||
K_getdistance,
|
||||
K_getsecondspassed,
|
||||
K_enable, K_disable, K_getdisabled
|
||||
};
|
||||
|
||||
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,
|
||||
S_member
|
||||
};
|
||||
|
||||
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,
|
||||
const Extensions *extensions = 0);
|
||||
///< 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
|
||||
|
||||
void listKeywords (std::vector<std::string>& keywords);
|
||||
///< Append all known keywords to \æ kaywords.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
92
components/compiler/scriptparser.cpp
Normal file
92
components/compiler/scriptparser.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
|
||||
#include "scriptparser.hpp"
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "skipparser.hpp"
|
||||
#include "errorhandler.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;
|
||||
}
|
||||
|
||||
/// \todo add an option to disable this nonsense
|
||||
if (keyword==Scanner::K_endif)
|
||||
{
|
||||
// surplus endif
|
||||
getErrorHandler().warning ("endif without matching if/elseif", loc);
|
||||
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
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();
|
||||
}
|
||||
}
|
54
components/compiler/scriptparser.hpp
Normal file
54
components/compiler/scriptparser.hpp
Normal file
|
@ -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
|
||||
|
41
components/compiler/skipparser.cpp
Normal file
41
components/compiler/skipparser.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
42
components/compiler/skipparser.hpp
Normal file
42
components/compiler/skipparser.hpp
Normal file
|
@ -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
|
||||
|
39
components/compiler/streamerrorhandler.cpp
Normal file
39
components/compiler/streamerrorhandler.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
#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) {}
|
||||
}
|
37
components/compiler/streamerrorhandler.hpp
Normal file
37
components/compiler/streamerrorhandler.hpp
Normal file
|
@ -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
|
64
components/compiler/stringparser.cpp
Normal file
64
components/compiler/stringparser.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
|
||||
#include "stringparser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "generator.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals)
|
||||
: Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool StringParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==StartState || mState==CommaState)
|
||||
{
|
||||
start();
|
||||
if (mSmashCase)
|
||||
Generator::pushString (mCode, mLiterals, Misc::StringUtils::lowerCase (name));
|
||||
else
|
||||
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();
|
||||
mSmashCase = false;
|
||||
Parser::reset();
|
||||
}
|
||||
|
||||
void StringParser::smashCase()
|
||||
{
|
||||
mSmashCase = true;
|
||||
}
|
||||
}
|
50
components/compiler/stringparser.hpp
Normal file
50
components/compiler/stringparser.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#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;
|
||||
bool mSmashCase;
|
||||
|
||||
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 smashCase();
|
||||
///< Transform all scanned strings to lower case
|
||||
|
||||
void reset();
|
||||
///< Reset parser to clean state (this includes the smashCase function).
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
20
components/compiler/tokenloc.hpp
Normal file
20
components/compiler/tokenloc.hpp
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue