/* "CodeWorker":	a scripting language for parsing and generating text.

Copyright (C) 1996-1997, 1999-2002 Cédric Lemaire

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

To contact the author: codeworker@free.fr
*/

#ifdef WIN32
#pragma warning (disable : 4786)
#endif

#include <set>

#include "ScpStream.h"
#include "UtlException.h"
#include "DtaProject.h"
#include "DtaPatternScript.h"
#include "GrfFunction.h"
#include "BNFClause.h"
#include "CGRuntime.h"
#include "CppCompilerEnvironment.h"

namespace CodeWorker {
	class CppStack {
	private:
		std::set<std::string> _setOfVariables;

	public:
		CppStack() {}
		~CppStack() {}

		bool addVariable(const std::string& sVariable);
		bool existVariable(const std::string& sVariable) const;
	};

	bool CppStack::addVariable(const std::string& sVariable) {
		std::set<std::string>::const_iterator cursor = _setOfVariables.find(sVariable);
		if (cursor != _setOfVariables.end()) return false;
		_setOfVariables.insert(sVariable);
		return true;
	}

	bool CppStack::existVariable(const std::string& sVariable) const {
		std::set<std::string>::const_iterator cursor = _setOfVariables.find(sVariable);
		return (cursor != _setOfVariables.end());
	}


	class CppVariableScope {
	private:
		std::list<CppStack*> _stack;
		std::string _sClauseReturnValue;
		bool _bHasEvaluatedExpressionInScope;

	public:
		CppVariableScope() : _bHasEvaluatedExpressionInScope(false) { addStack(); }
		~CppVariableScope() { removeStack(); }

		bool addVariable(const std::string& sVariable) { return _stack.front()->addVariable(sVariable); }
		bool existVariable(const std::string& sVariable) const;
		void addStack() { _stack.push_front(new CppStack); }
		void removeStack() { delete _stack.front(); _stack.pop_front(); }
		void setClauseReturnValue(const std::string& sClauseName);
		bool isClauseReturnValue(const std::string& sVariableName) const;
		void hasEvaluatedExpressionInScope(bool bEvaluated) { _bHasEvaluatedExpressionInScope = bEvaluated; }
		bool hasEvaluatedExpressionInScope() const { return _bHasEvaluatedExpressionInScope; }

	private:
		CppVariableScope(const CppVariableScope&);
		CppVariableScope& operator =(const CppVariableScope&);
	};

	bool CppVariableScope::existVariable(const std::string& sVariable) const {
		for (std::list<CppStack*>::const_iterator i = _stack.begin(); i != _stack.end(); i++) {
			if ((*i)->existVariable(sVariable)) return true;
		}
		return false;
	}

	void CppVariableScope::setClauseReturnValue(const std::string& sClauseName) {
		_sClauseReturnValue = sClauseName;
	}

	bool CppVariableScope::isClauseReturnValue(const std::string& sVariableName) const {
		return (_sClauseReturnValue == sVariableName);
	}


