Logo Search packages:      
Sourcecode: faust version File versions  Download package

lateq.cpp

/************************************************************************
 ************************************************************************
    FAUST compiler
      Copyright (C) 2003-2004 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.
 ************************************************************************
 ************************************************************************/



 /**********************************************************************
            - lateq.cpp : the Lateq methods definition (FAUST project) -
            - for automatic generation of documentation -
            - "lateq" stands for "LaTeX equations" -
            - The crucial method here is println -

            Historique :
            -----------
            17-10-2001 : (klass.cpp) implementation initiale (yo)
            18-10-2001 : (klass.cpp) Ajout de getFreshID (yo)
            02-11-2001 : (klass.cpp) Ajout de sous classes (yo)
            06-11-2001 : (klass.cpp) modif impression des classes (yo)
            16-08-2009 : (lateq.cpp) Creation de lateq depuis klass.cpp (kb)
            2009-11-21 : (lateq.cpp) Remodelage et documentation doxygen (kb)

***********************************************************************/

#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <set>
#include <sstream>

#include "lateq.hh"
#include "Text.hh"


map<string, string>           gDocMathStringMap;
set<string>                   gDocMathKeySet;

static int  getLateqIndex(const string& s);
static bool compLateqIndexes(const string& s1, const string& s2);
static void initDocMathKeySet();


template <class T>
inline std::string to_string (const T& t)
{
      std::stringstream ss;
      ss << t;
      return ss.str();
}


/****************************************************************
                        Top-level "println" method (public).
 *****************************************************************/


/**
 * @brief 
 * Top-level method to print a whole set of compiled LaTeX formulas,
 * corresponding to an <equation> faustdoc tag.
 *
 * @remark
 * These formulas must have been previously compiled, 
 * via the DocCompile class,
 * and stored in Lateq fields as LaTeX strings.
 */
void Lateq::println(ostream& docout)
{     
      /* 1. Make titles of sub-sets of formulas. */
      string suchthat         = gDocMathStringMap["suchthat"];
      
      string sInputs          = makeItemTitle(fInputSigsFormulas.size(), "inputsigtitle") + makeSignamesList(fInputSigsFormulas, "");
      string sOutputs         = makeItemTitle(fOutputSigsFormulas.size(), "outputsigtitle") + makeSignamesList(fOutputSigsFormulas, suchthat);
      string sConstants = makeItemTitle(fConstSigsFormulas.size(), "constsigtitle") + makeSignamesList(fConstSigsFormulas, suchthat);
      
      vector<list<string> > UISignamesVector = makeUISignamesVector(fUISigsFormulas);
      string sUIElements      = makeItemTitle(fUISigsFormulas.size(), "uisigtitle") + makeSignamesList(UISignamesVector, suchthat);

      unsigned int internalSigsCount = fParamSigsFormulas.size() + fStoreSigsFormulas.size() + fRecurSigsFormulas.size() + fRDTblSigsFormulas.size() + fRWTblSigsFormulas.size() + fSelectSigsFormulas.size() + fPrefixSigsFormulas.size();
      
      vector<list<string> > internalSigsFormulasList;
      if( ! fParamSigsFormulas.empty() )  internalSigsFormulasList.push_back(fParamSigsFormulas);
      if( ! fStoreSigsFormulas.empty() )  internalSigsFormulasList.push_back(fStoreSigsFormulas);
      if( ! fRecurSigsFormulas.empty() )  internalSigsFormulasList.push_back(fRecurSigsFormulas);
      if( ! fRDTblSigsFormulas.empty() )  internalSigsFormulasList.push_back(fRDTblSigsFormulas);
      if( ! fRWTblSigsFormulas.empty() )  internalSigsFormulasList.push_back(fRWTblSigsFormulas);
      if( ! fSelectSigsFormulas.empty() ) internalSigsFormulasList.push_back(fSelectSigsFormulas);
      if( ! fPrefixSigsFormulas.empty() ) internalSigsFormulasList.push_back(fPrefixSigsFormulas);
      
      string sInternals = makeItemTitle(internalSigsCount, "intermedsigtitle") + makeSignamesList(internalSigsFormulasList, suchthat);
      
      /* 2. Successively print each Lateq field containing LaTeX formulas, with a title. */
      
      docout << endl << gDocMathStringMap["lateqcomment"] << endl;
      docout << "\\begin{enumerate}" << endl << endl;
      
      printDGroup       (sOutputs, fOutputSigsFormulas, docout);
      printOneLine      (sInputs, docout);
      const string outputsTitle = "\\item " + sOutputs + "\\ $y_i$\\ " + gDocMathStringMap["for"] + " $i \\in [1," + to_string(fOutputSigsFormulas.size()) + "]$: ";
      printHierarchy    (sUIElements, fUISigsFormulas, docout);
      
      /* The "Internal signals" item gather several fields, like a "super-item"... */
      if( internalSigsCount > 0 ) {
            docout << sInternals;
      }
      fStoreSigsFormulas.sort(compLateqIndexes);
      printDGroup       ("", fParamSigsFormulas, docout);
      printDGroup       ("", fStoreSigsFormulas, docout);
      printDGroup       ("", fRecurSigsFormulas, docout);
      printDGroup       ("", fRDTblSigsFormulas, docout);
      printMath         ("", fRWTblSigsFormulas, docout);
      printMath         ("", fSelectSigsFormulas, docout);
      printMath         ("", fPrefixSigsFormulas, docout);

      printDGroup       (sConstants, fConstSigsFormulas, docout);
      
      docout << "\\end{enumerate}" << endl << endl;
}



