|
FAUST compiler
0.9.9.6b8
|
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
1.8.0