	CppScriptSession::CppScriptSession(const std::string& sFilename, const std::string& sCppRadical) : _sFilename(sFilename), _sCppRadical(sCppRadical), _header(0), _body(0) {
		_header = new DtaPatternScript;
		std::string sSourceFile = sCppRadical + ".h";
		ScpStream* pOldStream;
		_header->openGenerate(false, sSourceFile.c_str(), pOldStream);
		_body = new DtaPatternScript;
		sSourceFile = sCppRadical + ".cpp";
		_body->openGenerate(false, sSourceFile.c_str(), pOldStream);
		pushVariableScope();
	}
	CppScriptSession::CppScriptSession(const CppScriptSession& copy) : _header(copy._header), _body(copy._body) {
		_sIndentation = copy._sIndentation;
		_setOfProjectFunctions = copy._setOfProjectFunctions;
		_setOfProjectClauses = copy._setOfProjectClauses;
		_sFilename = copy._sFilename;
		_sCppRadical = copy._sCppRadical;
		copy._header = 0;
		copy._body = 0;
		_stackOfScopes = copy._stackOfScopes;
		copy._stackOfScopes = std::list<CppVariableScope*>();
	}
	CppScriptSession& CppScriptSession::operator =(const CppScriptSession& copy) {
		_sIndentation = copy._sIndentation;
		_setOfProjectFunctions = copy._setOfProjectFunctions;
		_setOfProjectClauses = copy._setOfProjectClauses;
		_sFilename = copy._sFilename;
		_sCppRadical = copy._sCppRadical;
		_header = copy._header;
		_body = copy._body;
		copy._header = 0;
		copy._body = 0;
		_stackOfScopes = copy._stackOfScopes;
		copy._stackOfScopes = std::list<CppVariableScope*>();
		return *this;
	}
	CppScriptSession::~CppScriptSession() {
		std::string sExceptionMessage;
		std::string sExceptionStack;
		if (_header != 0) {
			try {
				ScpStream* pOldStream = 0L;
				std::string sSourceFile = _sCppRadical + ".h";
				_header->closeGenerate(false, sSourceFile.c_str(), pOldStream);
			} catch(UtlException& exception) {
				sExceptionMessage = exception.getMessage();
				sExceptionStack = exception.getTraceStack();
			}
			delete _header;
		}
		if (_body != 0) {
			try {
				ScpStream* pOldStream = 0L;
				std::string sSourceFile = _sCppRadical + ".cpp";
				_body->closeGenerate(false, sSourceFile.c_str(), pOldStream);
			} catch(UtlException& exception) {
				if (!sExceptionMessage.empty() || !sExceptionStack.empty()) sExceptionMessage += "\n";
				sExceptionMessage += exception.getMessage();
				sExceptionStack += exception.getTraceStack();
			}
			delete _body;
		}

		for (std::list<CppVariableScope*>::iterator i = _stackOfScopes.begin(); i != _stackOfScopes.end(); ++i) {
			delete *i;
		}

		if (!sExceptionMessage.empty() || !sExceptionStack.empty()) throw UtlException(sExceptionMessage, sExceptionStack);
	}

	void CppScriptSession::incrementIndentation() {
		_sIndentation += "\t";
		_stackOfScopes.front()->addStack();
	}

	void CppScriptSession::decrementIndentation() {
		if (_sIndentation.size() == 1) _sIndentation = "";
		else _sIndentation = _sIndentation.substr(1);
		_stackOfScopes.front()->removeStack();
	}

	void CppScriptSession::pushVariableScope() const {
		_stackOfScopes.push_front(new CppVariableScope);
	}

	void CppScriptSession::popVariableScope() const {
		delete _stackOfScopes.front();
		_stackOfScopes.pop_front();
	}

	void CppScriptSession::pushForeach(GrfForeach* pForeach) {
		_listOfForeachStatements.push_front(pForeach);
	}

	GrfForeach* CppScriptSession::getLastForeach() const {
		return _listOfForeachStatements.front();
	}

	void CppScriptSession::popForeach() {
		_listOfForeachStatements.pop_front();
	}

	void CppScriptSession::catchFilename() {
		ScpStream* pOldStream = 0L;
		_header->catchGenerateExecution(false, pOldStream, 0L);
		delete _header;
		_header = 0;
		_body->catchGenerateExecution(false, pOldStream, 0L);
		delete _body;
		_body = 0;
	}


	CppNewVariableScopeEnvironment::CppNewVariableScopeEnvironment(CppCompilerEnvironment& env) : _session(env.getCurrentScriptSession()) {
		_stackOfScopes = _session._stackOfScopes;
		_session._stackOfScopes = std::list<CppVariableScope*>();
		_session.pushVariableScope();
	}

	CppNewVariableScopeEnvironment::~CppNewVariableScopeEnvironment() {
		_session.popVariableScope();
		_session._stackOfScopes = _stackOfScopes;
	}



