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