FAUST compiler  0.9.9.6b8
doc_compile.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021 
00022 /*****************************************************************************
00023     HISTORY
00024     22/01/05 : corrected bug on bool signals cached in float variables
00025     2009-08-16 : First "doc" version (kb)
00026     2009-11-22 : Some clean up (kb)
00027 *****************************************************************************/
00028 
00029 
00030 
00031 
00032 #include <stdio.h>
00033 #include <iostream>
00034 #include <sstream>
00035 #include <vector>
00036 #include <math.h>
00037 
00038 #include "doc_compile.hh"
00039 #include "sigtype.hh"
00040 #include "floats.hh"
00041 #include "sigprint.hh"
00042 #include "sigtyperules.hh"
00043 #include "recursivness.hh"
00044 #include "simplify.hh"
00045 #include "privatise.hh"
00046 #include "prim2.hh"
00047 #include "xtended.hh"
00048 #include "compatibility.hh"
00049 #include "ppsig.hh"
00050 #include "names.hh"
00051 #include "doc.hh"
00052 #include "tlib.hh"
00053 #include "doc_notice.hh"
00054 
00055 
00056 extern bool     gLessTempSwitch;
00057 extern int      gMaxCopyDelay;
00058 extern map<string, string>      gDocMathStringMap;
00059 
00060 extern bool     getSigListNickName(Tree t, Tree& id);
00061 
00062 static const unsigned int MAX_RIGHT_MEMBER  = 20;
00063 static const unsigned int MAX_SUB_EXPR      = 10;
00064 
00065 
00066 /*****************************************************************************
00067                         getFreshID
00068 *****************************************************************************/
00069 
00070 map<string, int>    DocCompiler::fIDCounters;
00071 
00072 string DocCompiler::getFreshID(const string& prefix)
00073 {
00074     if (fIDCounters.find(prefix) == fIDCounters.end()) {
00075         fIDCounters[prefix] = 1;
00076     }
00077     int n = fIDCounters[prefix];
00078     fIDCounters[prefix] = n+1;
00079     
00080     return subst("$0_{$1}", prefix, docT(n));
00081 }
00082 
00083 
00084 /*****************************************************************************
00085                             prepare
00086 *****************************************************************************/
00087 
00088 Tree DocCompiler::annotate(Tree LS)
00089 {
00090     recursivnessAnnotation(LS);     // Annotate LS with recursivness information
00091     typeAnnotation(LS);             // Annotate LS with type information
00092     sharingAnalysis(LS);            // annotate LS with sharing count
00093     fOccMarkup.mark(LS);            // annotate LS with occurences analysis
00094 
00095     return LS;
00096 }
00097 
00098 /*****************************************************************************
00099                             compileLateq
00100 *****************************************************************************/
00101 
00102 Lateq* DocCompiler::compileLateq (Tree L, Lateq* compiledEqn)
00103 {
00104     //cerr << "Documentator : compileLateq : L = "; printSignal(L, stdout, 0); cerr << endl;
00105     
00106     fLateq = compiledEqn; 
00107     int priority = 0;
00108     
00109     for (int i = 0; isList(L); L = tl(L), i++) {
00110         Tree sig = hd(L);
00111         Tree id;
00112         if(getSigNickname(sig, id)) {
00113             //cerr << "Documentator : compileLateq : NICKNAMEPROPERTY = " << tree2str(id) << endl;
00114             fLateq->addOutputSigFormula(subst("$0(t) = $1", tree2str(id), CS(sig, priority), docT(i))); 
00115         } else {
00116             //cerr << "Documentator : compileLateq : NO NICKNAMEPROPERTY" << endl;
00117             if (fLateq->outputs() == 1) {
00118                 fLateq->addOutputSigFormula(subst("y(t) = $0", CS(sig, priority))); 
00119                 gDocNoticeFlagMap["outputsig"] = true;
00120             } else {
00121                 fLateq->addOutputSigFormula(subst("$0(t) = $1", getFreshID("y"), CS(sig, priority)));   
00122                 gDocNoticeFlagMap["outputsigs"] = true;
00123             }
00124         }
00125     }
00126     return fLateq;
00127 }
00128 
00129 
00130 
00131 /*****************************************************************************
00132                              CS : compile a signal
00133 *****************************************************************************/
00134 
00141 bool DocCompiler::getCompiledExpression(Tree sig, string& cexp)
00142 {
00143     return fCompileProperty.get(sig, cexp);
00144 }
00145 
00146 
00153 string DocCompiler::setCompiledExpression(Tree sig, const string& cexp)
00154 {
00155     fCompileProperty.set(sig, cexp);
00156     return cexp;
00157 }
00158 
00159 
00165 string  DocCompiler::CS (Tree sig, int priority)
00166 {
00167     string      code;
00168 
00169     if (!getCompiledExpression(sig, code)) { // not compiled yet.
00170         code = generateCode(sig, priority);
00171         setCompiledExpression(sig, code);
00172     }
00173     return code;
00174 }
00175 
00176 
00177 
00178 /*****************************************************************************
00179                     generateCode : dispatch according to signal
00180 *****************************************************************************/
00181 
00182 
00193 string  DocCompiler::generateCode (Tree sig, int priority)
00194 {
00195     int     i;
00196     double  r;
00197     Tree    c, sel, x, y, z, u, label, ff, largs, type, name, file;
00198     
00199     if ( getUserData(sig) )                         { printGCCall(sig,"generateXtended");   return generateXtended  (sig, priority);        }
00200     else if ( isSigInt(sig, &i) )                   { printGCCall(sig,"generateNumber");    return generateNumber   (sig, docT(i));         }
00201     else if ( isSigReal(sig, &r) )                  { printGCCall(sig,"generateNumber");    return generateNumber   (sig, docT(r));         }
00202     else if ( isSigInput(sig, &i) )                 { printGCCall(sig,"generateInput");     return generateInput    (sig, docT(i+1));       }
00203     else if ( isSigOutput(sig, &i, x) )             { printGCCall(sig,"generateOutput");    return generateOutput   (sig, docT(i+1), CS(x, priority));  }
00204     
00205     else if ( isSigFixDelay(sig, x, y) )            { printGCCall(sig,"generateFixDelay");  return generateFixDelay (sig, x, y, priority);  }
00206     else if ( isSigPrefix(sig, x, y) )              { printGCCall(sig,"generatePrefix");    return generatePrefix   (sig, x, y, priority);  }
00207     else if ( isSigIota(sig, x) )                   { printGCCall(sig,"generateIota");      return generateIota     (sig, x);               }
00208     
00209     else if ( isSigBinOp(sig, &i, x, y) )           { printGCCall(sig,"generateBinOp");     return generateBinOp    (sig, i, x, y, priority);       }
00210     else if ( isSigFFun(sig, ff, largs) )           { printGCCall(sig,"generateFFun");      return generateFFun     (sig, ff, largs, priority);     }
00211     else if ( isSigFConst(sig, type, name, file) )  { printGCCall(sig,"generateFConst");    return generateFConst   (sig, tree2str(file), tree2str(name)); }
00212     else if ( isSigFVar(sig, type, name, file) )    { printGCCall(sig,"generateFVar");      return generateFVar     (sig, tree2str(file), tree2str(name)); }
00213     
00214     // new special tables for documentation purposes
00215 
00216     else if ( isSigDocConstantTbl(sig, x, y) )      { printGCCall(sig,"generateDocConstantTbl");    return generateDocConstantTbl (sig, x, y);  }
00217     else if ( isSigDocWriteTbl(sig,x,y,z,u) )       { printGCCall(sig,"generateDocWriteTbl");       return generateDocWriteTbl (sig, x, y, z, u); }
00218     else if ( isSigDocAccessTbl(sig, x, y) )        { printGCCall(sig, "generateDocAccessTbl");     return generateDocAccessTbl(sig, x, y); }
00219 
00220 
00221     else if ( isSigSelect2(sig, sel, x, y) )        { printGCCall(sig,"generateSelect2");   return generateSelect2  (sig, sel, x, y, priority);     }
00222     else if ( isSigSelect3(sig, sel, x, y, z) )     { printGCCall(sig,"generateSelect3");   return generateSelect3  (sig, sel, x, y, z, priority);  }
00223     
00224     else if ( isProj(sig, &i, x) )                  { printGCCall(sig,"generateRecProj");   return generateRecProj  (sig, x, i, priority);  }
00225     
00226     else if ( isSigIntCast(sig, x) )                { printGCCall(sig,"generateIntCast");   return generateIntCast  (sig, x, priority);     }
00227     else if ( isSigFloatCast(sig, x) )              { printGCCall(sig,"generateFloatCast"); return generateFloatCast(sig, x, priority);     }
00228     
00229     else if ( isSigButton(sig, label) )             { printGCCall(sig,"generateButton");    return generateButton   (sig, label);           }
00230     else if ( isSigCheckbox(sig, label) )           { printGCCall(sig,"generateCheckbox");  return generateCheckbox (sig, label);           }
00231     else if ( isSigVSlider(sig, label,c,x,y,z) )    { printGCCall(sig,"generateVSlider");   return generateVSlider  (sig, label, c,x,y,z);  }
00232     else if ( isSigHSlider(sig, label,c,x,y,z) )    { printGCCall(sig,"generateHSlider");   return generateHSlider  (sig, label, c,x,y,z);  }
00233     else if ( isSigNumEntry(sig, label,c,x,y,z) )   { printGCCall(sig,"generateNumEntry");  return generateNumEntry (sig, label, c,x,y,z);  }
00234     
00235     else if ( isSigVBargraph(sig, label,x,y,z) )    { printGCCall(sig,"generateVBargraph"); return CS(z, priority);}//generateVBargraph     (sig, label, x, y, CS(z, priority)); }
00236     else if ( isSigHBargraph(sig, label,x,y,z) )    { printGCCall(sig,"generateHBargraph"); return CS(z, priority);}//generateHBargraph     (sig, label, x, y, CS(z, priority)); }
00237     else if ( isSigAttach(sig, x, y) )              { printGCCall(sig,"generateAttach");    return generateAttach   (sig, x, y, priority); }
00238     
00239     else {
00240         cerr << "Error in d signal, unrecognized signal : " << *sig << endl;
00241         exit(1);
00242     }
00243     assert(0);
00244     return "error in generate code";
00245 }
00246 
00247 
00254 void DocCompiler::printGCCall(Tree sig, const string& calledFunction)
00255 {
00256     bool printCalls = false;
00257     bool maskSigs   = false;
00258     
00259     if(printCalls) {
00260         cerr << "  -> generateCode calls " << calledFunction;
00261         if(maskSigs) {
00262             cerr << endl;
00263         } else {
00264             cerr << " on " << ppsig(sig) << endl;
00265         }
00266     }
00267 }
00268 
00269 
00270 /*****************************************************************************
00271                                NUMBERS
00272 *****************************************************************************/
00273 
00274 
00275 string DocCompiler::generateNumber (Tree sig, const string& exp)
00276 {
00277     string      ctype, vname;
00278     Occurences* o = fOccMarkup.retrieve(sig);
00279 
00280     // check for number occuring in delays
00281     if (o->getMaxDelay()>0) {
00282         getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
00283         gDocNoticeFlagMap["recursigs"] = true;
00284         //cerr << "- r : generateNumber : \"" << vname << "\"" << endl;            
00285         generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00286     }
00287     return exp;
00288 }
00289 
00290 /*****************************************************************************
00291                                FOREIGN CONSTANTS
00292 *****************************************************************************/
00293 
00294 
00295 string DocCompiler::generateFConst (Tree sig, const string& file, const string& exp)
00296 {
00297     string      ctype, vname;
00298     Occurences* o = fOccMarkup.retrieve(sig);
00299 
00300     if (o->getMaxDelay()>0) {
00301         getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
00302         gDocNoticeFlagMap["recursigs"] = true;
00303         //cerr << "- r : generateFConst : \"" << vname << "\"" << endl;            
00304         generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00305     }
00306     
00307     if (exp == "fSamplingFreq") {
00308         //gDocNoticeFlagMap["fsamp"] = true;
00309         return "f_S";
00310     }
00311     
00312     return "\\mathrm{"+exp+"}";
00313 }
00314 
00315 /*****************************************************************************
00316                                FOREIGN VARIABLES
00317 *****************************************************************************/
00318 
00319 
00320 string DocCompiler::generateFVar (Tree sig, const string& file, const string& exp)
00321 {
00322     string      ctype, vname;
00323     Occurences* o = fOccMarkup.retrieve(sig);
00324 
00325     if (o->getMaxDelay()>0) {
00326         getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
00327         gDocNoticeFlagMap["recursigs"] = true;
00328         //cerr << "- r : generateFVar : \"" << vname << "\"" << endl;            
00329         setVectorNameProperty(sig, vname);
00330         generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00331     }
00332     return generateCacheCode(sig, exp);
00333 }
00334 
00335 
00336 /*****************************************************************************
00337                                INPUTS - OUTPUTS
00338 *****************************************************************************/
00339 
00340 
00341 string DocCompiler::generateInput (Tree sig, const string& idx)
00342 {
00343     if (fLateq->inputs() == 1) {
00344         setVectorNameProperty(sig, "x");
00345         fLateq->addInputSigFormula("x(t)"); 
00346         gDocNoticeFlagMap["inputsig"] = true;
00347         return generateCacheCode(sig, "x(t)");
00348     } else {
00349         setVectorNameProperty(sig, subst("x_{$0}", idx));
00350         fLateq->addInputSigFormula(subst("x_{$0}(t)", idx));
00351         gDocNoticeFlagMap["inputsigs"] = true;
00352         return generateCacheCode(sig, subst("x_{$0}(t)", idx));
00353     }
00354 }
00355 
00356 
00358 string DocCompiler::generateOutput (Tree sig, const string& idx, const string& arg)
00359 {
00360     string dst;
00361     
00362     if (fLateq->outputs() == 1) {
00363         dst = subst("y(t)", idx);
00364         gDocNoticeFlagMap["outputsig"] = true;
00365     } else {
00366         dst = subst("y_{$0}(t)", idx);
00367         gDocNoticeFlagMap["outputsigs"] = true;
00368     }
00369     
00370     fLateq->addOutputSigFormula(subst("$0 = $1", dst, arg));
00371     return dst;
00372 }
00373 
00374 
00375 /*****************************************************************************
00376                                BINARY OPERATION
00377 *****************************************************************************/
00378 
00400 
00401 static bool associative (int opcode) {
00402     return (opcode == kAdd) || (opcode == kMul) || (opcode == kAND) || (opcode == kOR) || (opcode == kXOR);
00403 }
00404 
00405 string DocCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2, int priority)
00406 {
00407     string s;
00408     int thisPriority = gBinOpLateqTable[opcode]->fPriority;
00409     
00410     /* Priority parenthesis handling. */
00411     string lpar = "";
00412     string rpar = "";
00413     if ( (thisPriority < priority) || ((thisPriority == priority) && !associative(opcode)) ) {
00414         // (a+b)*c or (a/b)/c need parenthesis
00415         lpar = " \\left(";
00416         rpar = "\\right) ";
00417     }
00418     
00419     Type t1 = getCertifiedSigType(arg1);
00420     Type t2 = getCertifiedSigType(arg2);
00421     bool intOpDetected = false;
00422     if ( (t1->nature() == kInt) && (t2->nature() == kInt) ) {
00423         intOpDetected = true;
00424     }
00425     
00426     string op;
00427     if(!intOpDetected) {
00428         op = gBinOpLateqTable[opcode]->fName;
00429     } else {
00430         switch (opcode) {
00431             case kAdd:
00432                 op = "\\oplus";
00433                 gDocNoticeFlagMap["intplus"] = true;
00434                 break;
00435             case kSub:
00436                 op = "\\ominus";
00437                 gDocNoticeFlagMap["intminus"] = true;
00438                 break;
00439             case kMul:
00440                 op = "\\odot";
00441                 gDocNoticeFlagMap["intmult"] = true;
00442                 break;
00443             case kDiv:
00444                 op = "\\oslash";
00445                 gDocNoticeFlagMap["intdiv"] = true;
00446                 gDocNoticeFlagMap["intcast"] = true; // "$normalize(int(i/j))$" in the notice.
00447                 break;
00448             default:
00449                 op = gBinOpLateqTable[opcode]->fName;
00450                 break;
00451         }
00452     }
00453     
00454     /* LaTeX frac{}{} handling VS general case. */
00455     if ( (opcode == kDiv) && (!intOpDetected) ) { 
00456         s = subst("$0\\frac{$1}{$2}$3", lpar, CS(arg1, 0), CS(arg2, 0), rpar);
00457     } else {
00458         s = subst("$0$1 $2 $3$4", lpar, CS(arg1, thisPriority), op, CS(arg2, thisPriority), rpar);
00459     }
00460     
00461 //  if (opcode == kMul) {
00462 //      gDocNoticeFlagMap["cdot"] = true;
00463 //  }
00464     
00465     return generateCacheCode(sig, s);
00466 }
00467 
00468 
00469 /*****************************************************************************
00470                                Primitive Operations
00471 *****************************************************************************/
00472 
00473 string DocCompiler::generateFFun(Tree sig, Tree ff, Tree largs, int priority)
00474 {
00475     string code = ffname(ff);
00476     code += '(';
00477     string sep = "";
00478     for (int i = 0; i< ffarity(ff); i++) {
00479         code += sep;
00480         code += CS(nth(largs, i), priority);
00481         sep = ", ";
00482     }
00483     code += ')';
00484     
00485     gDocNoticeFlagMap["foreignfun"] = true;
00486 
00487     return "\\mathrm{ff"+code+"}";
00488 }
00489 
00490 
00491 /*****************************************************************************
00492                                CACHE CODE
00493 *****************************************************************************/
00494 
00495 void DocCompiler::getTypedNames(Type t, const string& prefix, string& ctype, string& vname)
00496 {
00497     if (t->nature() == kInt) {
00498         ctype = "int"; vname = subst("$0", getFreshID(prefix));
00499     } else {
00500         ctype = ifloat(); vname = subst("$0", getFreshID(prefix));
00501     }
00502 }
00503 
00504 
00511 static bool isVerySimpleFormula(Tree sig)
00512 {
00513     int     i;
00514     double  r;
00515     Tree    type, name, file, label, c, x, y, z;
00516     
00517     return  isSigInt(sig, &i) 
00518     ||  isSigReal(sig, &r)
00519     ||  isSigInput(sig, &i)
00520     ||  isSigFConst(sig, type, name, file)
00521     ||  isSigButton(sig, label)
00522     ||  isSigCheckbox(sig, label)
00523     ||  isSigVSlider(sig, label,c,x,y,z)
00524     ||  isSigHSlider(sig, label,c,x,y,z)
00525     ||  isSigNumEntry(sig, label,c,x,y,z)
00526     ;
00527 }
00528 
00529 
00530 string DocCompiler::generateCacheCode(Tree sig, const string& exp)
00531 {
00532     //cerr << "!! entering generateCacheCode with sig=\"" << ppsig(sig) << "\"" << endl;    
00533     
00534     string      vname, ctype, code, vectorname;
00535     
00536     int         sharing = getSharingCount(sig);
00537     Occurences* o = fOccMarkup.retrieve(sig);
00538     
00539     // check reentrance
00540     if (getCompiledExpression(sig, code)) {
00541         //cerr << "!! generateCacheCode called a true getCompiledExpression" << endl;
00542         return code;
00543     }
00544     
00545     // check for expression occuring in delays
00546     if (o->getMaxDelay()>0) {
00547         if (getVectorNameProperty(sig, vectorname)) {
00548             return exp;
00549         }
00550         getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
00551         gDocNoticeFlagMap["recursigs"] = true;
00552         //cerr << "- r : generateCacheCode : vame=\"" << vname << "\", for sig=\"" << ppsig(sig) << "\"" << endl;
00553         if (sharing>1) {
00554             //cerr << "      generateCacheCode calls generateDelayVec(generateVariableStore) on vame=\"" << vname << "\"" << endl;            
00555             return generateDelayVec(sig, generateVariableStore(sig,exp), ctype, vname, o->getMaxDelay());
00556         } else {
00557             //cerr << "      generateCacheCode calls generateDelayVec(exp) on vame=\"" << vname << "\"" << endl;            
00558             return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00559         }
00560     } 
00561     else if (sharing == 1 || getVectorNameProperty(sig, vectorname) || isVerySimpleFormula(sig)) {
00562         //cerr << "! generateCacheCode : sharing == 1 : return \"" << exp << "\"" << endl;
00563         return exp;
00564     } 
00565     else if (sharing > 1) {
00566         //cerr << "! generateCacheCode : sharing > 1 : return \"" << exp << "\"" << endl;
00567         return generateVariableStore(sig, exp);
00568     } 
00569     else {
00570         cerr << "Error in sharing count (" << sharing << ") for " << *sig << endl;
00571         exit(1);
00572     }
00573     
00574     return "Error in generateCacheCode";
00575 }
00576 
00577 
00578 string DocCompiler::generateVariableStore(Tree sig, const string& exp)
00579 {
00580     string      vname, ctype;
00581     Type        t = getCertifiedSigType(sig);
00582     
00583     switch (t->variability()) {
00584             
00585         case kKonst :
00586             getTypedNames(t, "k", ctype, vname); 
00587             fLateq->addConstSigFormula(subst("$0 = $1", vname, exp));
00588             gDocNoticeFlagMap["constsigs"] = true;
00589             return vname;
00590             
00591         case kBlock :
00592             getTypedNames(t, "p", ctype, vname); 
00593             fLateq->addParamSigFormula(subst("$0(t) = $1", vname, exp));
00594             gDocNoticeFlagMap["paramsigs"] = true;
00595             setVectorNameProperty(sig, vname);
00596             return subst("$0(t)", vname);
00597             
00598         case kSamp :
00599             if(getVectorNameProperty(sig, vname)) {
00600                 return subst("$0(t)", vname);
00601             } else {
00602                 getTypedNames(t, "s", ctype, vname);
00603                 //cerr << "- generateVariableStore : \"" << subst("$0(t) = $1", vname, exp) << "\"" << endl;
00604                 fLateq->addStoreSigFormula(subst("$0(t) = $1", vname, exp));
00605                 gDocNoticeFlagMap["storedsigs"] = true;
00606                 setVectorNameProperty(sig, vname);
00607                 return subst("$0(t)", vname);
00608             }
00609             
00610         default:
00611             assert(0);
00612             return "";
00613     }
00614 }
00615 
00616 
00617 /*****************************************************************************
00618                                     CASTING
00619 *****************************************************************************/
00620 
00621 
00622 string DocCompiler::generateIntCast(Tree sig, Tree x, int priority)
00623 {
00624     gDocNoticeFlagMap["intcast"] = true;
00625              
00626     return generateCacheCode(sig, subst("\\mathrm{int}\\left($0\\right)", CS(x, 0)));
00627 }
00628 
00629 
00637 string DocCompiler::generateFloatCast (Tree sig, Tree x, int priority)
00638 {
00639     return generateCacheCode(sig, subst("$0", CS(x, priority)));
00640 }
00641 
00642 
00643 /*****************************************************************************
00644                             user interface elements
00645 *****************************************************************************/
00646 
00647 string DocCompiler::generateButton(Tree sig, Tree path)
00648 {
00649     string vname = getFreshID("{u_b}");
00650     string varname = vname + "(t)";
00651     fLateq->addUISigFormula(getUIDir(path), prepareBinaryUI(varname, path));
00652     gDocNoticeFlagMap["buttonsigs"] = true;
00653     return generateCacheCode(sig, varname);
00654 }
00655 
00656 string DocCompiler::generateCheckbox(Tree sig, Tree path)
00657 {
00658     string vname = getFreshID("{u_c}");
00659     string varname = vname + "(t)";
00660     fLateq->addUISigFormula(getUIDir(path), prepareBinaryUI(varname, path));
00661     gDocNoticeFlagMap["checkboxsigs"] = true;
00662     return generateCacheCode(sig, varname);
00663 }
00664 
00665 string DocCompiler::generateVSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
00666 {
00667     string varname = getFreshID("{u_s}") + "(t)";
00668     fLateq->addUISigFormula(getUIDir(path), prepareIntervallicUI(varname, path, cur, min, max));
00669     gDocNoticeFlagMap["slidersigs"] = true;
00670     return generateCacheCode(sig, varname);
00671 }
00672 
00673 string DocCompiler::generateHSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
00674 {
00675     string varname = getFreshID("{u_s}") + "(t)";
00676     fLateq->addUISigFormula(getUIDir(path), prepareIntervallicUI(varname, path, cur, min, max));
00677     gDocNoticeFlagMap["slidersigs"] = true;
00678     return generateCacheCode(sig, varname);
00679 }
00680 
00681 string DocCompiler::generateNumEntry(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
00682 {
00683     string varname = getFreshID("{u_n}") + "(t)";       
00684     fLateq->addUISigFormula(getUIDir(path), prepareIntervallicUI(varname, path, cur, min, max));
00685     gDocNoticeFlagMap["nentrysigs"] = true;
00686     return generateCacheCode(sig, varname);
00687 }
00688 
00689 
00690 string DocCompiler::generateVBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
00691 {
00692     string varname = getFreshID("{u_g}");
00693 
00694     Type t = getCertifiedSigType(sig);
00695     switch (t->variability()) {
00696 
00697         case kKonst :
00698             break;
00699 
00700         case kBlock :
00701             break;
00702 
00703         case kSamp :
00704             break;
00705     }
00706     return generateCacheCode(sig, varname);
00707 }
00708 
00709 
00710 string DocCompiler::generateHBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
00711 {
00712     string varname = getFreshID("{u_g}");
00713 
00714     Type t = getCertifiedSigType(sig);
00715     switch (t->variability()) {
00716 
00717         case kKonst :
00718             break;
00719 
00720         case kBlock :
00721             break;
00722 
00723         case kSamp :
00724             break;
00725     }
00726     return generateCacheCode(sig, varname);
00727 }
00728 
00729 
00730 string DocCompiler::generateAttach (Tree sig, Tree x, Tree y, int priority)
00731 {
00732     string vname;
00733     string exp;
00734     
00735     CS(y, priority);
00736     exp = CS(x, priority);
00737     
00738     if(getVectorNameProperty(x, vname)) {
00739         setVectorNameProperty(sig, vname);
00740     }
00741 
00742     return generateCacheCode(sig, exp);
00743 }
00744 
00745 
00746 
00747 
00748 /*****************************************************************************
00749                                     TABLES
00750  (note : tables here are siplified versions different from the ones used to 
00751   generate c++ code)
00752 *****************************************************************************/
00753 
00758 string DocCompiler::generateDocConstantTbl (Tree /*tbl*/, Tree size, Tree isig)
00759 {   
00760     string  vname, ctype;
00761     string  init = CS(isig,0);
00762 
00763     int     n;
00764     if (!isSigInt(size, &n)) {
00765         cerr << "error in DocCompiler::generateDocConstantTbl() : "
00766              << *size
00767              << " is not an integer expression and can't be used as a table size' "
00768              << endl;
00769     }
00770 
00771     // allocate a name v_i for the table
00772     getTypedNames(getCertifiedSigType(isig), "v", ctype, vname);
00773     
00774     // add a comment on tables in the notice
00775         gDocNoticeFlagMap["tablesigs"] = true;
00776     
00777     // add equation v[t] = isig(t)
00778         fLateq->addRDTblSigFormula(subst("$0[t] = $1 \\condition{when $$t \\in [0,$2]$$} ", vname, init, T(n-1)));
00779     
00780     // note that the name of the table can never be used outside an sigDocTableAccess
00781     return vname;
00782 }
00783 
00784 
00788 static bool isSeparator(char c)
00789 {
00790     bool w = (  ((c >= 'a') && (c <='z'))
00791             ||  ((c >= 'A') && (c <='Z'))
00792             ||  ((c >= '0') && (c <='9'))
00793             );
00794 
00795     return ! w;
00796 }
00797 
00798 
00802 static string replaceTimeBy(const string& src, char r)
00803 {
00804     string  dst;
00805     char    pre = 0;
00806     for (size_t i=0; i < src.size(); i++)
00807     {
00808         char x = src[i];
00809         if ((x=='t') && isSeparator(pre) && ((i == src.size()-1) || isSeparator(src[i+1]))) {
00810             dst.push_back(r);
00811         } else {
00812             dst.push_back(x);
00813         }
00814         pre = x;
00815     }
00816     return dst;
00817 }
00818 
00823 string DocCompiler::generateDocWriteTbl (Tree /*tbl*/, Tree size, Tree isig, Tree widx, Tree wsig)
00824 {
00825     string  vname, ctype;
00826     string  init = CS(isig,0);
00827     int     n;
00828     if (!isSigInt(size, &n)) {
00829         cerr << "error in DocCompiler::generateDocWriteTbl() : "
00830              << *size
00831              << " is not an integer expression and can't be used as a table size' "
00832              << endl;
00833     }
00834 
00835 
00836     // allocate a name w_i for the table
00837     getTypedNames(getCertifiedSigType(isig), "w", ctype, vname);
00838 
00839     // add a comment on tables in the notice
00840     gDocNoticeFlagMap["tablesigs"] = true;
00841 
00842     // describe the table equation
00843     string ltqRWTableDef;
00844     ltqRWTableDef += subst("$0(t)[i] = \n", vname);
00845     ltqRWTableDef += "\\left\\{\\begin{array}{ll}\n";
00846     ltqRWTableDef += subst("$0 & \\mbox{if \\,} t < 0 \\mbox{\\, and \\,}  i \\in [0,$1] \\\\\n",   replaceTimeBy(init,'i'), T(n-1));
00847     ltqRWTableDef += subst("$0 & \\mbox{if \\,} i = $1 \\\\\n", CS(wsig,0), CS(widx,0));
00848     ltqRWTableDef += subst("$0(t\\!-\\!1)[i] & \\mbox{otherwise} \\\\\n", vname);
00849     ltqRWTableDef += "\\end{array}\\right.";
00850         
00851     // add the table equation
00852         fLateq->addRWTblSigFormula(ltqRWTableDef); //w(t) = initsig(t)
00853     
00854     // note that the name of the table can never be used outside an sigDocTableAccess
00855     return vname;
00856 }
00857 
00858 
00863 string DocCompiler::generateDocAccessTbl (Tree sig, Tree tbl, Tree ridx)
00864 {
00865     // the compilation of a table always returns its name
00866     string  vname = CS(tbl, 0);
00867     string result = subst("$0[$1]", vname, CS(ridx,0) );
00868 
00869     return generateCacheCode(sig, result);
00870 }
00871 
00872 bool DocCompiler::isShortEnough(string& s, unsigned int max)
00873 {   
00874     return (s.length() <= max);
00875 }
00876 
00877 
00878 
00879 /*****************************************************************************
00880                                RECURSIONS
00881 *****************************************************************************/
00882 
00883 
00887 string DocCompiler::generateRecProj(Tree sig, Tree r, int i, int priority)
00888 {
00889     string  vname;
00890     Tree    var, le;
00891     
00892     //cerr << "*** generateRecProj sig : \"" << ppsig(sig) << "\"" << endl;            
00893 
00894     if ( ! getVectorNameProperty(sig, vname)) {
00895         assert(isRec(r, var, le));
00896         //cerr << "    generateRecProj has NOT YET a vname : " << endl;            
00897         //cerr << "--> generateRecProj calls generateRec on \"" << ppsig(sig) << "\"" << endl;            
00898         generateRec(r, var, le, priority);
00899         assert(getVectorNameProperty(sig, vname));
00900         //cerr << "<-- generateRecProj vname : \"" << subst("$0(t)", vname) << "\"" << endl;            
00901     } else {
00902         //cerr << "(generateRecProj has already a vname : \"" << subst("$0(t)", vname) << "\")" << endl;            
00903     }
00904     return subst("$0(t)", vname);
00905 }
00906 
00907 
00911 void DocCompiler::generateRec(Tree sig, Tree var, Tree le, int priority)
00912 {
00913     int             N = len(le);
00914 
00915     vector<bool>    used(N);
00916     vector<int>     delay(N);
00917     vector<string>  vname(N);
00918     vector<string>  ctype(N);
00919 
00920     // prepare each element of a recursive definition
00921     for (int i=0; i<N; i++) {
00922         Tree    e = sigProj(i,sig);     // recreate each recursive definition
00923         if (fOccMarkup.retrieve(e)) {
00924             // this projection is used
00925             used[i] = true;
00926             //cerr << "generateRec : used[" << i << "] = true" << endl;            
00927             getTypedNames(getCertifiedSigType(e), "r", ctype[i],  vname[i]);
00928             gDocNoticeFlagMap["recursigs"] = true;
00929             //cerr << "- r : generateRec setVectorNameProperty : \"" << vname[i] << "\"" << endl;
00930             setVectorNameProperty(e, vname[i]);
00931             delay[i] = fOccMarkup.retrieve(e)->getMaxDelay();
00932         } else {
00933             // this projection is not used therefore
00934             // we should not generate code for it
00935             used[i] = false;
00936             //cerr << "generateRec : used[" << i << "] = false" << endl;
00937         }
00938     }
00939 
00940     // generate delayline for each element of a recursive definition
00941     for (int i=0; i<N; i++) {
00942         if (used[i]) {
00943             generateDelayLine(ctype[i], vname[i], delay[i], CS(nth(le,i), priority));
00944         }
00945     }
00946 }
00947 
00948 
00949 /*****************************************************************************
00950                                PREFIX, DELAY A PREFIX VALUE
00951 *****************************************************************************/
00952 
00963 string DocCompiler::generatePrefix (Tree sig, Tree x, Tree e, int priority)
00964 {
00965     string var  = getFreshID("m");
00966     string exp0 = CS(x, priority);
00967     string exp1 = CS(e, priority); // ensure exp1 is compiled to have a vector name
00968     string vecname;
00969 
00970     if (! getVectorNameProperty(e, vecname)) {
00971         cerr << "No vector name for : " << ppsig(e) << endl;
00972         assert(0);
00973     }
00974     
00975     string ltqPrefixDef;
00976     ltqPrefixDef += subst("$0(t) = \n", var);
00977     ltqPrefixDef += "\\left\\{\\begin{array}{ll}\n";
00978     ltqPrefixDef += subst("$0 & \\mbox{, when \\,} t = 0\\\\\n", exp0);
00979     ltqPrefixDef += subst("$0 & \\mbox{, when \\,} t > 0\n", subst("$0(t\\!-\\!1)", vecname));
00980     ltqPrefixDef += "\\end{array}\\right.";
00981     
00982     fLateq->addPrefixSigFormula(ltqPrefixDef);
00983     gDocNoticeFlagMap["prefixsigs"] = true;
00984     
00985     return generateCacheCode(sig, subst("$0(t)", var));
00986 }
00987 
00988 
00989 /*****************************************************************************
00990                                IOTA(n)
00991 *****************************************************************************/
00992 
00996 string DocCompiler::generateIota (Tree sig, Tree n)
00997 {
00998     int size;
00999     if (!isSigInt(n, &size)) { fprintf(stderr, "error in generateIota\n"); exit(1); }
01000     //cout << "iota !" << endl;
01001     return subst(" t \\bmod{$0} ", docT(size));
01002 }
01003 
01004 
01005 
01006 // a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs
01007 
01008 
01012 string DocCompiler::generateSelect2  (Tree sig, Tree sel, Tree s1, Tree s2, int priority)
01013 {
01014     string var  = getFreshID("q");
01015     string expsel = CS(sel, 0);
01016     string exps1 = CS(s1, 0);
01017     string exps2 = CS(s2, 0);
01018     
01019     string ltqSelDef;
01020     ltqSelDef += subst("$0(t) = \n", var);
01021     ltqSelDef += "\\left\\{\\begin{array}{ll}\n";
01022     ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 0\\\\\n", exps1, expsel);
01023     ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 1\n", exps2, expsel);
01024     ltqSelDef += "\\end{array}\\right.";
01025     
01026     fLateq->addSelectSigFormula(ltqSelDef);
01027     gDocNoticeFlagMap["selectionsigs"] = true;
01028     
01029     //return generateCacheCode(sig, subst("$0(t)", var));
01030     setVectorNameProperty(sig, var);
01031     return subst("$0(t)", var);
01032 }
01033 
01034 
01038 string DocCompiler::generateSelect3  (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3, int priority)
01039 {
01040     string var  = getFreshID("q");
01041     string expsel = CS(sel, 0);
01042     string exps1 = CS(s1, 0);
01043     string exps2 = CS(s2, 0);
01044     string exps3 = CS(s3, 0);
01045     
01046     string ltqSelDef;
01047     ltqSelDef += subst("$0(t) = \n", var);
01048     ltqSelDef += "\\left\\{\\begin{array}{ll}\n";
01049     ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 0\\\\\n", generateVariableStore(s1, exps1), expsel);
01050     ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 1\\\\\n", generateVariableStore(s2, exps2), expsel);
01051     ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 2\n", generateVariableStore(s3, exps3), expsel);
01052     ltqSelDef += "\\end{array}\\right.";
01053     
01054     fLateq->addSelectSigFormula(ltqSelDef);
01055     gDocNoticeFlagMap["selectionsigs"] = true;
01056     
01057     //return generateCacheCode(sig, subst("$0(t)", var));
01058     setVectorNameProperty(sig, var);
01059     return subst("$0(t)", var);
01060 }
01061 
01062 
01067 string DocCompiler::generateXtended     (Tree sig, int priority)
01068 {
01069     xtended*        p = (xtended*) getUserData(sig);
01070     vector<string>  args;
01071     vector<Type>    types;
01072 
01073     for (int i=0; i<sig->arity(); i++) {
01074         args.push_back(CS(sig->branch(i), 0));
01075         types.push_back(getCertifiedSigType(sig->branch(i)));
01076     }
01077 
01078     if (p->needCache()) {
01079         //cerr << "!! generateXtended : <needCache> : calls generateCacheCode(sig, p->generateLateq(fLateq, args, types))" << endl;
01080         return generateCacheCode(sig, p->generateLateq(fLateq, args, types));
01081     } else {
01082         //cerr << "!! generateXtended : <do not needCache> : calls p->generateLateq(fLateq, args, types)" << endl;
01083         return p->generateLateq(fLateq, args, types);
01084     }
01085 }
01086 
01087 
01088 
01089 //------------------------------------------------------------------------------------------------
01090 
01091 
01092 /*****************************************************************************
01093                         vector name property
01094 *****************************************************************************/
01095 
01103 void DocCompiler::setVectorNameProperty(Tree sig, const string& vecname)
01104 {
01105     fVectorProperty.set(sig, vecname);
01106 }
01107 
01108 
01117 bool DocCompiler::getVectorNameProperty(Tree sig, string& vecname)
01118 {
01119     return fVectorProperty.get(sig, vecname);
01120 }
01121 
01122 
01123 
01124 /*****************************************************************************
01125                                N-SAMPLE FIXED DELAY : sig = exp@delay
01126 
01127     case 1-sample max delay :
01128         Y(t-0)  Y(t-1)
01129         Temp    Var                     gLessTempSwitch = false
01130         V[0]    V[1]                    gLessTempSwitch = true
01131 
01132     case max delay < gMaxCopyDelay :
01133         Y(t-0)  Y(t-1)  Y(t-2)  ...
01134         Temp    V[0]    V[1]    ...     gLessTempSwitch = false
01135         V[0]    V[1]    V[2]    ...     gLessTempSwitch = true
01136 
01137     case max delay >= gMaxCopyDelay :
01138         Y(t-0)  Y(t-1)  Y(t-2)  ...
01139         Temp    V[0]    V[1]    ...
01140         V[0]    V[1]    V[2]    ...
01141 
01142 
01143 *****************************************************************************/
01144 
01152 string DocCompiler::generateFixDelay (Tree sig, Tree exp, Tree delay, int priority)
01153 {
01154     int d;
01155     string vecname;
01156     
01157     CS(exp, 0); // ensure exp is compiled to have a vector name
01158     
01159     if (! getVectorNameProperty(exp, vecname)) {
01160         cerr << "No vector name for : " << ppsig(exp) << endl;
01161         assert(0);
01162     }
01163     
01164     if (isSigInt(delay, &d) && (d == 0)) {
01165         //cerr << "@ generateFixDelay : d = " << d << endl;
01166         return subst("$0(t)", vecname);
01167     } else {
01168         //cerr << "@ generateFixDelay : d = " << d << endl;
01169         return subst("$0(t\\!-\\!$1)", vecname, CS(delay, 7));
01170     }
01171 }
01172 
01173 
01178 string DocCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
01179 {
01180     string s = generateDelayVecNoTemp(sig, exp, ctype, vname, mxd);
01181     if (getCertifiedSigType(sig)->variability() < kSamp) {
01182         return exp;
01183     } else {
01184         return s;
01185     }
01186 }
01187 
01188 
01192 string DocCompiler::generateDelayVecNoTemp(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
01193 {
01194     assert(mxd > 0);
01195 
01196     //cerr << "  entering generateDelayVecNoTemp" << endl;
01197     
01198     string vectorname;
01199 
01200     // if generateVariableStore has already tagged sig, no definition is needed.
01201     if(getVectorNameProperty(sig, vectorname)) { 
01202         return subst("$0(t)", vectorname);
01203     } else {
01204         fLateq->addRecurSigFormula(subst("$0(t) = $1", vname, exp));
01205         setVectorNameProperty(sig, vname);
01206         return subst("$0(t)", vname);
01207     }
01208 }
01209 
01210 
01214 void DocCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
01215 {
01216     //assert(mxd > 0);
01217     if (mxd == 0) {
01218         fLateq->addRecurSigFormula(subst("$0(t) = $1", vname, exp));
01219     } else {
01220         fLateq->addRecurSigFormula(subst("$0(t) = $1", vname, exp));
01221     }
01222 }
01223 
01224 
01225 
01226 
01227 /****************************************************************
01228             User interface element utilities.
01229  *****************************************************************/
01230 
01231 
01244 string DocCompiler::getUIDir(Tree pathname)
01245 {   
01246     //cerr << "Documentator : getUIDir : print(pathname, stdout) = "; print(pathname, stdout); cerr << endl;
01247     string s;
01248     Tree dir = reverse(tl(pathname));
01249     while (!isNil(dir)) { 
01250         string tmp = tree2str(tl(hd(dir)));
01251         if ( (tmp[0] != '[') && (!tmp.empty()) ) {
01252             s += tmp + '/';
01253         }
01254         dir = tl(dir);
01255     }
01256     return s;
01257 }
01258 
01259 
01272 string DocCompiler::prepareBinaryUI(const string& name, Tree path)
01273 {   
01274     string label, unit;
01275     getUIDocInfos(path, label, unit);
01276     string s = "";
01277     label = (label.size()>0) ? ("\\textsf{\""+label+"\"} ") : "";
01278     unit = (unit.size()>0) ? ("\\ ("+unit+")") : "";
01279     s += label + unit;
01280     s += " & $" + name + "$";
01281     s += " $\\in$ $\\left\\{\\,0, 1\\,\\right\\}$";
01282     s += " & $(\\mbox{" + gDocMathStringMap["defaultvalue"] + "} = 0)$\\\\";
01283     return s;
01284 }
01285 
01286 
01302 string DocCompiler::prepareIntervallicUI(const string& name, Tree path, Tree tcur, Tree tmin, Tree tmax)
01303 {   
01304     string label, unit, cur, min, max;
01305     getUIDocInfos(path, label, unit);
01306     cur = docT(tree2float(tcur));
01307     min = docT(tree2float(tmin));
01308     max = docT(tree2float(tmax));
01309     
01310     string s = "";
01311     label = (label.size()>0) ? ("\\textsf{\""+label+"\"} ") : "";
01312     unit = (unit.size()>0) ? ("\\ ("+unit+")") : "";
01313     s += label + unit;
01314     s += " & $" + name + "$";
01315     s += " $\\in$ $\\left[\\," + min + ", " + max + "\\,\\right]$";
01316     s += " & $(\\mbox{" + gDocMathStringMap["defaultvalue"] + "} = " + cur + ")$\\\\";
01317     return s;
01318 }
01319 
01320 
01328 void DocCompiler::getUIDocInfos(Tree path, string& label, string& unit)
01329 {
01330     label = "";
01331     unit = "";
01332     
01333     map<string, set<string> >   metadata;
01334     extractMetadata(tree2str(hd(path)), label, metadata);
01335     
01336     set<string> myunits = metadata["unit"];
01337 //  for (set<string>::iterator i = myunits.begin(); i != myunits.end(); i++) {
01338 //      cerr << "Documentator : getUIDocInfos : metadata[\"unit\"] = " << *i << endl;
01339 //  }
01340     for (map<string, set<string> >::iterator i = metadata.begin(); i != metadata.end(); i++) {
01341         const string& key = i->first;
01342         const set<string>& values = i->second;
01343         for (set<string>::const_iterator j = values.begin(); j != values.end(); j++) {
01344             if(key == "unit") unit += *j;
01345         }
01346     }
01347 }
01348 
01349