/*	Convertidores de archivos

Permite convertir archivos de un formato a otro o filtrarlos.

Autor: Ariel Medina - Campeche, Campeche, México - Enero del 2004

*/

#ifndef __CONVERTERS_AMV
	#define __CONVERTERS_AMV

#include <fstream>
#include "stringAMV.h"
#include "REEvaluator.h"
#include "amvdefs.h"

namespace amv	{

//Quita los comentarios estilo C++ de un archivo, el nuevo archivo tiene el nombre del
//archivo original más el sufijo 's'
//Devuelve true si tiene éxito, false si falla
bool removeComments(const char *s)
{
string starget(s);
starget+="f";
char *ptarget=starget.str(), c, c1;

ifstream source(s);
ofstream target(ptarget);
delete [] ptarget;

if(source && target)
	{
	while(source.get(c))
		{
		c1=source.peek();
		if(c=='/' && c1=='/')
			{
			source.ignore(0x7fffffff,'\n');
			target<<'\n';
			}
		else if(c=='/' && c1=='*')
			{
			source.get(c);
			while(source.get(c))
				{
				c1=source.peek();
				if(c=='*' && c1=='/')
					{
					source.get(c);
					break;
					}
				}
			}
		else
			target<<c;
		}

	return true;
	}


return false;
}

//Palabras reservadas C++ que están el el archivo reservedWordsCPP.txt
/*
and and_eq asm auto bitand bitor
bool break case catch char class
compl const const_cast continue default delete
do double dynamic_cast else enum explicit
export extern false float for friend
goto if inline int long mutable
namespace new not not_eq operator or
or_eq private protected public register reinterpret_cast
return short signed sizeof static static_cast
struct switch template this throw true
try typedef typeid typename union unsigned
using virtual void volatile wchar_t while
xor xor_eq
*/

//devuelve el código HTML para caracteres especiales
string encodeHTML(char c)
{
switch(c)
	{
	case '<':
		return "<";
	case '>':
		return ">";
	default:
		string s;
		s.push_back(c);
		return s;
	}
}

//extrae las palabras reservadas del archivo reservedWords.txt
//y las coloca en una cadena de caracteres uniéndolas con el operador de alternancia,
//dicha cadena representa la expresión regular para las palabras reservadas
char *getReservedWords()
{
static REEvaluator REEtoken="#+";//uno o más símbolos no blancos
string s,s1;

ifstream source("..\\bibliotecas\\reservedWordsCPP.txt");
if(source)
	{
	REEtoken.skipNoSymbols(source);
	while(true)
		{
		if(REEtoken.getLexema(source,s1))
			{
			s+=s1;
			REEtoken.skipNoSymbols(source);
			if(!source.eof())
				s+="|";
			}
		else
			break;
		}
	}

return s.str();
}

//Convierte un archivo de código fuente C++ a formato html, el nuevo archivo tiene el nombre
//del archivo original más el sufijo .htm
//El análisis del archivo se hace por medio de REE (evaluador de expresiones regulares)
//Las palabras reservadas quedan en color azul, los comentarios en verde, las cadenas en gris
// y lo demás en negro
//Devuelve true si tiene éxito, false si falla
bool cpp2html(const char *s)
{
//la palabra reservada puede estar dentro de un identificador, por lo cual, debemos analizar los
//identificadores y luego preguntar si es palabra reservada
static REEvaluator REElineComment="//@*\n";/*comentario de una línea (buscar el más pequeño)
dos diagonales seguidas de 0 o más ocurrencias de cualquier símbolo, seguidos de '\n'
*/
static REEvaluator REEmultilineComment="/\\*@*\\*/";/*comentario multilínea (buscar el más pequeño)
'/*' seguido de 0 o más ocurrencias de cualquier símbolo seguidos de '*' y '/'
*/
static REEvaluator REEstring="\"@*\"";/*cadena de caracteres (leer con escape '\')
una comilla, seguida de 0 o más ocurrencias de cualquier símbolo, seguidos por otra comilla
se leerá con escape para que, si se encuentra una comilla precedida por '\' se lee pero
no se considera para evaluar, sino se sigue buscando otros símbolos
*/
static REEvaluator REEidentifier="(_|[a-zA-Z])(_|[a-zA-Z]|[0-9])*";/*identificador
una letra o el carácter de subrayado, seguido de una o más ocurrencias de letras, digitos o carácter
de subrayado
*/
char *p=getReservedWords();
static REEvaluator REEreservedWords=p;/*palabra reservada
una de las palabras reservadas
*/
delete []p;
p=0;

string starget(s);
string s1;
starget+=".htm";
char *ptarget=starget.str(), c;

ifstream source(s);
ofstream target(ptarget, ios_base::out| ios_base::trunc);
delete [] ptarget;

if(source && target)
	{
	target<<"<html><head><title>"<<s<<"</title>";
	target<<"<style>#reservedWord{color:blue} #lineComment,#multilineComment{color:green} #string{color:gray}</style>";
	target<<"</head><body style=\"color:black\">";
	target<<"<pre>\n";

	while(source)
		{
		if(REElineComment.getLexema(source,s1,true))
			{
			target<<"<span id=\"lineComment\">";
			for(int i=0; i<s1.size(); ++i)
				target<<encodeHTML(s1[i]);
			target<<"</span>";
			}
		else if(REEmultilineComment.getLexema(source,s1,true))
			{
			target<<"<span id=\"multilineComment\">";
			for(int i=0; i<s1.size(); ++i)
				target<<encodeHTML(s1[i]);
			target<<"</span>";
			}
		else if(REEidentifier.getLexema(source,s1))
			{
			if(REEreservedWords.eval(s1))
				{
				target<<"<span id=\"reservedWord\">";
				for(int i=0; i<s1.size(); ++i)
					target<<encodeHTML(s1[i]);
				target<<"</span>";
				}
			else
				{
				for(int i=0; i<s1.size(); ++i)
					target<<encodeHTML(s1[i]);
				}
			}
		else if(REEstring.getLexemaWithEscape(source,s1,'\\'))
			{
			target<<"<span id=\"string\">";
			for(int i=0; i<s1.size(); ++i)
				target<<encodeHTML(s1[i]);
			target<<"</span>";
			}
		else
			{
			if(source.get(c))
				target<<encodeHTML(c);
			}
		}
	target<<"</pre></body></html>";

	return true;
	}


return false;
}

}

#endif