1 /************************************************************************
2 ************************************************************************
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
24 /**********************************************************************
25 - lateq.cpp : the Lateq methods definition (FAUST project) -
26 - for automatic generation of documentation -
27 - "lateq" stands for "LaTeX equations" -
28 - The crucial method here is println -
32 17-10-2001 : (klass.cpp) implementation initiale (yo)
33 18-10-2001 : (klass.cpp) Ajout de getFreshID (yo)
34 02-11-2001 : (klass.cpp) Ajout de sous classes (yo)
35 06-11-2001 : (klass.cpp) modif impression des classes (yo)
36 16-08-2009 : (lateq.cpp) Creation de lateq depuis klass.cpp (kb)
37 2009-11-21 : (lateq.cpp) Remodelage et documentation doxygen (kb)
39 ***********************************************************************/
51 map
<string
, string
> gDocMathStringMap
;
52 set
<string
> gDocMathKeySet
;
54 static int getLateqIndex(const string
& s
);
55 static bool compLateqIndexes(const string
& s1
, const string
& s2
);
56 static void initDocMathKeySet();
60 inline std::string
to_string (const T
& t
)
68 /****************************************************************
69 Top-level "println" method (public).
70 *****************************************************************/
75 * Top-level method to print a whole set of compiled LaTeX formulas,
76 * corresponding to an <equation> faustdoc tag.
79 * These formulas must have been previously compiled,
80 * via the DocCompile class,
81 * and stored in Lateq fields as LaTeX strings.
83 void Lateq::println(ostream
& docout
)
85 /* 1. Make titles of sub-sets of formulas. */
86 string suchthat
= gDocMathStringMap
["suchthat"];
88 string sInputs
= makeItemTitle(fInputSigsFormulas
.size(), "inputsigtitle") + makeSignamesList(fInputSigsFormulas
, "");
89 string sOutputs
= makeItemTitle(fOutputSigsFormulas
.size(), "outputsigtitle") + makeSignamesList(fOutputSigsFormulas
, suchthat
);
90 string sConstants
= makeItemTitle(fConstSigsFormulas
.size(), "constsigtitle") + makeSignamesList(fConstSigsFormulas
, suchthat
);
92 vector
<list
<string
> > UISignamesVector
= makeUISignamesVector(fUISigsFormulas
);
93 string sUIElements
= makeItemTitle(fUISigsFormulas
.size(), "uisigtitle") + makeSignamesList(UISignamesVector
, suchthat
);
95 unsigned int internalSigsCount
= fParamSigsFormulas
.size() + fStoreSigsFormulas
.size() + fRecurSigsFormulas
.size() + fRDTblSigsFormulas
.size() + fRWTblSigsFormulas
.size() + fSelectSigsFormulas
.size() + fPrefixSigsFormulas
.size();
97 vector
<list
<string
> > internalSigsFormulasList
;
98 if( ! fParamSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fParamSigsFormulas
);
99 if( ! fStoreSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fStoreSigsFormulas
);
100 if( ! fRecurSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fRecurSigsFormulas
);
101 if( ! fRDTblSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fRDTblSigsFormulas
);
102 if( ! fRWTblSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fRWTblSigsFormulas
);
103 if( ! fSelectSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fSelectSigsFormulas
);
104 if( ! fPrefixSigsFormulas
.empty() ) internalSigsFormulasList
.push_back(fPrefixSigsFormulas
);
106 string sInternals
= makeItemTitle(internalSigsCount
, "intermedsigtitle") + makeSignamesList(internalSigsFormulasList
, suchthat
);
108 /* 2. Successively print each Lateq field containing LaTeX formulas, with a title. */
110 docout
<< endl
<< gDocMathStringMap
["lateqcomment"] << endl
;
111 docout
<< "\\begin{enumerate}" << endl
<< endl
;
113 printDGroup (sOutputs
, fOutputSigsFormulas
, docout
);
114 printOneLine (sInputs
, docout
);
115 const string outputsTitle
= "\\item " + sOutputs
+ "\\ $y_i$\\ " + gDocMathStringMap
["for"] + " $i \\in [1," + to_string(fOutputSigsFormulas
.size()) + "]$: ";
116 printHierarchy (sUIElements
, fUISigsFormulas
, docout
);
118 /* The "Internal signals" item gather several fields, like a "super-item"... */
119 if( internalSigsCount
> 0 ) {
120 docout
<< sInternals
;
122 fStoreSigsFormulas
.sort(compLateqIndexes
);
123 printDGroup ("", fParamSigsFormulas
, docout
);
124 printDGroup ("", fStoreSigsFormulas
, docout
);
125 printDGroup ("", fRecurSigsFormulas
, docout
);
126 printDGroup ("", fRDTblSigsFormulas
, docout
);
127 printMath ("", fRWTblSigsFormulas
, docout
);
128 printMath ("", fSelectSigsFormulas
, docout
);
129 printMath ("", fPrefixSigsFormulas
, docout
);
131 printDGroup (sConstants
, fConstSigsFormulas
, docout
);
133 docout
<< "\\end{enumerate}" << endl
<< endl
;
138 /****************************************************************
139 Item title making functions (public).
140 *****************************************************************/
143 string
Lateq::makeItemTitle(const unsigned int formulasListSize
, const string
& titleName
)
145 string item
= "\\item ";
147 /* Plural handling for titles of sub-sets of formulas. */
148 string title
= formulasListSize
> 1 ? gDocMathStringMap
[titleName
+ "2"] : gDocMathStringMap
[titleName
+ "1"];
154 string
Lateq::makeSigDomain(const list
<string
>& formulasList
)
157 string sigDomain
= "";
159 if (formulasList
.size() > 0) {
160 string firstEq
= *(formulasList
.begin());
161 signame
= getSigName(firstEq
);
163 if(formulasList
.size() > 1) {
164 sigDomain
= " $" + signame
+ "_i$ " + gDocMathStringMap
["for"] + " $i \\in [1," + to_string(formulasList
.size()) + "]$";
166 if(signame
== "x" || signame
== "y") {
167 sigDomain
= " $" + signame
+ "$"; ///< No indices for single input neither single output.
169 sigDomain
= " $" + signame
+ "_1$"; ///< Indices "1" for all other single signal.
173 sigDomain
= gDocMathStringMap
["emptyformulafield"];
179 string
Lateq::makeSignamesList(const list
<string
>& formulasList
, const string
& ending
)
181 if (formulasList
.size() > 0) {
182 return makeSigDomain(formulasList
) + " " + ending
;
184 return " (" + gDocMathStringMap
["emptyformulafield"] + ")";
189 string
Lateq::makeSignamesList(const vector
<list
<string
> >& formulasListsVector
, const string
& ending
)
191 if (formulasListsVector
.size() > 0) {
192 vector
<list
<string
> >::const_iterator it
;
193 string signames
= "";
195 for (it
= formulasListsVector
.begin(); it
!= formulasListsVector
.end(); ++it
) {
196 signames
+= sep
+ makeSigDomain(*it
);
197 (it
!= (formulasListsVector
.end() - 2)) ? sep
= ", " : sep
= " " + gDocMathStringMap
["and"] + " ";
199 return signames
+ " " + ending
;
201 return " (" + gDocMathStringMap
["emptyformulafield"] + ")";
206 string
Lateq::getSigName(const string
& s
)
211 found
= s
.find(" =");
212 if (found
!= string::npos
) { ///< Looking for a left member.
213 signame
= s
.substr (0, found
);
215 found
= s
.find("(t)");
216 if (found
!= string::npos
) { ///< Strip "(t)" argument if exists.
217 signame
= s
.substr (0, found
);
219 found
= signame
.find("[t]");
220 if (found
!= string::npos
) { ///< Strip "[t]" argument if exists (for tables).
221 signame
= s
.substr (0, found
);
223 found
= signame
.find_last_of("_");
224 if (found
!= string::npos
) { ///< Strip indice if exists.
225 signame
= signame
.substr (0, found
);
232 vector
<list
<string
> > Lateq::makeUISignamesVector(const multimap
<string
,string
>& field
)
234 map
<char,unsigned int> uiTypesMap
;
235 vector
<list
<string
> > uiSignamesVector
;
236 unsigned int vIndex
= 0;
238 multimap
<string
,string
>::const_iterator it
;
240 for (it
= field
.begin(); it
!= field
.end(); ++it
) {
241 char type
= getUISigType(it
->second
);
242 string signame
= getUISigName(it
->second
);
244 map
<char,unsigned int>::iterator uiTypesIt
;
245 uiTypesIt
= uiTypesMap
.find(type
);
246 if( uiTypesIt
!= uiTypesMap
.end()) {
247 uiSignamesVector
[uiTypesMap
[uiTypesIt
->second
]].push_back(signame
);
250 uiTypesMap
.insert(pair
<char,unsigned int>(type
, vIndex
));
251 list
<string
>* tmpList
= new(list
<string
>);
252 tmpList
->push_back(signame
);
253 uiSignamesVector
.push_back(*tmpList
);
257 return uiSignamesVector
;
261 string
Lateq::getUISigName(const string
& s
)
266 found
= s
.find("${u_");
267 if (found
!= string::npos
) { ///< Looking for a UI signal name "{u_?}_{i}(t)".
268 signame
= s
.substr (found
+1, 12);
275 char Lateq::getUISigType(const string
& s
)
280 found
= s
.find("${u_");
281 if (found
!= string::npos
) { ///< Looking for a UI signal name "{u_?}_{i}".
282 sigtype
= s
.at (found
+4);
290 /****************************************************************
291 Secondary printing methods (private).
292 *****************************************************************/
296 * Print a sorted list of input signals names ("x_i"),
297 * on a single line, separated by commas.
299 * @param[in] section The title to print for these formulas.
300 * @param[out] docout The LaTeX output file to print into.
302 void Lateq::printOneLine(const string
& section
, ostream
& docout
)
304 docout
<< section
<< endl
<< endl
;
309 * @brief Print a dgroup environment to auto-break long formulas.
312 * The "dgroup" and "dmath" environments belong to the "breqn" LaTeX package.
313 * The stared variants "dgroup*" and "dmath*" force unnumbered equations.
315 * @param[in] section The title to print for these formulas.
316 * @param[in] field The list of LaTeX formulas.
317 * @param[out] docout The LaTeX output file to print into.
319 void Lateq::printDGroup(const string
& section
, list
<string
>& field
, ostream
& docout
)
321 if (field
.size() > 0) {
322 docout
<< section
<< endl
;
323 tab(1,docout
); docout
<< "\\begin{dgroup*}" << endl
;
324 list
<string
>::const_iterator s
;
325 for (s
= field
.begin(); s
!= field
.end(); ++s
) {
326 tab(2,docout
); docout
<< "\\begin{" << "dmath*" << "}" << endl
;
327 tab(3,docout
); docout
<< "\t" << *s
<< endl
;
328 tab(2,docout
); docout
<< "\\end{" << "dmath*" << "}" << endl
;
330 tab(1,docout
); docout
<< "\\end{dgroup*}" << endl
;
337 * @brief Print formulas for user interface signals.
339 * @param[in] section The title to print for these formulas.
340 * @param[in] field This multimap contains pairs :
341 * 1. the path_string is printed as a sub-title item, when new;
342 * 2. each latex_string is printed as a preformated row of the
343 * supertabular environment (needed to handle long tables).
344 * @param[out] docout The LaTeX output file to print into.
347 * To decide when one should avoid to print an itemize environment,
348 * a "global" strategy is applied : in the particular case where
349 * ONLY empty paths were detected in the WHOLE container (all UIs
350 * are at the top level).
351 * In this particular case, UI strings are directly printed,
352 * and their (empty!) path is ignored...
353 * In the other case, we have to print an itemize environment
354 * and manage paths printing (empty AND non-empty paths) as items.
356 * @see DocCompiler::prepareIntervallicUI
357 * @see DocCompiler::prepareBinaryUI
359 void Lateq::printHierarchy(const string
& section
, multimap
<string
,string
>& field
, ostream
& docout
)
361 if (field
.size() > 0) {
362 docout
<< section
<< endl
;
364 bool hasSomePaths
= hasNotOnlyEmptyKeys(field
); ///< Manage itemize printing for pathnames.
365 unsigned int n
; ///< Manage latex indentation offset.
368 tab(0,docout
); docout
<< "\\begin{itemize}" << endl
;
374 multimap
<string
,string
>::iterator it
;
375 string uidir
= "improbable_starting_dirname";
376 bool startFlag
= true;
378 for (it
= field
.begin(); it
!= field
.end(); ++it
) {
379 /* Manage supertabular environment bounds and pathname printing. */
380 if (it
->first
!= uidir
) {
382 tab(n
+2,docout
); docout
<< "\\end{supertabular}" << endl
;
383 tab(n
+1,docout
); docout
<< "\\end{center}" << endl
;
388 /* Print the current pathname if new and if pathnames requested. */
389 if (it
->first
!= "") {
390 tab(n
+0,docout
); docout
<< "\\item \\textsf{" << it
->first
<< "}" << endl
;
392 tab(n
+0,docout
); docout
<< "\\item \\emph{" << gDocMathStringMap
["rootlevel"] << "}" << endl
;
395 tab(n
+1,docout
); docout
<< "\\begin{center}" << endl
;
396 tab(n
+2,docout
); docout
<< "\\begin{supertabular}{lll}" << endl
;
398 /* Print the current formula. */
399 tab(n
+3,docout
); docout
<< it
->second
<< endl
;
402 tab(n
+2,docout
); docout
<< "\\end{supertabular}" << endl
;
403 tab(n
+1,docout
); docout
<< "\\end{center}" << endl
;
405 tab(n
+0,docout
); docout
<< "\\end{itemize}" << endl
;
413 * @brief Print formulas for select2, select3 and prefix signals.
415 * @param[in] section The title to print for these formulas.
416 * @param[in] field The list of LaTeX arrays (for braces with two lines).
417 * @param[out] docout The LaTeX output file to print into.
419 * @see DocCompiler::generateSelect2
420 * @see DocCompiler::generateSelect3
421 * @see DocCompiler::generatePrefix
423 void Lateq::printMath(const string
& section
, list
<string
>& field
, ostream
& docout
)
425 if (field
.size() > 0) {
427 docout
<< "\\begin{displaymath}" << endl
;
428 list
<string
>::iterator s
;
429 for (s
= field
.begin(); s
!= field
.end(); ++s
) {
430 docout
<< *s
<< endl
;
432 docout
<< "\\end{displaymath}" << endl
;
438 /** Simple handling of indentation. */
439 void Lateq::tab (int n
, ostream
& docout
) const
441 while (n
--) docout
<< '\t';
446 * @brief Find out whether all keys of the multimap are empty or not.
449 * Check that some UIs have a path (non empty).
451 * In other other words :
452 * Check that all UIs are not at top-level.
454 bool Lateq::hasNotOnlyEmptyKeys(multimap
<string
,string
>& mm
)
456 typedef multimap
<string
,string
>::iterator MMIT
;
457 pair
<MMIT
,MMIT
> range
;
458 range
= mm
.equal_range(""); ///< Look for pairs with empty keys.
459 bool hasOnlyEmptyPaths
= (range
.first
== mm
.begin()) && (range
.second
== mm
.end());
460 return !hasOnlyEmptyPaths
;
466 * Dispatch initialization of autodoc container.
474 /****************************************************************
475 Internal static functions.
476 *****************************************************************/
480 * Compare indexes of two LaTeX strings,
481 * for the sort() method applied on list<string> fields.
483 static bool compLateqIndexes(const string
& s1
, const string
& s2
)
485 return getLateqIndex(s1
) < getLateqIndex(s2
);
490 * Find out the index of signals in LaTeX signal definition strings,
491 * between the first "_{" and "}" patterns.
493 * @param[in] s A LaTeX string to parse.
494 * @return <int> The index found, as an integer.
496 static int getLateqIndex(const string
& s
)
503 if (p1
==string::npos
) {
504 cerr
<< "Error : getLateqIndex found no \"{_\" substring.\n";
508 p2
= s
.find("}", p1
);
509 if (p2
==string::npos
) {
510 cerr
<< "Error : getLateqIndex found no \"}\" substring\n.";
514 sIndex
= s
.substr (p1
, p2
);
516 return atoi(sIndex
.c_str());
521 * Initialize gDocMathKeySet, a set containing all the keywords.
523 static void initDocMathKeySet()
525 gDocMathKeySet
.insert("inputsigtitle1");
526 gDocMathKeySet
.insert("inputsigtitle2");
527 gDocMathKeySet
.insert("outputsigtitle1");
528 gDocMathKeySet
.insert("outputsigtitle2");
529 gDocMathKeySet
.insert("constsigtitle1");
530 gDocMathKeySet
.insert("constsigtitle2");
531 gDocMathKeySet
.insert("uisigtitle1");
532 gDocMathKeySet
.insert("uisigtitle2");
533 gDocMathKeySet
.insert("intermedsigtitle1");
534 gDocMathKeySet
.insert("intermedsigtitle2");
535 gDocMathKeySet
.insert("lateqcomment");
536 gDocMathKeySet
.insert("emptyformulafield");
537 gDocMathKeySet
.insert("defaultvalue");
538 gDocMathKeySet
.insert("suchthat");
539 gDocMathKeySet
.insert("and");
540 gDocMathKeySet
.insert("for");
541 gDocMathKeySet
.insert("rootlevel");
543 gDocMathKeySet
.insert("dgmcaption");