1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00
vcmi/scripting/erm/ERMParser.h
2013-11-03 12:51:25 +00:00

279 lines
5.9 KiB
C++

#pragma once
#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
namespace ascii = spirit::ascii;
namespace phoenix = boost::phoenix;
/*
* 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
*
*/
class CERMPreprocessor
{
std::string fname;
std::ifstream file;
int lineNo;
enum {INVALID, ERM, VERM} version;
void getline(std::string &ret);
public:
CERMPreprocessor(const std::string &Fname);
std::string retreiveCommandLine();
int getCurLineNo() const
{
return lineNo;
}
};
//various classes that represent ERM/VERM AST
namespace ERM
{
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 boost::optional<int> Tval;
boost::optional<char> questionMark;
std::string varsym;
Tval val;
};
typedef boost::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 boost::variant<TVarExp, int> TIexp;
struct TArithmeticOp
{
TIexp lhs, 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 boost::variant<TVarConcatString, TStringConstant, TCurriedString, TSemiCompare, TMacroDef, TIexp, TVarpExp, boost::spirit::unused_type> TBodyOptionItem;
typedef std::vector<TBodyOptionItem> TNormalBodyOptionList;
struct TNormalBodyOption
{
char optionCode;
TNormalBodyOptionList params;
};
typedef boost::variant<TVRLogic, TVRArithmetic, TNormalBodyOption> TBodyOption;
typedef boost::variant<TIexp, TArithmeticOp > TIdentifierInternal;
typedef std::vector< TIdentifierInternal > Tidentifier;
struct TComparison
{
std::string compSign;
TIexp lhs, rhs;
};
struct Tcondition;
typedef
boost::optional<
boost::recursive_wrapper<Tcondition>
>
TconditionNode;
struct Tcondition
{
typedef boost::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;
boost::optional<Tidentifier> identifier;
boost::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 boost::variant<char, TStringConstant, TMacroUsage, TMacroDef> bodyItem;
typedef std::vector<TBodyOption> Tbody;
struct Tinstruction
{
TCmdName name;
boost::optional<Tidentifier> identifier;
boost::optional<Tcondition> condition;
Tbody body;
};
struct Treceiver
{
TCmdName name;
boost::optional<Tidentifier> identifier;
boost::optional<Tcondition> condition;
boost::optional<Tbody> body;
};
struct Tcommand
{
typedef boost::variant<
Ttrigger,
Tinstruction,
Treceiver,
TPostTrigger
>
Tcmd;
Tcmd cmd;
std::string comment;
};
//vector expression
typedef boost::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 EVOtions{VEXP, SYMBOL, CHAR, DOUBLE, INT, TCMD, STRINGC};
struct TVExp;
typedef boost::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 boost::variant<TVExp, TERMline> TLine;
}
struct LineInfo
{
ERM::TLine tl;
int realLineNum;
};
class ERMParser
{
private:
std::string srcFile;
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
enum ELineType{COMMAND_FULL, COMMENT, UNFINISHED, END_OF};
int countHatsBeforeSemicolon(const std::string & line) const;
ERM::TLine parseLine(const std::string & line, int realLineNo);
public:
ERMParser(std::string file);
std::vector<LineInfo> parseFile();
static ERM::TLine parseLine(const std::string & line);
};