2011-03-19 19:06:46 +02:00
# include "ERMParser.h"
2011-03-29 20:16:10 +03:00
# include <boost/version.hpp>
//To make compilation with older boost versions possible
//Don't know exact version - 1.46 works while 1.42 not
# if BOOST_VERSION >= 104600
2011-03-19 19:06:46 +02:00
# include <boost/spirit/include/qi.hpp>
# include <boost/bind.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>
2011-03-20 20:09:55 +02:00
# include <boost/fusion/include/adapt_struct.hpp>
2011-03-19 19:06:46 +02:00
# include <fstream>
namespace spirit = boost : : spirit ;
namespace qi = boost : : spirit : : qi ;
2011-03-20 20:09:55 +02:00
namespace ascii = spirit : : ascii ;
namespace phoenix = boost : : phoenix ;
2011-03-19 19:06:46 +02:00
2011-03-23 21:41:29 +02:00
//Greenspun's Tenth Rule of Programming:
//Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified,
//bug-ridden, slow implementation of half of Common Lisp.
//actually these macros help in dealing with boost::variant
2011-03-25 00:05:08 +02:00
2011-03-28 22:34:00 +03:00
# define BEGIN_TYPE_CASE(LinePrinterVisitor) struct LinePrinterVisitor : boost::static_visitor<> \
2011-03-23 21:41:29 +02:00
{
# define FOR_TYPE(TYPE, VAR) void operator()(TYPE const& VAR) const
2011-03-28 22:34:00 +03:00
# define DO_TYPE_CASE(LinePrinterVisitor, VAR) } ___UN; boost::apply_visitor(___UN, VAR);
2011-03-23 21:41:29 +02:00
2011-03-19 19:06:46 +02:00
ERMParser : : ERMParser ( std : : string file )
: srcFile ( file )
{ }
void ERMParser : : parseFile ( )
{
2011-03-20 00:27:05 +02:00
std : : ifstream file ( srcFile . c_str ( ) ) ;
2011-03-19 19:06:46 +02:00
if ( ! file . is_open ( ) )
{
tlog1 < < " File " < < srcFile < < " not found or unable to open \n " ;
return ;
}
//check header
char header [ 5 ] ;
file . getline ( header , ARRAY_COUNT ( header ) ) ;
2011-04-01 22:09:05 +03:00
if ( std : : string ( header ) ! = " ZVSE " & & std : : string ( header ) ! = " VERM " )
2011-03-19 19:06:46 +02:00
{
tlog1 < < " File " < < srcFile < < " has wrong header \n " ;
return ;
}
//parse file
char lineBuf [ 1024 ] ;
2011-03-25 22:38:24 +02:00
parsedLine = 1 ;
std : : string wholeLine ; //used for buffering multiline lines
bool inString = false ;
2011-03-27 20:24:30 +03:00
2011-03-19 19:06:46 +02:00
while ( file . good ( ) )
{
//reading line
file . getline ( lineBuf , ARRAY_COUNT ( lineBuf ) ) ;
if ( file . gcount ( ) = = ARRAY_COUNT ( lineBuf ) )
{
2011-03-25 22:38:24 +02:00
tlog1 < < " Encountered a problem during parsing " < < srcFile < < " too long line ( " < < parsedLine < < " ) \n " ;
2011-03-19 19:06:46 +02:00
}
2011-03-25 22:38:24 +02:00
switch ( classifyLine ( lineBuf , inString ) )
{
case ERMParser : : COMMAND_FULL :
case ERMParser : : COMMENT :
{
2011-03-28 22:34:00 +03:00
repairEncoding ( lineBuf , ARRAY_COUNT ( lineBuf ) ) ;
2011-03-25 22:38:24 +02:00
parseLine ( lineBuf ) ;
}
break ;
case ERMParser : : UNFINISHED_STRING :
{
if ( ! inString )
wholeLine = " " ;
inString = true ;
wholeLine + = lineBuf ;
}
break ;
case ERMParser : : END_OF_STRING :
{
inString = false ;
wholeLine + = lineBuf ;
2011-03-28 22:34:00 +03:00
repairEncoding ( wholeLine ) ;
2011-03-25 22:38:24 +02:00
parseLine ( wholeLine ) ;
}
break ;
}
2011-03-19 19:06:46 +02:00
//loop end
2011-03-25 22:38:24 +02:00
+ + parsedLine ;
2011-03-19 19:06:46 +02:00
}
}
void callme ( char const & i )
{
std : : cout < < " fd " ;
}
2011-03-20 20:09:55 +02:00
namespace ERM
{
2011-03-28 22:34:00 +03:00
struct TStringConstant
{
std : : string str ;
} ;
struct TMacroUsage
{
std : : string macro ;
} ;
//macro with '?', for write only
struct TQMacroUsage
{
std : : string qmacro ;
} ;
2011-03-27 20:24:30 +03:00
2011-03-28 22:34:00 +03:00
//definition of a macro
struct TMacroDef
{
std : : string macro ;
} ;
typedef std : : string TCmdName ;
2011-03-27 20:24:30 +03:00
struct TVarExpNotMacro
2011-03-21 22:34:44 +02:00
{
2011-03-28 22:34:00 +03:00
typedef boost : : optional < int > Tval ;
boost : : optional < char > questionMark ;
2011-03-27 20:24:30 +03:00
std : : string varsym ;
2011-03-28 22:34:00 +03:00
Tval val ;
2011-03-21 22:34:44 +02:00
} ;
2011-03-28 22:34:00 +03:00
2011-03-27 20:24:30 +03:00
typedef boost : : variant < TVarExpNotMacro , TMacroUsage > TVarExp ;
//write-only variable expression
2011-03-28 22:34:00 +03:00
struct TVarpExp
{
typedef boost : : variant < TVarExpNotMacro , TQMacroUsage > Tvartype ;
Tvartype var ;
} ;
2011-03-27 20:24:30 +03:00
//i-expression (identifier expression) - an integral constant, variable symbol or array symbol
2011-03-28 22:34:00 +03:00
typedef boost : : variant < TVarExp , int > TIexp ;
2011-03-21 22:34:44 +02:00
2011-03-25 22:38:24 +02:00
struct TArithmeticOp
{
2011-03-28 22:34:00 +03:00
TIexp lhs , rhs ;
2011-03-25 22:38:24 +02:00
char opcode ;
} ;
2011-03-27 20:24:30 +03:00
struct TVRLogic
{
char opcode ;
2011-03-28 22:34:00 +03:00
TIexp var ;
2011-03-27 20:24:30 +03:00
} ;
struct TVRArithmetic
{
char opcode ;
2011-03-28 22:34:00 +03:00
TIexp rhs ;
2011-03-27 20:24:30 +03:00
} ;
struct TSemiCompare
{
std : : string compSign ;
2011-03-28 22:34:00 +03:00
TIexp rhs ;
2011-03-27 20:24:30 +03:00
} ;
struct TCurriedString
{
2011-03-28 22:34:00 +03:00
TIexp iexp ;
2011-03-27 20:24:30 +03:00
TStringConstant string ;
} ;
struct TVarConcatString
{
TVarExp var ;
TStringConstant string ;
} ;
2011-03-28 22:34:00 +03:00
typedef boost : : variant < TVarConcatString , TStringConstant , TCurriedString , TSemiCompare , TMacroUsage , TMacroDef , TIexp , TVarpExp , qi : : unused_type > TBodyOptionItem ;
2011-03-27 20:24:30 +03:00
typedef std : : vector < TBodyOptionItem > TNormalBodyOptionList ;
struct TNormalBodyOption
{
char optionCode ;
TNormalBodyOptionList params ;
} ;
typedef boost : : variant < TVRLogic , TVRArithmetic , TNormalBodyOption > TBodyOption ;
2011-03-28 22:34:00 +03:00
typedef boost : : variant < TIexp , TArithmeticOp > TIdentifierInternal ;
typedef std : : vector < TIdentifierInternal > Tidentifier ;
2011-03-21 22:34:44 +02:00
2011-03-25 22:38:24 +02:00
struct TComparison
{
std : : string compSign ;
2011-03-28 22:34:00 +03:00
TIexp lhs , rhs ;
2011-03-25 22:38:24 +02:00
} ;
2011-03-21 22:34:44 +02:00
2011-03-28 22:34:00 +03:00
struct Tcondition ;
2011-03-21 22:34:44 +02:00
typedef
boost : : optional <
2011-03-28 22:34:00 +03:00
boost : : recursive_wrapper < Tcondition >
2011-03-21 22:34:44 +02:00
>
2011-03-28 22:34:00 +03:00
TconditionNode ;
2011-03-20 20:09:55 +02:00
2011-03-25 22:38:24 +02:00
2011-03-28 22:34:00 +03:00
struct Tcondition
2011-03-21 22:34:44 +02:00
{
2011-03-25 22:38:24 +02:00
typedef boost : : variant <
TComparison ,
int >
Tcond ; //comparison or condition flag
2011-03-25 00:05:08 +02:00
char ctype ;
2011-03-25 22:38:24 +02:00
Tcond cond ;
2011-03-28 22:34:00 +03:00
TconditionNode rhs ;
2011-03-21 22:34:44 +02:00
} ;
2011-03-28 22:34:00 +03:00
struct Ttrigger
2011-03-20 20:09:55 +02:00
{
2011-03-27 20:24:30 +03:00
TCmdName name ;
2011-03-28 22:34:00 +03:00
boost : : optional < Tidentifier > identifier ;
boost : : optional < Tcondition > condition ;
2011-03-20 20:09:55 +02:00
} ;
//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...
2011-03-27 20:24:30 +03:00
//typedef boost::variant<char, TStringConstant, TMacroUsage, TMacroDef> bodyItem;
2011-03-28 22:34:00 +03:00
typedef std : : vector < TBodyOption > Tbody ;
2011-03-20 20:09:55 +02:00
2011-03-28 22:34:00 +03:00
struct Tinstruction
2011-03-20 20:09:55 +02:00
{
2011-03-27 20:24:30 +03:00
TCmdName name ;
2011-03-28 22:34:00 +03:00
boost : : optional < Tidentifier > identifier ;
boost : : optional < Tcondition > condition ;
Tbody body ;
2011-03-20 20:09:55 +02:00
} ;
2011-03-28 22:34:00 +03:00
struct Treceiver
2011-03-20 20:09:55 +02:00
{
2011-03-27 20:24:30 +03:00
TCmdName name ;
2011-03-28 22:34:00 +03:00
boost : : optional < Tidentifier > identifier ;
boost : : optional < Tcondition > condition ;
boost : : optional < Tbody > body ;
2011-03-20 20:09:55 +02:00
} ;
2011-03-28 22:34:00 +03:00
struct TPostTrigger
2011-03-20 20:09:55 +02:00
{
2011-03-28 22:34:00 +03:00
TCmdName name ;
boost : : optional < Tidentifier > identifier ;
boost : : optional < Tcondition > condition ;
2011-03-20 20:09:55 +02:00
} ;
2011-03-28 22:34:00 +03:00
struct Tcommand
2011-03-23 21:41:29 +02:00
{
2011-03-28 22:34:00 +03:00
typedef boost : : variant <
Ttrigger ,
Tinstruction ,
Treceiver ,
TPostTrigger
>
Tcmd ;
Tcmd cmd ;
2011-03-23 21:41:29 +02:00
std : : string comment ;
} ;
2011-03-20 20:09:55 +02:00
2011-04-01 22:09:05 +03:00
//vector expression
2011-03-20 20:09:55 +02:00
2011-04-01 22:09:05 +03:00
typedef boost : : variant < Tcommand , std : : string , qi : : unused_type > TERMline ;
struct TSymbol
{
boost : : optional < std : : string > symModifier ; //'`', ',', ',@', '#''
std : : string sym ;
} ;
//for #'symbol expression
struct TVExp ;
typedef boost : : variant < boost : : recursive_wrapper < TVExp > , TSymbol , char , double , int , Tcommand , TStringConstant > TVOption ; //options in v-expression
//v-expression
struct TVExp
{
//char dummy;
std : : vector < TVOption > children ;
} ;
//script line
typedef boost : : variant < TVExp , TERMline > TLine ;
2011-03-20 20:09:55 +02:00
//console printer
2011-03-28 22:34:00 +03:00
struct VarPrinterVisitor : boost : : static_visitor < >
2011-03-25 00:05:08 +02:00
{
2011-03-27 20:24:30 +03:00
void operator ( ) ( TVarExpNotMacro const & val ) const
2011-03-25 00:05:08 +02:00
{
2011-03-27 20:24:30 +03:00
tlog2 < < val . varsym ;
if ( val . val . is_initialized ( ) )
{
tlog2 < < val . val . get ( ) ;
}
2011-03-25 00:05:08 +02:00
}
2011-03-27 20:24:30 +03:00
void operator ( ) ( TMacroUsage const & val ) const
2011-03-25 00:05:08 +02:00
{
2011-03-28 22:34:00 +03:00
tlog2 < < " $ " < < val . macro < < " & " ;
2011-03-25 00:05:08 +02:00
}
} ;
2011-03-27 20:24:30 +03:00
void varPrinter ( const TVarExp & var )
{
2011-03-28 22:34:00 +03:00
boost : : apply_visitor ( VarPrinterVisitor ( ) , var ) ;
2011-03-27 20:24:30 +03:00
}
2011-03-25 22:38:24 +02:00
2011-03-28 22:34:00 +03:00
struct IExpPrinterVisitor : boost : : static_visitor < >
2011-03-25 22:38:24 +02:00
{
2011-03-27 20:24:30 +03:00
void operator ( ) ( int const & constant ) const
2011-03-25 22:38:24 +02:00
{
2011-03-27 20:24:30 +03:00
tlog2 < < constant ;
2011-03-25 22:38:24 +02:00
}
2011-03-27 20:24:30 +03:00
void operator ( ) ( TVarExp const & var ) const
2011-03-25 22:38:24 +02:00
{
2011-03-27 20:24:30 +03:00
varPrinter ( var ) ;
2011-03-25 22:38:24 +02:00
}
2011-03-27 20:24:30 +03:00
} ;
2011-03-28 22:34:00 +03:00
void iexpPrinter ( const TIexp & exp )
2011-03-27 20:24:30 +03:00
{
2011-03-28 22:34:00 +03:00
boost : : apply_visitor ( IExpPrinterVisitor ( ) , exp ) ;
2011-03-25 22:38:24 +02:00
}
2011-03-28 22:34:00 +03:00
struct IdentifierPrinterVisitor : boost : : static_visitor < >
2011-03-25 22:38:24 +02:00
{
2011-03-28 22:34:00 +03:00
void operator ( ) ( TIexp const & iexp ) const
2011-03-25 22:38:24 +02:00
{
iexpPrinter ( iexp ) ;
}
void operator ( ) ( TArithmeticOp const & arop ) const
{
iexpPrinter ( arop . lhs ) ;
tlog2 < < " " < < arop . opcode < < " " ;
iexpPrinter ( arop . rhs ) ;
}
} ;
2011-03-28 22:34:00 +03:00
void identifierPrinter ( const boost : : optional < Tidentifier > & id )
2011-03-20 20:09:55 +02:00
{
2011-03-23 21:41:29 +02:00
if ( id . is_initialized ( ) )
2011-03-20 20:09:55 +02:00
{
2011-03-23 21:41:29 +02:00
tlog2 < < " identifier: " ;
2011-03-25 22:38:24 +02:00
BOOST_FOREACH ( TIdentifierInternal x , id . get ( ) )
2011-03-23 21:41:29 +02:00
{
2011-03-28 22:34:00 +03:00
tlog2 < < " # " ;
boost : : apply_visitor ( IdentifierPrinterVisitor ( ) , x ) ;
2011-03-23 21:41:29 +02:00
}
2011-03-20 20:09:55 +02:00
}
}
2011-03-28 22:34:00 +03:00
struct ConditionCondPrinterVisitor : boost : : static_visitor < >
2011-03-25 22:38:24 +02:00
{
void operator ( ) ( TComparison const & cmp ) const
{
iexpPrinter ( cmp . lhs ) ;
tlog2 < < " " < < cmp . compSign < < " " ;
iexpPrinter ( cmp . rhs ) ;
}
void operator ( ) ( int const & flag ) const
{
tlog2 < < " condflag " < < flag ;
}
} ;
2011-03-28 22:34:00 +03:00
void conditionPrinter ( const boost : : optional < Tcondition > & cond )
2011-03-20 20:09:55 +02:00
{
2011-03-23 21:41:29 +02:00
if ( cond . is_initialized ( ) )
2011-03-25 00:05:08 +02:00
{
2011-03-28 22:34:00 +03:00
Tcondition condp = cond . get ( ) ;
2011-03-25 22:38:24 +02:00
tlog2 < < " condition: " ;
2011-03-28 22:34:00 +03:00
boost : : apply_visitor ( ConditionCondPrinterVisitor ( ) , condp . cond ) ;
tlog2 < < " cond type: " < < condp . ctype ;
2011-03-25 00:05:08 +02:00
//recursive call
if ( condp . rhs . is_initialized ( ) )
{
2011-03-28 22:34:00 +03:00
tlog2 < < " rhs: " ;
boost : : optional < Tcondition > rhsc = condp . rhs . get ( ) . get ( ) ;
2011-03-25 00:05:08 +02:00
conditionPrinter ( rhsc ) ;
}
2011-03-28 22:34:00 +03:00
else
{
tlog2 < < " no rhs; " ;
}
2011-03-25 00:05:08 +02:00
}
2011-03-23 21:41:29 +02:00
}
2011-03-20 20:09:55 +02:00
2011-03-28 22:34:00 +03:00
struct BodyVarpPrinterVisitor : boost : : static_visitor < >
{ //<TVarExpNotMacro, TQMacroUsage>
void operator ( ) ( TVarExpNotMacro const & cmp ) const
{
if ( cmp . questionMark . is_initialized ( ) )
{
tlog2 < < cmp . questionMark . get ( ) ;
}
if ( cmp . val . is_initialized ( ) )
{
tlog2 < < " val: " < < cmp . val . get ( ) ;
}
tlog2 < < " varsym: | " < < cmp . varsym < < " | " ;
}
void operator ( ) ( TQMacroUsage const & cmp ) const
{
tlog2 < < " ???$$ " < < cmp . qmacro < < " $$ " ;
}
} ;
struct BodyOptionItemPrinterVisitor : boost : : static_visitor < >
2011-03-23 21:41:29 +02:00
{
2011-03-28 22:34:00 +03:00
//, , , , , , , , qi::unused_type
void operator ( ) ( TVarConcatString const & cmp ) const
{
tlog2 < < " +concat \" " ;
varPrinter ( cmp . var ) ;
tlog2 < < " with " < < cmp . string . str ;
}
void operator ( ) ( TStringConstant const & cmp ) const
{
tlog2 < < " \" " < < cmp . str < < " \" " ;
}
void operator ( ) ( TCurriedString const & cmp ) const
{
tlog2 < < " cs: " ;
iexpPrinter ( cmp . iexp ) ;
tlog2 < < " ' " < < cmp . string . str < < " ' " ;
}
void operator ( ) ( TSemiCompare const & cmp ) const
2011-03-20 20:09:55 +02:00
{
2011-03-28 22:34:00 +03:00
tlog2 < < cmp . compSign < < " ; rhs: " ;
iexpPrinter ( cmp . rhs ) ;
}
void operator ( ) ( TMacroUsage const & cmp ) const
{
tlog2 < < " $$ " < < cmp . macro < < " $$ " ;
}
void operator ( ) ( TMacroDef const & cmp ) const
{
tlog2 < < " @@ " < < cmp . macro < < " @@ " ;
}
void operator ( ) ( TIexp const & cmp ) const
{
iexpPrinter ( cmp ) ;
}
void operator ( ) ( TVarpExp const & cmp ) const
{
tlog2 < < " varp " ;
boost : : apply_visitor ( BodyVarpPrinterVisitor ( ) , cmp . var ) ;
}
void operator ( ) ( qi : : unused_type const & cmp ) const
{
tlog2 < < " nothing " ;
}
} ;
struct BodyOptionVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVRLogic const & cmp ) const
{
tlog2 < < cmp . opcode < < " " ;
iexpPrinter ( cmp . var ) ;
}
void operator ( ) ( TVRArithmetic const & cmp ) const
{
tlog2 < < cmp . opcode < < " " ;
iexpPrinter ( cmp . rhs ) ;
}
void operator ( ) ( TNormalBodyOption const & cmp ) const
{
tlog2 < < cmp . optionCode < < " ~ " ;
BOOST_FOREACH ( TBodyOptionItem optList , cmp . params )
{
boost : : apply_visitor ( BodyOptionItemPrinterVisitor ( ) , optList ) ;
}
}
} ;
void bodyPrinter ( const Tbody & body )
{
tlog2 < < " body items: " ;
BOOST_FOREACH ( TBodyOption bi , body )
{
tlog2 < < " ( " ;
apply_visitor ( BodyOptionVisitor ( ) , bi ) ;
tlog2 < < " ) " ;
}
}
struct CommandPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( Ttrigger const & trig ) const
{
tlog2 < < " trigger: " < < trig . name < < " " ;
2011-03-25 00:05:08 +02:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
2011-03-20 20:09:55 +02:00
}
2011-03-28 22:34:00 +03:00
void operator ( ) ( Tinstruction const & trig ) const
2011-03-20 20:09:55 +02:00
{
2011-03-28 22:34:00 +03:00
tlog2 < < " instruction: " < < trig . name < < " " ;
2011-03-25 00:05:08 +02:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
2011-03-28 22:34:00 +03:00
bodyPrinter ( trig . body ) ;
2011-03-20 20:09:55 +02:00
}
2011-03-28 22:34:00 +03:00
void operator ( ) ( Treceiver const & trig ) const
2011-03-25 00:05:08 +02:00
{
2011-03-28 22:34:00 +03:00
tlog2 < < " receiver: " < < trig . name < < " " ;
2011-03-20 20:09:55 +02:00
2011-03-25 00:05:08 +02:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
2011-03-28 22:34:00 +03:00
if ( trig . body . is_initialized ( ) )
bodyPrinter ( trig . body . get ( ) ) ;
2011-03-25 00:05:08 +02:00
}
2011-03-28 22:34:00 +03:00
void operator ( ) ( TPostTrigger const & trig ) const
2011-03-20 20:09:55 +02:00
{
2011-03-28 22:34:00 +03:00
tlog2 < < " post trigger: " < < trig . name < < " " ;
2011-03-25 00:05:08 +02:00
identifierPrinter ( trig . identifier ) ;
conditionPrinter ( trig . condition ) ;
2011-03-20 20:09:55 +02:00
}
} ;
2011-03-28 22:34:00 +03:00
struct LinePrinterVisitor : boost : : static_visitor < >
2011-03-20 20:09:55 +02:00
{
2011-03-28 22:34:00 +03:00
void operator ( ) ( Tcommand const & cmd ) const
2011-03-20 20:09:55 +02:00
{
2011-03-28 22:34:00 +03:00
CommandPrinterVisitor un ;
2011-03-25 00:05:08 +02:00
boost : : apply_visitor ( un , cmd . cmd ) ;
2011-03-23 21:41:29 +02:00
std : : cout < < " Line comment: " < < cmd . comment < < std : : endl ;
2011-03-20 20:09:55 +02:00
}
2011-03-25 00:05:08 +02:00
void operator ( ) ( std : : string const & comment ) const
2011-03-20 20:09:55 +02:00
{
}
2011-03-25 00:05:08 +02:00
void operator ( ) ( qi : : unused_type const & nothing ) const
2011-03-23 21:41:29 +02:00
{
}
2011-03-25 00:05:08 +02:00
} ;
2011-04-01 22:09:05 +03:00
void printERM ( const TERMline & ast )
2011-03-25 00:05:08 +02:00
{
tlog2 < < " " ;
2011-03-28 22:34:00 +03:00
boost : : apply_visitor ( LinePrinterVisitor ( ) , ast ) ;
2011-03-20 20:09:55 +02:00
}
2011-04-01 22:09:05 +03:00
void printTVExp ( const TVExp & exp ) ;
struct VOptionPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVExp const & cmd ) const
{
printTVExp ( cmd ) ;
}
void operator ( ) ( TSymbol const & cmd ) const
{
if ( cmd . symModifier . is_initialized ( ) )
{
tlog2 < < cmd . symModifier . get ( ) ;
}
tlog2 < < cmd . sym ;
}
void operator ( ) ( char const & cmd ) const
{
tlog2 < < " ' " < < cmd < < " ' " ;
}
void operator ( ) ( int const & cmd ) const
{
tlog2 < < cmd ;
}
void operator ( ) ( double const & cmd ) const
{
tlog2 < < cmd ;
}
void operator ( ) ( TERMline const & cmd ) const
{
printERM ( cmd ) ;
}
void operator ( ) ( TStringConstant const & cmd ) const
{
tlog2 < < " ^ " < < cmd . str < < " ^ " ;
}
} ;
void printTVExp ( const TVExp & exp )
{
tlog2 < < " [ " ;
BOOST_FOREACH ( TVOption opt , exp . children )
{
boost : : apply_visitor ( VOptionPrinterVisitor ( ) , opt ) ;
tlog2 < < " " ;
}
tlog2 < < " ] " ;
}
struct TLPrinterVisitor : boost : : static_visitor < >
{
void operator ( ) ( TVExp const & cmd ) const
{
printTVExp ( cmd ) ;
}
void operator ( ) ( TERMline const & cmd ) const
{
printERM ( cmd ) ;
}
} ;
void printAST ( const TLine & ast )
{
boost : : apply_visitor ( TLPrinterVisitor ( ) , ast ) ;
}
2011-03-20 20:09:55 +02:00
}
2011-03-28 22:34:00 +03:00
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TStringConstant ,
( std : : string , str )
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TMacroUsage ,
( std : : string , macro )
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TQMacroUsage ,
( std : : string , qmacro )
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TMacroDef ,
( std : : string , macro )
)
2011-03-21 22:34:44 +02:00
BOOST_FUSION_ADAPT_STRUCT (
2011-03-27 20:24:30 +03:00
ERM : : TVarExpNotMacro ,
2011-03-28 22:34:00 +03:00
( boost : : optional < char > , questionMark )
2011-03-27 20:24:30 +03:00
( std : : string , varsym )
2011-03-28 22:34:00 +03:00
( ERM : : TVarExpNotMacro : : Tval , val )
2011-03-21 22:34:44 +02:00
)
2011-03-25 22:38:24 +02:00
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TArithmeticOp ,
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , lhs )
2011-03-25 22:38:24 +02:00
( char , opcode )
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , rhs )
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TVarpExp ,
( ERM : : TVarpExp : : Tvartype , var )
2011-03-25 22:38:24 +02:00
)
2011-03-27 20:24:30 +03:00
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TVRLogic ,
( char , opcode )
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , var )
2011-03-27 20:24:30 +03:00
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TVRArithmetic ,
( char , opcode )
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , rhs )
2011-03-27 20:24:30 +03:00
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TNormalBodyOption ,
( char , optionCode )
( ERM : : TNormalBodyOptionList , params )
)
2011-03-20 20:09:55 +02:00
BOOST_FUSION_ADAPT_STRUCT (
2011-03-28 22:34:00 +03:00
ERM : : Ttrigger ,
2011-03-27 20:24:30 +03:00
( ERM : : TCmdName , name )
2011-03-28 22:34:00 +03:00
( boost : : optional < ERM : : Tidentifier > , identifier )
( boost : : optional < ERM : : Tcondition > , condition )
2011-03-20 20:09:55 +02:00
)
2011-03-25 22:38:24 +02:00
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TComparison ,
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , lhs )
2011-03-25 22:38:24 +02:00
( std : : string , compSign )
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , rhs )
2011-03-25 22:38:24 +02:00
)
2011-03-27 20:24:30 +03:00
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TSemiCompare ,
( std : : string , compSign )
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , rhs )
2011-03-27 20:24:30 +03:00
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TCurriedString ,
2011-03-28 22:34:00 +03:00
( ERM : : TIexp , iexp )
2011-03-27 20:24:30 +03:00
( ERM : : TStringConstant , string )
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TVarConcatString ,
( ERM : : TVarExp , var )
( ERM : : TStringConstant , string )
)
2011-03-21 22:34:44 +02:00
BOOST_FUSION_ADAPT_STRUCT (
2011-03-28 22:34:00 +03:00
ERM : : Tcondition ,
2011-03-25 00:05:08 +02:00
( char , ctype )
2011-03-28 22:34:00 +03:00
( ERM : : Tcondition : : Tcond , cond )
( ERM : : TconditionNode , rhs )
2011-03-21 22:34:44 +02:00
)
2011-03-20 20:09:55 +02:00
BOOST_FUSION_ADAPT_STRUCT (
2011-03-28 22:34:00 +03:00
ERM : : Tinstruction ,
2011-03-27 20:24:30 +03:00
( ERM : : TCmdName , name )
2011-03-28 22:34:00 +03:00
( boost : : optional < ERM : : Tidentifier > , identifier )
( boost : : optional < ERM : : Tcondition > , condition )
( ERM : : Tbody , body )
2011-03-20 20:09:55 +02:00
)
BOOST_FUSION_ADAPT_STRUCT (
2011-03-28 22:34:00 +03:00
ERM : : Treceiver ,
2011-03-27 20:24:30 +03:00
( ERM : : TCmdName , name )
2011-03-28 22:34:00 +03:00
( boost : : optional < ERM : : Tidentifier > , identifier )
( boost : : optional < ERM : : Tcondition > , condition )
( boost : : optional < ERM : : Tbody > , body )
2011-03-20 20:09:55 +02:00
)
BOOST_FUSION_ADAPT_STRUCT (
2011-03-28 22:34:00 +03:00
ERM : : TPostTrigger ,
( ERM : : TCmdName , name )
( boost : : optional < ERM : : Tidentifier > , identifier )
( boost : : optional < ERM : : Tcondition > , condition )
2011-03-20 20:09:55 +02:00
)
2011-03-23 21:41:29 +02:00
BOOST_FUSION_ADAPT_STRUCT (
2011-03-28 22:34:00 +03:00
ERM : : Tcommand ,
( ERM : : Tcommand : : Tcmd , cmd )
2011-03-23 21:41:29 +02:00
( std : : string , comment )
)
2011-04-01 22:09:05 +03:00
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TVExp ,
//(char, dummy)
( std : : vector < ERM : : TVOption > , children )
)
BOOST_FUSION_ADAPT_STRUCT (
ERM : : TSymbol ,
( boost : : optional < std : : string > , symModifier )
( std : : string , sym )
)
2011-03-20 20:09:55 +02:00
namespace ERM
{
template < typename Iterator >
2011-04-01 22:09:05 +03:00
struct ERM_grammar : qi : : grammar < Iterator , TLine ( ) , ascii : : space_type >
2011-03-20 20:09:55 +02:00
{
2011-04-01 22:09:05 +03:00
ERM_grammar ( ) : ERM_grammar : : base_type ( vline , " VERM script line " )
2011-03-20 20:09:55 +02:00
{
2011-03-27 20:24:30 +03:00
//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 ( ' @ ' ) ] ;
2011-03-28 22:34:00 +03:00
varExpNotMacro % = - qi : : char_ ( " ? " ) > > ( + ( qi : : char_ ( " a-z " ) - ' u ' ) ) > > - qi : : int_ ;
qMacroUsage % = qi : : lexeme [ qi : : lit ( " ?$ " ) > > * ( qi : : char_ - ' $ ' ) > > qi : : lit ( ' $ ' ) ] ;
2011-03-27 20:24:30 +03:00
varExp % = varExpNotMacro | macroUsage ;
iexp % = varExp | qi : : int_ ;
2011-03-28 22:34:00 +03:00
varp % = /* qi::lit("?") >> */ ( varExpNotMacro | qMacroUsage ) ;
comment % = * qi : : char_ ;
2011-04-01 22:09:05 +03:00
commentLine % = ( ~ qi : : char_ ( " ![ " ) > > comment | ( qi : : char_ ( ' ! ' ) > > ( ~ qi : : char_ ( " ?!$# " ) ) > > comment ) ) ;
2011-03-27 20:24:30 +03:00
cmdName % = qi : : lexeme [ qi : : repeat ( 2 ) [ qi : : char_ ] ] ;
2011-03-25 22:38:24 +02:00
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 ( ' / ' ) ;
comparison % = iexp > > ( * qi : : char_ ( " <=> " ) ) > > iexp ;
condition % = qi : : char_ ( " &|X/ " ) > > ( comparison | qi : : int_ ) > > - condition ;
2011-03-21 22:34:44 +02:00
trigger % = cmdName > > - identifier > > - condition > qi : : lit ( " ; " ) ; /////
string % = qi : : lexeme [ ' ^ ' > > * ( qi : : char_ - ' ^ ' ) > > ' ^ ' ] ;
2011-03-27 20:24:30 +03:00
VRLogic % = qi : : char_ ( " &|X " ) > > iexp ;
VRarithmetic % = qi : : char_ ( " +*:/%- " ) > > iexp ;
semiCompare % = * qi : : char_ ( " <=> " ) > > iexp ;
curStr % = iexp > > string ;
varConcatString % = varExp > > qi : : lit ( " + " ) > > string ;
2011-03-28 22:34:00 +03:00
bodyOptionItem % = varConcatString | curStr | string | semiCompare | macroUsage | macroDef | varp | iexp | qi : : eps ;
2011-03-27 20:24:30 +03:00
exactBodyOptionList % = ( bodyOptionItem % qi : : lit ( " / " ) ) ;
2011-03-28 22:34:00 +03:00
normalBodyOption = qi : : char_ ( " A-Z+ " ) > exactBodyOptionList ;
2011-03-27 20:24:30 +03:00
bodyOption % = VRLogic | VRarithmetic | normalBodyOption ;
body % = qi : : lit ( " : " ) > > + ( bodyOption ) > qi : : lit ( " ; " ) ;
2011-03-20 20:09:55 +02:00
instruction % = cmdName > > - identifier > > - condition > > body ;
2011-03-28 22:34:00 +03:00
receiver % = cmdName > > - identifier > > - condition > > - body ; //receiver without body exists... change needed
postTrigger % = cmdName > > - identifier > > - condition > qi : : lit ( " ; " ) ;
2011-03-23 21:41:29 +02:00
command % = ( qi : : lit ( " ! " ) > >
2011-03-20 20:09:55 +02:00
(
2011-03-23 21:41:29 +02:00
( qi : : lit ( " ? " ) > > trigger ) |
2011-03-27 20:24:30 +03:00
( qi : : lit ( " ! " ) > > receiver ) |
2011-03-25 22:38:24 +02:00
( qi : : lit ( " # " ) > > instruction ) |
2011-03-28 22:34:00 +03:00
( qi : : lit ( " $ " ) > > postTrigger )
2011-03-20 20:09:55 +02:00
) > > comment
) ;
rline % =
(
2011-03-23 21:41:29 +02:00
command | commentLine | spirit : : eps
2011-04-01 22:09:05 +03:00
) ;
vsym % = - ( qi : : string ( " ` " ) | qi : : string ( " , " ) | qi : : string ( " #, " ) | qi : : string ( " ,@ " ) | qi : : string ( " #' " ) ) > > + qi : : char_ ( " +*/$%&_=<>~a-zA-Z0-9- " ) ;
vopt % = vsym | ( qi : : lit ( " ! " ) > > qi : : char_ > > qi : : lit ( " ! " ) ) | qi : : double_ | qi : : int_ | command /*| vexp*/ | string ;
vexp % = qi : : lit ( " [ " ) > > * ( vopt ) > > qi : : lit ( " ] " ) ;
vline % = ( vexp | rline ) > spirit : : eoi ;
2011-03-20 20:09:55 +02:00
//error handling
string . name ( " string constant " ) ;
2011-03-21 22:34:44 +02:00
iexp . name ( " i-expression " ) ;
2011-03-20 20:09:55 +02:00
comment . name ( " comment " ) ;
commentLine . name ( " comment line " ) ;
cmdName . name ( " name of a command " ) ;
identifier . name ( " identifier " ) ;
condition . name ( " condition " ) ;
trigger . name ( " trigger " ) ;
body . name ( " body " ) ;
instruction . name ( " instruction " ) ;
receiver . name ( " receiver " ) ;
2011-03-28 22:34:00 +03:00
postTrigger . name ( " post trigger " ) ;
2011-03-20 20:09:55 +02:00
command . name ( " command " ) ;
2011-04-01 22:09:05 +03:00
rline . name ( " ERM script line " ) ;
vsym . name ( " V symbol " ) ;
vopt . name ( " V option " ) ;
vexp . name ( " V expression " ) ;
vline . name ( " VERM line " ) ;
2011-03-20 20:09:55 +02:00
qi : : on_error < qi : : fail >
(
2011-04-01 22:09:05 +03:00
vline
2011-03-20 20:09:55 +02:00
, std : : cout //or phoenix::ref(std::count), is there any difference?
< < phoenix : : val ( " Error! Expecting " )
< < qi : : _4 // what failed?
< < phoenix : : val ( " here: \" " )
< < phoenix : : construct < std : : string > ( qi : : _3 , qi : : _2 ) // iterators to error-pos, end
< < phoenix : : val ( " \" " )
< < std : : endl
) ;
}
2011-03-27 20:24:30 +03:00
qi : : rule < Iterator , TStringConstant ( ) , ascii : : space_type > string ;
qi : : rule < Iterator , TMacroUsage ( ) , ascii : : space_type > macroUsage ;
2011-03-28 22:34:00 +03:00
qi : : rule < Iterator , TQMacroUsage ( ) , ascii : : space_type > qMacroUsage ;
2011-03-27 20:24:30 +03:00
qi : : rule < Iterator , TMacroDef ( ) , ascii : : space_type > macroDef ;
qi : : rule < Iterator , TVarExpNotMacro ( ) , ascii : : space_type > varExpNotMacro ;
qi : : rule < Iterator , TVarExp ( ) , ascii : : space_type > varExp ;
2011-03-28 22:34:00 +03:00
qi : : rule < Iterator , TIexp ( ) , ascii : : space_type > iexp ;
2011-03-27 20:24:30 +03:00
qi : : rule < Iterator , TVarpExp ( ) , ascii : : space_type > varp ;
qi : : rule < Iterator , TArithmeticOp ( ) , ascii : : space_type > arithmeticOp ;
qi : : rule < Iterator , std : : string ( ) , ascii : : space_type > comment ;
qi : : rule < Iterator , std : : string ( ) , ascii : : space_type > commentLine ;
qi : : rule < Iterator , TCmdName ( ) , ascii : : space_type > cmdName ;
2011-03-28 22:34:00 +03:00
qi : : rule < Iterator , Tidentifier ( ) , ascii : : space_type > identifier ;
2011-03-27 20:24:30 +03:00
qi : : rule < Iterator , TComparison ( ) , ascii : : space_type > comparison ;
2011-03-28 22:34:00 +03:00
qi : : rule < Iterator , Tcondition ( ) , ascii : : space_type > condition ;
2011-03-27 20:24:30 +03:00
qi : : rule < Iterator , TVRLogic ( ) , ascii : : space_type > VRLogic ;
qi : : rule < Iterator , TVRArithmetic ( ) , ascii : : space_type > VRarithmetic ;
qi : : rule < Iterator , TSemiCompare ( ) , ascii : : space_type > semiCompare ;
qi : : rule < Iterator , TCurriedString ( ) , ascii : : space_type > curStr ;
qi : : rule < Iterator , TVarConcatString ( ) , ascii : : space_type > varConcatString ;
qi : : rule < Iterator , TBodyOptionItem ( ) , ascii : : space_type > bodyOptionItem ;
qi : : rule < Iterator , TNormalBodyOptionList ( ) , ascii : : space_type > exactBodyOptionList ;
qi : : rule < Iterator , TNormalBodyOption ( ) , ascii : : space_type > normalBodyOption ;
qi : : rule < Iterator , TBodyOption ( ) , ascii : : space_type > bodyOption ;
2011-03-28 22:34:00 +03:00
qi : : rule < Iterator , Ttrigger ( ) , ascii : : space_type > trigger ;
qi : : rule < Iterator , Tbody ( ) , ascii : : space_type > body ;
qi : : rule < Iterator , Tinstruction ( ) , ascii : : space_type > instruction ;
qi : : rule < Iterator , Treceiver ( ) , ascii : : space_type > receiver ;
qi : : rule < Iterator , TPostTrigger ( ) , ascii : : space_type > postTrigger ;
qi : : rule < Iterator , Tcommand ( ) , ascii : : space_type > command ;
2011-04-01 22:09:05 +03:00
qi : : rule < Iterator , TERMline ( ) , ascii : : space_type > rline ;
qi : : rule < Iterator , TSymbol ( ) , ascii : : space_type > vsym ;
qi : : rule < Iterator , TVOption ( ) , ascii : : space_type > vopt ;
qi : : rule < Iterator , TVExp ( ) , ascii : : space_type > vexp ;
qi : : rule < Iterator , TLine ( ) , ascii : : space_type > vline ;
2011-03-20 20:09:55 +02:00
} ;
} ;
2011-03-25 22:38:24 +02:00
void ERMParser : : parseLine ( const std : : string & line )
2011-03-19 19:06:46 +02:00
{
2011-03-20 20:09:55 +02:00
std : : string : : const_iterator beg = line . begin ( ) ,
2011-03-19 19:06:46 +02:00
end = line . end ( ) ;
2011-03-20 20:09:55 +02:00
ERM : : ERM_grammar < std : : string : : const_iterator > ERMgrammar ;
2011-04-01 22:09:05 +03:00
ERM : : TLine AST ;
2011-03-20 20:09:55 +02:00
2011-03-27 20:24:30 +03:00
// 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
2011-03-28 22:34:00 +03:00
// tlog2 << line << std::endl;
2011-04-01 22:09:05 +03:00
// ERM::printAST(AST);
2011-03-27 20:24:30 +03:00
// }
2011-03-25 22:38:24 +02:00
}
ERMParser : : ELineType ERMParser : : classifyLine ( const std : : string & line , bool inString ) const
{
ERMParser : : ELineType ret ;
if ( line [ 0 ] = = ' ! ' )
{
if ( countHatsBeforeSemicolon ( line ) % 2 = = 1 )
{
ret = ERMParser : : UNFINISHED_STRING ;
}
else
{
ret = ERMParser : : COMMAND_FULL ;
}
}
else
{
if ( inString )
{
if ( countHatsBeforeSemicolon ( line ) % 2 = = 1 )
{
ret = ERMParser : : END_OF_STRING ;
}
else
{
ret = ERMParser : : UNFINISHED_STRING ;
}
}
else
{
ret = ERMParser : : COMMENT ;
}
}
return ret ;
}
int ERMParser : : countHatsBeforeSemicolon ( const std : : string & line ) const
{
//CHECK: omit macros? or anything else?
int numOfHats = 0 ; //num of '^' before ';'
//check for unmatched ^
BOOST_FOREACH ( char c , line )
{
if ( c = = ' ; ' )
break ;
if ( c = = ' ^ ' )
+ + numOfHats ;
2011-03-25 00:05:08 +02:00
}
2011-03-25 22:38:24 +02:00
return numOfHats ;
2011-03-19 19:06:46 +02:00
}
2011-03-28 22:34:00 +03:00
void ERMParser : : repairEncoding ( std : : string & str ) const
{
for ( int g = 0 ; g < str . size ( ) ; + + g )
if ( str [ g ] & 0x80 )
str [ g ] = ' | ' ;
}
void ERMParser : : repairEncoding ( char * str , int len ) const
{
for ( int g = 0 ; g < len ; + + g )
if ( str [ g ] & 0x80 )
str [ g ] = ' | ' ;
}
2011-03-29 20:16:10 +03:00
# else
ERMParser : : ERMParser ( std : : string file ) { }
void ERMParser : : parseFile ( ) { }
# endif