mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-14 10:12:59 +02:00
02e429e973
Changes were reviewed manually
281 lines
5.4 KiB
C++
281 lines
5.4 KiB
C++
/*
|
|
* ERMParser.h, part of VCMI engine
|
|
*
|
|
* Authors: listed in file AUTHORS in main folder
|
|
*
|
|
* License: GNU General Public License v2.0 or later
|
|
* Full text of license available in license.txt file, in main folder
|
|
*
|
|
*/
|
|
#pragma once
|
|
|
|
#include <boost/spirit/home/support/unused.hpp>
|
|
#include <boost/variant/recursive_wrapper.hpp>
|
|
|
|
namespace spirit = boost::spirit;
|
|
|
|
class CERMPreprocessor
|
|
{
|
|
std::string fname;
|
|
std::stringstream sourceStream;
|
|
int lineNo;
|
|
|
|
|
|
void getline(std::string &ret);
|
|
|
|
public:
|
|
enum class Version : ui8
|
|
{
|
|
INVALID,
|
|
ERM,
|
|
VERM
|
|
};
|
|
Version version;
|
|
|
|
CERMPreprocessor(const std::string & source);
|
|
std::string retrieveCommandLine();
|
|
int getCurLineNo() const
|
|
{
|
|
return lineNo;
|
|
}
|
|
|
|
const std::string& getCurFileName() const
|
|
{
|
|
return fname;
|
|
}
|
|
};
|
|
|
|
//various classes that represent ERM/VERM AST
|
|
namespace ERM
|
|
{
|
|
using ValType = int; //todo: set to int64_t
|
|
using IType = int; //todo: set to int32_t
|
|
|
|
struct TStringConstant
|
|
{
|
|
std::string str;
|
|
};
|
|
struct TMacroUsage
|
|
{
|
|
std::string macro;
|
|
};
|
|
|
|
// //macro with '?', for write only
|
|
// struct TQMacroUsage
|
|
// {
|
|
// std::string qmacro;
|
|
// };
|
|
|
|
//definition of a macro
|
|
struct TMacroDef
|
|
{
|
|
std::string macro;
|
|
};
|
|
typedef std::string TCmdName;
|
|
|
|
struct TVarExpNotMacro
|
|
{
|
|
typedef std::optional<int> Tval;
|
|
std::optional<char> questionMark;
|
|
std::string varsym;
|
|
Tval val;
|
|
};
|
|
|
|
typedef std::variant<TVarExpNotMacro, TMacroUsage> TVarExp;
|
|
|
|
//write-only variable expression
|
|
struct TVarpExp
|
|
{
|
|
TVarExp var;
|
|
};
|
|
|
|
//i-expression (identifier expression) - an integral constant, variable symbol or array symbol
|
|
typedef std::variant<TVarExp, int> TIexp;
|
|
|
|
struct TArithmeticOp
|
|
{
|
|
TIexp lhs;
|
|
TIexp rhs;
|
|
char opcode;
|
|
};
|
|
|
|
struct TVRLogic
|
|
{
|
|
char opcode;
|
|
TIexp var;
|
|
};
|
|
|
|
struct TVRArithmetic
|
|
{
|
|
char opcode;
|
|
TIexp rhs;
|
|
};
|
|
|
|
struct TSemiCompare
|
|
{
|
|
std::string compSign;
|
|
TIexp rhs;
|
|
};
|
|
|
|
struct TCurriedString
|
|
{
|
|
TIexp iexp;
|
|
TStringConstant string;
|
|
};
|
|
|
|
struct TVarConcatString
|
|
{
|
|
TVarExp var;
|
|
TStringConstant string;
|
|
};
|
|
|
|
typedef std::variant<TVarConcatString, TStringConstant, TCurriedString, TSemiCompare, TMacroDef, TIexp, TVarpExp> TBodyOptionItem;
|
|
|
|
typedef std::vector<TBodyOptionItem> TNormalBodyOptionList;
|
|
|
|
struct TNormalBodyOption
|
|
{
|
|
char optionCode;
|
|
std::optional<TNormalBodyOptionList> params;
|
|
};
|
|
typedef std::variant<TVRLogic, TVRArithmetic, TNormalBodyOption> TBodyOption;
|
|
|
|
// typedef std::variant<TIexp, TArithmeticOp > TIdentifierInternal;
|
|
typedef std::vector< TIexp > Tidentifier;
|
|
|
|
struct TComparison
|
|
{
|
|
std::string compSign;
|
|
TIexp lhs;
|
|
TIexp rhs;
|
|
};
|
|
|
|
struct Tcondition;
|
|
typedef std::optional<boost::recursive_wrapper<Tcondition>> TconditionNode;
|
|
|
|
struct Tcondition
|
|
{
|
|
typedef std::variant<
|
|
TComparison,
|
|
int>
|
|
Tcond; //comparison or condition flag
|
|
char ctype;
|
|
Tcond cond;
|
|
TconditionNode rhs;
|
|
};
|
|
|
|
struct TTriggerBase
|
|
{
|
|
bool pre; //if false it's !$ post-trigger, elsewise it's !# (pre)trigger
|
|
TCmdName name;
|
|
std::optional<Tidentifier> identifier;
|
|
std::optional<Tcondition> condition;
|
|
};
|
|
|
|
struct Ttrigger : TTriggerBase
|
|
{
|
|
Ttrigger()
|
|
{
|
|
pre = true;
|
|
}
|
|
};
|
|
|
|
struct TPostTrigger : TTriggerBase
|
|
{
|
|
TPostTrigger()
|
|
{
|
|
pre = false;
|
|
}
|
|
};
|
|
|
|
//a dirty workaround for preprocessor magic that prevents the use types with comma in it in BOOST_FUSION_ADAPT_STRUCT
|
|
//see http://comments.gmane.org/gmane.comp.lib.boost.user/62501 for some info
|
|
//
|
|
//moreover, I encountered a quite serious bug in boost: http://boost.2283326.n4.nabble.com/container-hpp-111-error-C2039-value-type-is-not-a-member-of-td3352328.html
|
|
//not sure how serious it is...
|
|
|
|
//typedef std::variant<char, TStringConstant, TMacroUsage, TMacroDef> bodyItem;
|
|
typedef std::vector<TBodyOption> Tbody;
|
|
|
|
struct Tinstruction
|
|
{
|
|
TCmdName name;
|
|
std::optional<Tidentifier> identifier;
|
|
std::optional<Tcondition> condition;
|
|
Tbody body;
|
|
};
|
|
|
|
struct Treceiver
|
|
{
|
|
TCmdName name;
|
|
std::optional<Tidentifier> identifier;
|
|
std::optional<Tcondition> condition;
|
|
std::optional<Tbody> body;
|
|
};
|
|
|
|
struct Tcommand
|
|
{
|
|
typedef std::variant<
|
|
Ttrigger,
|
|
Tinstruction,
|
|
Treceiver,
|
|
TPostTrigger
|
|
>
|
|
Tcmd;
|
|
Tcmd cmd;
|
|
//std::string comment;
|
|
};
|
|
|
|
//vector expression
|
|
|
|
|
|
typedef std::variant<Tcommand, std::string, boost::spirit::unused_type> TERMline;
|
|
|
|
typedef std::string TVModifier; //'`', ',', ',@', '#''
|
|
|
|
struct TSymbol
|
|
{
|
|
std::vector<TVModifier> symModifier;
|
|
std::string sym;
|
|
};
|
|
|
|
//for #'symbol expression
|
|
|
|
enum EVOptions{VEXP, SYMBOL, CHAR, DOUBLE, INT, TCMD, STRINGC};
|
|
struct TVExp;
|
|
typedef std::variant<boost::recursive_wrapper<TVExp>, TSymbol, char, double, int, Tcommand, TStringConstant > TVOption; //options in v-expression
|
|
//v-expression
|
|
struct TVExp
|
|
{
|
|
std::vector<TVModifier> modifier;
|
|
std::vector<TVOption> children;
|
|
};
|
|
|
|
//script line
|
|
typedef std::variant<TVExp, TERMline> TLine;
|
|
|
|
template <typename T> struct ERM_grammar;
|
|
}
|
|
|
|
struct LineInfo
|
|
{
|
|
ERM::TLine tl;
|
|
int realLineNum;
|
|
};
|
|
|
|
class ERMParser
|
|
{
|
|
public:
|
|
std::shared_ptr<ERM::ERM_grammar<std::string::const_iterator>> ERMgrammar;
|
|
|
|
ERMParser();
|
|
virtual ~ERMParser();
|
|
|
|
std::vector<LineInfo> parseFile(CERMPreprocessor & preproc);
|
|
private:
|
|
void repairEncoding(char * str, int len) const; //removes nonstandard ascii characters from string
|
|
void repairEncoding(std::string & str) const; //removes nonstandard ascii characters from string
|
|
ERM::TLine parseLine(const std::string & line, int realLineNo);
|
|
ERM::TLine parseLine(const std::string & line);
|
|
};
|