1 /************************************************************************
2 ************************************************************************
4 Copyright (C) 2009 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 ******************************************************************************
28 The Documentator Language
31 ******************************************************************************
32 *****************************************************************************/
37 * @author Karim Barkati and Yann Orlarey
40 * @brief Implementation of documentation trees support and printing.
63 #include "errormsg.hh"
64 #include "doc_Text.hh"
65 #include "sigprint.hh"
66 #include "propagate.hh"
67 #include "enrobage.hh"
68 #include "drawschema.hh"
70 #include "simplify.hh"
71 #include "privatise.hh"
72 #include "recursivness.hh"
73 #include "sourcereader.hh"
75 #include "doc_compile.hh"
76 #include "doc_lang.hh"
77 #include "doc_notice.hh"
78 #include "doc_autodoc.hh"
79 #include "compatibility.hh"
83 #define MAXIDCHARS 5 ///< max numbers (characters) to represent ids (e.g. for directories).
88 /*****************************************************************************
89 Globals and prototyping
90 *****************************************************************************/
92 extern Tree gExpandedDefList
;
93 extern map
<Tree
, set
<Tree
> > gMetaDataSet
;
94 extern map
<string
, string
> gDocMetadatasStringMap
;
95 extern map
<string
, string
> gDocMathStringMap
;
96 extern bool gDetailsSwitch
;
97 extern bool gStripDocSwitch
;
98 extern string gFaustDirectory
;
99 extern string gFaustSuperDirectory
;
100 extern string gFaustSuperSuperDirectory
;
101 extern string gMasterDocument
;
102 extern string gMasterName
;
103 extern SourceReader gReader
;
105 extern string gDocName
; ///< Contains the filename for out documentation.
106 static const char* gDocDevSuffix
; ///< ".tex" (or .??? - used to choose output device).
107 static string gCurrentDir
; ///< Room to save current directory name.
108 static const string gLatexheaderfilename
= "latexheader.tex";
110 vector
<Tree
> gDocVector
; ///< Contains <mdoc> parsed trees: DOCTXT, DOCEQN, DOCDGM.
112 static struct tm gCompilationDate
;
114 bool gLstDependenciesSwitch
= true; ///< mdoc listing management.
115 bool gLstMdocTagsSwitch
= true; ///< mdoc listing management.
116 bool gLstDistributedSwitch
= true; ///< mdoc listing management.
118 enum { langEN
, langFR
, langIT
};
121 /* Printing functions */
122 static void printlatexheader(istream
& latexheader
, const string
& faustversion
, ostream
& docout
);
123 static void printfaustlistings(ostream
& docout
);
124 static void printfaustlisting(string
& path
, ostream
& docout
);
125 static void printlatexfooter(ostream
& docout
);
126 static void printdoccontent(const char* svgTopDir
, const vector
<Tree
>& docVector
, const string
& faustversion
, ostream
& docout
);
127 static void printfaustdocstamp(const string
& faustversion
, ostream
& docout
);
128 static void printDocEqn(Lateq
* ltq
, ostream
& docout
);
129 static void printDocDgm(const Tree expr
, const char* svgTopDir
, ostream
& docout
, int i
);
130 static void printDocMetadata(const Tree expr
, ostream
& docout
);
132 /* Primary sub-functions for <equation> handling */
133 static void prepareDocEqns( const vector
<Tree
>& docBoxes
, vector
<Lateq
*>& docCompiledEqnsVector
); ///< Caller function.
134 static void collectDocEqns( const vector
<Tree
>& docBoxes
, vector
<Tree
>& eqBoxes
); ///< step 0. Feed a vector.
135 static void mapEvalDocEqn( const vector
<Tree
>& eqBoxes
, const Tree
& env
, vector
<Tree
>& evalEqBoxes
); ///< step 1. Evaluate boxes.
136 static void mapGetEqName( const vector
<Tree
>& evalEqBoxes
, vector
<string
>& eqNames
); ///< step 2. Get boxes name.
137 static void calcEqnsNicknames( const vector
<string
>& eqNames
, vector
<string
>& eqNicknames
); ///< step 3. Calculate nicknames.
138 static void mapPrepareEqSig( const vector
<Tree
>& evalEqBoxes
, vector
<int>& eqInputs
, vector
<int>& eqOutputs
, vector
<Tree
>& eqSigs
); ///< step 4&5. Propagate and prepare signals.
139 static void mapSetSigNickname( const vector
<string
>& eqNicknames
, const vector
<int>& eqInputs
, const vector
<Tree
>& eqSigs
); ///< step 6. Set signals nicknames.
140 static void collectEqSigs( const vector
<Tree
>& eqSigs
, Tree
& superEqList
); ///< step 7. Collect all signals in a superlist.
141 static void annotateSuperList( DocCompiler
* DC
, Tree superEqList
); ///< step 8. Annotate superlist.
142 //static void calcAndSetLtqNames( Tree superEqList ); ///< step 9.
143 static void mapCompileDocEqnSigs( const vector
<Tree
>& eqSigs
, const vector
<int>& eqInputs
, const vector
<int>& eqOutputs
, DocCompiler
* DC
, vector
<Lateq
*>& docCompiledEqnsVector
); ///< step 10. Compile equations.
145 /* Secondary sub-functions for <equation> handling */
146 static string
calcNumberedName(const char* base
, int i
);
147 static void getBoxInputsAndOutputs(const Tree t
, int& numInputs
, int& numOutputs
);
148 static string
calcDocEqnInitial(const string s
);
150 /* Notice related functions */
151 static void initCompilationDate();
152 static struct tm
* getCompilationDate();
154 /* Files functions */
155 static int cholddir ();
156 static int mkchdir(const char* dirname
);
157 static int makedir(const char* dirname
);
158 static void getCurrentDir();
159 static istream
* openArchFile (const string
& filename
);
160 static char* legalFileName(const Tree t
, int n
, char* dst
);
161 static string
rmExternalDoubleQuotes(const string
& s
);
162 static void copyFaustSources(const char* projname
, const vector
<string
>& pathnames
);
163 vector
<string
>& docCodeSlicer(const string
& faustfile
, vector
<string
>& codeSlices
);
164 static void printdocCodeSlices(const string
& code
, ostream
& docout
);
165 static bool doesFileBeginWithCode(const string
& faustfile
);
167 //static void declareAutoDoc();
171 /*****************************************************************************
172 Types of Documentation Elements
173 *****************************************************************************/
175 Sym DOCTXT
= symbol ("DocTxt");
176 Tree
docTxt(const char* name
) { return tree( DOCTXT
, tree(symbol(name
)) ); }
177 bool isDocTxt(Tree t
) { return t
->node() == Node(DOCTXT
); }
178 bool isDocTxt(Tree t0
, const char** str
)
181 if ( isTree(t0
, DOCTXT
, t1
) && isSym(t1
->node(), &s
) ) {
189 Sym DOCEQN
= symbol ("DocEqn");
190 Tree
docEqn(Tree x
) { return tree(DOCEQN
, x
); }
191 bool isDocEqn(Tree t
, Tree
& x
) { return isTree(t
, DOCEQN
, x
); }
193 Sym DOCDGM
= symbol ("DocDgm");
194 Tree
docDgm(Tree x
) { return tree(DOCDGM
, x
); }
195 bool isDocDgm(Tree t
, Tree
& x
) { return isTree(t
, DOCDGM
, x
); }
197 Sym DOCNTC
= symbol ("DocNtc");
198 Tree
docNtc() { return tree(DOCNTC
); }
199 bool isDocNtc(Tree t
) { return isTree(t
, DOCNTC
); }
201 Sym DOCLST
= symbol ("DocLst");
202 Tree
docLst() { return tree(DOCLST
); }
203 bool isDocLst(Tree t
) { return isTree(t
, DOCLST
); }
205 Sym DOCMTD
= symbol ("DocMtd");
206 Tree
docMtd(Tree x
) { return tree(DOCMTD
, x
); }
207 bool isDocMtd(Tree t
, Tree
& x
) { return isTree(t
, DOCMTD
, x
); }
209 //string getDocTxt(Tree t) { return hd(t)->branch(0); }
213 /*****************************************************************************
214 Main Printing Function for the Documentation
215 *****************************************************************************/
219 * @brief The entry point to generate faust doc files.
221 * The entry point to generate the output LaTeX file, stored in the directory "<projname>-math/".
222 * This file eventually references images for diagrams, generated in SVG subdirectories.
223 * The device system was adapted from drawSchema's device system.
225 * @param[in] projname Basename of the new doc directory ("*-math").
226 * @param[in] docdev The doc device; only ".tex" is supported for the moment.
227 * @param[in] faustversion The current version of this Faust compiler.
229 void printDoc(const char* projname
, const char* docdev
, const char* faustversion
)
231 gDocDevSuffix
= docdev
;
233 /** File stuff : create doc directories and a tex file. */
234 //cerr << "Documentator : printDoc : gFaustDirectory = '" << gFaustDirectory << "'" << endl;
235 //cerr << "Documentator : printDoc : gFaustSuperDirectory = '" << gFaustSuperDirectory << "'" << endl;
236 //cerr << "Documentator : printDoc : gFaustSuperSuperDirectory = '" << gFaustSuperSuperDirectory << "'" << endl;
237 //cerr << "Documentator : printDoc : gCurrentDir = '" << gCurrentDir << "'" << endl;
239 makedir(projname
); // create a top directory to store files
241 string svgTopDir
= subst("$0/svg", projname
);
242 makedir(svgTopDir
.c_str()); // create a directory to store svg-* subdirectories.
244 string cppdir
= subst("$0/cpp", projname
);
245 makedir(cppdir
.c_str()); // create a cpp directory.
247 string pdfdir
= subst("$0/pdf", projname
);
248 makedir(pdfdir
.c_str()); // create a pdf directory.
250 /* Copy all Faust source files into an 'src' sub-directory. */
251 vector
<string
> pathnames
= gReader
.listSrcFiles();
252 copyFaustSources(projname
, pathnames
);
254 string texdir
= subst("$0/tex", projname
);
255 mkchdir(texdir
.c_str()); // create a directory and move into.
257 /** Create THE mathdoc tex file. */
258 ofstream
docout(subst("$0.$1", gDocName
, docdev
).c_str());
259 cholddir(); // return to current directory
261 /** Init and load translation file. */
262 loadTranslationFile(gDocLang
);
264 /** Simulate a default doc if no <mdoc> tag detected. */
265 if (gDocVector
.empty()) { declareAutoDoc(); }
267 /** Printing stuff : in the '.tex' ouptut file, eventually including SVG files. */
268 printfaustdocstamp(faustversion
, docout
); ///< Faust version and compilation date (comment).
269 istream
* latexheader
= openArchFile(gLatexheaderfilename
);
270 printlatexheader(*latexheader
, faustversion
, docout
); ///< Static LaTeX header (packages and setup).
271 printdoccontent(svgTopDir
.c_str(), gDocVector
, faustversion
, docout
); ///< Generate math contents (main stuff!).
272 printlatexfooter(docout
); ///< Static LaTeX footer.
277 /*****************************************************************************
278 LaTeX basic printing functions of the Documentation
279 *****************************************************************************/
282 * Print a static LaTeX header.
284 * @param[in] latexheader The file containing the static part of the LaTeX header.
285 * @param[in] faustversion The current version of this Faust compiler.
286 * @param[out] docout The LaTeX output file to print into.
288 static void printlatexheader(istream
& latexheader
, const string
& faustversion
, ostream
& docout
)
291 while(getline(latexheader
, s
)) docout
<< s
<< endl
;
293 /** Specific LaTeX macros for Faust */
294 docout
<< "\\newcommand{\\faustfilename}{" << gMasterDocument
<< "}" << endl
;
295 docout
<< "\\newcommand{\\faustdocdir}{" << gMasterName
<< "-mdoc}" << endl
;
296 docout
<< "\\newcommand{\\faustprogname}{" << gMasterName
<< "}" << endl
;
297 docout
<< "\\newcommand{\\faustversion}{" << faustversion
<< "}" << endl
;
299 strftime (datebuf
, 150, "%B %d, %Y", getCompilationDate());
300 docout
<< "\\newcommand{\\faustdocdate}{" << datebuf
<< "}" << endl
;
302 docout
<< endl
<< "\\begin{document}" << endl
;
307 * @Brief Print a metadata set.
309 * Each metadata is a set, in order to handle multiple items,
310 * like multiple authors, even if most of metadatas have
313 * @param[in] expr Parsed metadata keyname, as boxes tree.
314 * @param[out] docout The output file to print into.
316 static void printDocMetadata(const Tree expr
, ostream
& docout
)
318 if (gMetaDataSet
.count(expr
)) {
320 set
<Tree
> mset
= gMetaDataSet
[expr
];
322 for (set
<Tree
>::iterator j
= mset
.begin(); j
!= mset
.end(); j
++) {
323 docout
<< sep
<< rmExternalDoubleQuotes(tree2str(*j
));
331 * Print listings of each Faust code ".dsp" files,
332 * calling the 'printfaustlisting' function.
334 * @param[out] docout The LaTeX output file to print into.
336 static void printfaustlistings(ostream
& docout
)
338 if (gLstDependenciesSwitch
) {
339 vector
<string
> pathnames
= gReader
.listSrcFiles();
340 for (unsigned int i
=0; i
< pathnames
.size(); i
++) {
341 printfaustlisting(pathnames
[i
], docout
);
344 printfaustlisting(gMasterDocument
, docout
);
350 * Print a listing of the Faust code, in a LaTeX "listing" environment.
351 * Strip content of <mdoc> tags.
353 * @param[in] faustfile The source file containing the Faust code.
354 * @param[out] docout The LaTeX output file to print into.
356 static void printfaustlisting(string
& faustfile
, ostream
& docout
)
361 //cerr << "Documentator : printfaustlisting : Opening file '" << faustfile << "'" << endl;
362 src
.open(faustfile
.c_str(), ifstream::in
);
364 docout
<< endl
<< "\\bigskip\\bigskip" << endl
;
365 docout
<< "\\begin{lstlisting}[caption=\\texttt{" << filebasename(faustfile
.c_str()) << "}]" << endl
;
367 bool isInsideDoc
= false;
369 if (faustfile
!= "" && src
.good()) {
370 while(getline(src
, s
)) { /** We suppose there's only one <mdoc> tag per line. */
371 size_t foundopendoc
= s
.find("<mdoc>");
372 if (foundopendoc
!= string::npos
&& gStripDocSwitch
) isInsideDoc
= true;
374 if (isInsideDoc
== false)
377 size_t foundclosedoc
= s
.find("</mdoc>");
378 if (foundclosedoc
!= string::npos
&& gStripDocSwitch
) isInsideDoc
= false;
381 cerr
<< "ERROR : can't open faust source file " << faustfile
<< endl
;
385 docout
<< "\\end{lstlisting}" << endl
<< endl
;
390 * Print the static LaTeX footer.
392 * @param[out] docout The LaTeX output file to print into.
394 static void printlatexfooter(ostream
& docout
)
396 docout
<< endl
<< "\\end{document}" << endl
<< endl
;
401 * Print a "doc stamp" in the LaTeX document :
402 * - the Faust version,
403 * - the date of doc compilation,
404 * - faust's web site URL.
406 * @param[in] faustversion The current version of this Faust compiler.
407 * @param[out] docout The LaTeX output file to print into.
409 static void printfaustdocstamp(const string
& faustversion
, ostream
& docout
)
412 strftime (datebuf
, 150, "%c", getCompilationDate());
414 docout
<< "%% This documentation was generated with Faust version " << faustversion
<< endl
;
415 docout
<< "%% " << datebuf
<< endl
;
416 docout
<< "%% http://faust.grame.fr" << endl
<< endl
;
421 /*****************************************************************************
422 Main loop : launches prepare, evaluate, and print functions
423 *****************************************************************************/
426 * @brief Main documentator loop.
428 * First loop on gDocVector, which contains the faust <mdoc> trees.
429 * Second loop for each of these <mdoc> trees, which contain parsed input expressions of 3 types :
430 * DOCEQN for <equation> tags, DOCDGM for <diagram> tags, and DOCTXT for direct LaTeX text (no tag).
431 * - DOCTXT expressions printing is trivial.
432 * - DOCDGM expressions printing calls 'printDocDgm' to generate SVG files and print LaTeX "figure" code.
433 * - DOCEQN expressions printing calls 'printDocEqn' after an important preparing work
434 * has been done by 'prepareDocEqns'.
436 * @param[in] projname Basename of the new doc directory ("*-math").
437 * @param[in] docVector Contains all <mdoc> parsed content (as boxes).
438 * @param[in] faustversion The current version of this Faust compiler.
439 * @param[out] docout The output file to print into.
441 static void printdoccontent(const char* svgTopDir
, const vector
<Tree
>& docVector
, const string
& faustversion
, ostream
& docout
)
443 //cerr << endl << "Documentator : printdoccontent : " << docVector.size() << " <mdoc> tags read." << endl;
445 /** Equations need to be prepared (named and compiled) before printing. */
446 vector
<Lateq
*> docCompiledEqnsVector
;
447 prepareDocEqns( docVector
, docCompiledEqnsVector
); ///< Quite a lot of stuff there.
448 vector
<Lateq
*>::iterator eqn_it
= docCompiledEqnsVector
.begin();
450 int dgmIndex
= 1; ///< For diagram directories numbering.
452 vector
<string
> docMasterCodeMap
;
453 docMasterCodeMap
= docCodeSlicer(gMasterDocument
, docMasterCodeMap
);
455 vector
<Tree
>::const_iterator doc
;
456 vector
<string
>::const_iterator code
;
457 code
= docMasterCodeMap
.begin();
459 if(doesFileBeginWithCode(gMasterDocument
) && (! docMasterCodeMap
.empty()) && gLstDistributedSwitch
) {
460 printdocCodeSlices(*code
, docout
);
464 /** First level printing loop, on docVector. */
465 for (doc
=docVector
.begin(); doc
<docVector
.end(); doc
++, code
++) {
467 Tree L
= reverse(*doc
);
468 //cerr << "Entering into <mdoc> parsing..." << endl;
470 /** Second level printing loop, on each <mdoc>. */
473 if ( isDocEqn(hd(L
), expr
) ) { ///< After equations are well prepared and named.
474 printDocEqn(*eqn_it
++, docout
);
476 else if ( isDocDgm(hd(L
), expr
) ) {
477 printDocDgm(expr
, svgTopDir
, docout
, dgmIndex
++);
479 else if ( isDocMtd(hd(L
), expr
) ) {
480 printDocMetadata(expr
, docout
);
482 else if ( isDocTxt(hd(L
)) ) {
483 docout
<< *hd(L
)->branch(0); // Directly print registered doc text.
485 else if ( isDocNtc(hd(L
)) ) {
486 printDocNotice(faustversion
, docout
);
488 else if ( isDocLst(hd(L
)) ) {
489 printfaustlistings(docout
);
492 cerr
<< "ERROR : " << *hd(L
) << " is not a valid documentation type." << endl
;
496 //cerr << " ...end of <mdoc> parsing." << endl;
498 if ( code
!= docMasterCodeMap
.end() && gLstDistributedSwitch
) {
499 printdocCodeSlices(*code
, docout
);
506 /*****************************************************************************
507 Primary sub-functions for <equation> handling
508 *****************************************************************************/
511 * @brief Caller function for all steps of doc equations preparation.
513 * Note : many of the functions called put their result into their last argument
514 * in a "source / destination" manner,
515 * the "destination" being declared before the function call.
517 * @param[in] docBoxes The <mdoc> boxes to collect and prepare.
518 * @param[out] docCompiledEqnsVector The place to store compiled equations.
520 static void prepareDocEqns(const vector
<Tree
>& docBoxes
, vector
<Lateq
*>& docCompiledEqnsVector
)
522 vector
<Tree
> eqBoxes
; collectDocEqns( docBoxes
, eqBoxes
); ///< step 0. Feed a vector.
524 if(! eqBoxes
.empty() ) {
525 vector
<Tree
> evalEqBoxes
; mapEvalDocEqn( eqBoxes
, gExpandedDefList
, evalEqBoxes
); ///< step 1. Evaluate boxes.
526 vector
<string
> eqNames
; mapGetEqName( evalEqBoxes
, eqNames
); ///< step 2. Get boxes name.
527 vector
<string
> eqNicknames
; calcEqnsNicknames( eqNames
, eqNicknames
); ///< step 3. Calculate nicknames.
529 vector
<int> eqInputs
;
530 vector
<int> eqOutputs
;
531 vector
<Tree
> eqSigs
; mapPrepareEqSig( evalEqBoxes
, eqInputs
, eqOutputs
, eqSigs
); ///< step 4&5. Propagate and prepare signals.
532 mapSetSigNickname( eqNicknames
, eqInputs
, eqSigs
); ///< step 6. Set signals nicknames.
533 Tree superEqList
; collectEqSigs( eqSigs
, superEqList
); ///< step 7. Collect all signals in a superlist.
535 DocCompiler
* DC
= new DocCompiler(0, 0);
536 annotateSuperList( DC
, superEqList
); ///< step 8. Annotate superEqList.
537 //calcAndSetLtqNames( superEqList ); ///< step 9. (directly in 10.)
538 mapCompileDocEqnSigs( eqSigs
, eqInputs
, eqOutputs
, DC
, docCompiledEqnsVector
); ///< step 10. Compile every signal.
544 * #0. Collect every <equation> found in all <mdoc> faust comments.
546 * @param[in] docBoxes The <mdoc> boxes to filter.
547 * @param[out] eqBoxes The place to store only <equation> boxes.
549 static void collectDocEqns(const vector
<Tree
>& docBoxes
, vector
<Tree
>& eqBoxes
)
553 for (vector
<Tree
>::const_iterator doc
=docBoxes
.begin(); doc
<docBoxes
.end(); doc
++) {
554 Tree L
= reverse(*doc
);
557 if ( isDocEqn(hd(L
), expr
) ) {
558 eqBoxes
.push_back(expr
);
564 //cerr << "Documentator : collectDocEqns : " << nbdoceqn << " <equation> tags found." << endl;
569 * #1. Evaluate every doc <equation> (evaluation replaces abstractions by symbolic boxes).
571 * @param[in] eqBoxes The boxes to evaluate.
572 * @param[in] env The environment for the evaluation.
573 * @param[out] evalEqBoxes The place to store evaluated equations boxes.
575 static void mapEvalDocEqn(const vector
<Tree
>& eqBoxes
, const Tree
& env
, vector
<Tree
>& evalEqBoxes
)
577 //cerr << "###\n# Documentator : mapEvalDocEqn" << endl;
579 for ( vector
<Tree
>::const_iterator eq
=eqBoxes
.begin(); eq
< eqBoxes
.end(); eq
++)
581 evalEqBoxes
.push_back(evaldocexpr( *eq
, env
));
583 //cerr << "Documentator : end of mapEvalDocEqn\n---" << endl;
588 * #2. Get name if exists, else create one, and store it.
590 * @param[in] evalEqBoxes Evaluated box trees, eventually containing an equation name.
591 * @param[out] eqNames The place to store equations names.
593 static void mapGetEqName(const vector
<Tree
>& evalEqBoxes
, vector
<string
>& eqNames
)
595 //cerr << "###\n# Documentator : mapGetEqName" << endl;
598 for( vector
<Tree
>::const_iterator eq
= evalEqBoxes
.begin(); eq
< evalEqBoxes
.end(); eq
++, i
++ ) {
601 int n
,m
; getBoxType(*eq
, &n
, &m
); // eq name only for bd without inputs
602 if ( n
==0 && getDefNameProperty(*eq
, id
) ) {
606 s
= calcNumberedName("doceqn-", i
);
608 eqNames
.push_back( s
) ;
610 //cerr << "Documentator : end of mapGetEqName\n---" << endl;
615 * #3. Calculate a nickname for each equation and store it.
617 * @param[in] eqNames Equations names to parse.
618 * @param[out] eqNicknames The place to store calculated nicknames.
620 * @todo Should check unicity : check whether several names share the same initial,
621 * or else capture consonants for example.
623 static void calcEqnsNicknames(const vector
<string
>& eqNames
, vector
<string
>& eqNicknames
)
625 //cerr << "###\n# Documentator : calcEqnsNicknames" << endl;
629 for( vector
<string
>::const_iterator eq
= eqNames
.begin(); eq
< eqNames
.end(); eq
++ ) {
630 string init
= calcDocEqnInitial(*eq
);
632 /** Check duplicates */
633 // for( vector<string>::iterator it = v.begin(); it < v.end()-1; ++it ) {
634 // if (init == *it) {
635 // //cerr << "!! Warning Documentator : calcEqnsNicknames : duplicates \"" << init << "\"" << endl;
638 eqNicknames
.push_back(init
);
641 // for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
643 // c = count_if(eqNames.begin(), eqNames.end(), bind2nd(equal_to<string>(), *eq));
645 // cerr << "- Duplicate nickname !! " << *eq << endl;
647 // cerr << "(no duplicate) " << *eq << endl;
651 //cerr << "Documentator : end of calcEqnsNicknames\n---" << endl;
656 * #4&5. Propagate and prepare every doc <equation>.
658 * Call boxPropagateSig, deBruijn2Sym, simplify, and privatise.
660 * @param[in] evalEqBoxes Equations boxes to propagate as signals.
661 * @param[out] eqSigs The place to store prepared signals.
663 static void mapPrepareEqSig(const vector
<Tree
>& evalEqBoxes
, vector
<int>& eqInputs
, vector
<int>& eqOutputs
, vector
<Tree
>& eqSigs
)
665 //cerr << "###\n# Documentator : mapPrepareEqSig" << endl;
667 for( vector
<Tree
>::const_iterator eq
= evalEqBoxes
.begin(); eq
< evalEqBoxes
.end(); eq
++ ) {
669 int numInputs
, numOutputs
;
670 getBoxInputsAndOutputs(*eq
, numInputs
, numOutputs
);
671 //cerr << numInputs <<" ins and " << numOutputs <<" outs" << endl;
672 eqInputs
.push_back(numInputs
);
673 eqOutputs
.push_back(numOutputs
);
675 Tree lsig1
= boxPropagateSig( nil
, *eq
, makeSigInputList(numInputs
) );
676 //cerr << "output signals are : " << endl; printSignal(lsig1, stderr);
678 Tree lsig2
= deBruijn2Sym(lsig1
); ///< Convert debruijn recursion into symbolic recursion
679 Tree lsig3
= simplify(lsig2
); ///< Simplify by executing every computable operation
680 //Tree lsig4 = privatise(lsig3); ///< Un-share tables with multiple writers
681 Tree lsig4
= docTableConvertion(lsig3
); ///< convert regular tables into special doctables
682 ///< (regular tables are difficult to translate to equations)
684 eqSigs
.push_back(lsig4
);
686 //cerr << "Documentator : end of mapPrepareEqSig\n---" << endl;
691 * #6. Set signals nicknames.
693 * Do nothing for the moment !
694 * @param[in] eqNicknames Contains previously calculated nicknames.
695 * @param[out] eqSigs The signals to tag with a NICKNAMEPROPERTY.
697 static void mapSetSigNickname(const vector
<string
>& eqNicknames
, const vector
<int>& eqInputs
, const vector
<Tree
>& eqSigs
)
699 //cerr << "###\n# Documentator : mapSetSigNickname" << endl;
701 // Do nothing for the moment...
702 // for( unsigned int i=0; i < eqSigs.size(); i++ ) {
703 // if (eqInputs[i] == 0) // Only "generators" should be finally named with user equation (nick)name.
704 // setSigListNickName(eqSigs[i], eqNicknames[i]);
706 //cerr << "Documentator : end of mapSetSigNickname\n---" << endl;
711 * #7. Collect each prepared list of signals to construct a super list.
713 * @param[in] eqSigs Contains well-prepared and nicknamed signals.
714 * @param[out] superEqList The root where to 'cons' signals all together.
716 static void collectEqSigs(const vector
<Tree
>& eqSigs
, Tree
& superEqList
)
718 //cerr << "###\n# Documentator : collectEqSigs" << endl;
722 for( vector
<Tree
>::const_iterator it
= eqSigs
.begin(); it
< eqSigs
.end(); ++it
) {
723 superEqList
= cons( *it
, superEqList
);
725 //printSignal(superEqList, stdout, 0);
727 //cerr << endl << "Documentator : end of collectEqSigs\n---" << endl;
732 * #8. Annotate superEqList (to find candidate signals to be named later).
734 * @param[in] DC The signals compiler.
735 * @param[out] superEqList The super equations signal tree to annotate.
737 static void annotateSuperList(DocCompiler
* DC
, Tree superEqList
)
739 DC
->annotate(superEqList
);
744 // * #9. Calculated and set lateq (LaTeX equation) names.
745 // * Note : Transfered into mapCompileDocEqnSigs (DocCompiler::compileMultiSignal).
747 //static void calcAndSetLtqNames(Tree superEqList)
754 * #10. Name and compile prepared doc <equation> signals.
756 * @param[in] eqSigs Contains well-prepared and nicknamed signals.
757 * @param[in] DC The signals compiler.
758 * @param[out] docCompiledEqnsVector The place to store each compiled Lateq* object.
760 static void mapCompileDocEqnSigs(const vector
<Tree
>& eqSigs
, const vector
<int>& eqInputs
, const vector
<int>& eqOutputs
, DocCompiler
* DC
, vector
<Lateq
*>& docCompiledEqnsVector
)
762 //cerr << "###\n# Documentator : mapCompileDocEqnSigs" << endl;
764 for( unsigned int i
=0; i
< eqSigs
.size(); i
++ ) {
766 // docCompiledEqnsVector.push_back( DC->compileMultiSignal(*it, 0) );
767 docCompiledEqnsVector
.push_back( DC
->compileLateq(eqSigs
[i
], new Lateq(eqInputs
[i
], eqOutputs
[i
])) );
770 //cerr << "Documentator : end of mapCompileDocEqnSigs\n---" << endl;
775 /*****************************************************************************
776 Secondary sub-functions for <equation> handling
777 *****************************************************************************/
781 * Calculate an appropriate nickname for equations,
782 * from previous names.
784 * @param The string to parse.
785 * @return Essentially returns the initial character,
786 * except "Y" for "process", and "Z" for unnamed equations.
788 static string
calcDocEqnInitial(const string s
)
793 else if (s
.substr(0,6) == "doceqn")
802 * Just get the number of inputs and the number of outputs of a box.
804 * @param[in] t The box tree to get inputs and outputs from.
805 * @param[out] numInputs The place to store the number of inputs.
806 * @param[out] numOutputs The place to store the number of outputs.
808 static void getBoxInputsAndOutputs(const Tree t
, int& numInputs
, int& numOutputs
)
810 if (!getBoxType(t
, &numInputs
, &numOutputs
)) {
811 cerr
<< "ERROR during the evaluation of t : " << boxpp(t
) << endl
;
814 //cerr << "Documentator : " << numInputs <<" inputs and " << numOutputs <<" outputs for box : " << boxpp(t) << endl;
819 * Print doc equations, following the Lateq::println method.
821 * @param[in] ltq The object containing compiled LaTeX code of equations.
822 * @param[out] docout The output file to print into.
824 static void printDocEqn(Lateq
* ltq
, ostream
& docout
)
826 ltq
->println(docout
);
827 //cerr << "Documentator : printDocEqn : "; ltq->println(cerr); cerr << endl;
831 /*****************************************************************************
832 Sub-function for <diagram> handling
833 *****************************************************************************/
836 * @brief Doc diagrams handling.
839 * 1. evaluate expression
840 * 2. call svg drawing in the appropriate directory
841 * 3. print latex figure code with the appropriate directory reference
843 * @param[in] expr Parsed input expression, as boxes tree.
844 * @param[in] svgTopDir Basename of the new doc directory ("*-math/svg").
845 * @param[out] docout The output file to print into.
847 static void printDocDgm(const Tree expr
, const char* svgTopDir
, ostream
& docout
, int i
)
849 /** 1. Evaluate expression. */
850 Tree docdgm
= evaldocexpr(expr
, gExpandedDefList
);
851 if (gErrorCount
> 0) {
852 cerr
<< "Total of " << gErrorCount
<< " errors during evaluation of : diagram docdgm = " << boxpp(docdgm
) << ";\n";
857 * 2. Draw the diagram after its evaluation, in SVG.
858 * Warning : pdflatex can't directly include SVG files !
860 char dgmid
[MAXIDCHARS
+1];
861 sprintf(dgmid
, "%02d", i
);
862 string thisdgmdir
= subst("$0/svg-$1", svgTopDir
, dgmid
);
863 //cerr << "Documentator : printDocDgm : drawSchema in '" << gCurrentDir << "/" << thisdgmdir << "'" << endl;
865 drawSchema( docdgm
, thisdgmdir
.c_str(), "svg" );
867 /** 3. Print LaTeX figure code. */
869 const string dgmfilename
= legalFileName(docdgm
, 1024, temp
);
870 //docout << "figure \\ref{figure" << i << "}";
871 docout
<< "\\begin{figure}[ht!]" << endl
;
872 docout
<< "\t\\centering" << endl
;
873 docout
<< "\t\\includegraphics[width=\\textwidth]{" << subst("../svg/svg-$0/", dgmid
) << dgmfilename
<< "}" << endl
;
874 docout
<< "\t\\caption{" << gDocMathStringMap
["dgmcaption"] << " \\texttt{" << dgmfilename
<< "}}" << endl
;
875 docout
<< "\t\\label{figure" << i
<< "}" << endl
;
876 docout
<< "\\end{figure}" << endl
<< endl
;
878 /** 4. Warn about naming interferences (in the notice). */
879 gDocNoticeFlagMap
["nameconflicts"] = true;
880 gDocNoticeFlagMap
["svgdir"] = true;
885 /*****************************************************************************
887 *****************************************************************************/
891 * Slice faust code between "mdoc" sections.
893 * @param[in] faustfile Name of the input faust file to parse.
894 * @param[in] codeSlices The place to store code "slices".
896 vector
<string
>& docCodeSlicer(const string
& faustfile
, vector
<string
>& codeSlices
)
900 src
.open(faustfile
.c_str(), ifstream::in
);
903 bool isInsideDoc
= false;
905 if (faustfile
!= "" && src
.good()) {
906 while(getline(src
, s
)) { /** Caution: we suppose there's only one <mdoc> tag per line! */
907 size_t foundopendoc
= s
.find("<mdoc>");
909 if (foundopendoc
!= string::npos
) {
910 if (isInsideDoc
== false) { /** A change has come. ;) */
911 if (! tmp
.empty() ) {
912 codeSlices
.push_back(tmp
); }
918 if (isInsideDoc
== false) {
922 size_t foundclosedoc
= s
.find("</mdoc>");
923 if (foundclosedoc
!= string::npos
) isInsideDoc
= false;
926 cerr
<< "ERROR : can't open faust source file " << faustfile
<< endl
;
934 * Print faust code inside a listing environment.
936 * @param[in] code Faust code as a string (may contain '\n' characters).
937 * @param[out] docout The output file to print into.
939 static void printdocCodeSlices(const string
& code
, ostream
& docout
)
941 if ( ! code
.empty() ) {
942 docout
<< endl
<< "\\begin{lstlisting}[numbers=none, frame=none, basicstyle=\\small\\ttfamily, backgroundcolor=\\color{yobg}]" << endl
;
943 docout
<< code
<< endl
;
944 docout
<< "\\end{lstlisting}" << endl
<< endl
;
950 * Test whether a file does begin with some faust code or not.
952 * @param[in] faustfile Name of the input faust file to parse.
954 static bool doesFileBeginWithCode(const string
& faustfile
)
958 src
.open(faustfile
.c_str(), ifstream::in
);
960 if (faustfile
!= "" && src
.good()) {
962 size_t foundopendoc
= s
.find("<mdoc>");
963 if(int(foundopendoc
)==0) {
969 cerr
<< "ERROR : can't open faust source file " << faustfile
<< endl
;
976 //------------------------ dealing with files -------------------------
980 * Create a new directory in the current one.
982 static int makedir(const char* dirname
)
984 char buffer
[FAUST_PATH_MAX
];
985 gCurrentDir
= getcwd (buffer
, FAUST_PATH_MAX
);
987 if ( gCurrentDir
.c_str() != 0) {
988 int status
= mkdir(dirname
, S_IRWXU
| S_IRWXG
| S_IROTH
| S_IXOTH
);
989 if (status
== 0 || errno
== EEXIST
) {
999 * Create a new directory in the current one,
1000 * then 'cd' into this new directory.
1003 * The current directory is saved to be later restaured.
1005 static int mkchdir(const char* dirname
)
1007 char buffer
[FAUST_PATH_MAX
];
1008 gCurrentDir
= getcwd (buffer
, FAUST_PATH_MAX
);
1010 if ( gCurrentDir
.c_str() != 0) {
1011 int status
= mkdir(dirname
, S_IRWXU
| S_IRWXG
| S_IROTH
| S_IXOTH
);
1012 if (status
== 0 || errno
== EEXIST
) {
1013 if (chdir(dirname
) == 0) {
1024 * Switch back to the previously stored current directory
1026 static int cholddir ()
1028 if (chdir(gCurrentDir
.c_str()) == 0) {
1038 * Get current directory and store it in gCurrentDir.
1040 static void getCurrentDir ()
1042 char buffer
[FAUST_PATH_MAX
];
1043 gCurrentDir
= getcwd (buffer
, FAUST_PATH_MAX
);
1048 * Open architecture file.
1050 static istream
* openArchFile (const string
& filename
)
1053 getCurrentDir(); // Save the current directory.
1054 //cerr << "Documentator : openArchFile : Opening input file '" << filename << "'" << endl;
1055 if ( (file
= open_arch_stream(filename
.c_str())) ) {
1056 //cerr << "Documentator : openArchFile : Opening '" << filename << "'" << endl;
1058 cerr
<< "ERROR : can't open architecture file " << filename
<< endl
;
1061 cholddir(); // Return to current directory.
1067 * Transform the definition name property of tree <t> into a
1068 * legal file name. The resulting file name is stored in
1069 * <dst> a table of at least <n> chars. Returns the <dst> pointer
1072 static char* legalFileName(const Tree t
, int n
, char* dst
)
1076 if (getDefNameProperty(t
, id
)) {
1077 const char* src
= tree2str(id
);
1078 for (i
=0; isalnum(src
[i
]) && i
<16; i
++) {
1083 if (strcmp(dst
, "process") != 0) {
1084 // if it is not process add the hex address to make the name unique
1085 snprintf(&dst
[i
], n
-i
, "-%p", t
);
1091 * Simply concat a string with a number in a "%03d" format.
1092 * The number has MAXIDCHARS characters.
1094 static string
calcNumberedName(const char* base
, int i
)
1096 char nb
[MAXIDCHARS
+1];
1097 sprintf(nb
, "%03d", i
);
1098 return subst("$0$1", base
, nb
);
1102 * Remove the leading and trailing double quotes of a string
1103 * (but not those in the middle of the string)
1105 static string
rmExternalDoubleQuotes(const string
& s
)
1107 size_t i
= s
.find_first_not_of("\"");
1108 size_t j
= s
.find_last_not_of("\"");
1110 if ( (i
!= string::npos
) & (j
!= string::npos
) ) {
1111 return s
.substr(i
, 1+j
-i
);
1119 * Copy all Faust source files into an 'src' subdirectory.
1121 * @param[in] projname Basename of the new doc directory ("*-math").
1122 * @param[in] pathnames The paths list of the source files to copy.
1124 static void copyFaustSources(const char* projname
, const vector
<string
>& pathnames
)
1126 string srcdir
= subst("$0/src", projname
);
1127 //cerr << "Documentator : copyFaustSources : Creating directory '" << srcdir << "'" << endl;
1128 makedir(srcdir
.c_str()); // create a directory.
1130 for (unsigned int i
=0; i
< pathnames
.size(); i
++) {
1133 string faustfile
= pathnames
[i
];
1134 string copy
= subst("$0/$1", srcdir
, filebasename(faustfile
.c_str()));
1135 //cerr << "Documentator : copyFaustSources : Opening input file '" << faustfile << "'" << endl;
1136 //cerr << "Documentator : copyFaustSources : Opening output file '" << copy << "'" << endl;
1137 src
.open(faustfile
.c_str(), ifstream::in
);
1138 dst
.open(copy
.c_str(), ofstream::out
);
1140 while ( getline(src
,s
) ) dst
<< s
<< endl
;
1145 //------------------------ date managment -------------------------
1148 static void initCompilationDate()
1153 gCompilationDate
= *localtime(&now
);
1156 static struct tm
* getCompilationDate()
1158 initCompilationDate();
1159 return &gCompilationDate
;