/****************************************************************
                        Item title making functions (public).
 *****************************************************************/


string Lateq::makeItemTitle(const unsigned int formulasListSize, const string& titleName)
{
      string item       = "\\item ";
      
      /* Plural handling for titles of sub-sets of formulas. */
      string title      = formulasListSize > 1 ? gDocMathStringMap[titleName + "2"] : gDocMathStringMap[titleName + "1"];
      
      return item + title;
}


string Lateq::makeSigDomain(const list<string>& formulasList)
{
      string signame = "";
      string sigDomain = "";
      
      if (formulasList.size() > 0) {
            string firstEq = *(formulasList.begin());
            signame = getSigName(firstEq);
            
            if(formulasList.size() > 1) {
                  sigDomain = " $" + signame + "_i$ " + gDocMathStringMap["for"] + " $i \\in [1," + to_string(formulasList.size()) + "]$";
            } else {
                  if(signame == "x" || signame == "y") {
                        sigDomain = " $" + signame + "$"; ///< No indices for single input neither single output.
                  } else {
                        sigDomain = " $" + signame + "_1$"; ///< Indices "1" for all other single signal.
                  }
            }
      } else {
            sigDomain = gDocMathStringMap["emptyformulafield"];
      }
      return sigDomain;
}


string Lateq::makeSignamesList(const list<string>& formulasList, const string& ending)
{
      if (formulasList.size() > 0) {
            return makeSigDomain(formulasList) + " " + ending;
      } else {
            return " (" + gDocMathStringMap["emptyformulafield"] + ")";
      }
}


string Lateq::makeSignamesList(const vector<list<string> >& formulasListsVector, const string& ending)
{
      if (formulasListsVector.size() > 0) {
            vector<list<string> >::const_iterator it;
            string signames = "";
            string sep = " ";
            for (it = formulasListsVector.begin(); it != formulasListsVector.end(); ++it) {
                  signames += sep + makeSigDomain(*it);
                  (it != (formulasListsVector.end() - 2)) ? sep = ", " : sep = " " + gDocMathStringMap["and"] + " ";
            }
            return signames + " " + ending;
      } else {
            return " (" + gDocMathStringMap["emptyformulafield"] + ")";
      }
}


string Lateq::getSigName(const string& s)
{
      size_t found;
      string signame;
      
      found = s.find(" =");
      if (found != string::npos) { ///< Looking for a left member.
            signame = s.substr (0, found);
      }
      found = s.find("(t)");
      if (found != string::npos) { ///< Strip "(t)" argument if exists.
            signame = s.substr (0, found);
      }
      found = signame.find("[t]");
      if (found != string::npos) { ///< Strip "[t]" argument if exists (for tables).
            signame = s.substr (0, found);
      }
      found = signame.find_last_of("_");
      if (found != string::npos) { ///< Strip indice if exists.
            signame = signame.substr (0, found);
      }
      
      return signame;
}


vector<list<string> > Lateq::makeUISignamesVector(const multimap<string,string>& field)
{
      map<char,unsigned int> uiTypesMap;
      vector<list<string> > uiSignamesVector;
      unsigned int vIndex = 0;
      
      multimap<string,string>::const_iterator it;
      
      for (it = field.begin(); it != field.end(); ++it) {
            char type         = getUISigType(it->second);
            string signame    = getUISigName(it->second);
            
            map<char,unsigned int>::iterator uiTypesIt;
            uiTypesIt = uiTypesMap.find(type);
            if( uiTypesIt != uiTypesMap.end()) {
                  uiSignamesVector[uiTypesMap[uiTypesIt->second]].push_back(signame);
            } else {
                  ++vIndex;
                  uiTypesMap.insert(pair<char,unsigned int>(type, vIndex));
                  list<string>* tmpList = new(list<string>);
                  tmpList->push_back(signame);
                  uiSignamesVector.push_back(*tmpList);
            }
      }
      
      return uiSignamesVector;
}


