Rename interpretor to interpreter.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / compiler / documentator / doc.cpp
diff --git a/interpreter/preprocessor/faust-0.9.47mr3/compiler/documentator/doc.cpp b/interpreter/preprocessor/faust-0.9.47mr3/compiler/documentator/doc.cpp
new file mode 100644 (file)
index 0000000..00c956e
--- /dev/null
@@ -0,0 +1,1161 @@
+/************************************************************************
+ ************************************************************************
+ FAUST compiler
+ Copyright (C) 2009 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ************************************************************************
+ ************************************************************************/
+
+
+
+/*****************************************************************************
+ ******************************************************************************
+                                               The Documentator Language
+ ******************************************************************************
+ *****************************************************************************/
+
+
+/**
+ * @file doc.cpp
+ * @author Karim Barkati and Yann Orlarey
+ * @version 1.0
+ * @date 2009
+ * @brief Implementation of documentation trees support and printing.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <algorithm>
+#include <functional>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "ppbox.hh"
+#include "prim2.hh"
+#include "doc.hh"
+#include "eval.hh"
+#include "errormsg.hh"
+#include "doc_Text.hh"
+#include "sigprint.hh"
+#include "propagate.hh"
+#include "enrobage.hh"
+#include "drawschema.hh"
+#include "names.hh"
+#include "simplify.hh"
+#include "privatise.hh"
+#include "recursivness.hh"
+#include "sourcereader.hh"
+#include "lateq.hh"
+#include "doc_compile.hh"
+#include "doc_lang.hh"
+#include "doc_notice.hh"
+#include "doc_autodoc.hh"
+#include "compatibility.hh"
+
+
+
+#define MAXIDCHARS 5                           ///< max numbers (characters) to represent ids (e.g. for directories).
+
+using namespace std ;
+
+
+/*****************************************************************************
+                                               Globals and prototyping
+ *****************************************************************************/
+
+extern Tree                                            gExpandedDefList;
+extern map<Tree, set<Tree> >   gMetaDataSet;
+extern map<string, string>             gDocMetadatasStringMap;
+extern map<string, string>             gDocMathStringMap;
+extern bool                                    gDetailsSwitch;
+extern bool                                    gStripDocSwitch;
+extern string                                  gFaustDirectory;
+extern string                                  gFaustSuperDirectory;
+extern string                                  gFaustSuperSuperDirectory;
+extern string                                  gMasterDocument;
+extern string                                  gMasterName;
+extern SourceReader                            gReader;
+
+extern string                                  gDocName;                               ///< Contains the filename for out documentation.
+static const char*                             gDocDevSuffix;                  ///< ".tex" (or .??? - used to choose output device).
+static string                                  gCurrentDir;                    ///< Room to save current directory name.
+static const string                            gLatexheaderfilename = "latexheader.tex";
+
+vector<Tree>                                   gDocVector;                             ///< Contains <mdoc> parsed trees: DOCTXT, DOCEQN, DOCDGM.
+
+static struct tm                               gCompilationDate;
+
+bool                                                   gLstDependenciesSwitch  = true; ///< mdoc listing management.
+bool                                                   gLstMdocTagsSwitch              = true; ///< mdoc listing management.
+bool                                                   gLstDistributedSwitch   = true; ///< mdoc listing management.
+
+enum { langEN, langFR, langIT };
+string                         gDocLang;
+
+/* Printing functions */
+static void            printlatexheader(istream& latexheader, const string& faustversion, ostream& docout);
+static void            printfaustlistings(ostream& docout);
+static void            printfaustlisting(string& path, ostream& docout);
+static void            printlatexfooter(ostream& docout);
+static void            printdoccontent(const char* svgTopDir, const vector<Tree>& docVector, const string& faustversion, ostream& docout);
+static void            printfaustdocstamp(const string& faustversion, ostream& docout);
+static void            printDocEqn(Lateq* ltq, ostream& docout);
+static void            printDocDgm(const Tree expr, const char* svgTopDir, ostream& docout, int i);
+static void            printDocMetadata(const Tree expr, ostream& docout);
+
+/* Primary sub-functions for <equation> handling */
+static void    prepareDocEqns( const vector<Tree>& docBoxes, vector<Lateq*>& docCompiledEqnsVector );          ///< Caller function.
+static void    collectDocEqns( const vector<Tree>& docBoxes, vector<Tree>& eqBoxes );                                          ///< step 0. Feed a vector.
+static void    mapEvalDocEqn( const vector<Tree>& eqBoxes, const Tree& env, vector<Tree>& evalEqBoxes );       ///< step 1. Evaluate boxes.
+static void    mapGetEqName( const vector<Tree>& evalEqBoxes, vector<string>& eqNames );                                       ///< step 2. Get boxes name.
+static void    calcEqnsNicknames( const vector<string>& eqNames, vector<string>& eqNicknames );                        ///< step 3. Calculate nicknames.
+static void    mapPrepareEqSig( const vector<Tree>& evalEqBoxes, vector<int>& eqInputs, vector<int>& eqOutputs, vector<Tree>& eqSigs );        ///< step 4&5. Propagate and prepare signals.
+static void    mapSetSigNickname( const vector<string>& eqNicknames, const vector<int>& eqInputs, const vector<Tree>& eqSigs );        ///< step 6. Set signals nicknames.
+static void    collectEqSigs( const vector<Tree>& eqSigs, Tree& superEqList );                                                         ///< step 7. Collect all signals in a superlist.
+static void    annotateSuperList( DocCompiler* DC, Tree superEqList );                                                         ///< step 8. Annotate superlist.
+//static void  calcAndSetLtqNames( Tree superEqList );         ///< step 9. 
+static void    mapCompileDocEqnSigs( const vector<Tree>& eqSigs, const vector<int>& eqInputs, const vector<int>& eqOutputs, DocCompiler* DC, vector<Lateq*>& docCompiledEqnsVector );  ///< step 10. Compile equations.
+
+/* Secondary sub-functions for <equation> handling */
+static string  calcNumberedName(const char* base, int i);
+static void            getBoxInputsAndOutputs(const Tree t, int& numInputs, int& numOutputs);
+static string  calcDocEqnInitial(const string s);
+
+/* Notice related functions */
+static void            initCompilationDate();
+static struct tm* getCompilationDate();
+
+/* Files functions */
+static int             cholddir ();
+static int             mkchdir(const char* dirname);
+static int             makedir(const char* dirname);
+static void            getCurrentDir();
+static istream* openArchFile (const string& filename);
+static char*   legalFileName(const Tree t, int n, char* dst);
+static string  rmExternalDoubleQuotes(const string& s);
+static void            copyFaustSources(const char* projname, const vector<string>& pathnames);
+vector<string>& docCodeSlicer(const string& faustfile, vector<string>& codeSlices);
+static void            printdocCodeSlices(const string& code, ostream& docout);
+static bool            doesFileBeginWithCode(const string& faustfile);
+
+//static void          declareAutoDoc();
+
+
+
+/*****************************************************************************
+                                       Types of Documentation Elements
+ *****************************************************************************/
+
+Sym DOCTXT = symbol ("DocTxt");
+Tree docTxt(const char* name)          { return tree( DOCTXT, tree(symbol(name)) ); }
+bool isDocTxt(Tree t)                          { return t->node() == Node(DOCTXT); }
+bool isDocTxt(Tree t0, const char** str)
+{
+       Tree t1; Sym s;
+       if ( isTree(t0, DOCTXT, t1) && isSym(t1->node(), &s) ) {
+               *str = name(s);
+               return true;
+       } else {
+               return false;
+       }
+}
+
+Sym DOCEQN = symbol ("DocEqn");
+Tree docEqn(Tree x)                            { return tree(DOCEQN, x);               }
+bool isDocEqn(Tree t, Tree& x)                 { return isTree(t, DOCEQN, x);  }
+
+Sym DOCDGM = symbol ("DocDgm");
+Tree docDgm(Tree x)                            { return tree(DOCDGM, x);               }
+bool isDocDgm(Tree t, Tree& x)                 { return isTree(t, DOCDGM, x);  }
+
+Sym DOCNTC = symbol ("DocNtc");
+Tree docNtc()                                          { return tree(DOCNTC);                  }
+bool isDocNtc(Tree t)                          { return isTree(t, DOCNTC);     }
+
+Sym DOCLST = symbol ("DocLst");
+Tree docLst()                                          { return tree(DOCLST);                  }
+bool isDocLst(Tree t)                          { return isTree(t, DOCLST);     }
+
+Sym DOCMTD = symbol ("DocMtd");
+Tree docMtd(Tree x)                            { return tree(DOCMTD, x);               }
+bool isDocMtd(Tree t, Tree& x)                 { return isTree(t, DOCMTD, x);  }
+
+//string getDocTxt(Tree t)                     { return hd(t)->branch(0); }
+
+
+
+/*****************************************************************************
+                               Main Printing Function for the Documentation
+ *****************************************************************************/
+
+
+/**
+ * @brief The entry point to generate faust doc files.
+ *
+ * The entry point to generate the output LaTeX file, stored in the directory "<projname>-math/".
+ * This file eventually references images for diagrams, generated in SVG subdirectories.
+ * The device system was adapted from drawSchema's device system.
+ *
+ * @param[in]  projname                Basename of the new doc directory ("*-math").
+ * @param[in]  docdev                  The doc device; only ".tex" is supported for the moment.
+ * @param[in]  faustversion    The current version of this Faust compiler.
+ */
+void printDoc(const char* projname, const char* docdev, const char* faustversion)
+{
+       gDocDevSuffix = docdev;
+       
+       /** File stuff : create doc directories and a tex file. */
+       //cerr << "Documentator : printDoc : gFaustDirectory = '" << gFaustDirectory << "'" << endl;
+       //cerr << "Documentator : printDoc : gFaustSuperDirectory = '" << gFaustSuperDirectory << "'" << endl;
+       //cerr << "Documentator : printDoc : gFaustSuperSuperDirectory = '" << gFaustSuperSuperDirectory << "'" << endl;
+       //cerr << "Documentator : printDoc : gCurrentDir = '" << gCurrentDir << "'" << endl;
+       
+       makedir(projname);                      // create a top directory to store files
+       
+       string svgTopDir = subst("$0/svg", projname);
+       makedir(svgTopDir.c_str()); // create a directory to store svg-* subdirectories.
+       
+       string cppdir = subst("$0/cpp", projname);
+       makedir(cppdir.c_str());        // create a cpp directory.
+       
+       string pdfdir = subst("$0/pdf", projname);
+       makedir(pdfdir.c_str());        // create a pdf directory.
+       
+       /* Copy all Faust source files into an 'src' sub-directory. */
+       vector<string> pathnames = gReader.listSrcFiles();
+       copyFaustSources(projname, pathnames);
+       
+       string texdir = subst("$0/tex", projname);
+       mkchdir(texdir.c_str());        // create a directory and move into.
+
+        /** Create THE mathdoc tex file. */
+       ofstream docout(subst("$0.$1", gDocName, docdev).c_str());
+       cholddir();                                     // return to current directory
+       
+       /** Init and load translation file. */
+       loadTranslationFile(gDocLang);
+       
+       /** Simulate a default doc if no <mdoc> tag detected. */
+       if (gDocVector.empty()) { declareAutoDoc(); }   
+       
+       /** Printing stuff : in the '.tex' ouptut file, eventually including SVG files. */
+       printfaustdocstamp(faustversion, docout);                                               ///< Faust version and compilation date (comment).
+       istream* latexheader = openArchFile(gLatexheaderfilename);
+       printlatexheader(*latexheader, faustversion, docout);                                           ///< Static LaTeX header (packages and setup).
+       printdoccontent(svgTopDir.c_str(), gDocVector, faustversion, docout);           ///< Generate math contents (main stuff!).
+       printlatexfooter(docout);                                                                               ///< Static LaTeX footer.
+}
+
+
+
+/*****************************************************************************
+                       LaTeX basic printing functions of the Documentation
+ *****************************************************************************/
+
+/** 
+ * Print a static LaTeX header. 
+ *
+ * @param[in]  latexheader             The file containing the static part of the LaTeX header.
+ * @param[in]  faustversion    The current version of this Faust compiler.
+ * @param[out] docout                  The LaTeX output file to print into.
+ */
+static void printlatexheader(istream& latexheader, const string& faustversion, ostream& docout)
+{      
+       string  s;
+       while(getline(latexheader, s)) docout << s << endl;
+       
+       /** Specific LaTeX macros for Faust */
+       docout << "\\newcommand{\\faustfilename}{" << gMasterDocument << "}" << endl;
+       docout << "\\newcommand{\\faustdocdir}{" << gMasterName << "-mdoc}" << endl;
+       docout << "\\newcommand{\\faustprogname}{" << gMasterName << "}" << endl;
+       docout << "\\newcommand{\\faustversion}{" << faustversion << "}" << endl;
+       char datebuf [150];
+       strftime (datebuf, 150, "%B %d, %Y", getCompilationDate());
+       docout << "\\newcommand{\\faustdocdate}{" << datebuf << "}" << endl;
+       
+       docout << endl << "\\begin{document}" << endl;
+}
+
+
+/**
+ * @Brief Print a metadata set.
+ * 
+ * Each metadata is a set, in order to handle multiple items,
+ * like multiple authors, even if most of metadatas have
+ * unique items.
+ * 
+ * @param[in]  expr            Parsed metadata keyname, as boxes tree.
+ * @param[out] docout          The output file to print into.
+ */
+static void printDocMetadata(const Tree expr, ostream& docout)
+{
+       if (gMetaDataSet.count(expr)) {
+               string sep = "";
+               set<Tree> mset = gMetaDataSet[expr];
+               
+               for (set<Tree>::iterator j = mset.begin(); j != mset.end(); j++) {
+                       docout << sep << rmExternalDoubleQuotes(tree2str(*j));
+                       sep = ", ";
+               }
+       }
+}
+
+
+/** 
+ * Print listings of each Faust code ".dsp" files,
+ * calling the 'printfaustlisting' function.
+ *
+ * @param[out] docout          The LaTeX output file to print into.
+ */
+static void printfaustlistings(ostream& docout)
+{      
+       if (gLstDependenciesSwitch) {
+               vector<string> pathnames = gReader.listSrcFiles();
+               for (unsigned int i=0; i< pathnames.size(); i++) {
+                       printfaustlisting(pathnames[i], docout);
+               }
+       } else {
+               printfaustlisting(gMasterDocument, docout);
+       }
+}
+
+
+/** 
+ * Print a listing of the Faust code, in a LaTeX "listing" environment.
+ * Strip content of <mdoc> tags.
+ *
+ * @param[in]  faustfile       The source file containing the Faust code.
+ * @param[out] docout          The LaTeX output file to print into.
+ */
+static void printfaustlisting(string& faustfile, ostream& docout)
+{      
+       string  s;
+       ifstream src;
+       
+       //cerr << "Documentator : printfaustlisting : Opening file '" << faustfile << "'" << endl;
+       src.open(faustfile.c_str(), ifstream::in);
+       
+       docout << endl << "\\bigskip\\bigskip" << endl;
+       docout << "\\begin{lstlisting}[caption=\\texttt{" << filebasename(faustfile.c_str()) << "}]" << endl;
+
+       bool isInsideDoc = false;
+       
+       if (faustfile != "" && src.good()) {
+               while(getline(src, s)) { /** We suppose there's only one <mdoc> tag per line. */
+                       size_t foundopendoc  = s.find("<mdoc>");
+                       if (foundopendoc != string::npos && gStripDocSwitch) isInsideDoc = true;
+                       
+                       if (isInsideDoc == false)
+                               docout << s << endl;
+                       
+                       size_t foundclosedoc = s.find("</mdoc>");
+                       if (foundclosedoc != string::npos && gStripDocSwitch) isInsideDoc = false;
+               }
+       } else {
+               cerr << "ERROR : can't open faust source file " << faustfile << endl;
+               exit(1);
+       }
+       
+       docout << "\\end{lstlisting}" << endl << endl;
+}
+
+
+/** 
+ * Print the static LaTeX footer. 
+ *
+ * @param[out] docout          The LaTeX output file to print into.
+ */
+static void printlatexfooter(ostream& docout)
+{
+       docout << endl << "\\end{document}" << endl << endl;
+}
+
+
+/** 
+ * Print a "doc stamp" in the LaTeX document :
+ * - the Faust version,
+ * - the date of doc compilation,
+ * - faust's web site URL.
+ *
+ * @param[in]  faustversion    The current version of this Faust compiler.
+ * @param[out] docout                  The LaTeX output file to print into.
+ */
+static void printfaustdocstamp(const string& faustversion, ostream& docout)
+{
+       char datebuf [150];
+       strftime (datebuf, 150, "%c", getCompilationDate());
+       
+       docout << "%% This documentation was generated with Faust version " << faustversion << endl;
+       docout << "%% " << datebuf << endl;
+       docout << "%% http://faust.grame.fr" << endl << endl;
+}
+
+
+
+/*****************************************************************************
+                       Main loop : launches prepare, evaluate, and print functions
+ *****************************************************************************/
+
+/**
+ * @brief Main documentator loop.
+ *
+ * First loop on gDocVector, which contains the faust <mdoc> trees.
+ * Second loop for each of these <mdoc> trees, which contain parsed input expressions of 3 types :
+ * DOCEQN for <equation> tags, DOCDGM for <diagram> tags, and DOCTXT for direct LaTeX text (no tag).
+ * - DOCTXT expressions printing is trivial.
+ * - DOCDGM expressions printing calls 'printDocDgm' to generate SVG files and print LaTeX "figure" code.
+ * - DOCEQN expressions printing calls 'printDocEqn' after an important preparing work 
+ *   has been done by 'prepareDocEqns'.
+ *
+ * @param[in]  projname                Basename of the new doc directory ("*-math").
+ * @param[in]  docVector               Contains all <mdoc> parsed content (as boxes).
+ * @param[in]  faustversion    The current version of this Faust compiler.
+ * @param[out] docout                  The output file to print into.
+ **/
+static void printdoccontent(const char* svgTopDir, const vector<Tree>& docVector, const string& faustversion, ostream& docout)
+{
+       //cerr << endl << "Documentator : printdoccontent : " << docVector.size() << " <mdoc> tags read." << endl;
+       
+       /** Equations need to be prepared (named and compiled) before printing. */
+       vector<Lateq*>  docCompiledEqnsVector;
+       prepareDocEqns( docVector, docCompiledEqnsVector ); ///< Quite a lot of stuff there.
+       vector<Lateq*>::iterator eqn_it = docCompiledEqnsVector.begin();
+       
+       int dgmIndex = 1;                       ///< For diagram directories numbering.
+
+       vector<string> docMasterCodeMap;
+       docMasterCodeMap = docCodeSlicer(gMasterDocument, docMasterCodeMap);
+       
+       vector<Tree>::const_iterator doc;
+       vector<string>::const_iterator code;
+       code = docMasterCodeMap.begin();
+       
+       if(doesFileBeginWithCode(gMasterDocument) && (! docMasterCodeMap.empty()) && gLstDistributedSwitch ) {
+               printdocCodeSlices(*code, docout);
+               code++;
+       }
+       
+       /** First level printing loop, on docVector. */
+       for (doc=docVector.begin(); doc<docVector.end(); doc++, code++) {
+               
+               Tree L = reverse(*doc);
+               //cerr << "Entering into <mdoc> parsing..." << endl; 
+               
+               /** Second level printing loop, on each <mdoc>. */
+               while (isList(L)) {
+                       Tree expr;
+                       if ( isDocEqn(hd(L), expr) ) { ///< After equations are well prepared and named.
+                               printDocEqn(*eqn_it++, docout);
+                       }
+                       else if ( isDocDgm(hd(L), expr) ) { 
+                               printDocDgm(expr, svgTopDir, docout, dgmIndex++);
+                       }
+                       else if ( isDocMtd(hd(L), expr) ) { 
+                               printDocMetadata(expr, docout);
+                       }
+                       else if ( isDocTxt(hd(L)) ) { 
+                               docout << *hd(L)->branch(0); // Directly print registered doc text.
+                       }
+                       else if ( isDocNtc(hd(L)) ) { 
+                               printDocNotice(faustversion, docout);
+                       }
+                       else if ( isDocLst(hd(L)) ) { 
+                               printfaustlistings(docout);
+                       }
+                       else { 
+                               cerr << "ERROR : " << *hd(L) << " is not a valid documentation type." << endl; 
+                       }
+                       L = tl(L);
+               }
+               //cerr << " ...end of <mdoc> parsing." << endl; 
+               
+               if ( code != docMasterCodeMap.end() && gLstDistributedSwitch ) {
+                       printdocCodeSlices(*code, docout);
+               }
+       }
+}
+
+
+
+/*****************************************************************************
+                       Primary sub-functions for <equation> handling
+ *****************************************************************************/
+
+/**
+ * @brief Caller function for all steps of doc equations preparation.
+ *  
+ * Note : many of the functions called put their result into their last argument
+ * in a "source / destination" manner, 
+ * the "destination" being declared before the function call. 
+ *
+ * @param[in]  docBoxes                                The <mdoc> boxes to collect and prepare.
+ * @param[out] docCompiledEqnsVector   The place to store compiled equations.
+ */
+static void prepareDocEqns(const vector<Tree>& docBoxes, vector<Lateq*>& docCompiledEqnsVector)
+{      
+       vector<Tree>    eqBoxes;                collectDocEqns( docBoxes, eqBoxes );            ///< step 0. Feed a vector.
+       
+       if(! eqBoxes.empty() ) {
+               vector<Tree>    evalEqBoxes;    mapEvalDocEqn( eqBoxes, gExpandedDefList, evalEqBoxes );        ///< step 1. Evaluate boxes.
+               vector<string>  eqNames;                mapGetEqName( evalEqBoxes, eqNames );           ///< step 2. Get boxes name.
+               vector<string>  eqNicknames;    calcEqnsNicknames( eqNames, eqNicknames );      ///< step 3. Calculate nicknames.
+               
+               vector<int>             eqInputs;
+               vector<int>             eqOutputs;
+               vector<Tree>    eqSigs;                 mapPrepareEqSig( evalEqBoxes, eqInputs, eqOutputs, eqSigs );    ///< step 4&5. Propagate and prepare signals.
+               mapSetSigNickname( eqNicknames, eqInputs, eqSigs );                                                                     ///< step 6. Set signals nicknames.
+               Tree                    superEqList;    collectEqSigs( eqSigs, superEqList );           ///< step 7. Collect all signals in a superlist.
+               
+               DocCompiler* DC = new DocCompiler(0, 0);
+               annotateSuperList( DC, superEqList );                                                                           ///< step 8. Annotate superEqList.
+               //calcAndSetLtqNames( superEqList );                                                                            ///< step 9. (directly in 10.)
+               mapCompileDocEqnSigs( eqSigs, eqInputs, eqOutputs, DC, docCompiledEqnsVector );         ///< step 10. Compile every signal.
+       }
+}
+
+
+/**
+ * #0. Collect every <equation> found in all <mdoc> faust comments.
+ *
+ * @param[in]  docBoxes        The <mdoc> boxes to filter.
+ * @param[out] eqBoxes         The place to store only <equation> boxes.
+ */
+static void collectDocEqns(const vector<Tree>& docBoxes, vector<Tree>& eqBoxes)
+{
+       int nbdoceqn = 0;
+       
+       for (vector<Tree>::const_iterator doc=docBoxes.begin(); doc<docBoxes.end(); doc++) {
+               Tree L = reverse(*doc);
+               Tree expr;
+               while (isList(L)) {
+                       if ( isDocEqn(hd(L), expr) ) {
+                               eqBoxes.push_back(expr);
+                               nbdoceqn++;
+                       }
+                       L = tl(L);
+               }
+       }
+       //cerr << "Documentator : collectDocEqns : " << nbdoceqn << " <equation> tags found." << endl;
+}
+
+
+/**
+ * #1. Evaluate every doc <equation> (evaluation replaces abstractions by symbolic boxes).
+ *
+ * @param[in]  eqBoxes         The boxes to evaluate.
+ * @param[in]  env                     The environment for the evaluation.
+ * @param[out] evalEqBoxes     The place to store evaluated equations boxes.
+ */
+static void mapEvalDocEqn(const vector<Tree>& eqBoxes, const Tree& env, vector<Tree>& evalEqBoxes)
+{
+       //cerr << "###\n# Documentator : mapEvalDocEqn" << endl;
+       
+       for ( vector<Tree>::const_iterator eq=eqBoxes.begin(); eq < eqBoxes.end(); eq++)
+       {
+               evalEqBoxes.push_back(evaldocexpr( *eq, env ));
+       }
+       //cerr << "Documentator : end of mapEvalDocEqn\n---" << endl;
+}
+
+
+/**
+ * #2. Get name if exists, else create one, and store it.
+ *
+ * @param[in]  evalEqBoxes     Evaluated box trees, eventually containing an equation name.
+ * @param[out] eqNames         The place to store equations names.
+ */
+static void mapGetEqName(const vector<Tree>& evalEqBoxes, vector<string>& eqNames)
+{
+       //cerr << "###\n# Documentator : mapGetEqName" << endl;
+       
+       int i = 1;
+       for( vector<Tree>::const_iterator eq = evalEqBoxes.begin(); eq < evalEqBoxes.end(); eq++, i++ ) {
+               Tree id;
+               string s;
+               int n,m; getBoxType(*eq, &n, &m); // eq name only for bd without inputs
+               if ( n==0 && getDefNameProperty(*eq, id) ) {
+                       s = tree2str(id);
+               }
+               else {
+                       s = calcNumberedName("doceqn-", i);
+               }               
+               eqNames.push_back( s ) ;
+       }
+       //cerr << "Documentator : end of mapGetEqName\n---" << endl;
+}
+
+
+/**
+ * #3. Calculate a nickname for each equation and store it.
+ *
+ * @param[in]  eqNames         Equations names to parse.
+ * @param[out] eqNicknames     The place to store calculated nicknames.
+ *
+ * @todo Should check unicity : check whether several names share the same initial,
+ * or else capture consonants for example.
+ */
+static void calcEqnsNicknames(const vector<string>& eqNames, vector<string>& eqNicknames)
+{
+       //cerr << "###\n# Documentator : calcEqnsNicknames" << endl;
+       
+       vector<string> v;
+       
+       for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
+               string init = calcDocEqnInitial(*eq);
+               v.push_back(init);
+               /** Check duplicates */
+//             for( vector<string>::iterator it = v.begin(); it < v.end()-1; ++it ) {
+//                     if (init == *it) {
+//                             //cerr << "!! Warning Documentator : calcEqnsNicknames : duplicates \"" << init << "\"" << endl;
+//                     }
+//             }
+               eqNicknames.push_back(init);
+       }
+       
+//     for( vector<string>::const_iterator eq = eqNames.begin(); eq < eqNames.end(); eq++ ) {
+//             int c = 0;
+//             c = count_if(eqNames.begin(), eqNames.end(), bind2nd(equal_to<string>(), *eq));
+//             if (c > 0) { 
+//                     cerr << "- Duplicate nickname !! " << *eq << endl; 
+//             } else {
+//                     cerr << "(no duplicate) " << *eq << endl;
+//             }
+//     }
+       
+       //cerr << "Documentator : end of calcEqnsNicknames\n---" << endl;
+}
+
+
+/**
+ * #4&5. Propagate and prepare every doc <equation>.
+ *
+ * Call boxPropagateSig, deBruijn2Sym, simplify, and privatise.
+ *
+ * @param[in]  evalEqBoxes             Equations boxes to propagate as signals.
+ * @param[out] eqSigs                  The place to store prepared signals.
+ */
+static void mapPrepareEqSig(const vector<Tree>& evalEqBoxes, vector<int>& eqInputs, vector<int>& eqOutputs, vector<Tree>& eqSigs)
+{
+       //cerr << "###\n# Documentator : mapPrepareEqSig" << endl;
+       
+       for( vector<Tree>::const_iterator eq = evalEqBoxes.begin(); eq < evalEqBoxes.end(); eq++ ) {
+               
+               int numInputs, numOutputs;
+               getBoxInputsAndOutputs(*eq, numInputs, numOutputs);
+               //cerr << numInputs <<" ins and " << numOutputs <<" outs" << endl;
+               eqInputs.push_back(numInputs);
+               eqOutputs.push_back(numOutputs);
+               
+               Tree lsig1 = boxPropagateSig( nil, *eq , makeSigInputList(numInputs) );
+               //cerr << "output signals are : " << endl;  printSignal(lsig1, stderr);
+               
+               Tree lsig2 = deBruijn2Sym(lsig1);   ///< Convert debruijn recursion into symbolic recursion
+               Tree lsig3 = simplify(lsig2);           ///< Simplify by executing every computable operation
+        //Tree lsig4 = privatise(lsig3);               ///< Un-share tables with multiple writers
+        Tree lsig4 = docTableConvertion(lsig3);                ///< convert regular tables into special doctables
+                                                    ///< (regular tables are difficult to translate to equations)
+
+               eqSigs.push_back(lsig4);
+       }
+       //cerr << "Documentator : end of mapPrepareEqSig\n---" << endl;
+}
+
+
+/**
+ * #6. Set signals nicknames.
+ *
+ * Do nothing for the moment !
+ * @param[in]  eqNicknames             Contains previously calculated nicknames.
+ * @param[out] eqSigs                  The signals to tag with a NICKNAMEPROPERTY.
+ */
+static void mapSetSigNickname(const vector<string>& eqNicknames, const vector<int>& eqInputs, const vector<Tree>& eqSigs)
+{
+       //cerr << "###\n# Documentator : mapSetSigNickname" << endl;
+
+//     Do nothing for the moment...
+//     for( unsigned int i=0; i < eqSigs.size(); i++ ) {
+//             if (eqInputs[i] == 0) // Only "generators" should be finally named with user equation (nick)name.
+//                     setSigListNickName(eqSigs[i], eqNicknames[i]);
+//     }
+       //cerr << "Documentator : end of mapSetSigNickname\n---" << endl;
+}
+
+
+/**
+ * #7. Collect each prepared list of signals to construct a super list.
+ *
+ * @param[in]  eqSigs                  Contains well-prepared and nicknamed signals.
+ * @param[out] superEqList             The root where to 'cons' signals all together.
+ */
+static void collectEqSigs(const vector<Tree>& eqSigs, Tree& superEqList)
+{
+       //cerr << "###\n# Documentator : collectEqSigs" << endl;
+       
+       superEqList = nil;
+       
+       for( vector<Tree>::const_iterator it = eqSigs.begin(); it < eqSigs.end(); ++it ) {
+               superEqList = cons( *it, superEqList );
+       }
+       //printSignal(superEqList, stdout, 0);
+       
+       //cerr << endl << "Documentator : end of collectEqSigs\n---" << endl;
+}
+
+
+/**
+ * #8. Annotate superEqList (to find candidate signals to be named later).
+ *
+ * @param[in]  DC                      The signals compiler.
+ * @param[out] superEqList     The super equations signal tree to annotate. 
+ */
+static void    annotateSuperList(DocCompiler* DC, Tree superEqList)
+{
+       DC->annotate(superEqList);
+}
+
+
+///**
+// * #9. Calculated and set lateq (LaTeX equation) names.
+// * Note : Transfered into mapCompileDocEqnSigs (DocCompiler::compileMultiSignal).
+// */
+//static void  calcAndSetLtqNames(Tree superEqList)
+//{
+//     
+//}
+
+
+/**
+ * #10. Name and compile prepared doc <equation> signals.
+ *
+ * @param[in]  eqSigs                                  Contains well-prepared and nicknamed signals.
+ * @param[in]  DC                                              The signals compiler.
+ * @param[out] docCompiledEqnsVector   The place to store each compiled Lateq* object.
+ */
+static void mapCompileDocEqnSigs(const vector<Tree>& eqSigs, const vector<int>& eqInputs, const vector<int>& eqOutputs, DocCompiler* DC, vector<Lateq*>& docCompiledEqnsVector)
+{
+       //cerr << "###\n# Documentator : mapCompileDocEqnSigs" << endl;
+       
+       for( unsigned int i=0; i < eqSigs.size(); i++ ) {
+               
+               //              docCompiledEqnsVector.push_back( DC->compileMultiSignal(*it, 0) );
+               docCompiledEqnsVector.push_back( DC->compileLateq(eqSigs[i], new Lateq(eqInputs[i], eqOutputs[i])) );
+       }
+       
+       //cerr << "Documentator : end of mapCompileDocEqnSigs\n---" << endl;
+}
+
+
+
+/*****************************************************************************
+                               Secondary sub-functions for <equation> handling
+ *****************************************************************************/
+
+
+/**
+ * Calculate an appropriate nickname for equations,
+ * from previous names.
+ *
+ * @param      The string to parse.
+ * @return     Essentially returns the initial character, 
+ * except "Y" for "process", and "Z" for unnamed equations.
+ */
+static string calcDocEqnInitial(const string s)
+{
+       string nn;
+       if(s == "process")
+               nn = "Y";
+       else if (s.substr(0,6) == "doceqn")
+               nn = "Z";
+       else
+               nn += toupper(s[0]);
+       return nn;
+}
+
+
+/**
+ * Just get the number of inputs and the number of outputs of a box.
+ *
+ * @param[in]  t                       The box tree to get inputs and outputs from.
+ * @param[out] numInputs       The place to store the number of inputs.
+ * @param[out] numOutputs      The place to store the number of outputs.
+ */
+static void getBoxInputsAndOutputs(const Tree t, int& numInputs, int& numOutputs)
+{
+       if (!getBoxType(t, &numInputs, &numOutputs)) {
+               cerr << "ERROR during the evaluation of t : " << boxpp(t) << endl;
+               exit(1);
+       }
+       //cerr << "Documentator : " << numInputs <<" inputs and " << numOutputs <<" outputs for box : " << boxpp(t) << endl;
+}
+
+
+/**
+ * Print doc equations, following the Lateq::println method.
+ *
+ * @param[in]  ltq             The object containing compiled LaTeX code of equations.
+ * @param[out] docout  The output file to print into.
+ */
+static void printDocEqn(Lateq* ltq, ostream& docout) 
+{
+       ltq->println(docout);
+       //cerr << "Documentator : printDocEqn : "; ltq->println(cerr); cerr << endl;
+}
+
+
+/*****************************************************************************
+                                       Sub-function for <diagram> handling
+ *****************************************************************************/
+
+/**
+ * @brief Doc diagrams handling.
+ * 
+ * Three steps :
+ * 1. evaluate expression
+ * 2. call svg drawing in the appropriate directory
+ * 3. print latex figure code with the appropriate directory reference
+ *
+ * @param[in]  expr            Parsed input expression, as boxes tree.
+ * @param[in]  svgTopDir       Basename of the new doc directory ("*-math/svg").
+ * @param[out] docout          The output file to print into.
+ */
+static void printDocDgm(const Tree expr, const char* svgTopDir, ostream& docout, int i)
+{
+       /** 1. Evaluate expression. */
+       Tree docdgm = evaldocexpr(expr, gExpandedDefList);
+       if (gErrorCount > 0) {
+               cerr << "Total of " << gErrorCount << " errors during evaluation of : diagram docdgm = " << boxpp(docdgm) << ";\n";
+               exit(1);
+       }
+       
+       /**
+        * 2. Draw the diagram after its evaluation, in SVG.
+        * Warning : pdflatex can't directly include SVG files !
+        */
+       char dgmid[MAXIDCHARS+1];
+       sprintf(dgmid, "%02d", i);
+       string thisdgmdir = subst("$0/svg-$1", svgTopDir, dgmid);
+       //cerr << "Documentator : printDocDgm : drawSchema in '" << gCurrentDir << "/" << thisdgmdir << "'" << endl;
+       
+       drawSchema( docdgm, thisdgmdir.c_str(), "svg" );
+       
+       /** 3. Print LaTeX figure code. */
+       char temp[1024];
+       const string dgmfilename = legalFileName(docdgm, 1024, temp);
+       //docout << "figure \\ref{figure" << i << "}";
+       docout << "\\begin{figure}[ht!]" << endl;
+       docout << "\t\\centering" << endl;
+       docout << "\t\\includegraphics[width=\\textwidth]{" << subst("../svg/svg-$0/", dgmid) << dgmfilename << "}" << endl;
+       docout << "\t\\caption{" << gDocMathStringMap["dgmcaption"] << " \\texttt{" << dgmfilename << "}}" << endl;
+       docout << "\t\\label{figure" << i << "}" << endl;
+       docout << "\\end{figure}" << endl << endl;
+       
+       /** 4. Warn about naming interferences (in the notice). */
+       gDocNoticeFlagMap["nameconflicts"] = true;
+       gDocNoticeFlagMap["svgdir"] = true;
+}
+
+
+
+/*****************************************************************************
+                                                       Other sub-functions
+ *****************************************************************************/
+
+
+/**
+ * Slice faust code between "mdoc" sections.
+ *
+ * @param[in]  faustfile       Name of the input faust file to parse.
+ * @param[in]  codeSlices      The place to store code "slices".
+ */
+vector<string>& docCodeSlicer(const string& faustfile, vector<string>& codeSlices)
+{
+       string  s;
+       ifstream src;
+       src.open(faustfile.c_str(), ifstream::in);
+       string tmp = "";
+       
+       bool isInsideDoc = false;
+       
+       if (faustfile != "" && src.good()) {
+               while(getline(src, s)) { /** Caution: we suppose there's only one <mdoc> tag per line! */
+                       size_t foundopendoc  = s.find("<mdoc>");
+                       
+                       if (foundopendoc != string::npos) { 
+                               if (isInsideDoc == false) { /** A change has come. ;) */
+                                       if (! tmp.empty() ) {
+                                               codeSlices.push_back(tmp); }
+                                       tmp = "";
+                               }
+                               isInsideDoc = true;  
+                       }
+                       
+                       if (isInsideDoc == false) {
+                               tmp += s + '\n';
+                       }
+                       
+                       size_t foundclosedoc = s.find("</mdoc>");
+                       if (foundclosedoc != string::npos) isInsideDoc = false;
+               }
+       } else {
+               cerr << "ERROR : can't open faust source file " << faustfile << endl;
+               exit(1);
+       }
+       return codeSlices;
+}
+                       
+
+/**
+ * Print faust code inside a listing environment.
+ * 
+ * @param[in]  code            Faust code as a string (may contain '\n' characters).
+ * @param[out] docout          The output file to print into.
+ */
+static void printdocCodeSlices(const string& code, ostream& docout)
+{
+       if ( ! code.empty() ) {
+               docout << endl << "\\begin{lstlisting}[numbers=none, frame=none, basicstyle=\\small\\ttfamily, backgroundcolor=\\color{yobg}]" << endl;
+               docout << code << endl;
+               docout << "\\end{lstlisting}" << endl << endl;
+       }
+}
+
+
+/**
+ * Test whether a file does begin with some faust code or not.
+ *
+ * @param[in]  faustfile       Name of the input faust file to parse.
+ */
+static bool doesFileBeginWithCode(const string& faustfile)
+{
+       string  s;
+       ifstream src;
+       src.open(faustfile.c_str(), ifstream::in);
+       
+       if (faustfile != "" && src.good()) {
+               getline(src, s);
+               size_t foundopendoc = s.find("<mdoc>");
+               if(int(foundopendoc)==0) {
+                       return false;
+               } else {
+                       return true;
+               }
+       } else {
+               cerr << "ERROR : can't open faust source file " << faustfile << endl;
+               exit(1);
+       }
+}      
+
+
+
+//------------------------ dealing with files -------------------------
+
+
+/**
+ * Create a new directory in the current one.
+ */
+static int makedir(const char* dirname)
+{
+       char    buffer[FAUST_PATH_MAX];
+       gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
+       
+       if ( gCurrentDir.c_str() != 0) {
+               int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+               if (status == 0 || errno == EEXIST) {
+                       return 0;
+               }
+       }
+       perror("makedir");
+       exit(errno);
+}
+
+
+/**
+ * Create a new directory in the current one, 
+ * then 'cd' into this new directory.
+ * 
+ * @remark
+ * The current directory is saved to be later restaured.
+ */
+static int mkchdir(const char* dirname)
+{
+       char    buffer[FAUST_PATH_MAX];
+       gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
+
+       if ( gCurrentDir.c_str() != 0) {
+               int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+               if (status == 0 || errno == EEXIST) {
+                       if (chdir(dirname) == 0) {
+                               return 0;
+                       }
+               }
+       }
+       perror("mkchdir");
+       exit(errno);
+}
+
+
+/**
+ * Switch back to the previously stored current directory
+ */
+static int cholddir ()
+{
+       if (chdir(gCurrentDir.c_str()) == 0) {
+               return 0;
+       } else {
+               perror("cholddir");
+               exit(errno);
+       }
+}
+
+
+/**
+ * Get current directory and store it in gCurrentDir.
+ */
+static void getCurrentDir ()
+{
+       char    buffer[FAUST_PATH_MAX];
+    gCurrentDir = getcwd (buffer, FAUST_PATH_MAX);
+}
+
+
+/**
+ * Open architecture file.
+ */
+static istream* openArchFile (const string& filename)
+{
+       istream* file;
+       getCurrentDir();        // Save the current directory.
+       //cerr << "Documentator : openArchFile : Opening input file  '" << filename << "'" << endl;
+       if ( (file = open_arch_stream(filename.c_str())) ) {
+               //cerr << "Documentator : openArchFile : Opening '" << filename << "'" << endl;
+       } else {
+               cerr << "ERROR : can't open architecture file " << filename << endl;
+               exit(1);
+       }
+       cholddir();                     // Return to current directory.
+       return file;
+}
+
+
+/**
+ * Transform the definition name property of tree <t> into a
+ * legal file name.  The resulting file name is stored in
+ * <dst> a table of at least <n> chars. Returns the <dst> pointer
+ * for convenience.
+ */
+static char* legalFileName(const Tree t, int n, char* dst)
+{
+       Tree    id;
+       int     i=0;
+       if (getDefNameProperty(t, id)) {
+               const char*     src = tree2str(id);
+               for (i=0; isalnum(src[i]) && i<16; i++) {
+                       dst[i] = src[i];
+               }
+       }
+       dst[i] = 0;
+       if (strcmp(dst, "process") != 0) { 
+               // if it is not process add the hex address to make the name unique
+               snprintf(&dst[i], n-i, "-%p", t);
+       }
+       return dst;
+}
+
+/**
+ * Simply concat a string with a number in a "%03d" format.
+ * The number has MAXIDCHARS characters. 
+ **/
+static string calcNumberedName(const char* base, int i)
+{
+       char nb[MAXIDCHARS+1];
+       sprintf(nb, "%03d", i);
+       return subst("$0$1", base, nb);
+}
+
+/**
+ * Remove the leading and trailing double quotes of a string
+ * (but not those in the middle of the string)
+ */
+static string rmExternalDoubleQuotes(const string& s)
+{
+    size_t i = s.find_first_not_of("\"");
+    size_t j = s.find_last_not_of("\"");
+       
+    if ( (i != string::npos) & (j != string::npos) ) {
+        return s.substr(i, 1+j-i);
+    } else {
+        return "";
+    }
+}
+
+
+/** 
+ * Copy all Faust source files into an 'src' subdirectory.
+ *
+ * @param[in]  projname                Basename of the new doc directory ("*-math").
+ * @param[in]  pathnames               The paths list of the source files to copy.
+ */
+static void copyFaustSources(const char* projname, const vector<string>& pathnames)
+{
+       string srcdir = subst("$0/src", projname);
+       //cerr << "Documentator : copyFaustSources : Creating directory '" << srcdir << "'" << endl;
+       makedir(srcdir.c_str());        // create a directory.
+               
+       for (unsigned int i=0; i< pathnames.size(); i++) {
+               ifstream src;
+               ofstream dst;
+               string faustfile = pathnames[i];
+               string copy = subst("$0/$1", srcdir, filebasename(faustfile.c_str()));
+               //cerr << "Documentator : copyFaustSources : Opening input file  '" << faustfile << "'" << endl;
+               //cerr << "Documentator : copyFaustSources : Opening output file '" << copy << "'" << endl;
+               src.open(faustfile.c_str(), ifstream::in);
+               dst.open(copy.c_str(), ofstream::out);
+               string  s;
+               while ( getline(src,s) ) dst << s << endl;
+       }
+}
+
+
+//------------------------ date managment -------------------------
+
+
+static void initCompilationDate()
+{
+       time_t now;
+       
+       time(&now);
+       gCompilationDate = *localtime(&now);
+}
+
+static struct tm* getCompilationDate()
+{
+       initCompilationDate();
+       return &gCompilationDate;
+}
+