00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <fstream>
00027 #include <mpcl/system/all.hh>
00028 #include <mpcl/text/codegen/pattern_based_code_generator.hh>
00029 #include <mpcl/text/regex/matcher.hh>
00030
00031
00032
00033
00034
00035
00036 mpcl::text::codegen::TPatternBasedCodeGenerator::
00037 TPatternBasedCodeGenerator ( const TString& rkySOURCE_CDML_FILE ,
00038 const TString& rkyCDML_PATH ) :
00039 IStreamable<> () ,
00040 tInstructionMap () ,
00041 tVariableMap () ,
00042 yCdmlPath (rkyCDML_PATH) ,
00043 yDescription () ,
00044 yInherit () ,
00045 yPublic () ,
00046 ySystem () ,
00047 yTarget ()
00048 {
00049
00050 initConstants();
00051 loadFrom (rkySOURCE_CDML_FILE);
00052
00053 }
00054
00055
00056 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00057 clear (void)
00058 {
00059
00060 tInstructionMap.clear();
00061 yTarget.erase();
00062 yInherit.erase();
00063 yDescription.erase();
00064 yCdmlPath.erase();
00065
00066 }
00067
00068
00069 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00070 clearCode (void)
00071 {
00072
00073 TInstructionMap::iterator tInstructionIter;
00074 TInstructionBody::TClauseMap::iterator tClauseIter;
00075 TInstructionBody::TClauseMap::const_iterator ktClauseEnd;
00076
00077 tInstructionIter = tInstructionMap.begin();
00078 for (; ( tInstructionIter != tInstructionMap.end() ) ;++tInstructionIter)
00079 {
00080 tClauseIter = tInstructionIter->second.tClauseMap.begin();
00081 ktClauseEnd = tInstructionIter->second.tClauseMap.end();
00082 for (; ( tClauseIter != ktClauseEnd ) ;++tClauseIter)
00083 {
00084 tClauseIter->second.erase();
00085 }
00086 }
00087
00088 }
00089
00090
00091 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00092 loadFrom (const TString& rkySOURCE_CDML_FILE)
00093 {
00094
00095 using mpcl::system::tSystem;
00096 using std::basic_ifstream;
00097 using std::vector;
00098
00099 basic_ifstream<char> tCdmlIfstream;
00100 TString yCdmlFileName;
00101 bool gSuccess = false;
00102
00103
00104
00105
00106
00107 tCdmlIfstream.open (rkySOURCE_CDML_FILE.c_str());
00108 if ( !tCdmlIfstream.is_open() && !yCdmlPath.empty() )
00109 {
00110
00111
00112
00113 vector<TString> tPathVector = tSystem.getPathItems (yCdmlPath);
00114 vector<TString>::const_iterator I = tPathVector.begin();
00115
00116 yCdmlFileName = tSystem.getDirectorySeparator();
00117 yCdmlFileName += rkySOURCE_CDML_FILE;
00118 for (; ( I != tPathVector.end() ) ;++I)
00119 {
00120 tCdmlIfstream.clear();
00121 tCdmlIfstream.open ((*I + yCdmlFileName).c_str());
00122 if ( tCdmlIfstream.is_open() )
00123 {
00124 break;
00125 }
00126 }
00127 }
00128 if ( tCdmlIfstream.is_open() )
00129 {
00130
00131
00132
00133 gSuccess = true;
00134 read (tCdmlIfstream);
00135 tCdmlIfstream.close();
00136 }
00137 if ( !gSuccess )
00138 {
00139 TString yMessage = Format ("couldn't open file '%s'", rkySOURCE_CDML_FILE.c_str());
00140
00141 throw TFileNotFoundException (yMessage, __FILE__, __LINE__);
00142 }
00143
00144 }
00145
00146
00147 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00148 compile (void)
00149 {
00150
00151 size_t zOffset;
00152
00153
00154
00155
00156 yInherit.erase();
00157
00158
00159
00160
00161 {
00162 TStringToVariableMap::iterator I = tVariableMap.begin();
00163 TStringToVariableMap::const_iterator ktVariableEnd = tVariableMap.end();
00164
00165 for (; ( I != ktVariableEnd ) ;++I)
00166 {
00167 zOffset = I->second.find (pkcEOC_EntityPattern);
00168 if ( TString::npos != zOffset )
00169 {
00170 I->second.erase (zOffset);
00171 }
00172 }
00173 }
00174
00175
00176
00177
00178 {
00179 TInstructionMap::iterator I;
00180 TInstructionMap::const_iterator ktInstructionEnd;
00181 TInstructionBody::TClauseMap::iterator J;
00182 TInstructionBody::TClauseMap::const_iterator ktClauseEnd;
00183
00184 I = tInstructionMap.begin();
00185 ktInstructionEnd = tInstructionMap.end();
00186 for (; ( I != ktInstructionEnd ) ;++I)
00187 {
00188 J = I->second.tClauseMap.begin();
00189 ktClauseEnd = I->second.tClauseMap.end();
00190 for (; ( J != ktClauseEnd ) ;++J)
00191 {
00192 zOffset = J->second.find (pkcEOC_EntityPattern);
00193 if ( TString::npos != zOffset )
00194 {
00195 J->second.erase (zOffset);
00196 }
00197 }
00198 }
00199 }
00200
00201 }
00202
00203
00204 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00205 preprocessVariables (void)
00206 {
00207
00208 TStringToVariableMap::iterator I = tVariableMap.begin();
00209 TStringToVariableMap::const_iterator ktVariableEnd = tVariableMap.end();
00210
00211 for (; ( I != ktVariableEnd ) ;++I)
00212 {
00213 InstantiateEntities (I->second);
00214 }
00215
00216 }
00217
00218
00219 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00220 setDescription (const char* pkcSOURCE_DESCRIPTION)
00221 {
00222
00223 yDescription = pkcSOURCE_DESCRIPTION;
00224
00225 }
00226
00227
00228 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00229 setCdmlPath (const TString& rkyCDML_PATH)
00230 {
00231
00232 yCdmlPath = rkyCDML_PATH;
00233
00234 }
00235
00236
00237 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00238 initConstants (void) const
00239 {
00240
00241 using std::strlen;
00242
00243
00244
00245
00246 if ( !zEntityPrefixLength )
00247 {
00248 zEntityPrefixLength = strlen (pkcEntityPrefix);
00249 zGT_EntityPatternLength = strlen (pkcGT_EntityPattern);
00250 zGT_EntityValueLength = strlen (pkcGT_EntityValue);
00251 zLT_EntityPatternLength = strlen (pkcLT_EntityPattern);
00252 zLT_EntityValueLength = strlen (pkcLT_EntityValue);
00253 zNL_EntityPatternLength = strlen (pkcNL_EntityPattern);
00254 zNL_EntityValueLength = strlen (pkcNL_EntityValue);
00255 zEOC_EntityPatternLength = strlen (pkcEOC_EntityPattern);
00256 zAMP_EntityPatternLength = strlen (pkcAMP_EntityPattern);
00257 zAMP_EntityValueLength = strlen (pkcAMP_EntityValue);
00258 }
00259
00260 }
00261
00262
00263 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00264 inheritFrom (const TString& rkySOURCE_CDML_FILE)
00265 {
00266
00267
00268
00269
00270
00271
00272 TString yOldTarget = yTarget;
00273 TString yOldInherit = yInherit;
00274
00275 loadFrom (rkySOURCE_CDML_FILE);
00276 yTarget = yOldTarget;
00277 yInherit = yOldInherit;
00278
00279 }
00280
00281
00282 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00283 read (std::basic_istream<char_type, traits_type>& rtSOURCE_ISTREAM)
00284 {
00285
00286 # define PBCG_REMOVE_COMMENTS \
00287 { \
00288 while ( tMatcher.scan (pkcCommentTagPattern, NULL) ); \
00289 }
00290
00291 using text::regex::TMatcher;
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 bool gUpdateOnly = false;
00305 TMatcher tMatcher (rtSOURCE_ISTREAM);
00306
00307 yPublic.erase();
00308 ySystem.erase();
00309 yTarget.erase();
00310 yInherit.erase();
00311 tInstructionMap.clear();
00312 tMatcher.setCaseSensitiveness (false);
00313 PBCG_REMOVE_COMMENTS;
00314
00315
00316
00317
00318 if ( !tMatcher.scan (pkcDOCTYPE_TagPattern_1, NULL) )
00319 {
00320 if ( !tMatcher.scan (pkcDOCTYPE_TagPattern_2, NULL) )
00321 {
00322 if ( !tMatcher.scan (pkcDOCTYPE_TagPattern_3, &ySystem, NULL) )
00323 {
00324 tMatcher.scan (pkcDOCTYPE_TagPattern_4, &yPublic, NULL);
00325 }
00326 }
00327 }
00328 PBCG_REMOVE_COMMENTS;
00329
00330
00331
00332
00333 if ( !tMatcher.scan (pkcCDML_TagPattern_1, &yTarget, NULL) )
00334 {
00335 if ( !tMatcher.scan (pkcCDML_TagPattern_2, &yTarget, &yInherit, NULL) )
00336 {
00337 if ( !tMatcher.scan (pkcCDML_TagPattern_3, &yInherit, &yTarget, NULL) )
00338 {
00339 throw TNotCdmlFileException ("file doesn't conform CDML", __FILE__, __LINE__);
00340 }
00341 }
00342
00343
00344
00345
00346
00347 inheritFrom (yInherit + ".cdml");
00348 gUpdateOnly = true;
00349 }
00350 PBCG_REMOVE_COMMENTS;
00351
00352
00353
00354
00355 tMatcher.scan (pkcDESC_ElementPattern, &yDescription, NULL);
00356 PBCG_REMOVE_COMMENTS;
00357
00358
00359
00360
00361 if ( tMatcher.scan (pkcDECLARE_TagPattern, NULL) > 0 )
00362 {
00363 TString yName;
00364 TString yValue;
00365 TString yType;
00366 bool gFound;
00367
00368 if ( !gUpdateOnly )
00369 {
00370 do
00371 {
00372
00373
00374
00375
00376 PBCG_REMOVE_COMMENTS;
00377 gFound = ( tMatcher.scan (pkcVARIABLE_ElementPattern_1, &yName, &yValue, NULL) > 0 );
00378 if ( !gFound )
00379 {
00380 gFound = ( tMatcher.scan (pkcVARIABLE_ElementPattern_2, &yName, &yType, &yValue, NULL) > 0 );
00381 }
00382 if ( !gFound )
00383 {
00384 gFound = ( tMatcher.scan (pkcVARIABLE_ElementPattern_3, &yType, &yName, &yValue, NULL) > 0 );
00385 }
00386 if ( gFound )
00387 {
00388 yType.uppercase();
00389 if ( yType == "FILE" )
00390 {
00391 tVariableMap.bind (yName, TVariableString (yValue, TVariableString::eFile));
00392 }
00393 else if ( yType == "OPTIONAL" )
00394 {
00395 tVariableMap.bind (yName, TVariableString (yValue, TVariableString::eOptional));
00396 }
00397 else
00398 {
00399 tVariableMap.bind (yName, TVariableString (yValue));
00400 }
00401 yName.erase();
00402 yValue.erase();
00403 yType.erase();
00404 PBCG_REMOVE_COMMENTS;
00405 }
00406 } while ( gFound );
00407 }
00408 else
00409 {
00410 do
00411 {
00412
00413
00414
00415
00416 PBCG_REMOVE_COMMENTS;
00417 gFound = ( tMatcher.scan (pkcVARIABLE_ElementPattern_1, &yName, &yValue, NULL) > 0 );
00418 if ( !gFound )
00419 {
00420 gFound = ( tMatcher.scan (pkcVARIABLE_ElementPattern_2, &yName, &yType, &yValue, NULL) > 0 );
00421 }
00422 if ( !gFound )
00423 {
00424 gFound = ( tMatcher.scan (pkcVARIABLE_ElementPattern_3, &yType, &yName, &yValue, NULL) > 0 );
00425 }
00426 if ( gFound )
00427 {
00428 yType.uppercase();
00429 if ( yType == "FILE" )
00430 {
00431
00432
00433
00434 if ( tVariableMap.end() == tVariableMap.find (yName) )
00435 {
00436
00437
00438
00439
00440 tVariableMap.bind (yName, TVariableString (yValue, TVariableString::eFile));
00441 }
00442 else
00443 {
00444 if ( tVariableMap [yName].type() == TVariableString::eFile )
00445 {
00446 tVariableMap [yName] = yValue;
00447 }
00448 else
00449 {
00450 TString yMessage = Format ( "variable '%s' already has another type" ,
00451 yName.c_str() );
00452
00453 throw TBadInstantiateSyntaxException (yMessage, __FILE__, __LINE__);
00454 }
00455 }
00456 }
00457 else if ( yType == "OPTIONAL" )
00458 {
00459
00460
00461
00462 if ( tVariableMap.end() == tVariableMap.find (yName) )
00463 {
00464
00465
00466
00467
00468 tVariableMap.bind (yName, TVariableString (yValue, TVariableString::eOptional));
00469 }
00470 else
00471 {
00472 if ( tVariableMap [yName].type() == TVariableString::eOptional )
00473 {
00474 tVariableMap [yName] = yValue;
00475 }
00476 else
00477 {
00478 TString yMessage = Format ( "variable '%s' already has another type" ,
00479 yName.c_str() );
00480
00481 throw TBadInstantiateSyntaxException (yMessage, __FILE__, __LINE__);
00482 }
00483 }
00484 }
00485 else
00486 {
00487
00488
00489
00490 if ( tVariableMap.end() == tVariableMap.find (yName) )
00491 {
00492 tVariableMap.bind (yName, TVariableString (yValue));
00493 }
00494 else
00495 {
00496 if ( tVariableMap [yName].type() == TVariableString::eNormal )
00497 {
00498 tVariableMap [yName] = yValue;
00499 }
00500 else
00501 {
00502 TString yMessage = Format ( "variable '%s' already has another type" ,
00503 yName.c_str() );
00504
00505 throw TBadInstantiateSyntaxException (yMessage, __FILE__, __LINE__);
00506 }
00507 }
00508 }
00509 yName.erase();
00510 yValue.erase();
00511 yType.erase();
00512 PBCG_REMOVE_COMMENTS;
00513 }
00514 } while ( gFound );
00515 }
00516 tMatcher.scan (pkcDECLARE_EndTagPattern, NULL);
00517 PBCG_REMOVE_COMMENTS;
00518 }
00519
00520
00521
00522
00523 if ( !gUpdateOnly )
00524 {
00525
00526
00527
00528 rtSOURCE_ISTREAM >> tInstructionMap;
00529 }
00530 else
00531 {
00532
00533
00534
00535
00536 TInstructionMap::const_iterator I;
00537 TInstructionMap::const_iterator ktSourceInstructionEnd;
00538 TInstructionMap tSourceInstructionMap;
00539
00540
00541
00542
00543 rtSOURCE_ISTREAM >> tSourceInstructionMap;
00544
00545
00546
00547
00548 I = tSourceInstructionMap.begin();
00549 ktSourceInstructionEnd = tSourceInstructionMap.end();
00550 for (; ( I != ktSourceInstructionEnd ) ;++I)
00551 {
00553 TInstructionBody::TClauseMap::const_iterator J;
00554
00556 TInstructionBody::TClauseMap::iterator K;
00557
00559 TInstructionBody::TClauseMap::const_iterator ktSourceClauseEnd;
00560
00562 TInstructionBody::TClauseMap&
00563 rtTargetClauseMap = tInstructionMap [I->first].tClauseMap;
00564
00565
00566
00567
00568 J = I->second.tClauseMap.begin();
00569 ktSourceClauseEnd = I->second.tClauseMap.end();
00570 for (; ( J != ktSourceClauseEnd ) ;++J)
00571 {
00572 const TClauseTagString& rktSourceClauseTag = J->first;
00573
00574 if ( !rktSourceClauseTag.hasTarget() )
00575 {
00576
00577
00578
00579
00580
00581
00582
00583 TClauseTagString yTargetClauseTag;
00584 TClauseBodyString yTargetClauseBody;
00585
00586 K = rtTargetClauseMap.find (rktSourceClauseTag);
00587 if ( K == rtTargetClauseMap.end() )
00588 {
00589 TString yMessage =
00590 Format ( "clause '%s' in instruction '%s' is not defined in parent CDMLs" ,
00591 rktSourceClauseTag.c_str() ,
00592 I->first.c_str() );
00593
00594 throw TBadInstantiateSyntaxException (yMessage, __FILE__, __LINE__);
00595 }
00596
00597
00598
00599
00600 yTargetClauseTag = K->first;
00601 yTargetClauseBody = K->second;
00602 rtTargetClauseMap.erase (K);
00603 yTargetClauseTag.overloadFrom (rktSourceClauseTag);
00604 yTargetClauseBody = J->second;
00605 rtTargetClauseMap.bind (yTargetClauseTag, yTargetClauseBody);
00606 }
00607 else
00608 {
00609 K = rtTargetClauseMap.find (rktSourceClauseTag);
00610 if ( K == rtTargetClauseMap.end() )
00611 {
00612
00613
00614
00615 rtTargetClauseMap.bind (rktSourceClauseTag, J->second);
00616 }
00617 else
00618 {
00619
00620
00621
00622
00623
00624
00625
00626 TClauseTagString yTargetClauseTag = K->first;
00627 TClauseBodyString yTargetClauseBody = K->second;
00628
00629 rtTargetClauseMap.erase (K);
00630 yTargetClauseTag.overloadFrom (rktSourceClauseTag);
00631 rtTargetClauseMap.bind (yTargetClauseTag, yTargetClauseBody);
00632 }
00633 }
00634 }
00635 }
00636 }
00637 PBCG_REMOVE_COMMENTS;
00638
00639
00640
00641
00642 tMatcher.scan (pkcCDML_EndTagPattern, NULL);
00643 PBCG_REMOVE_COMMENTS;
00644
00645 # undef PBCG_REMOVE_COMMENTS
00646
00647 }
00648
00649
00650
00651
00652
00653
00654 const mpcl::text::codegen::TStringToVariableMap& mpcl::text::codegen::TPatternBasedCodeGenerator::
00655 variables (void) const
00656 {
00657
00658 return tVariableMap;
00659
00660 }
00661
00662
00663 const mpcl::text::codegen::TClauseBodyString& mpcl::text::codegen::TPatternBasedCodeGenerator::
00664 codePatternFor ( const char* pkcINSTRUCTION_NAME ,
00665 const char* pkcCLAUSE_NAME ) const
00666 {
00667
00668 TInstructionMap::const_iterator ktIter = tInstructionMap.find (pkcINSTRUCTION_NAME);
00669
00670 if ( ktIter == tInstructionMap.end() )
00671 {
00672 TString yMessage;
00673
00674 yMessage = Format ("instruction '%s' not found", pkcINSTRUCTION_NAME);
00675 throw TNotFoundException (yMessage, __FILE__, __LINE__);
00676 }
00677 return ktIter->second.clauseBody (pkcCLAUSE_NAME);
00678
00679 }
00680
00681
00682 mpcl::text::codegen::TInstructionBody& mpcl::text::codegen::TPatternBasedCodeGenerator::
00683 instruction (const char* pkcINSTRUCTION_NAME)
00684 {
00685
00686 TInstructionMap::iterator tIter = tInstructionMap.find (pkcINSTRUCTION_NAME);
00687
00688 if ( tIter == tInstructionMap.end() )
00689 {
00690 TString yMessage;
00691
00692 yMessage = Format ("instruction '%s' not found", pkcINSTRUCTION_NAME);
00693 throw TNotFoundException (yMessage, __FILE__, __LINE__);
00694 }
00695 return tIter->second;
00696
00697 }
00698
00699
00700 const mpcl::text::codegen::TInstructionBody& mpcl::text::codegen::TPatternBasedCodeGenerator::
00701 instruction (const char* pkcINSTRUCTION_NAME) const
00702 {
00703
00704 TInstructionMap::const_iterator ktIter = tInstructionMap.find (pkcINSTRUCTION_NAME);
00705
00706 if ( ktIter == tInstructionMap.end() )
00707 {
00708 TString yMessage;
00709
00710 yMessage = Format ("instruction '%s' not found", pkcINSTRUCTION_NAME);
00711 throw TNotFoundException (yMessage, __FILE__, __LINE__);
00712 }
00713 return ktIter->second;
00714
00715 }
00716
00717
00718 bool mpcl::text::codegen::TPatternBasedCodeGenerator::
00719 existsClause (const char* pkcINSTRUCTION_NAME, const char* pkcCLAUSE_NAME) const
00720 {
00721
00722 bool gSuccess = false;
00723 TInstructionMap::const_iterator tIter = tInstructionMap.find (pkcINSTRUCTION_NAME);
00724
00725 if ( tInstructionMap.end() != tIter )
00726 {
00727 gSuccess = tIter->second.existsClause (pkcCLAUSE_NAME);
00728 }
00729 return gSuccess;
00730
00731 }
00732
00733
00734 void mpcl::text::codegen::TPatternBasedCodeGenerator::
00735 write (std::basic_ostream<char_type, traits_type>& rtTARGET_OSTREAM) const
00736 {
00737
00738 rtTARGET_OSTREAM << "<!doctype cdml";
00739 if ( !yPublic.empty() )
00740 {
00741 rtTARGET_OSTREAM << " public \"" << yPublic << "\"";
00742 }
00743 else if ( !ySystem.empty() )
00744 {
00745 rtTARGET_OSTREAM << " system \"" << ySystem << "\"";
00746 }
00747 rtTARGET_OSTREAM << ">\n<cdml target=\"" << yTarget << "\"";
00748 if ( !yInherit.empty() )
00749 {
00750 rtTARGET_OSTREAM << " inherit=\"" << yInherit << '"';
00751 }
00752 rtTARGET_OSTREAM << ">\n";
00753 if ( !yDescription.empty() )
00754 {
00755 rtTARGET_OSTREAM << "<desc>\n" << yDescription << "\n</desc>\n";
00756 }
00757 if ( !tVariableMap.empty() )
00758 {
00759 TStringToVariableMap::const_iterator ktIter = tVariableMap.begin();
00760 TStringToVariableMap::const_iterator ktEnd = tVariableMap.end();
00761
00762 rtTARGET_OSTREAM << "<declare>\n";
00763 for (; ( ktIter != ktEnd ) ;++ktIter)
00764 {
00765 rtTARGET_OSTREAM << "<variable name=\"" << ktIter->first << "\"";
00766 switch (ktIter->second.type())
00767 {
00768 case TVariableString::eNormal:
00769 {
00770 rtTARGET_OSTREAM << " type=normal";
00771 break;
00772 }
00773 case TVariableString::eFile:
00774 {
00775 rtTARGET_OSTREAM << " type=file";
00776 break;
00777 }
00778 case TVariableString::eOptional:
00779 {
00780 rtTARGET_OSTREAM << " type=optional";
00781 break;
00782 }
00783 }
00784 rtTARGET_OSTREAM << ">" << ktIter->second << "</variable>\n";
00785 }
00786 rtTARGET_OSTREAM << "</declare>\n";
00787 }
00788 rtTARGET_OSTREAM << tInstructionMap;
00789 rtTARGET_OSTREAM << "</cdml>\n";
00790
00791 }