	CppCompilerEnvironment::CppCompilerEnvironment(const std::string& sCppProjectDirectory, const std::string& sCodeWorkerDirectory) : _bBracketsToNextBlock(true), _bCarriageReturnAfterBlock(true), _iSwitchNumber(0), _iCursorNumber(0), _bErrorEncountered(false), _iPointerToDeclarations(0), _pCurrentClause(0L), _iBNFStepperCursor(0), _iInlineScriptCounter(0) {
		if ((sCppProjectDirectory[0] == '/') || (!sCppProjectDirectory.empty() && (sCppProjectDirectory[1] == ':'))) _sCppProjectDirectory = CGRuntime::canonizePath(sCppProjectDirectory);
		else _sCppProjectDirectory = CGRuntime::relativePath(sCppProjectDirectory, CGRuntime::getWorkingPath());
		if (_sCppProjectDirectory[_sCppProjectDirectory.size() - 1] != '/') _sCppProjectDirectory += "/";
		_sCodeWorkerDirectory = CGRuntime::canonizePath(sCodeWorkerDirectory);
		if (_sCodeWorkerDirectory[_sCodeWorkerDirectory.size() - 1] != '/') _sCodeWorkerDirectory += "/";
		addGlobalVariable("_ARGS");
		addGlobalVariable("_REQUEST"); // for CGI program
		try {
			std::string sCWIncludeDir = _sCodeWorkerDirectory;
			if (CGRuntime::existFile(sCWIncludeDir + "include/UtlException.h")) sCWIncludeDir += "include/";
			CGRuntime::copySmartFile(sCWIncludeDir + "UtlException.h", _sCppProjectDirectory + "UtlException.h");
			CGRuntime::copySmartFile(sCWIncludeDir + "CppParsingTree.h", _sCppProjectDirectory + "CppParsingTree.h");
			CGRuntime::copySmartFile(sCWIncludeDir + "CGRuntime.h", _sCppProjectDirectory + "CGRuntime.h");
			CGRuntime::copySmartFile(sCWIncludeDir + "CGExternalHandling.h", _sCppProjectDirectory + "CGExternalHandling.h");
		} catch(UtlException&) {
			CGRuntime::traceLine("WARNING: (considering '" + _sCodeWorkerDirectory + "' as the root path of 'CodeWorker') unable to copy files 'UtlException.h' + 'CppParsingTree.h' + 'CGRuntime.h' in the project directory '" + _sCppProjectDirectory + "'");
		}
	}

	CppCompilerEnvironment::~CppCompilerEnvironment() {
		if (!_bErrorEncountered) {
			generateDSP();
			generateMakefile();
		}
	}