string Lateq::getUISigName(const string& s)
{
      size_t found;
      string signame;
      
      found = s.find("${u_");
      if (found != string::npos) { ///< Looking for a UI signal name "{u_?}_{i}(t)".
            signame = s.substr (found+1, 12);
      }
      
      return signame;
}


char Lateq::getUISigType(const string& s)
{
      size_t found;
      char sigtype = '0';
      
      found = s.find("${u_");
      if (found != string::npos) { ///< Looking for a UI signal name "{u_?}_{i}".
            sigtype = s.at (found+4);
      }
      
      return sigtype;
}



/****************************************************************
                        Secondary printing methods (private).
 *****************************************************************/


/**
 * Print a sorted list of input signals names ("x_i"),
 * on a single line, separated by commas.
 *
 * @param[in]     section           The title to print for these formulas.
 * @param[out]    docout            The LaTeX output file to print into.
 */
void Lateq::printOneLine(const string& section, ostream& docout)
{
      docout << section << endl << endl;
}


/**
 * @brief Print a dgroup environment to auto-break long formulas.
 *
 * @remark
 * The "dgroup" and "dmath" environments belong to the "breqn" LaTeX package.
 * The stared variants "dgroup*" and "dmath*" force unnumbered equations.
 *
 * @param[in]     section           The title to print for these formulas.
 * @param[in]     field       The list of LaTeX formulas.
 * @param[out]    docout            The LaTeX output file to print into.
 */
void Lateq::printDGroup(const string& section, list<string>& field, ostream& docout)
{
      if (field.size() > 0) {
            docout << section << endl;
            tab(1,docout); docout << "\\begin{dgroup*}" << endl;
            list<string>::const_iterator s;
            for (s = field.begin(); s != field.end(); ++s) {
                  tab(2,docout); docout << "\\begin{" << "dmath*" << "}" << endl;
                  tab(3,docout); docout << "\t" << *s << endl;
                  tab(2,docout); docout << "\\end{" << "dmath*" << "}" << endl;
            }
            tab(1,docout); docout << "\\end{dgroup*}" << endl;
            docout << endl;
      }
}


/**
 * @brief Print formulas for user interface signals.
 *
 * @param[in]     section           The title to print for these formulas.
 * @param[in]     field       This multimap contains pairs :
 * 1. the path_string is printed as a sub-title item, when new;
 * 2. each latex_string is printed as a preformated row of the  
 * supertabular environment (needed to handle long tables).
 * @param[out]    docout            The LaTeX output file to print into.
 *
 * @remark
 * To decide when one should avoid to print an itemize environment, 
 * a "global" strategy is applied : in the particular case where 
 * ONLY empty paths were detected in the WHOLE container (all UIs
 * are at the top level).
 * In this particular case, UI strings are directly printed, 
 * and their (empty!) path is ignored...
 * In the other case, we have to print an itemize environment
 * and manage paths printing (empty AND non-empty paths) as items.
 *
 * @see DocCompiler::prepareIntervallicUI
 * @see DocCompiler::prepareBinaryUI
 */
void Lateq::printHierarchy(const string& section, multimap<string,string>& field, ostream& docout)
{
      if (field.size() > 0) {
            docout << section << endl;

            bool hasSomePaths = hasNotOnlyEmptyKeys(field); ///< Manage itemize printing for pathnames.
            unsigned int n;   ///< Manage latex indentation offset.
                        
            if (hasSomePaths) {
                  tab(0,docout); docout << "\\begin{itemize}" << endl;
                  n = 1;
            } else {
                  n = 0;
            }

            multimap<string,string>::iterator it;
            string uidir = "improbable_starting_dirname";
            bool startFlag = true;

            for (it = field.begin(); it != field.end(); ++it) {
                  /* Manage supertabular environment bounds and pathname printing. */
                  if (it->first != uidir) {
                        if (!startFlag) {
                              tab(n+2,docout); docout << "\\end{supertabular}" << endl;
                              tab(n+1,docout); docout << "\\end{center}" << endl;
                        } else { 
                              startFlag = false; 
                        }
                        if (hasSomePaths) {
                              /* Print the current pathname if new and if pathnames requested. */
                              if (it->first != "") {
                                    tab(n+0,docout); docout << "\\item \\textsf{" << it->first << "}" << endl;
                              } else { 
                                    tab(n+0,docout); docout << "\\item \\emph{" << gDocMathStringMap["rootlevel"] << "}" << endl;
                              }
                        }
                        tab(n+1,docout); docout << "\\begin{center}" << endl;
                        tab(n+2,docout); docout << "\\begin{supertabular}{lll}" << endl;
                  }
                  /* Print the current formula. */
                  tab(n+3,docout); docout << it->second << endl;
                  uidir = it->first;
            }
            tab(n+2,docout); docout << "\\end{supertabular}" << endl;
            tab(n+1,docout); docout << "\\end{center}" << endl;
            if (hasSomePaths) {
                  tab(n+0,docout); docout << "\\end{itemize}" << endl;
            }
            docout << endl;
      }
}


