cmCableClassSet.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. /*=========================================================================
  2. Program: Insight Segmentation & Registration Toolkit
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Insight Consortium. All rights reserved.
  8. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmCableClassSet.h"
  14. /**
  15. * Add to the set of required sources to define the class.
  16. */
  17. void cmCableClass::AddSources(const Sources& sources)
  18. {
  19. for(Sources::const_iterator s = sources.begin(); s != sources.end(); ++s)
  20. {
  21. m_Sources.insert(*s);
  22. }
  23. }
  24. /**
  25. * Add to the set of required sources to define the class.
  26. */
  27. void cmCableClass::AddSource(const char* source)
  28. {
  29. m_Sources.insert(source);
  30. }
  31. /**
  32. * The destructor frees all the cmCableClass instances in the set.
  33. */
  34. cmCableClassSet::~cmCableClassSet()
  35. {
  36. for(CableClassMap::const_iterator i = m_CableClassMap.begin();
  37. i != m_CableClassMap.end(); ++i)
  38. {
  39. delete i->second;
  40. }
  41. }
  42. /**
  43. * Add a class to the set.
  44. * Automatically replace ">>" with "> >" to prevent template class name
  45. * problems after replacements.
  46. */
  47. void cmCableClassSet::AddClass(const char* in_name,
  48. cmCableClass* cableClass)
  49. {
  50. cmStdString name = in_name;
  51. for(cmStdString::size_type pos = name.find(">>");
  52. pos != cmStdString::npos; pos = name.find(">>", pos+2))
  53. {
  54. name.replace(pos, 2, "> >");
  55. }
  56. m_CableClassMap.insert(CableClassMap::value_type(name, cableClass));
  57. }
  58. /**
  59. * Add a source to every class in the set. This should only be done after
  60. * all classes have been inserted.
  61. */
  62. void cmCableClassSet::AddSource(const char* name)
  63. {
  64. for(CableClassMap::iterator c = m_CableClassMap.begin();
  65. c != m_CableClassMap.end(); ++c)
  66. {
  67. c->second->AddSource(name);
  68. }
  69. }
  70. /**
  71. * Get the size of the internal CableClassMap used to store the set.
  72. */
  73. unsigned int cmCableClassSet::Size() const
  74. {
  75. return m_CableClassMap.size();
  76. }
  77. /**
  78. * Get a begin iterator to the internal CableClassMap used to store the
  79. * set.
  80. */
  81. cmCableClassSet::CableClassMap::const_iterator cmCableClassSet::Begin() const
  82. {
  83. return m_CableClassMap.begin();
  84. }
  85. /**
  86. * Get an end iterator to the internal CableClassMap used to store the
  87. * set.
  88. */
  89. cmCableClassSet::CableClassMap::const_iterator cmCableClassSet::End() const
  90. {
  91. return m_CableClassMap.end();
  92. }
  93. /**
  94. * A utility class to generate element combinations from all possible
  95. * substitutions of set members into a $ token.
  96. */
  97. class ElementCombinationGenerator
  98. {
  99. public:
  100. ElementCombinationGenerator(const char* in_element, cmMakefile* in_makefile,
  101. cmCableClassSet* out_set):
  102. m_Makefile(in_makefile), m_OutputSet(out_set)
  103. {
  104. this->ParseInputElement(in_element);
  105. }
  106. ~ElementCombinationGenerator();
  107. void Generate();
  108. public:
  109. /**
  110. * Represent a substitution.
  111. */
  112. class Substitution
  113. {
  114. public:
  115. Substitution() {}
  116. void Bind(const cmStdString& in_code, const cmCableClass* in_class)
  117. {
  118. m_Code = in_code;
  119. m_Class = in_class;
  120. }
  121. const cmCableClass* GetClass() const
  122. { return m_Class; }
  123. const cmStdString& GetCode() const
  124. { return m_Code; }
  125. private:
  126. /**
  127. * The cmCableClass associated with this substitution.
  128. */
  129. const cmCableClass* m_Class;
  130. /**
  131. * The code to be used for the substitution.
  132. */
  133. cmStdString m_Code;
  134. };
  135. /**
  136. * Interface to the parts of an input string of code, possibly with
  137. * $SomeSetName tokens in it. An indivitual Portion will be either
  138. * a StringPortion, which has no substitutions, or a ReplacePortion,
  139. * which has only a substitution, and no hard-coded text.
  140. *
  141. * This is used by cmCableClassSet::GenerateElementCombinations() to
  142. * hold the pieces of a string after the set substitution tokens
  143. * have been extracted.
  144. */
  145. class Portion
  146. {
  147. public:
  148. /**
  149. * Get the C++ code corresponding to this Portion of a string.
  150. */
  151. virtual cmStdString GetCode() const =0;
  152. /**
  153. * Get the class corresponding to this Portion of a string. This is NULL
  154. * for StringPortion, and points to a cmCableClass for ReplacePortion.
  155. */
  156. virtual const cmCableClass* GetClass() const
  157. { return NULL; }
  158. virtual ~Portion() {}
  159. };
  160. /**
  161. * Represent a hard-coded part of an input string, that has no substitutions
  162. * in it. The tag for this part of a string is always empty.
  163. */
  164. class StringPortion: public Portion
  165. {
  166. public:
  167. StringPortion(const cmStdString& in_code): m_Code(in_code) {}
  168. virtual cmStdString GetCode() const
  169. { return m_Code; }
  170. virtual const cmCableClass* GetClass() const
  171. { return NULL; }
  172. virtual ~StringPortion() {}
  173. private:
  174. /**
  175. * Hold this Portion's contribution to the output string.
  176. */
  177. cmStdString m_Code;
  178. };
  179. /**
  180. * Represent the "$SomeSetName" portion of an input string. This has a
  181. * reference to the Substitution holding the real output to generate.
  182. */
  183. class ReplacePortion;
  184. friend class ReplacePortion;
  185. class ReplacePortion: public Portion
  186. {
  187. public:
  188. ReplacePortion(const Substitution& in_substitution):
  189. m_Substitution(in_substitution) {}
  190. virtual cmStdString GetCode() const
  191. { return m_Substitution.GetCode(); }
  192. virtual const cmCableClass* GetClass() const
  193. { return m_Substitution.GetClass(); }
  194. virtual ~ReplacePortion() {}
  195. private:
  196. /**
  197. * Refer to the real Substitution for this Portion's contribution.
  198. */
  199. const Substitution& m_Substitution;
  200. };
  201. typedef std::list<Portion*> Portions;
  202. typedef std::map<const cmCableClassSet*, Substitution*> Substitutions;
  203. /**
  204. * The makefile in which to lookup set names.
  205. */
  206. cmMakefile* m_Makefile;
  207. /**
  208. * The cmCableClassSet instance to be filled with combinations.
  209. */
  210. cmCableClassSet* m_OutputSet;
  211. /**
  212. * The class name parsed out for this element, before set expansion.
  213. */
  214. cmStdString m_ClassName;
  215. /**
  216. * The tag name parsed out or generated for this element.
  217. */
  218. cmStdString m_Tag;
  219. /**
  220. * The set of sources parsed out for this element.
  221. */
  222. cmCableClass::Sources m_Sources;
  223. /**
  224. * The parts of the input string after parsing of the tokens.
  225. */
  226. Portions m_Portions;
  227. /**
  228. * Map from substitution's Set to actual Substitution.
  229. */
  230. Substitutions m_Substitutions;
  231. private:
  232. void Generate(Substitutions::const_iterator);
  233. void ParseInputElement(const char*);
  234. void SplitClassName();
  235. cmStdString ParseSetName(cmStdString::const_iterator&,
  236. cmStdString::const_iterator) const;
  237. void FindTagSource();
  238. bool GenerateTag(const cmStdString&);
  239. };
  240. /**
  241. * Destructor frees portions and substitutions that were allocated by
  242. * constructor.
  243. */
  244. ElementCombinationGenerator
  245. ::~ElementCombinationGenerator()
  246. {
  247. // Free the string portions that were allocated.
  248. for(Portions::iterator portion = m_Portions.begin();
  249. portion != m_Portions.end(); ++portion)
  250. {
  251. delete *portion;
  252. }
  253. // Free the substitutions that were allocated.
  254. for(Substitutions::iterator sub = m_Substitutions.begin();
  255. sub != m_Substitutions.end(); ++sub)
  256. {
  257. delete sub->second;
  258. }
  259. }
  260. /**
  261. * Generate all element combinations possible with the set of
  262. * substitutions available. The given output set is filled with
  263. * all the combinations.
  264. */
  265. void
  266. ElementCombinationGenerator
  267. ::Generate()
  268. {
  269. // If there are no substitutions to be made, just generate this
  270. // single combination.
  271. if(m_Substitutions.empty())
  272. {
  273. cmCableClass* cableClass = new cmCableClass(m_Tag);
  274. cableClass->AddSources(m_Sources);
  275. m_OutputSet->AddClass(m_ClassName.c_str(), cableClass);
  276. return;
  277. }
  278. // We must generate all combinations of substitutions.
  279. // Begin the recursion with the first substitution.
  280. this->Generate(m_Substitutions.begin());
  281. }
  282. /**
  283. * Internal helper to Generate() which generates all
  284. * combinations in a recursive, depth-first order.
  285. */
  286. void
  287. ElementCombinationGenerator
  288. ::Generate(Substitutions::const_iterator substitution)
  289. {
  290. // Test our position in the list of substitutions to be bound.
  291. if(substitution == m_Substitutions.end())
  292. {
  293. // All substitutions have been prepared. Generate this combination.
  294. cmStdString tag = m_Tag;
  295. cmStdString code = "";
  296. // The set of sources for the generated combination. It will
  297. // always include the sources parsed from the original element
  298. // string.
  299. cmCableClass::Sources sources = m_Sources;
  300. // Put together all the pieces, with substitutions.
  301. for(Portions::const_iterator i = m_Portions.begin();
  302. i != Portions::const_iterator(m_Portions.end()); ++i)
  303. {
  304. // See if there is a class associated with this portion.
  305. const cmCableClass* curClassPortion = (*i)->GetClass();
  306. if(curClassPortion)
  307. {
  308. // Append the tag from the class portion.
  309. tag.append(curClassPortion->GetTag());
  310. // Include any sources needed by the class in this combination's set.
  311. for(cmCableClass::Sources::const_iterator
  312. s = curClassPortion->SourcesBegin();
  313. s != curClassPortion->SourcesEnd(); ++s)
  314. {
  315. sources.insert(*s);
  316. }
  317. }
  318. // Append the portion's code to this combination's code.
  319. code.append((*i)->GetCode());
  320. }
  321. // Add this combination to the output set.
  322. cmCableClass* cableClass = new cmCableClass(tag);
  323. cableClass->AddSources(sources);
  324. m_OutputSet->AddClass(code.c_str(), cableClass);
  325. }
  326. else
  327. {
  328. // Get the set for this substitution.
  329. const cmCableClassSet* set = substitution->first;
  330. if(set == m_OutputSet)
  331. {
  332. // We cannot iterate over the set currently being defined.
  333. cmSystemTools::Error("CABLE class set self-reference!");
  334. return;
  335. }
  336. // Prepare an iterator to the next substitution.
  337. Substitutions::const_iterator nextSubstitution = substitution;
  338. ++nextSubstitution;
  339. // We must iterate over all possible values for this substitution.
  340. for(cmCableClassSet::CableClassMap::const_iterator element = set->Begin();
  341. element != set->End(); ++element)
  342. {
  343. // Bind the substitution to this element.
  344. substitution->second->Bind(element->first, element->second);
  345. // Move on to the next substitution.
  346. this->Generate(nextSubstitution);
  347. }
  348. }
  349. }
  350. /**
  351. * Called from constructor. Parses the given string to extract the
  352. * class information specified.
  353. *
  354. * The format of the string is
  355. * [tag:]class_name[;source1;source2;...]
  356. */
  357. void
  358. ElementCombinationGenerator
  359. ::ParseInputElement(const char* in_element)
  360. {
  361. // A regular expression to match the tagged element specification.
  362. cmRegularExpression taggedElement =
  363. "^([A-Za-z_0-9]*)[ \t]*:[ \t]*([^:].*|::.*)$";
  364. // A regular expression to match the element when more source files are given.
  365. cmRegularExpression sourcesRemain("^([^;]*);(.*)$");
  366. cmStdString elementWithoutTag;
  367. cmStdString sourceString;
  368. bool tagGiven = false;
  369. // See if the element was tagged, and if so, pull off the tag.
  370. if(taggedElement.find(in_element))
  371. {
  372. // A tag was given. Use it.
  373. tagGiven = true;
  374. m_Tag = taggedElement.match(1);
  375. elementWithoutTag = taggedElement.match(2);
  376. }
  377. else
  378. {
  379. // No tag was given. We will try to generate it later.
  380. elementWithoutTag = in_element;
  381. }
  382. // Separate the class name.
  383. if(sourcesRemain.find(elementWithoutTag.c_str()))
  384. {
  385. m_ClassName = sourcesRemain.match(1);
  386. sourceString = sourcesRemain.match(2);
  387. }
  388. else
  389. {
  390. m_ClassName = elementWithoutTag;
  391. }
  392. // Find any source files specified with the ";source" syntax.
  393. while(sourcesRemain.find(sourceString.c_str()))
  394. {
  395. m_Sources.insert(sourcesRemain.match(1));
  396. sourceString = sourcesRemain.match(2);
  397. }
  398. if(sourceString != "")
  399. {
  400. m_Sources.insert(sourceString);
  401. }
  402. // If no tag was given, try to generate one.
  403. if(!tagGiven)
  404. {
  405. if(!this->GenerateTag(m_ClassName))
  406. {
  407. cmSystemTools::Error("Cannot generate tag for class name: ",
  408. m_ClassName.c_str(),
  409. "\nPlease supply one with the \"tag:..\" syntax.");
  410. }
  411. }
  412. // If there is a .h with the name of the tag, add it as a source.
  413. this->FindTagSource();
  414. // Split the class name up into portions for the combination
  415. // generation method.
  416. this->SplitClassName();
  417. }
  418. /**
  419. * Parses the class name into portions. Plain text in the string is
  420. * held by a StringPortion, and a $ token for replacement is
  421. * represented by a ReplacePortion.
  422. */
  423. void
  424. ElementCombinationGenerator
  425. ::SplitClassName()
  426. {
  427. // Break the input code into blocks alternating between literal code and
  428. // set-substitution tokens (like $SomeSetName).
  429. cmStdString currentPortion = "";
  430. for(cmStdString::const_iterator c=m_ClassName.begin();
  431. c != m_ClassName.end(); ++c)
  432. {
  433. // Look for the '$' to mark the beginning of a token.
  434. if(*c != '$')
  435. {
  436. currentPortion.insert(currentPortion.end(), *c);
  437. }
  438. else
  439. {
  440. // If there is a portion of the string, record it.
  441. if(currentPortion.length() > 0)
  442. {
  443. m_Portions.push_back(new StringPortion(currentPortion));
  444. currentPortion = "";
  445. }
  446. // Skip over the '$' character.
  447. ++c;
  448. // Get element set name token.
  449. cmStdString setName = this->ParseSetName(c, m_ClassName.end());
  450. // We have a complete set name. Look it up in makefile's data
  451. // collection.
  452. cmData* d = m_Makefile->LookupData(setName.c_str());
  453. // This should be a dynamic_cast, but we don't want to require RTTI.
  454. cmCableClassSet* set = static_cast<cmCableClassSet*>(d);
  455. if(set)
  456. {
  457. // We have a valid set name. Prepare the substitution entry
  458. // for it.
  459. Substitution* sub;
  460. if(m_Substitutions.count(set) == 0)
  461. {
  462. sub = new Substitution();
  463. m_Substitutions[set] = sub;
  464. }
  465. else
  466. {
  467. sub = m_Substitutions[set];
  468. }
  469. m_Portions.push_back(new ReplacePortion(*sub));
  470. setName = "";
  471. }
  472. else
  473. {
  474. // Invalid set name. Complain.
  475. cmSystemTools::Error("Unknown name of CABLE class set: ",
  476. setName.c_str());
  477. }
  478. // Let the loop look at this character again.
  479. --c;
  480. }
  481. }
  482. // If there is a final portion of the string, record it.
  483. if(currentPortion.length() > 0)
  484. {
  485. m_Portions.push_back(new StringPortion(currentPortion));
  486. }
  487. }
  488. /**
  489. * Parse out the name of a Set specified after a $ in the element's string.
  490. * This is called with "c" pointing to the first character after the $,
  491. * and "end" equal to the string's end iterator.
  492. *
  493. * Returns the set name after parsing. "c" will point to the first
  494. * character after the end of the set name.
  495. */
  496. cmStdString
  497. ElementCombinationGenerator
  498. ::ParseSetName(cmStdString::const_iterator& c, cmStdString::const_iterator end) const
  499. {
  500. cmStdString setName = "";
  501. // Check for the $(setName) syntax.
  502. // If the first character after the '$' is a left paren, we scan for the
  503. // matching paren, and take everything in-between as the set name.
  504. if((c != end) && (*c == '('))
  505. {
  506. unsigned int depth = 1;
  507. ++c;
  508. while(c != end)
  509. {
  510. char ch = *c++;
  511. if(ch == '(') { ++depth; }
  512. else if(ch == ')') { --depth; }
  513. if(depth == 0) { break; }
  514. setName.insert(setName.end(), ch);
  515. }
  516. return setName;
  517. }
  518. // The $(setName) syntax was not used.
  519. // Look for all characters that can be part of a qualified C++
  520. // identifier.
  521. while(c != end)
  522. {
  523. char ch = *c;
  524. if(((ch >= 'a') && (ch <= 'z'))
  525. || ((ch >= 'A') && (ch <= 'Z'))
  526. || ((ch >= '0') && (ch <= '9'))
  527. || (ch == '_') || (ch == ':'))
  528. {
  529. setName.insert(setName.end(), ch);
  530. ++c;
  531. }
  532. else
  533. {
  534. break;
  535. }
  536. }
  537. return setName;
  538. }
  539. /**
  540. * After the tag for an element has been determined, but before
  541. * combination expansion is done, this is called to search for a
  542. * header file in the makefile's include path with the name of the
  543. * tag. This makes specifying lists of classes that are declared in
  544. * header files with their own name very convenient.
  545. */
  546. void ElementCombinationGenerator::FindTagSource()
  547. {
  548. // If there is no tag, don't bother with this step.
  549. if(m_Tag == "")
  550. {
  551. return;
  552. }
  553. // Get the makefile's include path.
  554. const std::vector<std::string>& includePath =
  555. m_Makefile->GetIncludeDirectories();
  556. // Search the path for a file called "(m_Tag).h".
  557. for(std::vector<std::string>::const_iterator dir = includePath.begin();
  558. dir != includePath.end(); ++dir)
  559. {
  560. cmStdString filePath = *dir;
  561. m_Makefile->ExpandVariablesInString(filePath);
  562. filePath += "/"+m_Tag+".h";
  563. if(cmSystemTools::FileExists(filePath.c_str()))
  564. {
  565. m_Sources.insert(m_Tag+".h");
  566. return;
  567. }
  568. }
  569. }
  570. /**
  571. * Given the string representing a set element, automatically generate
  572. * the element tag for it. This function determines how the output
  573. * language of all CABLE-generated wrappers will look.
  574. */
  575. bool ElementCombinationGenerator::GenerateTag(const cmStdString& element)
  576. {
  577. // Hold the regular expressions for matching against the element.
  578. cmRegularExpression regex;
  579. // If the element's code begins in a $, it is referring to a set name.
  580. // The set's elements have their own tags, so we don't need one.
  581. regex.compile("^[ \t]*\\$");
  582. if(regex.find(element))
  583. { m_Tag = ""; return true; }
  584. // Test for simple integer
  585. regex.compile("^[ \t]*([0-9]*)[ \t]*$");
  586. if(regex.find(element))
  587. {
  588. m_Tag = "_";
  589. m_Tag.append(regex.match(1));
  590. return true;
  591. }
  592. // Test for basic integer type
  593. regex.compile("^[ \t]*(unsigned[ ]|signed[ ])?[ \t]*(char|short|int|long|long[ ]long)[ \t]*$");
  594. if(regex.find(element))
  595. {
  596. m_Tag = "_";
  597. if(regex.match(1) == "unsigned ")
  598. { m_Tag.append("u"); }
  599. if(regex.match(2) == "long long")
  600. { m_Tag.append("llong"); }
  601. else
  602. { m_Tag.append(regex.match(2)); }
  603. return true;
  604. }
  605. // Test for basic floating-point type
  606. regex.compile("^[ \t]*(long[ ])?[ \t]*(float|double)[ \t]*$");
  607. if(regex.find(element))
  608. {
  609. m_Tag = "_";
  610. if(regex.start(1) > 0 && regex.match(1) == "long ")
  611. {
  612. m_Tag.append("l");
  613. }
  614. m_Tag.append(regex.match(2));
  615. return true;
  616. }
  617. // Test for basic wide-character type
  618. regex.compile("^[ \t]*(wchar_t)[ \t]*$");
  619. if(regex.find(element))
  620. {
  621. m_Tag = "_wchar";
  622. return true;
  623. }
  624. // Test for type name (possibly with template arguments).
  625. regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)(<.*)?[ \t]*$");
  626. if(regex.find(element))
  627. {
  628. // The tag is the same as the type. If there were template arguments,
  629. // they are ignored since they may have their own tags.
  630. m_Tag = regex.match(1);
  631. return true;
  632. }
  633. // Test for a name with a single namespace qualifier.
  634. regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)::([A-Za-z_][A-Za-z0-9_]*)(<.*)?[ \t]*$");
  635. if(regex.find(element))
  636. {
  637. // The tag is the same as the namespace and type concatenated together.
  638. m_Tag = regex.match(1);
  639. m_Tag.append(regex.match(2));
  640. return true;
  641. }
  642. // We can't generate a tag.
  643. m_Tag = "";
  644. return false;
  645. }
  646. /**
  647. * Given an element in string form, parse out the information from it,
  648. * generate the combinations of set substitutions, and add all the
  649. * elements that result.
  650. */
  651. void cmCableClassSet::ParseAndAddElement(const char* in_element,
  652. cmMakefile* makefile)
  653. {
  654. // Create an object to handle the generation.
  655. ElementCombinationGenerator combinationGenerator(in_element, makefile, this);
  656. // Generate the combinations.
  657. combinationGenerator.Generate();
  658. }