	void CppCompilerEnvironment::generateDSP() {
		std::string sBinDir = _sCodeWorkerDirectory;
		if (CGRuntime::existFile(sBinDir + "bin/CodeWorker.lib")) sBinDir += "bin/";
		else if (CGRuntime::existFile(sBinDir + "../bin/CodeWorker.lib")) sBinDir += "../bin/";
		else if (CGRuntime::existFile(sBinDir + "lib/CodeWorker.lib")) sBinDir += "lib/";
		else if (CGRuntime::existFile(sBinDir + "../lib/CodeWorker.lib")) sBinDir += "../lib/";
		else sBinDir += "Release/";
		std::string sProjectName = getRadical(_listOfProjectModules.front());
		std::string::size_type iIndex = sProjectName.find_last_of('_');
		if ((iIndex != std::string::npos) && (iIndex != 0)) sProjectName = sProjectName.substr(0, iIndex);
		std::auto_ptr<ScpStream> pMakeFile(new ScpStream(_sCppProjectDirectory + sProjectName + ".dsp", ScpStream::IN | ScpStream::OUT));
		if (pMakeFile->empty()) {
			(*pMakeFile) << "# Microsoft Developer Studio Project File - Name=\"" << sProjectName << "\" - Package Owner=<4>\r\n";
			(*pMakeFile) << "# Microsoft Developer Studio Generated Build File, Format Version 6.00\r\n";
			(*pMakeFile) << "# ** DO NOT EDIT **\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# TARGTYPE \"Win32 (x86) Console Application\" 0x0103\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "CFG=" << sProjectName << " - Win32 Debug\r\n";
			(*pMakeFile) << "!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r\n";
			(*pMakeFile) << "!MESSAGE use the Export Makefile command and run\r\n";
			(*pMakeFile) << "!MESSAGE \r\n";
			(*pMakeFile) << "!MESSAGE NMAKE /f \"" << sProjectName << ".mak\".\r\n";
			(*pMakeFile) << "!MESSAGE \r\n";
			(*pMakeFile) << "!MESSAGE You can specify a configuration when running NMAKE\r\n";
			(*pMakeFile) << "!MESSAGE by defining the macro CFG on the command line. For example:\r\n";
			(*pMakeFile) << "!MESSAGE \r\n";
			(*pMakeFile) << "!MESSAGE NMAKE /f \"" << sProjectName << ".mak\" CFG=\"" << sProjectName << " - Win32 Debug\"\r\n";
			(*pMakeFile) << "!MESSAGE \r\n";
			(*pMakeFile) << "!MESSAGE Possible choices for configuration are:\r\n";
			(*pMakeFile) << "!MESSAGE \r\n";
			(*pMakeFile) << "!MESSAGE \"" << sProjectName << " - Win32 Release\" (based on \"Win32 (x86) Console Application\")\r\n";
			(*pMakeFile) << "!MESSAGE \"" << sProjectName << " - Win32 Debug\" (based on \"Win32 (x86) Console Application\")\r\n";
			(*pMakeFile) << "!MESSAGE \r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# Begin Project\r\n";
			(*pMakeFile) << "# PROP AllowPerConfigDependencies 0\r\n";
			(*pMakeFile) << "# PROP Scc_ProjName \"\"\r\n";
			(*pMakeFile) << "# PROP Scc_LocalPath \"\"\r\n";
			(*pMakeFile) << "CPP=cl.exe\r\n";
			(*pMakeFile) << "RSC=rc.exe\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "!IF  \"$(CFG)\" == \"" << sProjectName << " - Win32 Release\"\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# PROP BASE Use_MFC 0\r\n";
			(*pMakeFile) << "# PROP BASE Use_Debug_Libraries 0\r\n";
			(*pMakeFile) << "# PROP BASE Output_Dir \"Release\"\r\n";
			(*pMakeFile) << "# PROP BASE Intermediate_Dir \"Release\"\r\n";
			(*pMakeFile) << "# PROP BASE Target_Dir \"\"\r\n";
			(*pMakeFile) << "# PROP Use_MFC 0\r\n";
			(*pMakeFile) << "# PROP Use_Debug_Libraries 0\r\n";
			(*pMakeFile) << "# PROP Output_Dir \"Release\"\r\n";
			(*pMakeFile) << "# PROP Intermediate_Dir \"Release\"\r\n";
			(*pMakeFile) << "# PROP Ignore_Export_Lib 0\r\n";
			(*pMakeFile) << "# PROP Target_Dir \"\"\r\n";
			(*pMakeFile) << "# ADD BASE CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /YX /FD /c\r\n";
			(*pMakeFile) << "# ADD CPP /nologo /MD /W3 /GR /GX /O2 /D \"NDEBUG\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /FD /c\r\n";
			(*pMakeFile) << "# SUBTRACT CPP /YX\r\n";
			(*pMakeFile) << "# ADD BASE RSC /l 0x40c /d \"NDEBUG\"\r\n";
			(*pMakeFile) << "# ADD RSC /l 0x40c /d \"NDEBUG\"\r\n";
			(*pMakeFile) << "BSC32=bscmake.exe\r\n";
			(*pMakeFile) << "# ADD BASE BSC32 /nologo\r\n";
			(*pMakeFile) << "# ADD BSC32 /nologo\r\n";
			(*pMakeFile) << "LINK32=link.exe\r\n";
			(*pMakeFile) << "# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r\n";
			(*pMakeFile) << "# ADD LINK32 " << sBinDir << "CodeWorker.lib ws2_32.lib rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "!ELSEIF  \"$(CFG)\" == \"" << sProjectName << " - Win32 Debug\"\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# PROP BASE Use_MFC 0\r\n";
			(*pMakeFile) << "# PROP BASE Use_Debug_Libraries 1\r\n";
			(*pMakeFile) << "# PROP BASE Output_Dir \"Debug\"\r\n";
			(*pMakeFile) << "# PROP BASE Intermediate_Dir \"Debug\"\r\n";
			(*pMakeFile) << "# PROP BASE Target_Dir \"\"\r\n";
			(*pMakeFile) << "# PROP Use_MFC 0\r\n";
			(*pMakeFile) << "# PROP Use_Debug_Libraries 1\r\n";
			(*pMakeFile) << "# PROP Output_Dir \"Debug\"\r\n";
			(*pMakeFile) << "# PROP Intermediate_Dir \"Debug\"\r\n";
			(*pMakeFile) << "# PROP Ignore_Export_Lib 0\r\n";
			(*pMakeFile) << "# PROP Target_Dir \"\"\r\n";
			(*pMakeFile) << "# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /YX /FD /GZ /c\r\n";
			(*pMakeFile) << "# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /D \"_DEBUG\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /FD /GZ /c\r\n";
			(*pMakeFile) << "# SUBTRACT CPP /YX\r\n";
			(*pMakeFile) << "# ADD BASE RSC /l 0x40c /d \"_DEBUG\"\r\n";
			(*pMakeFile) << "# ADD RSC /l 0x40c /d \"_DEBUG\"\r\n";
			(*pMakeFile) << "BSC32=bscmake.exe\r\n";
			(*pMakeFile) << "# ADD BASE BSC32 /nologo\r\n";
			(*pMakeFile) << "# ADD BSC32 /nologo\r\n";
			(*pMakeFile) << "LINK32=link.exe\r\n";
			(*pMakeFile) << "# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r\n";
			(*pMakeFile) << "# ADD LINK32 " << _sCodeWorkerDirectory << "Debug/CodeWorkerD.lib ws2_32.lib rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "!ENDIF \r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# Begin Target\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# Name \"" << sProjectName << " - Win32 Release\"\r\n";
			(*pMakeFile) << "# Name \"" << sProjectName << " - Win32 Debug\"\r\n";
			(*pMakeFile) << "# Begin Group \"Source Files\"\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\r\n";
		} else {
			if (!pMakeFile->findString("# Begin Source File")) throw UtlException("bad format encountered into Visual C++ project \"" + sProjectName + ".dsp\": unable to find tag '# Begin Source File'");
			pMakeFile->setOutputLocation(pMakeFile->getInputLocation() - 19);
		}
		std::list<std::string>::const_iterator i;
		for (i = _listOfProjectModules.begin(); i != _listOfProjectModules.end(); i++) {
			(*pMakeFile) << "# Begin Source File\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "SOURCE=\".\\" << getRelativePath(*i) << ".cpp\"\r\n";
			(*pMakeFile) << "# End Source File\r\n";
		}
		(*pMakeFile) << "# End Group\r\n";
		(*pMakeFile) << "# Begin Group \"Header Files\"\r\n";
		(*pMakeFile) << "\r\n";
		(*pMakeFile) << "# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\r\n";
		for (i = _listOfProjectModules.begin(); i != _listOfProjectModules.end(); i++) {
			std::string::size_type iIndex = i->find_last_of("/\\");
			std::string sFile;
			if (iIndex != std::string::npos) sFile = i->substr(iIndex + 1);
			else sFile = *i;
			(*pMakeFile) << "# Begin Source File\r\n";
			(*pMakeFile) << "\r\n";
			(*pMakeFile) << "SOURCE=\".\\" << getRelativePath(*i) << ".h\"\r\n";
			(*pMakeFile) << "# End Source File\r\n";
		}
		(*pMakeFile) << "# Begin Source File\r\n";
		(*pMakeFile) << "\r\n";
		(*pMakeFile) << "SOURCE=.\\CppParsingTree.h\r\n";
		(*pMakeFile) << "# End Source File\r\n";
		(*pMakeFile) << "# Begin Source File\r\n";
		(*pMakeFile) << "\r\n";
		(*pMakeFile) << "SOURCE=.\\UtlException.h\r\n";
		(*pMakeFile) << "# End Source File\r\n";
		(*pMakeFile) << "# End Group\r\n";
		(*pMakeFile) << "# Begin Group \"Resource Files\"\r\n";
		(*pMakeFile) << "\r\n";
		(*pMakeFile) << "# PROP Default_Filter \"ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe\"\r\n";
		(*pMakeFile) << "# End Group\r\n";
		(*pMakeFile) << "# End Target\r\n";
		(*pMakeFile) << "# End Project\r\n";
		std::auto_ptr<ScpStream> pOldMakeFile(new ScpStream(_sCppProjectDirectory + sProjectName + ".dsp", ScpStream::IN | ScpStream::OUT));
		int iPosition;
		if (!pMakeFile->equals(*pOldMakeFile, iPosition)) pMakeFile->saveIntoFile(_sCppProjectDirectory + sProjectName + ".dsp", true);
	}

