1 /* "CodeWorker":	a scripting language for parsing and generating text.
2 
3 Copyright (C) 1996-1997, 1999-2002 C�dric Lemaire
4 
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9 
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19 To contact the author: codeworker@free.fr
20 */
21 
22 #ifdef WIN32
23 #pragma warning (disable : 4786)
24 #endif
25 
26 #include "UtlException.h"
27 #include "ScpStream.h"
28 #include "CppCompilerEnvironment.h"
29 
30 #include "CGRuntime.h"
31 
32 #include "DtaScript.h"
33 #include "DtaProject.h"
34 #include "DtaClass.h"
35 #include "DtaBNFScript.h"
36 #include "DtaVisitor.h"
37 #include "BNFClause.h"
38 
39 
40 namespace CodeWorker {
~BNFClauseMatchingArea()41 	BNFClauseMatchingArea::~BNFClauseMatchingArea() {
42 		for (std::list<BNFClauseMatchingArea*>::iterator i = childs.begin(); i != childs.end(); ++i) {
43 			delete *i;
44 		}
45 	}
46 
purgeChildsAfterPosition(int iPosition)47 	void BNFClauseMatchingArea::purgeChildsAfterPosition(int iPosition) {
48 		while (!childs.empty() && (childs.back()->endPosition > iPosition)) {
49 			delete childs.back();
50 			childs.pop_back();
51 		}
52 	}
53 
54 	class BNFClauseMatchingAreaValidator {
55 	private:
56 		DtaBNFScript* pBNFScript_;
57 		BNFClauseMatchingArea* pOld_;
58 
59 	public:
BNFClauseMatchingAreaValidator(BNFClause * pClause,DtaBNFScript * pBNFScript)60 		BNFClauseMatchingAreaValidator(BNFClause* pClause, DtaBNFScript* pBNFScript) {
61 			if (!pBNFScript->hasCoverageRecording()) {
62 				pBNFScript_ = NULL;
63 			} else {
64 				pBNFScript_ = pBNFScript;
65 				pOld_ = pBNFScript->getParentClauseMatching();
66 				pBNFScript->setParentClauseMatching(new BNFClauseMatchingArea(pClause, CGRuntime::getInputLocation()));
67 			}
68 		}
~BNFClauseMatchingAreaValidator()69 		~BNFClauseMatchingAreaValidator() {
70 			if (pBNFScript_ != NULL) {
71 				if (pBNFScript_->getParentClauseMatching()->endPosition < 0) {
72 					// the clause has failed!
73 					delete pBNFScript_->getParentClauseMatching();
74 //					if (pOld_ != NULL) pOld_->popChild();
75 					pBNFScript_->setParentClauseMatching(pOld_);
76 				} else {
77 					// the clause has succeeded, keep the matching
78 					// and don't loose the header clause matching!
79 					if (pOld_ != NULL) pBNFScript_->setParentClauseMatching(pOld_);
80 				}
81 			}
82 		}
validate()83 		void validate() {
84 			if (pBNFScript_ != NULL) {
85 				BNFClauseMatchingArea* pNew = pBNFScript_->getParentClauseMatching();
86 				if (pNew->endPosition < 0) {
87 					// prevents against multiple call to 'validate()' (shouldn't)
88 					pNew->endPosition = CGRuntime::getInputLocation();
89 					if (pOld_ != NULL) pOld_->pushChild(pNew);
90 				}
91 			}
92 		}
93 	};
94 
95 
96 	int BNFClause::NO_RETURN_TYPE    = 0;
97 	int BNFClause::LIST_RETURN_TYPE  = 1;
98 	int BNFClause::NODE_RETURN_TYPE  = 2;
99 	int BNFClause::VALUE_RETURN_TYPE = 3;
100 
101 
BNFClause(DtaBNFScript * pBNFScript,GrfBlock * pParent,const std::string & sName,const std::string & sTemplateKey,bool bGenericKey,const std::vector<std::string> & listOfParameters,const std::vector<EXPRESSION_TYPE> & listOfParameterTypes)102 	BNFClause::BNFClause(DtaBNFScript* pBNFScript, GrfBlock* pParent, const std::string& sName, const std::string& sTemplateKey, bool bGenericKey, const std::vector<std::string>& listOfParameters, const std::vector<EXPRESSION_TYPE>& listOfParameterTypes) : _pBNFScript(pBNFScript), GrfBlock(pParent), _sName(sName), _sTemplateKey(sTemplateKey), _bGenericKey(bGenericKey), _pTemplateClause(NULL), _pGenericTemplateClause(NULL), _iReturnType(0), _parameters(listOfParameters), _parameterTypes(listOfParameterTypes), _pOverloadClause(NULL), _bPropagatedParameters(false), _iPreprocessingIgnoreMode(0/*UNDEFINED_IGNORE*/), _pPreprocessingIgnoreClause(NULL) {
103 	}
104 
BNFClause(DtaBNFScript * pBNFScript,GrfBlock * pParent,const std::string & sName,int iArity)105 	BNFClause::BNFClause(DtaBNFScript* pBNFScript, GrfBlock* pParent, const std::string& sName, int iArity) : _pBNFScript(pBNFScript), GrfBlock(pParent), _sName(sName), _bGenericKey(false), _pTemplateClause(NULL), _pGenericTemplateClause(NULL), _iReturnType(0), _pOverloadClause(NULL), _bPropagatedParameters(false), _iPreprocessingIgnoreMode(0/*UNDEFINED_IGNORE*/), _pPreprocessingIgnoreClause(NULL) {
106 		_parameters.resize(iArity);
107 		_parameterTypes.resize(iArity);
108 	}
109 
~BNFClause()110 	BNFClause::~BNFClause() {
111 		delete _pOverloadClause;
112 	}
113 
accept(DtaVisitor & visitor,DtaVisitorEnvironment & env)114 	void BNFClause::accept(DtaVisitor& visitor, DtaVisitorEnvironment& env) {
115 		visitor.visitBNFClause(*this, env);
116 	}
117 
setPreprocessingIgnoreMode(int iPreprocessingIgnoreMode,BNFClause * pIgnoreClause)118 	void BNFClause::setPreprocessingIgnoreMode(int/*IGNORE_MODE*/ iPreprocessingIgnoreMode, BNFClause* pIgnoreClause) {
119 		_iPreprocessingIgnoreMode = iPreprocessingIgnoreMode;
120 		_pPreprocessingIgnoreClause = pIgnoreClause;
121 		if (_pTemplateClause != NULL) {
122 			// the default template clause might have been created implicitly,
123 			// so the preprocessing ignore mode isn't initialized
124 			_pTemplateClause->_iPreprocessingIgnoreMode = _iPreprocessingIgnoreMode;
125 			_pTemplateClause->_pPreprocessingIgnoreClause = _pPreprocessingIgnoreClause;
126 		}
127 	}
128 
isABNFCommand() const129 	bool BNFClause::isABNFCommand() const { return true; }
130 
setTemplateClause(BNFClause * pTemplateClause)131 	void BNFClause::setTemplateClause(BNFClause* pTemplateClause) {
132 		_pTemplateClause = pTemplateClause;
133 		if (isGenericKey()) _pTemplateClause->_pGenericTemplateClause = this;
134 		else _pTemplateClause->_mapOfTemplateInstantiations[_sTemplateKey] = this;
135 	}
136 
getInstantiatedClause(const std::string & sInstantiationKey) const137 	BNFClause* BNFClause::getInstantiatedClause(const std::string& sInstantiationKey) const {
138 		std::map<std::string, BNFClause*>::const_iterator cursor = _mapOfTemplateInstantiations.find(sInstantiationKey);
139 		if (cursor == _mapOfTemplateInstantiations.end()) {
140 			if (sInstantiationKey.empty() && (getNbCommands() != 0)) return const_cast<BNFClause*>(this);
141 			return _pGenericTemplateClause;
142 		}
143 		return cursor->second;
144 	}
145 
setParameter(int i,const std::string & sParameter,EXPRESSION_TYPE iType)146 	void BNFClause::setParameter(int i, const std::string& sParameter, EXPRESSION_TYPE iType) {
147 		_parameters[i] = sParameter;
148 		_parameterTypes[i] = iType;
149 	}
150 
setOverloadClause(BNFClause * pOverloadClause)151 	void BNFClause::setOverloadClause(BNFClause* pOverloadClause) {
152 		if (_pOverloadClause != NULL) _pOverloadClause->setOverloadClause(pOverloadClause);
153 		else _pOverloadClause = pOverloadClause;
154 	}
155 
propagateParameters(ExprScriptExpression & theFilter,const std::string & sFunctionQuantity,const std::vector<std::string> & listOfParameters,const std::vector<EXPRESSION_TYPE> & listOfParameterTypes)156 	bool BNFClause::propagateParameters(ExprScriptExpression& theFilter, const std::string& sFunctionQuantity, const std::vector<std::string>& listOfParameters, const std::vector<EXPRESSION_TYPE>& listOfParameterTypes) {
157 		DtaScriptVariable theContext;
158 		std::string sSignature = getSignature();
159 		theContext.setValueAtVariable(sFunctionQuantity.c_str(), sSignature.c_str());
160 		std::string sResult = theFilter.getValue(theContext);
161 		bool bResult = (!sResult.empty());
162 		if (bResult) {
163 			_bPropagatedParameters = true;
164 			if (listOfParameters.size() < getArity()) throw UtlException("while propagating parameters on non terminals, not enough parameters assigned to " + sFunctionQuantity + "='" + sSignature + "'");
165 			std::string::size_type i;
166 			for (i = 0; i < getArity(); ++i) {
167 				if (getParameterType(i) != listOfParameterTypes[i]) throw UtlException("while propagating parameters on non terminals, incompatible parameter type assigned to " + sFunctionQuantity + "='" + sSignature + "'/parameter='" + listOfParameters[i] + "'");
168 			}
169 			for (i = getArity(); i < listOfParameterTypes.size(); ++i) {
170 				_parameters.push_back(listOfParameters[i]);
171 				_parameterTypes.push_back(listOfParameterTypes[i]);
172 			}
173 		}
174 		if ((_pGenericTemplateClause != NULL) && _pGenericTemplateClause->propagateParameters(theFilter, sFunctionQuantity, listOfParameters, listOfParameterTypes)) bResult = true;
175 		for (std::map<std::string, BNFClause*>::iterator i = _mapOfTemplateInstantiations.begin(); i != _mapOfTemplateInstantiations.end(); ++i) {
176 			if (i->second->propagateParameters(theFilter, sFunctionQuantity, listOfParameters, listOfParameterTypes)) bResult = true;
177 		}
178 		if ((_pOverloadClause != NULL) && _pOverloadClause->propagateParameters(theFilter, sFunctionQuantity, listOfParameters, listOfParameterTypes)) bResult = true;
179 		if (bResult && !_bPropagatedParameters) {
180 			ExprScriptConstant alwaysTrue(true);
181 			propagateParameters(alwaysTrue, sFunctionQuantity, listOfParameters, listOfParameterTypes);
182 		}
183 		return bResult;
184 	}
185 
186 
addBNFLocalVariable(const std::string & sVarName,EXPRESSION_TYPE varType)187 	bool BNFClause::addBNFLocalVariable(const std::string& sVarName, EXPRESSION_TYPE varType) {
188 		return addLocalVariable(sVarName, varType);
189 	}
190 
getLocalVariable(const std::string & sVarName) const191 	EXPRESSION_TYPE BNFClause::getLocalVariable(const std::string& sVarName) const {
192 		EXPRESSION_TYPE result = GrfBlock::getLocalVariable(sVarName);
193 		if (result == UNKNOWN_EXPRTYPE) {
194 			int iIndex = 0;
195 			for (std::vector<std::string>::const_iterator i = _parameters.begin(); i != _parameters.end(); i++) {
196 				if ((*i) == sVarName) {
197 					result = getParameterType(iIndex);
198 					break;
199 				}
200 				++iIndex;
201 			}
202 		}
203 		return result;
204 	}
205 
getVariable(const std::string & sVarName) const206 	EXPRESSION_TYPE BNFClause::getVariable(const std::string& sVarName) const {
207 		EXPRESSION_TYPE result = getLocalVariable(sVarName);
208 		if (result == UNKNOWN_EXPRTYPE) {
209 			if ((sVarName == "this") || (sVarName == "project") || (sVarName == "null") || (DtaProject::getInstance().getGlobalVariableType(sVarName) != UNKNOWN_EXPRTYPE)) return NODE_EXPRTYPE;
210 		}
211 		return result;
212 	}
213 
214 
execute(DtaScriptVariable & visibility)215 	SEQUENCE_INTERRUPTION_LIST BNFClause::execute(DtaScriptVariable& visibility) {
216 		throw UtlException("internal error: call 'BNFClause::executeClause(..., 0)' instead of 'BNFClause::execute(...)'");
217 	}
218 
executeClause(DtaScriptVariable & visibility,int iSuperCallDepth)219 	SEQUENCE_INTERRUPTION_LIST BNFClause::executeClause(DtaScriptVariable& visibility, int iSuperCallDepth) {
220 		SEQUENCE_INTERRUPTION_LIST result;
221 		BNFClauseMatchingAreaValidator matchingAreaValidator(this, _pBNFScript);
222 		if (iSuperCallDepth == 0) {
223 			register BNFClause* pLastOverloadClause = this;
224 			while (pLastOverloadClause->_pOverloadClause != NULL) pLastOverloadClause = pLastOverloadClause->_pOverloadClause;
225 			result = pLastOverloadClause->GrfBlock::execute(visibility);
226 		} else {
227 			result = executeInternalSuperClause(visibility, iSuperCallDepth);
228 			if (result == CONTINUE_INTERRUPTION) result = NO_INTERRUPTION;
229 			if (iSuperCallDepth > 0) throw UtlException("'#super' has failed: no overloaded non-terminal found for '" + getSignature() + "'");
230 		}
231 		if (result != BREAK_INTERRUPTION) {
232 			matchingAreaValidator.validate();
233 		}
234 		return result;
235 	}
236 
executeInternalSuperClause(DtaScriptVariable & visibility,int & iSuperCallDepth)237 	SEQUENCE_INTERRUPTION_LIST BNFClause::executeInternalSuperClause(DtaScriptVariable& visibility, int &iSuperCallDepth) {
238 		SEQUENCE_INTERRUPTION_LIST result;
239 		if (_pOverloadClause != NULL) {
240 			result = _pOverloadClause->executeInternalSuperClause(visibility, iSuperCallDepth);
241 			iSuperCallDepth--;
242 			if (iSuperCallDepth == 0) result = GrfBlock::execute(visibility);
243 		} else {
244 			result = NO_INTERRUPTION;
245 		}
246 		return result;
247 	}
248 
getSignature() const249 	std::string BNFClause::getSignature() const {
250 		std::string sText;
251 		BNFClause* pOverloadClause = _pOverloadClause;
252 		while (pOverloadClause != NULL) {
253 			sText += "super::";
254 			pOverloadClause = pOverloadClause->_pOverloadClause;
255 		}
256 		sText += getName();
257 		if (!_sTemplateKey.empty()) {
258 			if (_bGenericKey) sText += "<" + _sTemplateKey + ">";
259 			else sText += "<\"" + _sTemplateKey + "\">";
260 		}
261 		if (!_parameters.empty()) {
262 			sText += "(";
263 			int iIndex = 0;
264 			for (std::vector<std::string>::const_iterator i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
265 				if (i != _parameters.begin()) sText += ", ";
266 				sText += (*i);
267 				EXPRESSION_TYPE exprType = getParameterType(iIndex);
268 				switch(exprType & 0x00FF) {
269 					case VALUE_EXPRTYPE: sText += " : value";break;
270 					case REFERENCE_EXPRTYPE: sText += " : reference";break;
271 					case ITERATOR_EXPRTYPE: sText += " : iterator";break;
272 					case NODE_EXPRTYPE:	sText += " : node";break;
273 					default:
274 						throw UtlException("internal error in BNFClause::getSignature(): unhandled parameter type");
275 				}
276 				DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
277 				if (pTypeSpecifier != NULL) {
278 					sText += "<" + pTypeSpecifier->getName() + ">";
279 				}
280 			}
281 			sText += ")";
282 		}
283 		switch(getReturnType()) {
284 			case 0/*NO_RETURN_TYPE*/: break;
285 			case 1/*LIST_RETURN_TYPE*/: sText += " : list";break;
286 			case 2/*NODE_RETURN_TYPE*/: sText += " : node";break;
287 			case 3/*VALUE_RETURN_TYPE*/: sText += " : value";break;
288 			default:
289 				throw UtlException("internal error in BNFClause::toString(): unhandled enum");
290 		}
291 		return sText;
292 	}
293 
toString() const294 	std::string BNFClause::toString() const {
295 		std::string sText = getSignature();
296 		sText += " ::= ";
297 		if (getNbCommands() == 1) {
298 			sText += getCommands()[0]->toString();
299 		} else {
300 			std::string sPrefix(sText.size(), ' ');
301 			for (std::vector<GrfCommand*>::const_iterator i = getCommands().begin(); i != getCommands().end(); i++) {
302 				if (i != getCommands().begin()) {
303 					sText += "\n";
304 					sText += sPrefix + "| ";
305 				} else {
306 					sText += "  ";
307 				}
308 				sText += "[";
309 				(*i)->toString();
310 				sText += "]";
311 			}
312 		}
313 		return sText + ";";
314 	}
315 
compileCppFunction(CppCompilerEnvironment & theCompilerEnvironment) const316 	void BNFClause::compileCppFunction(CppCompilerEnvironment& theCompilerEnvironment) const {
317 		theCompilerEnvironment.setBNFStepperCursor(0);
318 		const BNFClause* pParentClause = theCompilerEnvironment.getCurrentClause();
319 		int iPointerToDeclarations = theCompilerEnvironment.getPointerToDeclarations();
320 		theCompilerEnvironment.newClause(this);
321 		// create the name of the clause
322 		std::string sClauseName = getName();
323 		if (isATemplateInstantiation()) {
324 			if (_bGenericKey) sClauseName = "_compilerTemplateClause_" + sClauseName + "_compilerGeneric";
325 			else sClauseName = "_compilerTemplateClause_" + sClauseName + "_compilerInstantiation_" + theCompilerEnvironment.convertTemplateKey(_sTemplateKey);
326 		} else if (sClauseName[0] == '#') sClauseName = "_compilerDirectiveClause_" + sClauseName.substr(1);
327 		else sClauseName = "_compilerClause_" + sClauseName;
328 		std::vector<std::string>::const_iterator i;
329 		int iIndex = 0;
330 		if (isATemplateInstantiation() && _sTemplateKey.empty()) {
331 			// prototype of the dispatcher for template clauses, in the C++ header
332 			theCompilerEnvironment.getHeader() << theCompilerEnvironment.getIndentation() << "\t\tstatic bool " << sClauseName << "(const std::string& _compilerTemplateClause_dispatching, ";
333 			for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
334 				switch(getParameterType(iIndex) & 0x00FF) {
335 					case VALUE_EXPRTYPE: theCompilerEnvironment.getHeader() << "CodeWorker::CppParsingTree_value ";break;
336 					case ITERATOR_EXPRTYPE:
337 					case REFERENCE_EXPRTYPE: theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
338 					case NODE_EXPRTYPE:	theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
339 					default:
340 						throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
341 				}
342 				theCompilerEnvironment.getHeader() << (*i) << ", ";
343 			}
344 			theCompilerEnvironment.getHeader() << "CodeWorker::CGBNFRuntimeEnvironment& theEnvironment);";
345 			theCompilerEnvironment.getHeader().endl();
346 			iIndex = 0;
347 			theCompilerEnvironment.getHeader() << theCompilerEnvironment.getIndentation() << "\t\tstatic bool " << sClauseName << "(const std::string& _compilerTemplateClause_dispatching, const CodeWorker::CppParsingTree_var& _compilerClause_returnValue, ";
348 			for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
349 				EXPRESSION_TYPE exprType = getParameterType(iIndex);
350 				if ((exprType & ~0x00FF) == 0) {
351 					switch(exprType) {
352 						case VALUE_EXPRTYPE: theCompilerEnvironment.getHeader() << "CodeWorker::CppParsingTree_value ";break;
353 						case ITERATOR_EXPRTYPE:
354 						case REFERENCE_EXPRTYPE: theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
355 						case NODE_EXPRTYPE:	theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
356 						default:
357 							throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
358 					}
359 				} else {
360 					DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
361 					theCompilerEnvironment.getHeader() << pTypeSpecifier->getCppTypeSpecifier() << " ";
362 				}
363 				theCompilerEnvironment.getHeader() << (*i) << ", ";
364 			}
365 			theCompilerEnvironment.getHeader() << "CodeWorker::CGBNFRuntimeEnvironment& theEnvironment);";
366 			theCompilerEnvironment.getHeader().endl();
367 		}
368 		// prototype in the C++ header, without return value
369 		iIndex = 0;
370 		theCompilerEnvironment.getHeader() << theCompilerEnvironment.getIndentation() << "\t\tstatic bool " << sClauseName << "(";
371 		for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
372 			EXPRESSION_TYPE exprType = getParameterType(iIndex);
373 			if ((exprType & ~0x00FF) == 0) {
374 				switch(exprType) {
375 					case VALUE_EXPRTYPE: theCompilerEnvironment.getHeader() << "CodeWorker::CppParsingTree_value ";break;
376 					case ITERATOR_EXPRTYPE:
377 					case REFERENCE_EXPRTYPE: theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
378 					case NODE_EXPRTYPE:	theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
379 					default:
380 						throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
381 				}
382 			} else {
383 				DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
384 				theCompilerEnvironment.getHeader() << pTypeSpecifier->getCppTypeSpecifier() << " ";
385 			}
386 			theCompilerEnvironment.getHeader() << (*i) << ", ";
387 		}
388 		theCompilerEnvironment.getHeader() << "CodeWorker::CGBNFRuntimeEnvironment& theEnvironment);";
389 		theCompilerEnvironment.getHeader().endl();
390 		// prototype in the C++ header with return value
391 		iIndex = 0;
392 		theCompilerEnvironment.getHeader() << theCompilerEnvironment.getIndentation() << "\t\tstatic bool " << sClauseName << "(const CodeWorker::CppParsingTree_var& _compilerClause_returnValue, ";
393 		for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
394 			EXPRESSION_TYPE exprType = getParameterType(iIndex);
395 			if ((exprType & ~0x00FF) == 0) {
396 				switch(exprType) {
397 					case VALUE_EXPRTYPE: theCompilerEnvironment.getHeader() << "CodeWorker::CppParsingTree_value ";break;
398 					case ITERATOR_EXPRTYPE:
399 					case REFERENCE_EXPRTYPE: theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
400 					case NODE_EXPRTYPE:	theCompilerEnvironment.getHeader() << "const CodeWorker::CppParsingTree_var& ";break;
401 					default:
402 						throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
403 				}
404 			} else {
405 				DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
406 				theCompilerEnvironment.getHeader() << pTypeSpecifier->getCppTypeSpecifier() << " ";
407 			}
408 			theCompilerEnvironment.getHeader() << (*i) << ", ";
409 		}
410 		theCompilerEnvironment.getHeader() << "CodeWorker::CGBNFRuntimeEnvironment& theEnvironment);";
411 		theCompilerEnvironment.getHeader().endl();
412 
413 		// implementations of the clause in the C++ body
414 		CW_BODY_INDENT << "//**";
415 		CW_BODY_ENDL;
416 		CW_BODY_INDENT << "// " << toString();
417 		CW_BODY_ENDL;
418 		CW_BODY_INDENT << "//**";
419 		CW_BODY_ENDL;
420 		if (isATemplateInstantiation() && _sTemplateKey.empty()) {
421 			// implementation of the dispatcher for template clauses, in the C++ body
422 			CW_BODY_INDENT << "bool " << DtaScript::convertFilenameAsIdentifier(theCompilerEnvironment.getRadical()) << "::" << sClauseName << "(const std::string& _compilerTemplateClause_dispatching, ";
423 			iIndex = 0;
424 			for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
425 				EXPRESSION_TYPE exprType = getParameterType(iIndex);
426 				if ((exprType & ~0x00FF) == 0) {
427 					switch(exprType) {
428 						case VALUE_EXPRTYPE: CW_BODY_STREAM << "CppParsingTree_value ";break;
429 						case ITERATOR_EXPRTYPE:
430 						case REFERENCE_EXPRTYPE: CW_BODY_STREAM << "const CppParsingTree_var& ";break;
431 						case NODE_EXPRTYPE:	CW_BODY_STREAM << "const CppParsingTree_var& ";break;
432 						default:
433 							throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
434 					}
435 				} else {
436 					DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
437 					CW_BODY_STREAM << pTypeSpecifier->getCppTypeSpecifier() << " ";
438 				}
439 				CW_BODY_STREAM << (*i) << ", ";
440 			}
441 			CW_BODY_STREAM << "CGBNFRuntimeEnvironment& theEnvironment) {";
442 			CW_BODY_ENDL;
443 			CW_BODY_STREAM << "	CppParsingTree_value _compilerClauseThis;";
444 			CW_BODY_ENDL;
445 			CW_BODY_STREAM << "	return " << sClauseName << "(_compilerTemplateClause_dispatching, _compilerClauseThis, ";
446 			for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
447 				CW_BODY_STREAM << (*i) << ", ";
448 			}
449 			CW_BODY_STREAM << "theEnvironment);";
450 			CW_BODY_ENDL;
451 			CW_BODY_STREAM << "}";
452 			CW_BODY_ENDL;
453 			CW_BODY_ENDL;
454 			CW_BODY_INDENT << "bool " << DtaScript::convertFilenameAsIdentifier(theCompilerEnvironment.getRadical()) << "::" << sClauseName << "(const std::string& _compilerTemplateClause_dispatching, const CppParsingTree_var& _compilerClause_returnValue, ";
455 			iIndex = 0;
456 			for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
457 				EXPRESSION_TYPE exprType = getParameterType(iIndex);
458 				if ((exprType & ~0x00FF) == 0) {
459 					switch(exprType) {
460 						case VALUE_EXPRTYPE: CW_BODY_STREAM << "CppParsingTree_value ";break;
461 						case ITERATOR_EXPRTYPE:
462 						case REFERENCE_EXPRTYPE: CW_BODY_STREAM << "const CppParsingTree_var& ";break;
463 						case NODE_EXPRTYPE:	CW_BODY_STREAM << "const CppParsingTree_var& ";break;
464 						default:
465 							throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
466 					}
467 				} else {
468 					DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
469 					CW_BODY_STREAM << pTypeSpecifier->getCppTypeSpecifier() << " ";
470 				}
471 				CW_BODY_STREAM << (*i) << ", ";
472 			}
473 			CW_BODY_STREAM << "CGBNFRuntimeEnvironment& theEnvironment) {";
474 			CW_BODY_ENDL;
475 			// core of the dispatcher
476 			if (_mapOfTemplateInstantiations.size() < 8) {
477 				// just a battery of if/else on the key for determining the correct function call
478 				for (std::map<std::string, BNFClause*>::const_iterator j = _mapOfTemplateInstantiations.begin(); j != _mapOfTemplateInstantiations.end(); ++j) {
479 					CW_BODY_STREAM << "\t";
480 					if (j != _mapOfTemplateInstantiations.begin()) CW_BODY_STREAM << "else ";
481 					CW_BODY_STREAM << "if (_compilerTemplateClause_dispatching == ";
482 					CW_BODY_STREAM.writeString(j->first);
483 					CW_BODY_STREAM << ") return " << sClauseName << theCompilerEnvironment.convertTemplateKey(j->first) << "(_compilerClause_returnValue, ";
484 					for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
485 						CW_BODY_STREAM << (*i) << ", ";
486 					}
487 					CW_BODY_STREAM << "theEnvironment);";
488 					CW_BODY_ENDL;
489 				}
490 			} else {
491 				// a switch/case depending on a hash code issued of the key
492 				std::map<long, std::list<std::string> > keysByCode;
493 				for (std::map<std::string, BNFClause*>::const_iterator j = _mapOfTemplateInstantiations.begin(); j != _mapOfTemplateInstantiations.end(); ++j) {
494 					long iHashCode = 0;
495 					char* u = (char*) (j->first.c_str());
496 					while (*u != '\0') iHashCode = iHashCode * 31 + (((long) *u++) % 31);
497 					keysByCode[iHashCode].push_back(j->first);
498 				}
499 				CW_BODY_STREAM << "\tlong _compilerInternal_hashCode = 0;";
500 				CW_BODY_ENDL;
501 				CW_BODY_STREAM << "\tchar* _compilerInternal_u = (char*) (_compilerTemplateClause_dispatching.c_str());";
502 				CW_BODY_ENDL;
503 				CW_BODY_STREAM << "\twhile (*_compilerInternal_u != '\\0') _compilerInternal_hashCode = _compilerInternal_hashCode * 31 + (((long) *_compilerInternal_u++) % 31);";
504 				CW_BODY_ENDL;
505 				CW_BODY_STREAM << "\tswitch(_compilerInternal_hashCode) {";
506 				CW_BODY_ENDL;
507 				for (std::map<long, std::list<std::string> >::const_iterator k = keysByCode.begin(); k != keysByCode.end(); ++k) {
508 					CW_BODY_STREAM << "\t\tcase " << k->first << ": ";
509 					CW_BODY_ENDL;
510 					for (std::list<std::string>::const_iterator l = k->second.begin(); l != k->second.end(); ++l) {
511 						CW_BODY_STREAM << "\t\t\tif (_compilerTemplateClause_dispatching == ";
512 						CW_BODY_STREAM.writeString(*l);
513 						CW_BODY_STREAM << ") return " << sClauseName << theCompilerEnvironment.convertTemplateKey(*l) << "(_compilerClause_returnValue, ";
514 						for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
515 							CW_BODY_STREAM << (*i) << ", ";
516 						}
517 						CW_BODY_STREAM << "theEnvironment);";
518 						CW_BODY_ENDL;
519 					}
520 					CW_BODY_STREAM << "\t\t\tbreak;";
521 					CW_BODY_ENDL;
522 				}
523 				CW_BODY_STREAM << "\t}";
524 				CW_BODY_ENDL;
525 			}
526 			if (_pGenericTemplateClause != NULL) {
527 				CW_BODY_STREAM << "\treturn _compilerTemplateClause_" + getName() + "_compilerGeneric(_compilerClause_returnValue, ";
528 				for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
529 					CW_BODY_STREAM << (*i) << ", ";
530 				}
531 				CW_BODY_STREAM << "theEnvironment);";CW_BODY_ENDL;
532 			} else {
533 				CW_BODY_STREAM << "\tif (!_compilerTemplateClause_dispatching.empty()) throw UtlException(\"template clause '" << getName() << "<\\\"\" + _compilerTemplateClause_dispatching + \"\\\">' hasn't been implemented\");";CW_BODY_ENDL;
534 				if (getNbCommands() == 0) {
535 					CW_BODY_STREAM << "\treturn true;";CW_BODY_ENDL;
536 				} else {
537 					CW_BODY_STREAM << "\treturn " << sClauseName << "(_compilerClause_returnValue, ";
538 					for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
539 						CW_BODY_STREAM << (*i) << ", ";
540 					}
541 					CW_BODY_STREAM << "theEnvironment);";
542 					CW_BODY_ENDL;
543 				}
544 			}
545 			CW_BODY_STREAM << "}";
546 			CW_BODY_ENDL;
547 			CW_BODY_ENDL;
548 		}
549 		// implementation of the clause in the C++ body, with a return value
550 		CW_BODY_INDENT << "bool " << DtaScript::convertFilenameAsIdentifier(theCompilerEnvironment.getRadical()) << "::" << sClauseName << "(const CppParsingTree_var& _compilerClause_returnValue, ";
551 		iIndex = 0;
552 		for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
553 			EXPRESSION_TYPE exprType = getParameterType(iIndex);
554 			if ((exprType & ~0x00FF) == 0) {
555 				switch(exprType) {
556 					case VALUE_EXPRTYPE: CW_BODY_STREAM << "CppParsingTree_value ";break;
557 					case ITERATOR_EXPRTYPE:
558 					case REFERENCE_EXPRTYPE: CW_BODY_STREAM << "const CppParsingTree_var& ";break;
559 					case NODE_EXPRTYPE:	CW_BODY_STREAM << "const CppParsingTree_var& ";break;
560 					default:
561 						throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
562 				}
563 			} else {
564 				DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
565 				CW_BODY_STREAM << pTypeSpecifier->getCppTypeSpecifier() << " ";
566 			}
567 			CW_BODY_STREAM << (*i) << ", ";
568 		}
569 		CW_BODY_STREAM << "CGBNFRuntimeEnvironment& theEnvironment) {";CW_BODY_ENDL;
570 		theCompilerEnvironment.setPointerToDeclarations(CW_BODY_STREAM.getOutputLocation());
571 		theCompilerEnvironment.incrementIndentation();
572 		theCompilerEnvironment.pushVariableScope();
573 		if (_pBNFScript->hasCoverageRecording()) {
574 			// coverage recording required
575 			CW_BODY_INDENT << "CGBNFRuntimeClauseMatchingAreaValidator _compilerClauseMatching(\"" << CGRuntime::composeCLikeString(getSignature()) << "\", &theEnvironment);";CW_BODY_ENDL;
576 		}
577 		CW_BODY_INDENT << "CGBNFClauseScope _compilerClauseScope;";CW_BODY_ENDL;
578 		CW_BODY_STREAM.newFloatingLocation("CLAUSE SCOPE DECLARATION");
579 		CW_BODY_INDENT << "bool _compilerClauseSuccess = true;";CW_BODY_ENDL;
580 		for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
581 			theCompilerEnvironment.addVariable((*i));
582 		}
583 		if (getReturnType() != 0/*NO_RETURN_TYPE*/) {
584 			// the clause admits a return value
585 			theCompilerEnvironment.setClauseReturnValue(getName());
586 		}
587 		theCompilerEnvironment.bracketsToNextBlock(false);
588 		GrfBlock::compileCpp(theCompilerEnvironment);
589 		if (theCompilerEnvironment.hasEvaluatedExpressionInScope()) {
590 			for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
591 				std::string sDynamicVariable = theCompilerEnvironment.getIndentation() + "_compilerClauseScope.insertNode(\"" + *i + "\").setReference(" + *i + ");" + ScpStream::ENDL;
592 				ScpStream* pOwner = 0;
593 				CW_BODY_STREAM.insertText(sDynamicVariable, CW_BODY_STREAM.getFloatingLocation("CLAUSE SCOPE DECLARATION", pOwner));
594 			}
595 		}
596 		if (_pBNFScript->hasCoverageRecording()) {
597 			// coverage recording required
598 			CW_BODY_INDENT << "if (_compilerClauseSuccess) _compilerClauseMatching.validate();";CW_BODY_ENDL;
599 		}
600 		CW_BODY_INDENT << "return _compilerClauseSuccess;";CW_BODY_ENDL;
601 		theCompilerEnvironment.popVariableScope();
602 		theCompilerEnvironment.decrementIndentation();
603 		CW_BODY_INDENT << "}";
604 		CW_BODY_ENDL;
605 		CW_BODY_ENDL;
606 		// implementation of the clause in the C++ body, without a return value
607 		CW_BODY_INDENT << "bool " << DtaScript::convertFilenameAsIdentifier(theCompilerEnvironment.getRadical()) << "::" << sClauseName << "(";
608 		iIndex = 0;
609 		for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
610 			EXPRESSION_TYPE exprType = getParameterType(iIndex);
611 			if ((exprType & ~0x00FF) == 0) {
612 				switch(exprType) {
613 					case VALUE_EXPRTYPE: CW_BODY_STREAM << "CppParsingTree_value ";break;
614 					case ITERATOR_EXPRTYPE:
615 					case REFERENCE_EXPRTYPE: CW_BODY_STREAM << "const CppParsingTree_var& ";break;
616 					case NODE_EXPRTYPE:	CW_BODY_STREAM << "const CppParsingTree_var& ";break;
617 					default:
618 						throw UtlException("internal error in BNFClause::compileCppFunction(): unhandled parameter type");
619 				}
620 			} else {
621 				DtaClass* pTypeSpecifier = DtaClass::getClass(exprType);
622 				CW_BODY_STREAM << pTypeSpecifier->getCppTypeSpecifier() << " ";
623 			}
624 			CW_BODY_STREAM << (*i) << ", ";
625 		}
626 		CW_BODY_STREAM << "CGBNFRuntimeEnvironment& theEnvironment) {";
627 		CW_BODY_ENDL;
628 		CW_BODY_STREAM << "	CppParsingTree_value _compilerClauseThis;";
629 		CW_BODY_ENDL;
630 		CW_BODY_STREAM << "	return " << sClauseName << "(_compilerClauseThis, ";
631 		for (i = _parameters.begin(); i != _parameters.end(); i++, iIndex++) {
632 			CW_BODY_STREAM << (*i) << ", ";
633 		}
634 		CW_BODY_STREAM << "theEnvironment);";
635 		CW_BODY_ENDL;
636 		CW_BODY_STREAM << "}";
637 		CW_BODY_ENDL;
638 		CW_BODY_ENDL;
639 		theCompilerEnvironment.setCurrentClause(pParentClause);
640 		theCompilerEnvironment.setPointerToDeclarations(iPointerToDeclarations);
641 	}
642 }
643