From 3c393843e63ee90514da11fc97bad942488a8c02 Mon Sep 17 00:00:00 2001 From: mateuszb Date: Sun, 27 Mar 2011 17:24:30 +0000 Subject: [PATCH] * ERM parsing mostly done, some strange cases of body syntax, undocumented expressions and encoding issues still remain. --- client/CAnimation.cpp | 6 +- lib/ERMParser.cpp | 262 +++++++++++++++++++++++++++++++----------- 2 files changed, 200 insertions(+), 68 deletions(-) diff --git a/client/CAnimation.cpp b/client/CAnimation.cpp index 0a1e5346a..cdf0cd52e 100644 --- a/client/CAnimation.cpp +++ b/client/CAnimation.cpp @@ -1117,7 +1117,7 @@ size_t CAnimation::size(size_t group) const std::set CAnimation::loadedAnims; -void CAnimation::getAnimInfo() +void CAnimation::getAnimInfo() { tlog1<<"Animation stats: Loaded "<::iterator it = loadedAnims.begin(); it != loadedAnims.end(); it++) @@ -1127,8 +1127,8 @@ void CAnimation::getAnimInfo() if (!anim->images.empty()) tlog1<<", "<images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first; tlog1<<"\n"; - } -} + } +} CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, unsigned char Flags): frame(Frame), diff --git a/lib/ERMParser.cpp b/lib/ERMParser.cpp index 70bc8687b..60dc6c8ed 100644 --- a/lib/ERMParser.cpp +++ b/lib/ERMParser.cpp @@ -55,6 +55,7 @@ void ERMParser::parseFile() parsedLine = 1; std::string wholeLine; //used for buffering multiline lines bool inString = false; + while(file.good()) { //reading line @@ -103,13 +104,25 @@ void callme(char const& i) namespace ERM { - //i-expression (identifier expression) - an integral constant, variable symbol or array symbol - struct iexpT + typedef std::string TStringConstant; + typedef std::string TMacroUsage; + typedef std::string TMacroDef; + typedef std::string TCmdName; + + + struct TVarExpNotMacro { - typedef boost::optional > valT; - boost::optional varsym; + typedef boost::optional valT; + std::string varsym; valT val; }; + typedef boost::variant TVarExp; + + //write-only variable expression + typedef TVarExp TVarpExp; + + //i-expression (identifier expression) - an integral constant, variable symbol or array symbol + typedef boost::variant iexpT; struct TArithmeticOp { @@ -117,6 +130,47 @@ namespace ERM char opcode; }; + struct TVRLogic + { + char opcode; + iexpT var; + }; + + struct TVRArithmetic + { + char opcode; + iexpT rhs; + }; + + struct TSemiCompare + { + std::string compSign; + iexpT rhs; + }; + + struct TCurriedString + { + iexpT 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 > identifierT; @@ -147,7 +201,7 @@ namespace ERM struct triggerT { - std::string name; + TCmdName name; boost::optional identifier; boost::optional condition; }; @@ -158,12 +212,12 @@ namespace ERM //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 bodyTbody; + //typedef boost::variant bodyItem; + typedef std::vector bodyTbody; struct instructionT { - std::string name; + TCmdName name; boost::optional identifier; boost::optional condition; bodyTbody body; @@ -171,7 +225,7 @@ namespace ERM struct receiverT { - std::string name; + TCmdName name; boost::optional identifier; boost::optional condition; bodyTbody body; @@ -202,29 +256,43 @@ namespace ERM //console printer - struct UNT : boost::static_visitor<> + struct VarPrinter : boost::static_visitor<> { - void operator()(int const& val) const + void operator()(TVarExpNotMacro const& val) const { - tlog2 << val << " "; + tlog2 << val.varsym; + if(val.val.is_initialized()) + { + tlog2 << val.val.get(); + } } - void operator()(std::string const& str) const + void operator()(TMacroUsage const& val) const { - tlog2 << str << " "; + tlog2 << "$" << val << "&"; + } + }; + + void varPrinter(const TVarExp & var) + { + boost::apply_visitor(VarPrinter(), var); + } + + struct _IEP : boost::static_visitor<> + { + void operator()(int const & constant) const + { + tlog2 << constant; + } + void operator()(TVarExp const & var) const + { + varPrinter(var); } }; - void iexpPrinter(const iexpT exp) + void iexpPrinter(const iexpT & exp) { - if(exp.varsym.is_initialized()) - { - tlog2 << exp.varsym.get() << " "; - } - if(exp.val.is_initialized()) - { - boost::apply_visitor(UNT(), exp.val.get()); - } + boost::apply_visitor(_IEP(), exp); } struct IdentifierVisitor : boost::static_visitor<> @@ -348,9 +416,9 @@ namespace ERM } BOOST_FUSION_ADAPT_STRUCT( - ERM::iexpT, - (boost::optional, varsym) - (ERM::iexpT::valT, val) + ERM::TVarExpNotMacro, + (std::string, varsym) + (ERM::TVarExpNotMacro::valT, val) ) BOOST_FUSION_ADAPT_STRUCT( @@ -360,9 +428,27 @@ BOOST_FUSION_ADAPT_STRUCT( (ERM::iexpT, rhs) ) +BOOST_FUSION_ADAPT_STRUCT( + ERM::TVRLogic, + (char, opcode) + (ERM::iexpT, var) + ) + +BOOST_FUSION_ADAPT_STRUCT( + ERM::TVRArithmetic, + (char, opcode) + (ERM::iexpT, rhs) + ) + +BOOST_FUSION_ADAPT_STRUCT( + ERM::TNormalBodyOption, + (char, optionCode) + (ERM::TNormalBodyOptionList, params) + ) + BOOST_FUSION_ADAPT_STRUCT( ERM::triggerT, - (std::string, name) + (ERM::TCmdName, name) (boost::optional, identifier) (boost::optional, condition) ) @@ -374,6 +460,24 @@ BOOST_FUSION_ADAPT_STRUCT( (ERM::iexpT, rhs) ) +BOOST_FUSION_ADAPT_STRUCT( + ERM::TSemiCompare, + (std::string, compSign) + (ERM::iexpT, rhs) + ) + +BOOST_FUSION_ADAPT_STRUCT( + ERM::TCurriedString, + (ERM::iexpT, iexp) + (ERM::TStringConstant, string) + ) + +BOOST_FUSION_ADAPT_STRUCT( + ERM::TVarConcatString, + (ERM::TVarExp, var) + (ERM::TStringConstant, string) + ) + BOOST_FUSION_ADAPT_STRUCT( ERM::conditionT, (char, ctype) @@ -381,10 +485,9 @@ BOOST_FUSION_ADAPT_STRUCT( (ERM::conditionNodeT, rhs) ) - BOOST_FUSION_ADAPT_STRUCT( ERM::instructionT, - (std::string, name) + (ERM::TCmdName, name) (boost::optional, identifier) (boost::optional, condition) (ERM::bodyTbody, body) @@ -392,7 +495,7 @@ BOOST_FUSION_ADAPT_STRUCT( BOOST_FUSION_ADAPT_STRUCT( ERM::receiverT, - (std::string, name) + (ERM::TCmdName, name) (boost::optional, identifier) (boost::optional, condition) (ERM::bodyTbody, body) @@ -413,15 +516,20 @@ BOOST_FUSION_ADAPT_STRUCT( namespace ERM { template - struct ERM_grammar : qi::grammar + struct ERM_grammar : qi::grammar { ERM_grammar() : ERM_grammar::base_type(rline, "ERM script line") { - macro %= qi::lit('$') >> *(qi::char_ - '$') >> qi::lit('$'); - iexp %= -(*qi::char_("a-z") - 'u') >> -(qi::int_ | macro); + //do not build too complicated expressions, e.g. (a >> b) | c, qi has problems with them + macroUsage %= qi::lexeme[qi::lit('$') >> *(qi::char_ - '$') >> qi::lit('$')]; + macroDef %= qi::lexeme[qi::lit('@') >> *(qi::char_ - '@') >> qi::lit('@')]; + varExpNotMacro %= (+(qi::char_("?a-z") - 'u')) >> -qi::int_; + varExp %= varExpNotMacro | macroUsage; + iexp %= varExp | qi::int_; + varp %= qi::char_("?") > varExp; comment %= *(qi::char_); - commentLine %= ~qi::char_('!') >> comment; - cmdName %= qi::repeat(2)[qi::char_]; + commentLine %= (~qi::char_('!') >> comment | (qi::char_('!') >> (~qi::char_("?!#")) >> comment )); + cmdName %= qi::lexeme[qi::repeat(2)[qi::char_]]; arithmeticOp %= iexp >> qi::char_ >> iexp; //identifier is usually a vector of i-expressions but VR receiver performs arithmetic operations on it identifier %= (iexp | arithmeticOp) % qi::lit('/'); @@ -430,14 +538,25 @@ namespace ERM trigger %= cmdName >> -identifier >> -condition > qi::lit(";"); ///// string %= qi::lexeme['^' >> *(qi::char_ - '^') >> '^']; - body %= qi::lit(":") > *( qi::char_("a-zA-Z0-9/ @*?%+-:|&=><-") | string | macro) > qi::lit(";"); + + VRLogic %= qi::char_("&|X") >> iexp; + VRarithmetic %= qi::char_("+*:/%-") >> iexp; + semiCompare %= *qi::char_("<=>") >> iexp; + curStr %= iexp >> string; + varConcatString %= varExp >> qi::lit("+") >> string; + bodyOptionItem %= varConcatString | curStr | string | semiCompare | macroUsage | macroDef | iexp | varp | qi::eps; + exactBodyOptionList %= (bodyOptionItem % qi::lit("/")); + normalBodyOption = qi::char_("A-Z") > exactBodyOptionList; + bodyOption %= VRLogic | VRarithmetic | normalBodyOption; + body %= qi::lit(":") >> +(bodyOption) > qi::lit(";"); + instruction %= cmdName >> -identifier >> -condition >> body; receiver %= cmdName >> -identifier >> -condition >> body; //receiver without body exists... change needed postOBtrigger %= qi::lit("$OB") >> -identifier >> -condition > qi::lit(";"); command %= (qi::lit("!") >> ( (qi::lit("?") >> trigger) | - ((qi::lit("!") | qi::lit("d!") | qi::lit(" !")) >> receiver) | + (qi::lit("!") >> receiver) | (qi::lit("#") >> instruction) | postOBtrigger ) >> comment @@ -479,24 +598,37 @@ namespace ERM } - qi::rule string; + qi::rule string; - qi::rule macro; - qi::rule iexp; - qi::rule arithmeticOp; - qi::rule comment; - qi::rule commentLine; - qi::rule cmdName; - qi::rule identifier; - qi::rule comparison; - qi::rule condition; - qi::rule trigger; - qi::rule body; - qi::rule instruction; - qi::rule receiver; - qi::rule postOBtrigger; - qi::rule command; - qi::rule rline; + qi::rule macroUsage; + qi::rule macroDef; + qi::rule varExpNotMacro; + qi::rule varExp; + qi::rule iexp; + qi::rule varp; + qi::rule arithmeticOp; + qi::rule comment; + qi::rule commentLine; + qi::rule cmdName; + qi::rule identifier; + qi::rule comparison; + qi::rule condition; + qi::rule VRLogic; + qi::rule VRarithmetic; + qi::rule semiCompare; + qi::rule curStr; + qi::rule varConcatString; + qi::rule bodyOptionItem; + qi::rule exactBodyOptionList; + qi::rule normalBodyOption; + qi::rule bodyOption; + qi::rule trigger; + qi::rule body; + qi::rule instruction; + qi::rule receiver; + qi::rule postOBtrigger; + qi::rule command; + qi::rule rline; }; }; @@ -508,17 +640,17 @@ void ERMParser::parseLine( const std::string & line ) ERM::ERM_grammar ERMgrammar; ERM::lineT AST; - bool r = qi::parse(beg, end, ERMgrammar, AST); - if(!r || beg != end) - { - tlog1 << "Parse error for line (" << parsedLine << ") : " << line << std::endl; - tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl; - } - else - { - //parsing succeeded - //ERM::printLineAST(AST); - } +// bool r = qi::phrase_parse(beg, end, ERMgrammar, ascii::space, AST); +// if(!r || beg != end) +// { +// tlog1 << "Parse error for line (" << parsedLine << ") : " << line << std::endl; +// tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl; +// } +// else +// { +// //parsing succeeded +// //ERM::printLineAST(AST); +// } } ERMParser::ELineType ERMParser::classifyLine( const std::string & line, bool inString ) const