	void CppCompilerEnvironment::generateMakefile() {
		std::string sBinDir = _sCodeWorkerDirectory;
		if (CGRuntime::existFile(sBinDir + "bin/libCodeWorker.a")) sBinDir += "bin/";
		else if (CGRuntime::existFile(sBinDir + "../bin/libCodeWorker.a")) sBinDir += "../bin/";
		else if (CGRuntime::existFile(sBinDir + "lib/libCodeWorker.a")) sBinDir += "lib/";
		else if (CGRuntime::existFile(sBinDir + "../lib/libCodeWorker.a")) sBinDir += "../lib/";
		std::string sProjectName = getRadical(_listOfProjectModules.front());
		std::string::size_type iIndex = sProjectName.find_last_of('_');
		if ((iIndex != std::string::npos) && (iIndex != 0)) sProjectName = sProjectName.substr(0, iIndex);
		std::auto_ptr<ScpStream> pMakeFile(new ScpStream(_sCppProjectDirectory + "Makefile", ScpStream::IN | ScpStream::OUT));
		std::auto_ptr<ScpStream> pOldMakeFile(new ScpStream(_sCppProjectDirectory + "Makefile", ScpStream::IN | ScpStream::OUT));
		(*pMakeFile) << "INCDIRS	= -I.\n";
		(*pMakeFile) << "CXXFLAGS	= -O2 -g $(INCDIRS)\n";
		(*pMakeFile) << "LFLAGS	= -g -lm -ldl -L" << sBinDir << " -lcodeworker\n";
		(*pMakeFile) << "CC	= g++\n";
		(*pMakeFile) << "\n";
		(*pMakeFile) << "OBJECTS = ";
		std::list<std::string>::const_iterator i;
		for (i = _listOfProjectModules.begin(); i != _listOfProjectModules.end(); i++) {
			std::string sRadical = getRelativePath(*i);
			if (pMakeFile->getColCount() + sRadical.size() > 70) {
				(*pMakeFile) << "\\\n\t\t  ";
			} else {
				(*pMakeFile) << " ";
			}
			(*pMakeFile) << getRelativePath(*i) << ".o";
		}
		(*pMakeFile) << "\n\n";
		(*pMakeFile) << "all: build\n";
		(*pMakeFile) << "build: $(OBJECTS)\n";
		(*pMakeFile) << "\t$(CC) -o " << sProjectName << " $(OBJECTS) $(LFLAGS)\n";
		(*pMakeFile) << "clean:\n";
		(*pMakeFile) << "\t-rm -f *.o " << sProjectName << " core\n";
		int iPosition;
		if (!pMakeFile->equals(*pOldMakeFile, iPosition)) pMakeFile->saveIntoFile(_sCppProjectDirectory + "Makefile", true);
	}

