#pragma once #include #include #include #include #include #include #include #include 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 Tval; boost::optional questionMark; std::string varsym; Tval val; }; typedef boost::variant TVarExp; //write-only variable expression struct TVarpExp { TVarExp var; }; //i-expression (identifier expression) - an integral constant, variable symbol or array symbol typedef boost::variant 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 TBodyOptionItem; typedef std::vector TNormalBodyOptionList; struct TNormalBodyOption { char optionCode; TNormalBodyOptionList params; }; typedef boost::variant TBodyOption; typedef boost::variant TIdentifierInternal; typedef std::vector< TIdentifierInternal > Tidentifier; struct TComparison { std::string compSign; TIexp lhs, rhs; }; struct Tcondition; typedef boost::optional< boost::recursive_wrapper > 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 identifier; boost::optional 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 bodyItem; typedef std::vector Tbody; struct Tinstruction { TCmdName name; boost::optional identifier; boost::optional condition; Tbody body; }; struct Treceiver { TCmdName name; boost::optional identifier; boost::optional condition; boost::optional body; }; struct Tcommand { typedef boost::variant< Ttrigger, Tinstruction, Treceiver, TPostTrigger > Tcmd; Tcmd cmd; std::string comment; }; //vector expression typedef boost::variant TERMline; typedef std::string TVModifier; //'`', ',', ',@', '#'' struct TSymbol { std::vector symModifier; std::string sym; }; //for #'symbol expression enum EVOtions{VEXP, SYMBOL, CHAR, DOUBLE, INT, TCMD, STRINGC}; struct TVExp; typedef boost::variant, TSymbol, char, double, int, Tcommand, TStringConstant > TVOption; //options in v-expression //v-expression struct TVExp { std::vector modifier; std::vector children; }; //script line typedef boost::variant 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 parseFile(); static ERM::TLine parseLine(const std::string & line); };