/**
 * @brief Print formulas for select2, select3 and prefix signals.
 *
 * @param[in]     section           The title to print for these formulas.
 * @param[in]     field       The list of LaTeX arrays (for braces with two lines).
 * @param[out]    docout            The LaTeX output file to print into.
 * 
 * @see DocCompiler::generateSelect2
 * @see DocCompiler::generateSelect3
 * @see DocCompiler::generatePrefix
 */
void Lateq::printMath(const string& section, list<string>& field, ostream& docout)
{
      if (field.size() > 0) {
            docout << section;
            docout << "\\begin{displaymath}" << endl;
            list<string>::iterator s;
            for (s = field.begin(); s != field.end(); ++s) {
                  docout << *s << endl;         
            }
            docout << "\\end{displaymath}" << endl;
            docout << endl;         
      }
}


/** Simple handling of indentation. */
void Lateq::tab (int n, ostream& docout) const
{ 
      while (n--) docout << '\t'; 
}


/**
 * @brief Find out whether all keys of the multimap are empty or not.
 * 
 * In other words :
 * Check that some UIs have a path (non empty). 
 *
 * In other other words :
 * Check that all UIs are not at top-level.
 */
bool Lateq::hasNotOnlyEmptyKeys(multimap<string,string>& mm) 
{
      typedef multimap<string,string>::iterator MMIT;
      pair<MMIT,MMIT> range;
      range = mm.equal_range("");   ///< Look for pairs with empty keys.
      bool hasOnlyEmptyPaths = (range.first == mm.begin()) && (range.second == mm.end());
      return !hasOnlyEmptyPaths;
}



/** 
 * Dispatch initialization of autodoc container.
 */
void initDocMath() 
{
      initDocMathKeySet();
}


/****************************************************************
                        Internal static functions.
 *****************************************************************/


/**
 * Compare indexes of two LaTeX strings, 
 * for the sort() method applied on list<string> fields.
 */
static bool compLateqIndexes(const string& s1, const string& s2)
{
      return getLateqIndex(s1) < getLateqIndex(s2);
}


/**
 * Find out the index of signals in LaTeX signal definition strings,
 * between the first "_{" and "}" patterns.
 *
 * @param[in]     s           A LaTeX string to parse.
 * @return        <int> The index found, as an integer.
 */
static int getLateqIndex(const string& s)
{
      size_t p1;
      size_t p2;
      string sIndex;
            
      p1 = s.find("_{"); 
      if (p1==string::npos) {
            cerr << "Error : getLateqIndex found no \"{_\" substring.\n";
            exit(1); }
      p1 += 2;
      
      p2 = s.find("}", p1); 
      if (p2==string::npos) {
            cerr << "Error : getLateqIndex found no \"}\" substring\n.";
            exit(1); }
      p2 -= 3;
      
      sIndex = s.substr (p1, p2);

      return atoi(sIndex.c_str());
}


/** 
 * Initialize gDocMathKeySet, a set containing all the keywords.
 */
static void initDocMathKeySet()
{
      gDocMathKeySet.insert("inputsigtitle1");
      gDocMathKeySet.insert("inputsigtitle2");
      gDocMathKeySet.insert("outputsigtitle1");
      gDocMathKeySet.insert("outputsigtitle2");
      gDocMathKeySet.insert("constsigtitle1");
      gDocMathKeySet.insert("constsigtitle2");
      gDocMathKeySet.insert("uisigtitle1");
      gDocMathKeySet.insert("uisigtitle2");
      gDocMathKeySet.insert("intermedsigtitle1");
      gDocMathKeySet.insert("intermedsigtitle2");
      gDocMathKeySet.insert("lateqcomment");
      gDocMathKeySet.insert("emptyformulafield");
      gDocMathKeySet.insert("defaultvalue");
      gDocMathKeySet.insert("suchthat");
      gDocMathKeySet.insert("and");
      gDocMathKeySet.insert("for");
      gDocMathKeySet.insert("rootlevel");

      gDocMathKeySet.insert("dgmcaption");
}



Generated by  Doxygen 1.6.0   Back to index