1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00
vcmi/lib/ERMParser.cpp
Ivan Savenko 7209f158a1 - gcc/Linux fixes
- added --nointro parameter to skip intro videos
- minor fixes to scenario selection menu
2011-03-19 22:27:05 +00:00

110 lines
3.0 KiB
C++

#include "ERMParser.h"
#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>
#include <fstream>
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
ERMParser::ERMParser(std::string file)
:srcFile(file)
{}
void ERMParser::parseFile()
{
std::ifstream file(srcFile.c_str());
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));
if(std::string(header) != "ZVSE")
{
tlog1 << "File " << srcFile << " has wrong header\n";
return;
}
//parse file
char lineBuf[1024];
int lineNum = 1;
while(file.good())
{
//reading line
file.getline(lineBuf, ARRAY_COUNT(lineBuf));
if(file.gcount() == ARRAY_COUNT(lineBuf))
{
tlog1 << "Encountered a problem during parsing " << srcFile << " too long line " << lineNum << "\n";
}
//parsing
parseLine(lineBuf);
//loop end
++lineNum;
}
}
void callme(char const& i)
{
std::cout << "fd";
}
void ERMParser::parseLine( std::string line )
{
namespace ascii = spirit::ascii;
namespace phoenix = boost::phoenix;
typedef std::string::iterator sit;
qi::rule<sit> comment = *(qi::char_);
qi::rule<sit> commentLine = ~qi::char_('!') >> comment;
qi::rule<sit> cmdName = qi::repeat(2)[ascii::alpha];
qi::rule<sit> identifier = qi::int_ % '/';
qi::rule<sit> condition = qi::char_('&') >> +(qi::int_ | qi::char_("a-zA-Z&/|")) >> qi::char_(":;");
qi::rule<sit> trigger = cmdName >> -identifier >> -condition;
qi::rule<sit> string = qi::char_('^') >> ascii::print >> qi::char_('^');
qi::rule<sit> body = *(qi::char_("a-zA-Z0-9/ ") | string);
qi::rule<sit> instruction = cmdName >> -identifier >> -condition >> body;
qi::rule<sit> receiver = cmdName >> -identifier >> -condition >> body;
qi::rule<sit> postOBtrigger = "$OB" >> -identifier >> -condition;
qi::rule<sit> rline =
(
(qi::char_('!') >>
(
(qi::char_('?') >> trigger) |
(qi::char_('!') >> instruction) |
(qi::char_('#') >> receiver) |
postOBtrigger
) >> comment
)
| commentLine | spirit::eoi
);
qi::on_error<qi::fail>
(
rline
, 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
);
sit beg = line.begin(),
end = line.end();
bool r = qi::parse(beg, end, rline);
if(!r || beg != end)
{
tlog1 << "Parse error for line " << line << std::endl;
tlog1 << "\tCannot parse: " << std::string(beg, end) << std::endl;
}
}