	ScpStream& CppCompilerEnvironment::getHeader() const {
		DtaPatternScript* pScript = getCurrentScriptSession()._header;
		return *(pScript->getOutputStream());
	}

	ScpStream& CppCompilerEnvironment::getMainHeader() const {
		DtaPatternScript* pScript = _listOfScriptSessions.back()._header;
		return *(pScript->getOutputStream());
	}

	ScpStream& CppCompilerEnvironment::getBody() const {
		DtaPatternScript* pScript = getCurrentScriptSession()._body;
		return *(pScript->getOutputStream());
	}

	std::string CppCompilerEnvironment::filename2Module(const std::string& sFilename) {
		std::string sModule;
		std::string::size_type iIndex = sFilename.find_last_of('.');
		if (iIndex != std::string::npos) {
			sModule = sFilename.substr(0, iIndex) + '_' + sFilename.substr(iIndex + 1);
		} else sModule = sFilename;
		return sModule;
	}

	bool CppCompilerEnvironment::pushFilename(const std::string& sFilename) {
		std::string sModule = filename2Module(sFilename);
		for (std::list<std::string>::const_iterator i = _listOfProjectModules.begin(); i != _listOfProjectModules.end(); i++) {
			if ((*i) == sModule) return false;
		}
		CppScriptSession session(sFilename, _sCppProjectDirectory + getRadical(sModule));
		_listOfScriptSessions.push_front(session);
		_listOfProjectModules.push_back(sModule);
		return true;
	}

