1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Added ERM preprocessor (removing comments, empty lines, joining multi-line commends).

This commit is contained in:
Michał W. Urbańczyk 2011-04-03 21:38:47 +00:00
parent 3fc570a8e9
commit 0aad12ae67
2 changed files with 154 additions and 70 deletions

View File

@ -1,3 +1,4 @@
#define VCMI_DLL
#include "ERMParser.h"
#include <boost/version.hpp>
//To make compilation with older boost versions possible
@ -13,6 +14,7 @@
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <fstream>
#include <boost/algorithm/string/trim.hpp>
namespace spirit = boost::spirit;
namespace qi = boost::spirit::qi;
@ -33,7 +35,125 @@ namespace phoenix = boost::phoenix;
#define DO_TYPE_CASE(LinePrinterVisitor, VAR) } ___UN; boost::apply_visitor(___UN, VAR);
CERMPreprocessor::CERMPreprocessor(const std::string &Fname) : fname(Fname), file(Fname), lineNo(0), version(INVALID)
{
if(!file.is_open())
{
tlog1 << "File " << Fname << " not found or unable to open\n";
return;
}
//check header
std::string header;
getline(header);
if(header == "ZVSE")
version = ERM;
else if(header == "VERM")
version = VERM;
else
{
tlog1 << "File " << fname << " has wrong header\n";
return;
}
}
std::string CERMPreprocessor::retreiveCommandLine()
{
std::string wholeCommand;
//parse file
bool verm = false;
bool openedString = false;
int openedBraces = 0;
while(file.good())
{
std::string line ;
getline(line); //reading line
int dash = line.find_first_of('^');
bool inTheMiddle = openedBraces || openedString;
if(!inTheMiddle)
{
if(line.size() < 2)
continue;
if(line[0] != '!' ) //command lines must begin with ! -> otherwise treat as comment
continue;
verm = line[1] == '[';
}
if(openedString)
{
wholeCommand += "\\n";
if(dash != std::string::npos)
{
wholeCommand += line.substr(0, dash);
line.erase(0,dash);
}
else //no closing marker -> the whole line is further part of string
{
wholeCommand += line;
continue;
}
}
int i = 0;
for(; i < line.length(); i++)
{
char c = line[i];
if(!openedString)
{
if(c == '[')
openedBraces++;
else if(c == ']')
{
openedBraces--;
if(!openedBraces) //the last brace has been matched -> stop "parsing", everything else in the line is comment
{
i++;
break;
}
}
else if(c == '^')
openedString = true;
else if(c == ';') // a ';' that is in command line (and not in string) ends the command -> throw away rest
{
line.erase(i+!verm, line.length() - i - !verm); //leave ';' at the end only at ERM commands
break;
}
}
else if(c == '^')
openedString = false;
}
if(verm && !openedBraces && i < line.length())
{
line.erase(i, line.length() - i);
}
wholeCommand += line;
if(!openedBraces && !openedString)
return wholeCommand;
//loop end
}
if(openedBraces || openedString)
tlog1 << "Ill-formed file: " << fname << std::endl;
return "";
}
void CERMPreprocessor::getline(std::string &ret)
{
lineNo++;
std::getline(file, ret);
boost::trim(ret); //get rid of wspace
}
ERMParser::ERMParser(std::string file)
:srcFile(file)
@ -41,64 +161,15 @@ ERMParser::ERMParser(std::string file)
void ERMParser::parseFile()
{
std::ifstream file(srcFile.c_str());
if(!file.is_open())
CERMPreprocessor preproc(srcFile);
while(1)
{
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" && std::string(header) != "VERM")
{
tlog1 << "File " << srcFile << " has wrong header\n";
return;
}
//parse file
char lineBuf[1024];
parsedLine = 1;
std::string wholeLine; //used for buffering multiline lines
bool inString = false;
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 (" << parsedLine << ")\n";
}
std::string command = preproc.retreiveCommandLine();
if(command.length() == 0)
break;
switch(classifyLine(lineBuf, inString))
{
case ERMParser::COMMAND_FULL:
case ERMParser::COMMENT:
{
repairEncoding(lineBuf, ARRAY_COUNT(lineBuf));
parseLine(lineBuf);
}
break;
case ERMParser::UNFINISHED:
{
if(!inString)
wholeLine = " ";
inString = true;
wholeLine += lineBuf;
}
break;
case ERMParser::END_OF:
{
inString = false;
wholeLine += lineBuf;
repairEncoding(wholeLine);
parseLine(wholeLine);
}
break;
}
//loop end
++parsedLine;
repairEncoding(command);
parseLine(command);
}
}
@ -107,8 +178,6 @@ void callme(char const& i)
std::cout << "fd";
}
namespace ERM
{
struct TStringConstant
@ -924,18 +993,18 @@ void ERMParser::parseLine( const std::string & line )
ERM::ERM_grammar<std::string::const_iterator> ERMgrammar;
ERM::TLine 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
// tlog2 << line << std::endl;
// ERM::printAST(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
// tlog2 << line << std::endl;
// ERM::printAST(AST);
// }
}
ERMParser::ELineType ERMParser::classifyLine( const std::string & line, bool inString ) const

View File

@ -1,5 +1,20 @@
#pragma once
#include "../global.h"
#include <fstream>
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();
};
class ERMParser
{