+++ /dev/null
-/************************************************************************
- ************************************************************************
- 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.
- ************************************************************************
- ************************************************************************/
-
-/*****************************************************************************
- HISTORY
- 22/01/05 : corrected bug on bool signals cached in float variables
- 2009-08-16 : First "doc" version (kb)
- 2009-11-22 : Some clean up (kb)
-*****************************************************************************/
-
-
-
-
-#include <stdio.h>
-#include <iostream>
-#include <sstream>
-#include <vector>
-#include <math.h>
-
-#include "doc_compile.hh"
-#include "sigtype.hh"
-#include "floats.hh"
-#include "sigprint.hh"
-#include "sigtyperules.hh"
-#include "recursivness.hh"
-#include "simplify.hh"
-#include "privatise.hh"
-#include "prim2.hh"
-#include "xtended.hh"
-#include "compatibility.hh"
-#include "ppsig.hh"
-#include "names.hh"
-#include "doc.hh"
-#include "tlib.hh"
-#include "doc_notice.hh"
-
-
-extern bool gLessTempSwitch;
-extern int gMaxCopyDelay;
-extern map<string, string> gDocMathStringMap;
-
-extern bool getSigListNickName(Tree t, Tree& id);
-
-static const unsigned int MAX_RIGHT_MEMBER = 20;
-static const unsigned int MAX_SUB_EXPR = 10;
-
-
-/*****************************************************************************
- getFreshID
-*****************************************************************************/
-
-map<string, int> DocCompiler::fIDCounters;
-
-string DocCompiler::getFreshID(const string& prefix)
-{
- if (fIDCounters.find(prefix) == fIDCounters.end()) {
- fIDCounters[prefix] = 1;
- }
- int n = fIDCounters[prefix];
- fIDCounters[prefix] = n+1;
-
- return subst("$0_{$1}", prefix, docT(n));
-}
-
-
-/*****************************************************************************
- prepare
-*****************************************************************************/
-
-Tree DocCompiler::annotate(Tree LS)
-{
- recursivnessAnnotation(LS); // Annotate LS with recursivness information
- typeAnnotation(LS); // Annotate LS with type information
- sharingAnalysis(LS); // annotate LS with sharing count
- fOccMarkup.mark(LS); // annotate LS with occurences analysis
-
- return LS;
-}
-
-/*****************************************************************************
- compileLateq
-*****************************************************************************/
-
-Lateq* DocCompiler::compileLateq (Tree L, Lateq* compiledEqn)
-{
- //cerr << "Documentator : compileLateq : L = "; printSignal(L, stdout, 0); cerr << endl;
-
- fLateq = compiledEqn; ///< Dynamic field !
- int priority = 0;
-
- for (int i = 0; isList(L); L = tl(L), i++) {
- Tree sig = hd(L);
- Tree id;
- if(getSigNickname(sig, id)) {
- //cerr << "Documentator : compileLateq : NICKNAMEPROPERTY = " << tree2str(id) << endl;
- fLateq->addOutputSigFormula(subst("$0(t) = $1", tree2str(id), CS(sig, priority), docT(i)));
- } else {
- //cerr << "Documentator : compileLateq : NO NICKNAMEPROPERTY" << endl;
- if (fLateq->outputs() == 1) {
- fLateq->addOutputSigFormula(subst("y(t) = $0", CS(sig, priority)));
- gDocNoticeFlagMap["outputsig"] = true;
- } else {
- fLateq->addOutputSigFormula(subst("$0(t) = $1", getFreshID("y"), CS(sig, priority)));
- gDocNoticeFlagMap["outputsigs"] = true;
- }
- }
- }
- return fLateq;
-}
-
-
-
-/*****************************************************************************
- CS : compile a signal
-*****************************************************************************/
-
-/**
- * Test if a signal is already compiled
- * @param sig the signal expression to compile.
- * @param name the string representing the compiled expression.
- * @return true is already compiled
- */
-bool DocCompiler::getCompiledExpression(Tree sig, string& cexp)
-{
- return fCompileProperty.get(sig, cexp);
-}
-
-
-/**
- * Set the string of a compiled expression is already compiled
- * @param sig the signal expression to compile.
- * @param cexp the string representing the compiled expression.
- * @return the cexp (for commodity)
- */
-string DocCompiler::setCompiledExpression(Tree sig, const string& cexp)
-{
- fCompileProperty.set(sig, cexp);
- return cexp;
-}
-
-
-/**
- * Compile a signal
- * @param sig the signal expression to compile.
- * @return the C code translation of sig as a string
- */
-string DocCompiler::CS (Tree sig, int priority)
-{
- string code;
-
- if (!getCompiledExpression(sig, code)) { // not compiled yet.
- code = generateCode(sig, priority);
- setCompiledExpression(sig, code);
- }
- return code;
-}
-
-
-
-/*****************************************************************************
- generateCode : dispatch according to signal
-*****************************************************************************/
-
-
-/**
- * @brief Main code generator dispatch.
- *
- * According to the type of the input signal, generateCode calls
- * the appropriate generator with appropriate arguments.
- *
- * @param sig The signal expression to compile.
- * @param priority The environment priority of the expression.
- * @return <string> The LaTeX code translation of the signal.
- */
-string DocCompiler::generateCode (Tree sig, int priority)
-{
- int i;
- double r;
- Tree c, sel, x, y, z, u, label, ff, largs, type, name, file;
-
- if ( getUserData(sig) ) { printGCCall(sig,"generateXtended"); return generateXtended (sig, priority); }
- else if ( isSigInt(sig, &i) ) { printGCCall(sig,"generateNumber"); return generateNumber (sig, docT(i)); }
- else if ( isSigReal(sig, &r) ) { printGCCall(sig,"generateNumber"); return generateNumber (sig, docT(r)); }
- else if ( isSigInput(sig, &i) ) { printGCCall(sig,"generateInput"); return generateInput (sig, docT(i+1)); }
- else if ( isSigOutput(sig, &i, x) ) { printGCCall(sig,"generateOutput"); return generateOutput (sig, docT(i+1), CS(x, priority)); }
-
- else if ( isSigFixDelay(sig, x, y) ) { printGCCall(sig,"generateFixDelay"); return generateFixDelay (sig, x, y, priority); }
- else if ( isSigPrefix(sig, x, y) ) { printGCCall(sig,"generatePrefix"); return generatePrefix (sig, x, y, priority); }
- else if ( isSigIota(sig, x) ) { printGCCall(sig,"generateIota"); return generateIota (sig, x); }
-
- else if ( isSigBinOp(sig, &i, x, y) ) { printGCCall(sig,"generateBinOp"); return generateBinOp (sig, i, x, y, priority); }
- else if ( isSigFFun(sig, ff, largs) ) { printGCCall(sig,"generateFFun"); return generateFFun (sig, ff, largs, priority); }
- else if ( isSigFConst(sig, type, name, file) ) { printGCCall(sig,"generateFConst"); return generateFConst (sig, tree2str(file), tree2str(name)); }
- else if ( isSigFVar(sig, type, name, file) ) { printGCCall(sig,"generateFVar"); return generateFVar (sig, tree2str(file), tree2str(name)); }
-
- // new special tables for documentation purposes
-
- else if ( isSigDocConstantTbl(sig, x, y) ) { printGCCall(sig,"generateDocConstantTbl"); return generateDocConstantTbl (sig, x, y); }
- else if ( isSigDocWriteTbl(sig,x,y,z,u) ) { printGCCall(sig,"generateDocWriteTbl"); return generateDocWriteTbl (sig, x, y, z, u); }
- else if ( isSigDocAccessTbl(sig, x, y) ) { printGCCall(sig, "generateDocAccessTbl"); return generateDocAccessTbl(sig, x, y); }
-
-
- else if ( isSigSelect2(sig, sel, x, y) ) { printGCCall(sig,"generateSelect2"); return generateSelect2 (sig, sel, x, y, priority); }
- else if ( isSigSelect3(sig, sel, x, y, z) ) { printGCCall(sig,"generateSelect3"); return generateSelect3 (sig, sel, x, y, z, priority); }
-
- else if ( isProj(sig, &i, x) ) { printGCCall(sig,"generateRecProj"); return generateRecProj (sig, x, i, priority); }
-
- else if ( isSigIntCast(sig, x) ) { printGCCall(sig,"generateIntCast"); return generateIntCast (sig, x, priority); }
- else if ( isSigFloatCast(sig, x) ) { printGCCall(sig,"generateFloatCast"); return generateFloatCast(sig, x, priority); }
-
- else if ( isSigButton(sig, label) ) { printGCCall(sig,"generateButton"); return generateButton (sig, label); }
- else if ( isSigCheckbox(sig, label) ) { printGCCall(sig,"generateCheckbox"); return generateCheckbox (sig, label); }
- else if ( isSigVSlider(sig, label,c,x,y,z) ) { printGCCall(sig,"generateVSlider"); return generateVSlider (sig, label, c,x,y,z); }
- else if ( isSigHSlider(sig, label,c,x,y,z) ) { printGCCall(sig,"generateHSlider"); return generateHSlider (sig, label, c,x,y,z); }
- else if ( isSigNumEntry(sig, label,c,x,y,z) ) { printGCCall(sig,"generateNumEntry"); return generateNumEntry (sig, label, c,x,y,z); }
-
- else if ( isSigVBargraph(sig, label,x,y,z) ) { printGCCall(sig,"generateVBargraph"); return CS(z, priority);}//generateVBargraph (sig, label, x, y, CS(z, priority)); }
- else if ( isSigHBargraph(sig, label,x,y,z) ) { printGCCall(sig,"generateHBargraph"); return CS(z, priority);}//generateHBargraph (sig, label, x, y, CS(z, priority)); }
- else if ( isSigAttach(sig, x, y) ) { printGCCall(sig,"generateAttach"); return generateAttach (sig, x, y, priority); }
-
- else {
- cerr << "Error in d signal, unrecognized signal : " << *sig << endl;
- exit(1);
- }
- assert(0);
- return "error in generate code";
-}
-
-
-/**
- * Print calling information of generateCode, for debug purposes.
- *
- * @remark
- * To turn printing on, turn the 'printCalls' boolean to true.
- */
-void DocCompiler::printGCCall(Tree sig, const string& calledFunction)
-{
- bool printCalls = false;
- bool maskSigs = false;
-
- if(printCalls) {
- cerr << " -> generateCode calls " << calledFunction;
- if(maskSigs) {
- cerr << endl;
- } else {
- cerr << " on " << ppsig(sig) << endl;
- }
- }
-}
-
-
-/*****************************************************************************
- NUMBERS
-*****************************************************************************/
-
-
-string DocCompiler::generateNumber (Tree sig, const string& exp)
-{
- string ctype, vname;
- Occurences* o = fOccMarkup.retrieve(sig);
-
- // check for number occuring in delays
- if (o->getMaxDelay()>0) {
- getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
- gDocNoticeFlagMap["recursigs"] = true;
- //cerr << "- r : generateNumber : \"" << vname << "\"" << endl;
- generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
- }
- return exp;
-}
-
-/*****************************************************************************
- FOREIGN CONSTANTS
-*****************************************************************************/
-
-
-string DocCompiler::generateFConst (Tree sig, const string& file, const string& exp)
-{
- string ctype, vname;
- Occurences* o = fOccMarkup.retrieve(sig);
-
- if (o->getMaxDelay()>0) {
- getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
- gDocNoticeFlagMap["recursigs"] = true;
- //cerr << "- r : generateFConst : \"" << vname << "\"" << endl;
- generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
- }
-
- if (exp == "fSamplingFreq") {
- //gDocNoticeFlagMap["fsamp"] = true;
- return "f_S";
- }
-
- return "\\mathrm{"+exp+"}";
-}
-
-/*****************************************************************************
- FOREIGN VARIABLES
-*****************************************************************************/
-
-
-string DocCompiler::generateFVar (Tree sig, const string& file, const string& exp)
-{
- string ctype, vname;
- Occurences* o = fOccMarkup.retrieve(sig);
-
- if (o->getMaxDelay()>0) {
- getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
- gDocNoticeFlagMap["recursigs"] = true;
- //cerr << "- r : generateFVar : \"" << vname << "\"" << endl;
- setVectorNameProperty(sig, vname);
- generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
- }
- return generateCacheCode(sig, exp);
-}
-
-
-/*****************************************************************************
- INPUTS - OUTPUTS
-*****************************************************************************/
-
-
-string DocCompiler::generateInput (Tree sig, const string& idx)
-{
- if (fLateq->inputs() == 1) {
- setVectorNameProperty(sig, "x");
- fLateq->addInputSigFormula("x(t)");
- gDocNoticeFlagMap["inputsig"] = true;
- return generateCacheCode(sig, "x(t)");
- } else {
- setVectorNameProperty(sig, subst("x_{$0}", idx));
- fLateq->addInputSigFormula(subst("x_{$0}(t)", idx));
- gDocNoticeFlagMap["inputsigs"] = true;
- return generateCacheCode(sig, subst("x_{$0}(t)", idx));
- }
-}
-
-
-/** Unused for the moment ! */
-string DocCompiler::generateOutput (Tree sig, const string& idx, const string& arg)
-{
- string dst;
-
- if (fLateq->outputs() == 1) {
- dst = subst("y(t)", idx);
- gDocNoticeFlagMap["outputsig"] = true;
- } else {
- dst = subst("y_{$0}(t)", idx);
- gDocNoticeFlagMap["outputsigs"] = true;
- }
-
- fLateq->addOutputSigFormula(subst("$0 = $1", dst, arg));
- return dst;
-}
-
-
-/*****************************************************************************
- BINARY OPERATION
-*****************************************************************************/
-
-/**
- * Generate binary operations, managing priority parenthesis.
- * ((a*b)+c) can be written (a*b+c) if priority(*) > priority(+)
- * ((a*b)*c) can be writteb (a*b*c) if * is associative
- * Associative operation should have a distinc priority from other operations.
- * Non associative operations can share the same priority.
- *
- * @param sig The signal expression to treat.
- * @param opcode The operation code, as described in gBinOpLateqTable.
- * @param arg1 The first operand.
- * @param arg2 The second operand.
- * @param priority The priority of the environment of the expression.
- *
- * @return <string> The LaTeX code translation of the signal, cached.
- *
- * @remark The case of LaTeX frac{}{} is special.
- *
- * @todo Handle integer arithmetics, by testing arguments type,
- * and printing dedicated operators (\oplus, \odot, \ominus, \oslash).
- */
-
-/// associative operations are + * | & xor
-static bool associative (int opcode) {
- return (opcode == kAdd) || (opcode == kMul) || (opcode == kAND) || (opcode == kOR) || (opcode == kXOR);
-}
-
-string DocCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2, int priority)
-{
- string s;
- int thisPriority = gBinOpLateqTable[opcode]->fPriority;
-
- /* Priority parenthesis handling. */
- string lpar = "";
- string rpar = "";
- if ( (thisPriority < priority) || ((thisPriority == priority) && !associative(opcode)) ) {
- // (a+b)*c or (a/b)/c need parenthesis
- lpar = " \\left(";
- rpar = "\\right) ";
- }
-
- Type t1 = getCertifiedSigType(arg1);
- Type t2 = getCertifiedSigType(arg2);
- bool intOpDetected = false;
- if ( (t1->nature() == kInt) && (t2->nature() == kInt) ) {
- intOpDetected = true;
- }
-
- string op;
- if(!intOpDetected) {
- op = gBinOpLateqTable[opcode]->fName;
- } else {
- switch (opcode) {
- case kAdd:
- op = "\\oplus";
- gDocNoticeFlagMap["intplus"] = true;
- break;
- case kSub:
- op = "\\ominus";
- gDocNoticeFlagMap["intminus"] = true;
- break;
- case kMul:
- op = "\\odot";
- gDocNoticeFlagMap["intmult"] = true;
- break;
- case kDiv:
- op = "\\oslash";
- gDocNoticeFlagMap["intdiv"] = true;
- gDocNoticeFlagMap["intcast"] = true; // "$normalize(int(i/j))$" in the notice.
- break;
- default:
- op = gBinOpLateqTable[opcode]->fName;
- break;
- }
- }
-
- /* LaTeX frac{}{} handling VS general case. */
- if ( (opcode == kDiv) && (!intOpDetected) ) {
- s = subst("$0\\frac{$1}{$2}$3", lpar, CS(arg1, 0), CS(arg2, 0), rpar);
- } else {
- s = subst("$0$1 $2 $3$4", lpar, CS(arg1, thisPriority), op, CS(arg2, thisPriority), rpar);
- }
-
-// if (opcode == kMul) {
-// gDocNoticeFlagMap["cdot"] = true;
-// }
-
- return generateCacheCode(sig, s);
-}
-
-
-/*****************************************************************************
- Primitive Operations
-*****************************************************************************/
-
-string DocCompiler::generateFFun(Tree sig, Tree ff, Tree largs, int priority)
-{
- string code = ffname(ff);
- code += '(';
- string sep = "";
- for (int i = 0; i< ffarity(ff); i++) {
- code += sep;
- code += CS(nth(largs, i), priority);
- sep = ", ";
- }
- code += ')';
-
- gDocNoticeFlagMap["foreignfun"] = true;
-
- return "\\mathrm{ff"+code+"}";
-}
-
-
-/*****************************************************************************
- CACHE CODE
-*****************************************************************************/
-
-void DocCompiler::getTypedNames(Type t, const string& prefix, string& ctype, string& vname)
-{
- if (t->nature() == kInt) {
- ctype = "int"; vname = subst("$0", getFreshID(prefix));
- } else {
- ctype = ifloat(); vname = subst("$0", getFreshID(prefix));
- }
-}
-
-
-/**
- * Test if exp is very simple that is it
- * can't be considered a real component
- * @param exp the signal we want to test
- * @return true if it a very simple signal
- */
-static bool isVerySimpleFormula(Tree sig)
-{
- int i;
- double r;
- Tree type, name, file, label, c, x, y, z;
-
- return isSigInt(sig, &i)
- || isSigReal(sig, &r)
- || isSigInput(sig, &i)
- || isSigFConst(sig, type, name, file)
- || isSigButton(sig, label)
- || isSigCheckbox(sig, label)
- || isSigVSlider(sig, label,c,x,y,z)
- || isSigHSlider(sig, label,c,x,y,z)
- || isSigNumEntry(sig, label,c,x,y,z)
- ;
-}
-
-
-string DocCompiler::generateCacheCode(Tree sig, const string& exp)
-{
- //cerr << "!! entering generateCacheCode with sig=\"" << ppsig(sig) << "\"" << endl;
-
- string vname, ctype, code, vectorname;
-
- int sharing = getSharingCount(sig);
- Occurences* o = fOccMarkup.retrieve(sig);
-
- // check reentrance
- if (getCompiledExpression(sig, code)) {
- //cerr << "!! generateCacheCode called a true getCompiledExpression" << endl;
- return code;
- }
-
- // check for expression occuring in delays
- if (o->getMaxDelay()>0) {
- if (getVectorNameProperty(sig, vectorname)) {
- return exp;
- }
- getTypedNames(getCertifiedSigType(sig), "r", ctype, vname);
- gDocNoticeFlagMap["recursigs"] = true;
- //cerr << "- r : generateCacheCode : vame=\"" << vname << "\", for sig=\"" << ppsig(sig) << "\"" << endl;
- if (sharing>1) {
- //cerr << " generateCacheCode calls generateDelayVec(generateVariableStore) on vame=\"" << vname << "\"" << endl;
- return generateDelayVec(sig, generateVariableStore(sig,exp), ctype, vname, o->getMaxDelay());
- } else {
- //cerr << " generateCacheCode calls generateDelayVec(exp) on vame=\"" << vname << "\"" << endl;
- return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
- }
- }
- else if (sharing == 1 || getVectorNameProperty(sig, vectorname) || isVerySimpleFormula(sig)) {
- //cerr << "! generateCacheCode : sharing == 1 : return \"" << exp << "\"" << endl;
- return exp;
- }
- else if (sharing > 1) {
- //cerr << "! generateCacheCode : sharing > 1 : return \"" << exp << "\"" << endl;
- return generateVariableStore(sig, exp);
- }
- else {
- cerr << "Error in sharing count (" << sharing << ") for " << *sig << endl;
- exit(1);
- }
-
- return "Error in generateCacheCode";
-}
-
-
-string DocCompiler::generateVariableStore(Tree sig, const string& exp)
-{
- string vname, ctype;
- Type t = getCertifiedSigType(sig);
-
- switch (t->variability()) {
-
- case kKonst :
- getTypedNames(t, "k", ctype, vname); ///< "k" for constants.
- fLateq->addConstSigFormula(subst("$0 = $1", vname, exp));
- gDocNoticeFlagMap["constsigs"] = true;
- return vname;
-
- case kBlock :
- getTypedNames(t, "p", ctype, vname); ///< "p" for "parameter".
- fLateq->addParamSigFormula(subst("$0(t) = $1", vname, exp));
- gDocNoticeFlagMap["paramsigs"] = true;
- setVectorNameProperty(sig, vname);
- return subst("$0(t)", vname);
-
- case kSamp :
- if(getVectorNameProperty(sig, vname)) {
- return subst("$0(t)", vname);
- } else {
- getTypedNames(t, "s", ctype, vname);
- //cerr << "- generateVariableStore : \"" << subst("$0(t) = $1", vname, exp) << "\"" << endl;
- fLateq->addStoreSigFormula(subst("$0(t) = $1", vname, exp));
- gDocNoticeFlagMap["storedsigs"] = true;
- setVectorNameProperty(sig, vname);
- return subst("$0(t)", vname);
- }
-
- default:
- assert(0);
- return "";
- }
-}
-
-
-/*****************************************************************************
- CASTING
-*****************************************************************************/
-
-
-string DocCompiler::generateIntCast(Tree sig, Tree x, int priority)
-{
- gDocNoticeFlagMap["intcast"] = true;
-
- return generateCacheCode(sig, subst("\\mathrm{int}\\left($0\\right)", CS(x, 0)));
-}
-
-
-/**
- * @brief Don't generate float cast !
- *
- * It is just a kind of redirection.
- * Calling generateCacheCode ensures to create a new
- * variable name if the input signal expression is shared.
- */
-string DocCompiler::generateFloatCast (Tree sig, Tree x, int priority)
-{
- return generateCacheCode(sig, subst("$0", CS(x, priority)));
-}
-
-
-/*****************************************************************************
- user interface elements
-*****************************************************************************/
-
-string DocCompiler::generateButton(Tree sig, Tree path)
-{
- string vname = getFreshID("{u_b}");
- string varname = vname + "(t)";
- fLateq->addUISigFormula(getUIDir(path), prepareBinaryUI(varname, path));
- gDocNoticeFlagMap["buttonsigs"] = true;
- return generateCacheCode(sig, varname);
-}
-
-string DocCompiler::generateCheckbox(Tree sig, Tree path)
-{
- string vname = getFreshID("{u_c}");
- string varname = vname + "(t)";
- fLateq->addUISigFormula(getUIDir(path), prepareBinaryUI(varname, path));
- gDocNoticeFlagMap["checkboxsigs"] = true;
- return generateCacheCode(sig, varname);
-}
-
-string DocCompiler::generateVSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
-{
- string varname = getFreshID("{u_s}") + "(t)";
- fLateq->addUISigFormula(getUIDir(path), prepareIntervallicUI(varname, path, cur, min, max));
- gDocNoticeFlagMap["slidersigs"] = true;
- return generateCacheCode(sig, varname);
-}
-
-string DocCompiler::generateHSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
-{
- string varname = getFreshID("{u_s}") + "(t)";
- fLateq->addUISigFormula(getUIDir(path), prepareIntervallicUI(varname, path, cur, min, max));
- gDocNoticeFlagMap["slidersigs"] = true;
- return generateCacheCode(sig, varname);
-}
-
-string DocCompiler::generateNumEntry(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
-{
- string varname = getFreshID("{u_n}") + "(t)";
- fLateq->addUISigFormula(getUIDir(path), prepareIntervallicUI(varname, path, cur, min, max));
- gDocNoticeFlagMap["nentrysigs"] = true;
- return generateCacheCode(sig, varname);
-}
-
-
-string DocCompiler::generateVBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
-{
- string varname = getFreshID("{u_g}");
-
- Type t = getCertifiedSigType(sig);
- switch (t->variability()) {
-
- case kKonst :
- break;
-
- case kBlock :
- break;
-
- case kSamp :
- break;
- }
- return generateCacheCode(sig, varname);
-}
-
-
-string DocCompiler::generateHBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
-{
- string varname = getFreshID("{u_g}");
-
- Type t = getCertifiedSigType(sig);
- switch (t->variability()) {
-
- case kKonst :
- break;
-
- case kBlock :
- break;
-
- case kSamp :
- break;
- }
- return generateCacheCode(sig, varname);
-}
-
-
-string DocCompiler::generateAttach (Tree sig, Tree x, Tree y, int priority)
-{
- string vname;
- string exp;
-
- CS(y, priority);
- exp = CS(x, priority);
-
- if(getVectorNameProperty(x, vname)) {
- setVectorNameProperty(sig, vname);
- }
-
- return generateCacheCode(sig, exp);
-}
-
-
-
-
-/*****************************************************************************
- TABLES
- (note : tables here are siplified versions different from the ones used to
- generate c++ code)
-*****************************************************************************/
-
-/**
- * Generate the equation of a constant table (its content is time constant).
- * Returns the name of the table
- */
-string DocCompiler::generateDocConstantTbl (Tree /*tbl*/, Tree size, Tree isig)
-{
- string vname, ctype;
- string init = CS(isig,0);
-
- int n;
- if (!isSigInt(size, &n)) {
- cerr << "error in DocCompiler::generateDocConstantTbl() : "
- << *size
- << " is not an integer expression and can't be used as a table size' "
- << endl;
- }
-
- // allocate a name v_i for the table
- getTypedNames(getCertifiedSigType(isig), "v", ctype, vname);
-
- // add a comment on tables in the notice
- gDocNoticeFlagMap["tablesigs"] = true;
-
- // add equation v[t] = isig(t)
- fLateq->addRDTblSigFormula(subst("$0[t] = $1 \\condition{when $$t \\in [0,$2]$$} ", vname, init, T(n-1)));
-
- // note that the name of the table can never be used outside an sigDocTableAccess
- return vname;
-}
-
-
-/**
- * tests if a charactere is a word separator
- */
-static bool isSeparator(char c)
-{
- bool w = ( ((c >= 'a') && (c <='z'))
- || ((c >= 'A') && (c <='Z'))
- || ((c >= '0') && (c <='9'))
- );
-
- return ! w;
-}
-
-
-/**
- * Replaces the occurences of 't' in a formula with another character
- */
-static string replaceTimeBy(const string& src, char r)
-{
- string dst;
- char pre = 0;
- for (size_t i=0; i < src.size(); i++)
- {
- char x = src[i];
- if ((x=='t') && isSeparator(pre) && ((i == src.size()-1) || isSeparator(src[i+1]))) {
- dst.push_back(r);
- } else {
- dst.push_back(x);
- }
- pre = x;
- }
- return dst;
-}
-
-/**
- * Generate the equation of a write table, which content is time dependent.
- * It is basically a signal of vectors.
- */
-string DocCompiler::generateDocWriteTbl (Tree /*tbl*/, Tree size, Tree isig, Tree widx, Tree wsig)
-{
- string vname, ctype;
- string init = CS(isig,0);
- int n;
- if (!isSigInt(size, &n)) {
- cerr << "error in DocCompiler::generateDocWriteTbl() : "
- << *size
- << " is not an integer expression and can't be used as a table size' "
- << endl;
- }
-
-
- // allocate a name w_i for the table
- getTypedNames(getCertifiedSigType(isig), "w", ctype, vname);
-
- // add a comment on tables in the notice
- gDocNoticeFlagMap["tablesigs"] = true;
-
- // describe the table equation
- string ltqRWTableDef;
- ltqRWTableDef += subst("$0(t)[i] = \n", vname);
- ltqRWTableDef += "\\left\\{\\begin{array}{ll}\n";
- ltqRWTableDef += subst("$0 & \\mbox{if \\,} t < 0 \\mbox{\\, and \\,} i \\in [0,$1] \\\\\n", replaceTimeBy(init,'i'), T(n-1));
- ltqRWTableDef += subst("$0 & \\mbox{if \\,} i = $1 \\\\\n", CS(wsig,0), CS(widx,0));
- ltqRWTableDef += subst("$0(t\\!-\\!1)[i] & \\mbox{otherwise} \\\\\n", vname);
- ltqRWTableDef += "\\end{array}\\right.";
-
- // add the table equation
- fLateq->addRWTblSigFormula(ltqRWTableDef); //w(t) = initsig(t)
-
- // note that the name of the table can never be used outside an sigDocTableAccess
- return vname;
-}
-
-
-/**
- * Generate the equation of a write table, which content is time dependent.
- * It is basically a signal of vectors.
- */
-string DocCompiler::generateDocAccessTbl (Tree sig, Tree tbl, Tree ridx)
-{
- // the compilation of a table always returns its name
- string vname = CS(tbl, 0);
- string result = subst("$0[$1]", vname, CS(ridx,0) );
-
- return generateCacheCode(sig, result);
-}
-
-bool DocCompiler::isShortEnough(string& s, unsigned int max)
-{
- return (s.length() <= max);
-}
-
-
-
-/*****************************************************************************
- RECURSIONS
-*****************************************************************************/
-
-
-/**
- * Generate code for a projection of a group of mutually recursive definitions
- */
-string DocCompiler::generateRecProj(Tree sig, Tree r, int i, int priority)
-{
- string vname;
- Tree var, le;
-
- //cerr << "*** generateRecProj sig : \"" << ppsig(sig) << "\"" << endl;
-
- if ( ! getVectorNameProperty(sig, vname)) {
- assert(isRec(r, var, le));
- //cerr << " generateRecProj has NOT YET a vname : " << endl;
- //cerr << "--> generateRecProj calls generateRec on \"" << ppsig(sig) << "\"" << endl;
- generateRec(r, var, le, priority);
- assert(getVectorNameProperty(sig, vname));
- //cerr << "<-- generateRecProj vname : \"" << subst("$0(t)", vname) << "\"" << endl;
- } else {
- //cerr << "(generateRecProj has already a vname : \"" << subst("$0(t)", vname) << "\")" << endl;
- }
- return subst("$0(t)", vname);
-}
-
-
-/**
- * Generate code for a group of mutually recursive definitions
- */
-void DocCompiler::generateRec(Tree sig, Tree var, Tree le, int priority)
-{
- int N = len(le);
-
- vector<bool> used(N);
- vector<int> delay(N);
- vector<string> vname(N);
- vector<string> ctype(N);
-
- // prepare each element of a recursive definition
- for (int i=0; i<N; i++) {
- Tree e = sigProj(i,sig); // recreate each recursive definition
- if (fOccMarkup.retrieve(e)) {
- // this projection is used
- used[i] = true;
- //cerr << "generateRec : used[" << i << "] = true" << endl;
- getTypedNames(getCertifiedSigType(e), "r", ctype[i], vname[i]);
- gDocNoticeFlagMap["recursigs"] = true;
- //cerr << "- r : generateRec setVectorNameProperty : \"" << vname[i] << "\"" << endl;
- setVectorNameProperty(e, vname[i]);
- delay[i] = fOccMarkup.retrieve(e)->getMaxDelay();
- } else {
- // this projection is not used therefore
- // we should not generate code for it
- used[i] = false;
- //cerr << "generateRec : used[" << i << "] = false" << endl;
- }
- }
-
- // generate delayline for each element of a recursive definition
- for (int i=0; i<N; i++) {
- if (used[i]) {
- generateDelayLine(ctype[i], vname[i], delay[i], CS(nth(le,i), priority));
- }
- }
-}
-
-
-/*****************************************************************************
- PREFIX, DELAY A PREFIX VALUE
-*****************************************************************************/
-
-/**
- * Generate LaTeX code for "prefix", a 1sample-delay explicitely initialized.
- *
- * @param sig The signal expression to treat.
- * @param x The initial value for the delay line.
- * @param e The value for the delay line, after initialization.
- * @param priority The priority of the environment of the expression.
- *
- * @return <string> The LaTeX code translation of the signal, cached.
- */
-string DocCompiler::generatePrefix (Tree sig, Tree x, Tree e, int priority)
-{
- string var = getFreshID("m");
- string exp0 = CS(x, priority);
- string exp1 = CS(e, priority); // ensure exp1 is compiled to have a vector name
- string vecname;
-
- if (! getVectorNameProperty(e, vecname)) {
- cerr << "No vector name for : " << ppsig(e) << endl;
- assert(0);
- }
-
- string ltqPrefixDef;
- ltqPrefixDef += subst("$0(t) = \n", var);
- ltqPrefixDef += "\\left\\{\\begin{array}{ll}\n";
- ltqPrefixDef += subst("$0 & \\mbox{, when \\,} t = 0\\\\\n", exp0);
- ltqPrefixDef += subst("$0 & \\mbox{, when \\,} t > 0\n", subst("$0(t\\!-\\!1)", vecname));
- ltqPrefixDef += "\\end{array}\\right.";
-
- fLateq->addPrefixSigFormula(ltqPrefixDef);
- gDocNoticeFlagMap["prefixsigs"] = true;
-
- return generateCacheCode(sig, subst("$0(t)", var));
-}
-
-
-/*****************************************************************************
- IOTA(n)
-*****************************************************************************/
-
-/**
- * Generate a "iota" time function, n-cyclical.
- */
-string DocCompiler::generateIota (Tree sig, Tree n)
-{
- int size;
- if (!isSigInt(n, &size)) { fprintf(stderr, "error in generateIota\n"); exit(1); }
- //cout << "iota !" << endl;
- return subst(" t \\bmod{$0} ", docT(size));
-}
-
-
-
-// a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs
-
-
-/**
- * Generate a select2 code
- */
-string DocCompiler::generateSelect2 (Tree sig, Tree sel, Tree s1, Tree s2, int priority)
-{
- string var = getFreshID("q");
- string expsel = CS(sel, 0);
- string exps1 = CS(s1, 0);
- string exps2 = CS(s2, 0);
-
- string ltqSelDef;
- ltqSelDef += subst("$0(t) = \n", var);
- ltqSelDef += "\\left\\{\\begin{array}{ll}\n";
- ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 0\\\\\n", exps1, expsel);
- ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 1\n", exps2, expsel);
- ltqSelDef += "\\end{array}\\right.";
-
- fLateq->addSelectSigFormula(ltqSelDef);
- gDocNoticeFlagMap["selectionsigs"] = true;
-
- //return generateCacheCode(sig, subst("$0(t)", var));
- setVectorNameProperty(sig, var);
- return subst("$0(t)", var);
-}
-
-
-/**
- * Generate a select3 code
- */
-string DocCompiler::generateSelect3 (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3, int priority)
-{
- string var = getFreshID("q");
- string expsel = CS(sel, 0);
- string exps1 = CS(s1, 0);
- string exps2 = CS(s2, 0);
- string exps3 = CS(s3, 0);
-
- string ltqSelDef;
- ltqSelDef += subst("$0(t) = \n", var);
- ltqSelDef += "\\left\\{\\begin{array}{ll}\n";
- ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 0\\\\\n", generateVariableStore(s1, exps1), expsel);
- ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 1\\\\\n", generateVariableStore(s2, exps2), expsel);
- ltqSelDef += subst("$0 & \\mbox{if \\,} $1 = 2\n", generateVariableStore(s3, exps3), expsel);
- ltqSelDef += "\\end{array}\\right.";
-
- fLateq->addSelectSigFormula(ltqSelDef);
- gDocNoticeFlagMap["selectionsigs"] = true;
-
- //return generateCacheCode(sig, subst("$0(t)", var));
- setVectorNameProperty(sig, var);
- return subst("$0(t)", var);
-}
-
-
-/**
- * retrieve the type annotation of sig
- * @param sig the signal we want to know the type
- */
-string DocCompiler::generateXtended (Tree sig, int priority)
-{
- xtended* p = (xtended*) getUserData(sig);
- vector<string> args;
- vector<Type> types;
-
- for (int i=0; i<sig->arity(); i++) {
- args.push_back(CS(sig->branch(i), 0));
- types.push_back(getCertifiedSigType(sig->branch(i)));
- }
-
- if (p->needCache()) {
- //cerr << "!! generateXtended : <needCache> : calls generateCacheCode(sig, p->generateLateq(fLateq, args, types))" << endl;
- return generateCacheCode(sig, p->generateLateq(fLateq, args, types));
- } else {
- //cerr << "!! generateXtended : <do not needCache> : calls p->generateLateq(fLateq, args, types)" << endl;
- return p->generateLateq(fLateq, args, types);
- }
-}
-
-
-
-//------------------------------------------------------------------------------------------------
-
-
-/*****************************************************************************
- vector name property
-*****************************************************************************/
-
-/**
- * Set the vector name property of a signal, the name of the vector used to
- * store the previous values of the signal to implement a delay.
- * @param sig the signal expression.
- * @param vecname the string representing the vector name.
- * @return true is already compiled
- */
-void DocCompiler::setVectorNameProperty(Tree sig, const string& vecname)
-{
- fVectorProperty.set(sig, vecname);
-}
-
-
-/**
- * Get the vector name property of a signal, the name of the vector used to
- * store the previous values of the signal to implement a delay.
- * @param sig the signal expression.
- * @param vecname the string where to store the vector name.
- * @return true if the signal has this property, false otherwise
- */
-
-bool DocCompiler::getVectorNameProperty(Tree sig, string& vecname)
-{
- return fVectorProperty.get(sig, vecname);
-}
-
-
-
-/*****************************************************************************
- N-SAMPLE FIXED DELAY : sig = exp@delay
-
- case 1-sample max delay :
- Y(t-0) Y(t-1)
- Temp Var gLessTempSwitch = false
- V[0] V[1] gLessTempSwitch = true
-
- case max delay < gMaxCopyDelay :
- Y(t-0) Y(t-1) Y(t-2) ...
- Temp V[0] V[1] ... gLessTempSwitch = false
- V[0] V[1] V[2] ... gLessTempSwitch = true
-
- case max delay >= gMaxCopyDelay :
- Y(t-0) Y(t-1) Y(t-2) ...
- Temp V[0] V[1] ...
- V[0] V[1] V[2] ...
-
-
-*****************************************************************************/
-
-/**
- * Generate code for accessing a delayed signal. The generated code depend of
- * the maximum delay attached to exp and the gLessTempSwitch.
- *
- * @todo Priorités à revoir pour le parenthésage (associativité de - et /),
- * avec gBinOpLateqTable dans binop.cpp.
- */
-string DocCompiler::generateFixDelay (Tree sig, Tree exp, Tree delay, int priority)
-{
- int d;
- string vecname;
-
- CS(exp, 0); // ensure exp is compiled to have a vector name
-
- if (! getVectorNameProperty(exp, vecname)) {
- cerr << "No vector name for : " << ppsig(exp) << endl;
- assert(0);
- }
-
- if (isSigInt(delay, &d) && (d == 0)) {
- //cerr << "@ generateFixDelay : d = " << d << endl;
- return subst("$0(t)", vecname);
- } else {
- //cerr << "@ generateFixDelay : d = " << d << endl;
- return subst("$0(t\\!-\\!$1)", vecname, CS(delay, 7));
- }
-}
-
-
-/**
- * Generate code for the delay mecchanism. The generated code depend of the
- * maximum delay attached to exp and the "less temporaries" switch
- */
-string DocCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
-{
- string s = generateDelayVecNoTemp(sig, exp, ctype, vname, mxd);
- if (getCertifiedSigType(sig)->variability() < kSamp) {
- return exp;
- } else {
- return s;
- }
-}
-
-
-/**
- * Generate code for the delay mecchanism without using temporary variables
- */
-string DocCompiler::generateDelayVecNoTemp(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
-{
- assert(mxd > 0);
-
- //cerr << " entering generateDelayVecNoTemp" << endl;
-
- string vectorname;
-
- // if generateVariableStore has already tagged sig, no definition is needed.
- if(getVectorNameProperty(sig, vectorname)) {
- return subst("$0(t)", vectorname);
- } else {
- fLateq->addRecurSigFormula(subst("$0(t) = $1", vname, exp));
- setVectorNameProperty(sig, vname);
- return subst("$0(t)", vname);
- }
-}
-
-
-/**
- * Generate code for the delay mecchanism without using temporary variables
- */
-void DocCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
-{
- //assert(mxd > 0);
- if (mxd == 0) {
- fLateq->addRecurSigFormula(subst("$0(t) = $1", vname, exp));
- } else {
- fLateq->addRecurSigFormula(subst("$0(t) = $1", vname, exp));
- }
-}
-
-
-
-
-/****************************************************************
- User interface element utilities.
- *****************************************************************/
-
-
-/**
- * @brief Get the directory of a user interface element.
- *
- * Convert the input reversed path tree into a string.
- * The name of the UI is stripped (the head of the path tree),
- * the rest of the tree is a list of pointed pairs, where the names
- * are contained by the tail of these pointed pairs.
- * Metadatas (begining by '[') are stripped.
- *
- * @param[in] pathname The path tree to convert.
- * @return <string> A directory-like string.
- */
-string DocCompiler::getUIDir(Tree pathname)
-{
- //cerr << "Documentator : getUIDir : print(pathname, stdout) = "; print(pathname, stdout); cerr << endl;
- string s;
- Tree dir = reverse(tl(pathname));
- while (!isNil(dir)) {
- string tmp = tree2str(tl(hd(dir)));
- if ( (tmp[0] != '[') && (!tmp.empty()) ) {
- s += tmp + '/';
- }
- dir = tl(dir);
- }
- return s;
-}
-
-
-/**
- * @brief Prepare binary user interface elements (button, checkbox).
- *
- * - Format a LaTeX output string as a supertabular row with 3 columns :
- * "\begin{supertabular}{lll}". @see Lateq::printHierarchy
- * - The UI range is only a set of two values : {0, 1}.
- * - The UI current value is automatically 0.
- *
- * @param[in] name The LaTeX name of the UI signal (eg. "{u_b}_{i}(t)").
- * @param[in] path The path tree to parse.
- * @return <string> The LaTeX output string.
- */
-string DocCompiler::prepareBinaryUI(const string& name, Tree path)
-{
- string label, unit;
- getUIDocInfos(path, label, unit);
- string s = "";
- label = (label.size()>0) ? ("\\textsf{\""+label+"\"} ") : "";
- unit = (unit.size()>0) ? ("\\ ("+unit+")") : "";
- s += label + unit;
- s += " & $" + name + "$";
- s += " $\\in$ $\\left\\{\\,0, 1\\,\\right\\}$";
- s += " & $(\\mbox{" + gDocMathStringMap["defaultvalue"] + "} = 0)$\\\\";
- return s;
-}
-
-
-/**
- * @brief Prepare "intervallic" user interface elements (sliders, nentry).
- *
- * - Format a LaTeX output string as a supertabular row with 3 columns :
- * "\begin{supertabular}{lll}". @see Lateq::printHierarchy
- * - The UI range is an bounded interval : [tmin, tmax].
- * - The UI current value is tcur.
- *
- * @param[in] name The LaTeX name of the UI signal (eg. "{u_s}_{i}(t)").
- * @param[in] path The path tree to parse.
- * @param[in] tcur The current UI value tree to convert.
- * @param[in] tmin The minimum UI value tree to convert.
- * @param[in] tmax The maximum UI value tree to convert.
- * @return <string> The LaTeX output string.
- */
-string DocCompiler::prepareIntervallicUI(const string& name, Tree path, Tree tcur, Tree tmin, Tree tmax)
-{
- string label, unit, cur, min, max;
- getUIDocInfos(path, label, unit);
- cur = docT(tree2float(tcur));
- min = docT(tree2float(tmin));
- max = docT(tree2float(tmax));
-
- string s = "";
- label = (label.size()>0) ? ("\\textsf{\""+label+"\"} ") : "";
- unit = (unit.size()>0) ? ("\\ ("+unit+")") : "";
- s += label + unit;
- s += " & $" + name + "$";
- s += " $\\in$ $\\left[\\," + min + ", " + max + "\\,\\right]$";
- s += " & $(\\mbox{" + gDocMathStringMap["defaultvalue"] + "} = " + cur + ")$\\\\";
- return s;
-}
-
-
-/**
- * Get information on a user interface element for documentation.
- *
- * @param[in] path The UI full pathname to parse.
- * @param[out] label The place to store the UI name.
- * @param[out] unit The place to store the UI unit.
- */
-void DocCompiler::getUIDocInfos(Tree path, string& label, string& unit)
-{
- label = "";
- unit = "";
-
- map<string, set<string> > metadata;
- extractMetadata(tree2str(hd(path)), label, metadata);
-
- set<string> myunits = metadata["unit"];
-// for (set<string>::iterator i = myunits.begin(); i != myunits.end(); i++) {
-// cerr << "Documentator : getUIDocInfos : metadata[\"unit\"] = " << *i << endl;
-// }
- for (map<string, set<string> >::iterator i = metadata.begin(); i != metadata.end(); i++) {
- const string& key = i->first;
- const set<string>& values = i->second;
- for (set<string>::const_iterator j = values.begin(); j != values.end(); j++) {
- if(key == "unit") unit += *j;
- }
- }
-}
-
-