	std::string CppCompilerEnvironment::getRadical() const {
		return getRadical(getCurrentScriptSession()._sCppRadical);
	}

	std::string CppCompilerEnvironment::getMainRadical() const {
		return getRadical(_listOfScriptSessions.back()._sCppRadical);
	}

	std::string CppCompilerEnvironment::getRadical(const std::string& sFile) {
		std::string sRadical = sFile;
		std::string::size_type iIndex = sRadical.find('.');
		if (iIndex != std::string::npos) sRadical = sRadical.substr(0, iIndex);
		iIndex = sRadical.find_last_of("/\\");
		if (iIndex != std::string::npos) sRadical = sRadical.substr(iIndex + 1);
		return sRadical;
	}

	std::string CppCompilerEnvironment::getRelativePath(const std::string& sFile) {
		std::string sRadical;
		std::string::size_type iIndex = sFile.find_last_of("/\\");
		if (iIndex != std::string::npos) sRadical = sFile.substr(iIndex + 1);
		else sRadical = sFile;
		return sRadical;
	}

	std::string CppCompilerEnvironment::convertTemplateKey(const std::string& sKey) {
		std::string sText;
		for (std::string::size_type i = 0; i < sKey.size(); i++) {
			char a = sKey[i];
			if (((a >= 'A') && (a <= 'Z')) || ((a >= 'a') && (a <= 'z')) || ((a >= '0') && (a <= '9'))) sText += a;
			else switch(a) {
				case '+': sText += "_compilerPlus_";break;
				case '-': sText += "_compilerMinus_";break;
				case '.': sText += "_compilerDot_";break;
				case ',': sText += "_compilerComma_";break;
				default: sText += '_';
			}
		}
		return sText;
	}

	std::string CppCompilerEnvironment::convertToCppVariable(const std::string& sVariable) {
		if ((sVariable == "namespace") || (sVariable == "class")) return "_compilerCppVariable_" + sVariable;
		return sVariable;
	}

	std::string CppCompilerEnvironment::getIncludeParentScript() const {
		std::string sRadical;
		if (_listOfScriptSessions.front()._sFilename != _listOfScriptSessions.back()._sFilename) {
			std::list<CppScriptSession>::const_iterator cursor = _listOfScriptSessions.begin();
			++cursor;
			sRadical = filename2Module(cursor->_sFilename);
		}
		return sRadical;
	}

	void CppCompilerEnvironment::incrementIndentation() {
		_listOfScriptSessions.front().incrementIndentation();
	}

	void CppCompilerEnvironment::pushVariableScope() {
		_listOfScriptSessions.front().pushVariableScope();
	}

	std::string CppCompilerEnvironment::newInlineScriptFilename() {
		_iInlineScriptCounter++;
		char tcFile[80];
		sprintf(tcFile, "InlineScript2File_%d", _iInlineScriptCounter);
		return tcFile;
	}

