1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

* ERM parser improvements

This commit is contained in:
mateuszb
2011-03-23 19:41:29 +00:00
parent c6f1d87ede
commit fca2b5da7a
2 changed files with 117 additions and 79 deletions

View File

@@ -14,6 +14,20 @@ namespace qi = boost::spirit::qi;
namespace ascii = spirit::ascii; namespace ascii = spirit::ascii;
namespace phoenix = boost::phoenix; namespace phoenix = boost::phoenix;
//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
#define BEGIN_TYPE_CASE(UN) struct UN : boost::static_visitor<> \
{
#define FOR_TYPE(TYPE, VAR) void operator()(TYPE const& VAR) const
#define DO_TYPE_CASE(UN, VAR) };boost::apply_visitor(UN(), VAR);
ERMParser::ERMParser(std::string file) ERMParser::ERMParser(std::string file)
:srcFile(file) :srcFile(file)
{} {}
@@ -136,87 +150,105 @@ namespace ERM
triggerT, triggerT,
instructionT, instructionT,
receiverT, receiverT,
postOBtriggerT, postOBtriggerT
qi::unused_type
> >
commandT; commandTcmd;
typedef boost::variant<commandT, qi::unused_type> lineT; struct commandT
{
commandTcmd cmd;
std::string comment;
};
typedef boost::variant<commandT, std::string, qi::unused_type> lineT;
//console printer //console printer
void identifierPrinter(const identifierT & id) void identifierPrinter(const boost::optional<identifierT> & id)
{ {
BOOST_FOREACH(iexpT x, id) if(id.is_initialized())
{
tlog2 << "identifier: ";
BOOST_FOREACH(iexpT x, *id)
{ {
tlog2 << "\\" << x.varsym << x.val; tlog2 << "\\" << x.varsym << x.val;
} }
} }
struct CommandPrinter : boost::static_visitor<>
{
void operator()(triggerT const& trig) const
{
tlog2 << "trigger: " << trig.name << " identifier: ";
identifierPrinter(*trig.identifier);
tlog2 << " condition: " << *trig.condition;
} }
void operator()(instructionT const& trig) const void conditionPrinter(const boost::optional<conditionT> & cond)
{ {
tlog2 << "instruction: " << trig.name << " identifier: "; if(cond.is_initialized())
identifierPrinter(*trig.identifier); tlog2 << " condition: " << *cond;
tlog2 << " condition: " << *trig.condition;
tlog2 << " body items:";
BOOST_FOREACH(bodyItem bi, trig.body)
{
tlog2 << " " << bi;
} }
}
void operator()(receiverT const& trig) const
{
tlog2 << "receiver: " << trig.name << " identifier: ";
identifierPrinter(*trig.identifier);
tlog2 << " condition: " << *trig.condition;
}
void operator()(postOBtriggerT const& trig) const
{
tlog2 << "post OB trigger; " << " identifier: ";
identifierPrinter(*trig.identifier);
tlog2 << " condition: " << *trig.condition;
}
void operator()(qi::unused_type const& text) const
{
//tlog2 << "Empty line/comment line" << std::endl;
}
};
struct ERMprinter : boost::static_visitor<> struct ERMprinter : boost::static_visitor<>
{ {
void operator()(commandT const& cmd) const void operator()(commandT const& cmd) const
{ {
CommandPrinter()(cmd);
} }
void operator()(std::string const& nothing) const
{
//tlog2 << "comment line" << std::endl;
}
void operator()(qi::unused_type const& nothing) const void operator()(qi::unused_type const& nothing) const
{ {
//tlog2 << "Empty line/comment line" << std::endl; //tlog2 << "Empty line" << std::endl;
} }
}; };
void printLineAST(const lineT & ast) void printLineAST(const lineT & ast)
{ {
tlog2 << ""; tlog2 << "";
ast.apply_visitor(ERMprinter()); BEGIN_TYPE_CASE(psa)
FOR_TYPE(commandT, cmd)
{
BEGIN_TYPE_CASE(cmt)
FOR_TYPE(triggerT, trig)
{
tlog2 << "trigger: " << trig.name;
identifierPrinter(trig.identifier);
conditionPrinter(trig.condition);
}
FOR_TYPE(instructionT, trig)
{
tlog2 << "instruction: " << trig.name;
identifierPrinter(trig.identifier);
conditionPrinter(trig.condition);
tlog2 << " body items: ";
BOOST_FOREACH(bodyItem bi, trig.body)
{
tlog2 << " " << bi;
}
}
FOR_TYPE(receiverT, trig)
{
tlog2 << "receiver: " << trig.name;
identifierPrinter(trig.identifier);
conditionPrinter(trig.condition);
}
FOR_TYPE(postOBtriggerT, trig)
{
tlog2 << "post OB trigger; ";
identifierPrinter(trig.identifier);
conditionPrinter(trig.condition);
}
DO_TYPE_CASE(cmt, cmd.cmd);
std::cout << "Line comment: " << cmd.comment << std::endl;
}
FOR_TYPE(std::string, comment)
{
}
FOR_TYPE(qi::unused_type, nothing)
{
}
DO_TYPE_CASE(psa, ast);
} }
} }
@@ -262,6 +294,12 @@ BOOST_FUSION_ADAPT_STRUCT(
(boost::optional<ERM::conditionT>, condition) (boost::optional<ERM::conditionT>, condition)
) )
BOOST_FUSION_ADAPT_STRUCT(
ERM::commandT,
(ERM::commandTcmd, cmd)
(std::string, comment)
)
namespace ERM namespace ERM
{ {
template<typename Iterator> template<typename Iterator>
@@ -271,8 +309,8 @@ namespace ERM
{ {
macro %= qi::lit('$') >> *(qi::char_ - '$') >> qi::lit('$'); macro %= qi::lit('$') >> *(qi::char_ - '$') >> qi::lit('$');
iexp %= -(*qi::char_("a-z") - 'u') >> -(qi::int_ | macro); iexp %= -(*qi::char_("a-z") - 'u') >> -(qi::int_ | macro);
comment = *(qi::char_); comment %= *(qi::char_);
commentLine = ~qi::char_('!') >> comment; commentLine %= ~qi::char_('!') >> comment;
cmdName %= qi::repeat(2)[qi::char_]; cmdName %= qi::repeat(2)[qi::char_];
identifier %= (iexp % qi::lit('/')); identifier %= (iexp % qi::lit('/'));
@@ -284,19 +322,19 @@ namespace ERM
instruction %= cmdName >> -identifier >> -condition >> body; instruction %= cmdName >> -identifier >> -condition >> body;
receiver %= cmdName >> -identifier >> -condition >> body; receiver %= cmdName >> -identifier >> -condition >> body;
postOBtrigger %= qi::lit("$OB") >> -identifier >> -condition > qi::lit(";"); postOBtrigger %= qi::lit("$OB") >> -identifier >> -condition > qi::lit(";");
command %= (qi::char_('!') >> command %= (qi::lit("!") >>
( (
(qi::char_('?') >> trigger) | (qi::lit("?") >> trigger) |
(qi::char_('!') >> instruction) | (qi::lit("!") >> instruction) |
(qi::char_('#') >> receiver) | (qi::lit("#") >> receiver) |
postOBtrigger postOBtrigger
) >> comment ) >> comment
); );
rline %= rline %=
( (
command | commentLine | spirit::eoi command | commentLine | spirit::eps
); ) > spirit::eoi;
//error handling //error handling
@@ -333,8 +371,8 @@ namespace ERM
qi::rule<Iterator, std::string()> macro; qi::rule<Iterator, std::string()> macro;
qi::rule<Iterator, iexpT()> iexp; qi::rule<Iterator, iexpT()> iexp;
qi::rule<Iterator, void()> comment; qi::rule<Iterator, std::string()> comment;
qi::rule<Iterator, void()> commentLine; qi::rule<Iterator, std::string()> commentLine;
qi::rule<Iterator, std::string()> cmdName; qi::rule<Iterator, std::string()> cmdName;
qi::rule<Iterator, identifierT()> identifier; qi::rule<Iterator, identifierT()> identifier;
qi::rule<Iterator, conditionT()> condition; qi::rule<Iterator, conditionT()> condition;
@@ -356,15 +394,15 @@ void ERMParser::parseLine( std::string line )
ERM::ERM_grammar<std::string::const_iterator> ERMgrammar; ERM::ERM_grammar<std::string::const_iterator> ERMgrammar;
ERM::lineT AST; ERM::lineT AST;
bool r = qi::parse(beg, end, ERMgrammar, AST); // bool r = qi::parse(beg, end, ERMgrammar, AST);
if(!r || beg != end) // if(!r || beg != end)
{ // {
// tlog1 << "Parse error for line " << line << std::endl; // tlog1 << "Parse error for line " << line << std::endl;
// tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl; // tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl;
} // }
else // else
{ // {
//parsing succeeded // //parsing succeeded
// ERM::printLineAST(AST); // ERM::printLineAST(AST);
} // }
} }

View File

@@ -5,7 +5,7 @@ class ERMParser
{ {
private: private:
std::string srcFile; std::string srcFile;
int parsedLine;
void parseLine(std::string line); void parseLine(std::string line);