ソースを参照

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

Michał W. Urbańczyk 14 年 前
コミット
0aad12ae67
2 ファイル変更139 行追加55 行削除
  1. 124 55
      lib/ERMParser.cpp
  2. 15 0
      lib/ERMParser.h

+ 124 - 55
lib/ERMParser.cpp

@@ -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,81 +35,148 @@ namespace phoenix = boost::phoenix;
 
 #define DO_TYPE_CASE(LinePrinterVisitor, VAR) } ___UN; boost::apply_visitor(___UN, VAR);
 
-
-
-ERMParser::ERMParser(std::string file)
-	:srcFile(file)
-{}
-
-void ERMParser::parseFile()
+CERMPreprocessor::CERMPreprocessor(const std::string &Fname) : fname(Fname), file(Fname), lineNo(0), version(INVALID)
 {
-	std::ifstream file(srcFile.c_str());
 	if(!file.is_open())
 	{
-		tlog1 << "File " << srcFile << " not found or unable to open\n";
+		tlog1 << "File " << Fname << " 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")
+	std::string header;
+	getline(header);
+
+	if(header == "ZVSE")
+		version = ERM;
+	else if(header == "VERM")
+		version = VERM;
+	else
 	{
-		tlog1 << "File " << srcFile << " has wrong header\n";
+		tlog1 << "File " << fname << " has wrong header\n";
 		return;
 	}
+}
+
+std::string CERMPreprocessor::retreiveCommandLine()
+{
+	std::string wholeCommand;
+
 	//parse file
-	char lineBuf[1024];
-	parsedLine = 1;
-	std::string wholeLine; //used for buffering multiline lines
-	bool inString = false;
-	
+	bool verm = false;
+	bool openedString = false;
+	int openedBraces = 0;
+
+
 	while(file.good())
 	{
-		//reading line
-		file.getline(lineBuf, ARRAY_COUNT(lineBuf));
-		if(file.gcount() == ARRAY_COUNT(lineBuf))
+
+		std::string line ;
+		getline(line); //reading line
+
+
+		int dash = line.find_first_of('^');
+		bool inTheMiddle = openedBraces || openedString;
+
+		if(!inTheMiddle)
 		{
-			tlog1 << "Encountered a problem during parsing " << srcFile << " too long line (" << parsedLine << ")\n";
+			if(line.size() < 2)
+				continue;
+			if(line[0] != '!' ) //command lines must begin with ! -> otherwise treat as comment
+				continue;
+			verm = line[1] == '[';
 		}
 
-		switch(classifyLine(lineBuf, inString))
+		if(openedString)
 		{
-		case ERMParser::COMMAND_FULL:
-		case ERMParser::COMMENT:
+			wholeCommand += "\\n";
+			if(dash != std::string::npos)
 			{
-				repairEncoding(lineBuf, ARRAY_COUNT(lineBuf));
-				parseLine(lineBuf);
+				wholeCommand += line.substr(0, dash);
+				line.erase(0,dash);
 			}
-			break;
-		case ERMParser::UNFINISHED:
+			else //no closing marker -> the whole line is further part of string
 			{
-				if(!inString)
-					wholeLine = " ";
-				inString = true;
-				wholeLine += lineBuf;
+				wholeCommand += line;
+				continue;
 			}
-			break;
-		case ERMParser::END_OF:
+		}
+
+		int i = 0;
+		for(; i < line.length(); i++)
+		{
+			char c = line[i];
+			if(!openedString)
 			{
-				inString = false;
-				wholeLine += lineBuf;
-				repairEncoding(wholeLine);
-				parseLine(wholeLine);
+				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;
+				}
 			}
-			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
-		++parsedLine;
 	}
+
+	if(openedBraces || openedString)
+		tlog1 << "Ill-formed file: " << fname << std::endl;
+	return "";
 }
 
-void callme(char const& i)
+void CERMPreprocessor::getline(std::string &ret)
 {
-	std::cout << "fd";
+	lineNo++;
+	std::getline(file, ret);
+	boost::trim(ret); //get rid of wspace
 }
 
+ERMParser::ERMParser(std::string file)
+	:srcFile(file)
+{}
+
+void ERMParser::parseFile()
+{
+	CERMPreprocessor preproc(srcFile);
+	while(1)
+	{
+		std::string command = preproc.retreiveCommandLine();
+		if(command.length() == 0)
+			break;
+
+		repairEncoding(command);
+		parseLine(command);
+	}
+}
 
+void callme(char const& i)
+{
+	std::cout << "fd";
+}
 
 namespace ERM
 {
@@ -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

+ 15 - 0
lib/ERMParser.h

@@ -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
 {