	void CppCompilerEnvironment::newFunction(const GrfFunction* pFunction) {
		_listOfScriptSessions.front()._setOfProjectFunctions.insert(pFunction->getFunctionName());
		_pCurrentFunction = pFunction;
	}

	void CppCompilerEnvironment::newClause(const BNFClause* pClause) {
		_listOfScriptSessions.front()._setOfProjectFunctions.insert(pClause->getName());
		_pCurrentClause = pClause;
	}

	std::string CppCompilerEnvironment::getFunctionModule(const std::string& sFunction) const {
		for (std::list<CppScriptSession>::const_iterator i = _listOfScriptSessions.begin(); i != _listOfScriptSessions.end(); i++) {
			if (i->_setOfProjectFunctions.find(sFunction) != i->_setOfProjectFunctions.end()) return i->_sCppRadical;
		}
		return _listOfScriptSessions.front()._sCppRadical;
	}

	std::string CppCompilerEnvironment::getClauseModule(const std::string& sClause) const {
		for (std::list<CppScriptSession>::const_iterator i = _listOfScriptSessions.begin(); i != _listOfScriptSessions.end(); i++) {
			if (i->_setOfProjectClauses.find(sClause) != i->_setOfProjectClauses.end()) return i->_sCppRadical;
		}
		return _listOfScriptSessions.front()._sCppRadical;
	}

	void CppCompilerEnvironment::popVariableScope() {
		_listOfScriptSessions.front().popVariableScope();
	}

	bool CppCompilerEnvironment::addVariable(const std::string& sVariable) {
		return _listOfScriptSessions.front()._stackOfScopes.front()->addVariable(sVariable);
	}

	bool CppCompilerEnvironment::existVariable(const std::string& sVariable) const {
		return _listOfScriptSessions.front()._stackOfScopes.front()->existVariable(sVariable) | (_globalVariables.find(sVariable) != _globalVariables.end());
	}

	void CppCompilerEnvironment::addGlobalVariable(const std::string& sVariable) {
		_globalVariables.insert(sVariable);
	}

	void CppCompilerEnvironment::setClauseReturnValue(const std::string& sClauseName) {
		_listOfScriptSessions.front()._stackOfScopes.front()->setClauseReturnValue(sClauseName);
	}

	bool CppCompilerEnvironment::isClauseReturnValue(const std::string& sVariableName) const {
		return _listOfScriptSessions.front()._stackOfScopes.front()->isClauseReturnValue(sVariableName);
	}

	void CppCompilerEnvironment::hasEvaluatedExpressionInScope(bool bEvaluated) {
		_listOfScriptSessions.front()._stackOfScopes.front()->hasEvaluatedExpressionInScope(bEvaluated);
	}

	bool CppCompilerEnvironment::hasEvaluatedExpressionInScope() const {
		return _listOfScriptSessions.front()._stackOfScopes.front()->hasEvaluatedExpressionInScope();
	}

	int CppCompilerEnvironment::newSwitch() {
		_iSwitchNumber++;
		return _iSwitchNumber;
	}

	int CppCompilerEnvironment::newCursor() {
		_iCursorNumber++;
		return _iCursorNumber;
	}

	void CppCompilerEnvironment::decrementIndentation() {
		_listOfScriptSessions.front().decrementIndentation();
	}

	void CppCompilerEnvironment::pushForeach(GrfForeach* pForeach) {
		_listOfScriptSessions.front().pushForeach(pForeach);
	}

	GrfForeach* CppCompilerEnvironment::getLastForeach() const {
		return _listOfScriptSessions.front().getLastForeach();
	}

	void CppCompilerEnvironment::popForeach() {
		_listOfScriptSessions.front().popForeach();
	}

	void CppCompilerEnvironment::catchFilename(UtlException& exception) {
		_listOfScriptSessions.front().catchFilename();
		_bErrorEncountered = true;
		throw UtlException(exception.getTraceStack(), exception.getMessage());
	}

	void CppCompilerEnvironment::popFilename() {
		_listOfScriptSessions.pop_front();
	}
}
//##markup##"build C++ headers"
