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 00024 /***************************************************************************** 00025 ****************************************************************************** 00026 FAUST SIGNAL COMPILER 00027 Y. Orlarey, (c) Grame 2002 00028 ------------------------------------------------------------------------------ 00029 Compile a list of FAUST signals into a C++ class . 00030 00031 History : 00032 --------- 00033 2002-02-08 : First version 00034 00035 ****************************************************************************** 00036 *****************************************************************************/ 00037 00038 00039 00040 #include "compile.hh" 00041 #include "sigtype.hh" 00042 00043 #include <stdio.h> 00044 00045 #include "sigprint.hh" 00046 #include "sigtype.hh" 00047 #include "sigtyperules.hh" 00048 #include "prim2.hh" 00049 00050 00051 00052 /***************************************************************************** 00053 ****************************************************************************** 00054 00055 CODE GENERATION METHODS 00056 00057 ****************************************************************************** 00058 *****************************************************************************/ 00059 00060 00061 /***************************************************************************** 00062 utilities 00063 *****************************************************************************/ 00064 /* 00065 static Klass* signal2klass (const string& name, Tree sig) 00066 { 00067 Type t = getSigType(sig, NULLENV); 00068 if (t->nature() == kInt) { 00069 00070 Compiler C( new SigIntGenKlass(name) ); 00071 C.compileSingleSignal(sig); 00072 return C.getClass(); 00073 00074 } else { 00075 00076 Compiler C( new SigFloatGenKlass(name) ); 00077 C.compileSingleSignal(sig); 00078 return C.getClass(); 00079 00080 } 00081 } 00082 */ 00083 /***************************************************************************** 00084 INPUTS - OUTPUTS 00085 *****************************************************************************/ 00086 00087 /* 00088 string Compiler::generateInput (Tree tEnv, Tree sig, const string& idx) 00089 { 00090 return subst("input$0[i]", idx); 00091 } 00092 00093 00094 string Compiler::generateOutput (Tree tEnv, Tree sig, const string& idx, const string& arg) 00095 { 00096 string dst = subst("output$0[i]", idx); 00097 fClass->addExecCode(subst("$0 = $1;", dst, arg)); 00098 return dst; 00099 } 00100 */ 00101 00102 /***************************************************************************** 00103 BINARY OPERATION 00104 *****************************************************************************/ 00105 /* 00106 string Compiler::generateBinOp(Tree tEnv, Tree sig, int opcode, Tree arg1, Tree arg2) 00107 { 00108 return generateCacheCode(tEnv, sig, subst("($0 $1 $2)", CS(tEnv, arg1), gBinOpTable[opcode]->fName, CS(tEnv, arg2))); 00109 } 00110 */ 00111 00112 /***************************************************************************** 00113 Primitive Operations 00114 *****************************************************************************/ 00115 /* 00116 string Compiler::generateFFun(Tree tEnv, Tree sig, Tree ff, Tree largs) 00117 { 00118 addIncludeFile(ffincfile(ff)); //printf("inc file %s\n", ffincfile(ff)); 00119 addLibrary(fflibfile(ff)); //printf("lib file %s\n", fflibfile(ff)); 00120 switch (ffarity(ff)) { 00121 case 0 : return generateCacheCode(tEnv, sig, subst("$0()", ffname(ff))); 00122 case 1 : return generateCacheCode(tEnv, sig, subst("$0($1)", ffname(ff), CS(tEnv, nth(largs,0)))); 00123 case 2 : return generateCacheCode(tEnv, sig, subst("$0($1, $2)", ffname(ff), CS(tEnv, nth(largs,0)), CS(tEnv, nth(largs,1)))); 00124 case 3 : return generateCacheCode(tEnv, sig, subst("$0($1, $2, $3)", ffname(ff), CS(tEnv, nth(largs,0)), CS(tEnv, nth(largs,1)), CS(tEnv, nth(largs,2)))); 00125 default : fprintf(stderr, "error inside generateFFun"); exit(1); 00126 } 00127 return "Arity Error in FFun"; 00128 } 00129 */ 00130 00131 /***************************************************************************** 00132 CACHE CODE 00133 *****************************************************************************/ 00134 /* 00135 string Compiler::generateCacheCode(Tree tEnv, Tree sig, const string& exp) 00136 { 00137 string vname, ctype; 00138 int sharing = shcount(fSharingKey, sig); 00139 00140 00141 if (sharing == 1) { 00142 00143 return exp; 00144 00145 } else if (sharing > 1) { 00146 Type t = getSigType(sig, tEnv); 00147 // cerr << "generation du cache code pour : " << exp << " qui est de type " << t << endl; 00148 00149 switch (t->variability()) { 00150 00151 case kKonst : 00152 00153 if (t->nature() == kInt) { 00154 vname = getFreshID("idata"); 00155 ctype = "int"; 00156 } else { 00157 vname = getFreshID("fdata"); 00158 ctype = "float"; 00159 } 00160 00161 fClass->addDeclCode(subst("$0 \t$1;", ctype, vname)); 00162 fClass->addInitCode(subst("$0 = $1;", vname, exp)); 00163 break; 00164 00165 case kBlock : 00166 00167 if (t->nature() == kInt) { 00168 vname = getFreshID("itemp"); 00169 ctype = "int"; 00170 } else { 00171 vname = getFreshID("ftemp"); 00172 ctype = "float"; 00173 } 00174 00175 fClass->addSlowCode(subst("$0 $1 = $2;", ctype, vname, exp)); 00176 break; 00177 00178 case kSamp : 00179 00180 if (t->nature() == kInt) { 00181 vname = getFreshID("itemp"); 00182 ctype = "int"; 00183 } else { 00184 vname = getFreshID("ftemp"); 00185 ctype = "float"; 00186 } 00187 00188 fClass->addExecCode(subst("$0 $1 = $2;", ctype, vname, exp)); 00189 break; 00190 } 00191 return vname; 00192 00193 } else { 00194 00195 fprintf(stderr, "Error in sharing count\n"); 00196 exit(1); 00197 } 00198 00199 return "Error in generateCacheCode"; 00200 } 00201 */ 00202 00203 00204 00205 /***************************************************************************** 00206 CASTING 00207 *****************************************************************************/ 00208 /* 00209 00210 string Compiler::generateIntCast(Tree tEnv, Tree sig, Tree x) 00211 { 00212 return generateCacheCode(tEnv, sig, subst("int($0)", CS(tEnv, x))); 00213 } 00214 00215 string Compiler::generateFloatCast (Tree tEnv, Tree sig, Tree x) 00216 { 00217 return generateCacheCode(tEnv, sig, subst("float($0)", CS(tEnv, x))); 00218 } 00219 */ 00220 /***************************************************************************** 00221 user interface elements 00222 *****************************************************************************/ 00223 /* 00224 string Compiler::generateButton(Tree tEnv, Tree sig, Tree path) 00225 { 00226 string varname = getFreshID("fbutton"); 00227 fClass->addDeclCode(subst("float \t$0;", varname)); 00228 fClass->addInitCode(subst("$0 = 0.0;", varname)); 00229 addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig)); 00230 return generateCacheCode(tEnv, sig, varname); 00231 } 00232 00233 string Compiler::generateCheckbox(Tree tEnv, Tree sig, Tree path) 00234 { 00235 string varname = getFreshID("fcheckbox"); 00236 fClass->addDeclCode(subst("float \t$0;", varname)); 00237 fClass->addInitCode(subst("$0 = 0.0;", varname)); 00238 addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig)); 00239 return generateCacheCode(tEnv, sig, varname); 00240 } 00241 00242 00243 string Compiler::generateVSlider(Tree tEnv, Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step) 00244 { 00245 string varname = getFreshID("fslider"); 00246 fClass->addDeclCode(subst("float \t$0;", varname)); 00247 fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur)))); 00248 addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig)); 00249 return generateCacheCode(tEnv, sig, varname); 00250 } 00251 00252 string Compiler::generateHSlider(Tree tEnv, Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step) 00253 { 00254 string varname = getFreshID("fslider"); 00255 fClass->addDeclCode(subst("float \t$0;", varname)); 00256 fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur)))); 00257 addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig)); 00258 return generateCacheCode(tEnv, sig, varname); 00259 } 00260 00261 string Compiler::generateNumEntry(Tree tEnv, Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step) 00262 { 00263 string varname = getFreshID("fentry"); 00264 fClass->addDeclCode(subst("float \t$0;", varname)); 00265 fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur)))); 00266 addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig)); 00267 return generateCacheCode(tEnv, sig, varname); 00268 } 00269 00270 00271 void Compiler::addUIWidget(Tree path, Tree widget) 00272 { 00273 fUIRoot = putSubFolder(fUIRoot, path, widget); 00274 } 00275 00276 void Compiler::generateWidgetCode(Tree label, Tree varname, Tree sig) 00277 { 00278 Tree path, c, x, y, z; 00279 00280 if ( isSigButton(sig, path) ) { 00281 fClass->addUICode(subst("interface->addButton($0, &$1);", tree2str(label), tree2str(varname))); 00282 00283 } else if ( isSigCheckbox(sig, path) ) { 00284 fClass->addUICode(subst("interface->addCheckbox($0, &$1);", tree2str(label), tree2str(varname))); 00285 00286 } else if ( isSigVSlider(sig, path,c,x,y,z) ) { 00287 fClass->addUICode(subst("interface->addVerticalSlider($0, &$1, $2, $3, $4, $5);", 00288 tree2str(label), 00289 tree2str(varname), 00290 T(tree2float(c)), 00291 T(tree2float(x)), 00292 T(tree2float(y)), 00293 T(tree2float(z)))); 00294 00295 } else if ( isSigHSlider(sig, path,c,x,y,z) ) { 00296 fClass->addUICode(subst("interface->addHorizontalSlider($0, &$1, $2, $3, $4, $5);", 00297 tree2str(label), 00298 tree2str(varname), 00299 T(tree2float(c)), 00300 T(tree2float(x)), 00301 T(tree2float(y)), 00302 T(tree2float(z)))); 00303 00304 } else if ( isSigNumEntry(sig, path,c,x,y,z) ) { 00305 fClass->addUICode(subst("interface->addNumEntry($0, &$1, $2, $3, $4, $5);", 00306 tree2str(label), 00307 tree2str(varname), 00308 T(tree2float(c)), 00309 T(tree2float(x)), 00310 T(tree2float(y)), 00311 T(tree2float(z)))); 00312 00313 } else { 00314 fprintf(stderr, "Error in generating widget code\n"); 00315 exit(1); 00316 } 00317 } 00318 00319 00320 void Compiler::generateUserInterfaceTree(Tree t) 00321 { 00322 Tree label, elements, varname, sig; 00323 00324 if (isUiFolder(t, label, elements)) { 00325 const int orient = tree2int(left(label)); 00326 const char * str = tree2str(right(label)); 00327 const char * model; 00328 00329 switch (orient) { 00330 case 0 : model = "interface->openVerticalBox($0);"; break; 00331 case 1 : model = "interface->openHorizontalBox($0);"; break; 00332 case 2 : model = "interface->openTabBox($0);"; break; 00333 default : 00334 fprintf(stderr, "error in user interface generation 1\n"); 00335 exit(1); 00336 } 00337 fClass->addUICode(subst(model, str)); 00338 generateUserInterfaceElements(elements); 00339 fClass->addUICode("interface->closeBox();"); 00340 00341 } else if (isUiWidget(t, label, varname, sig)) { 00342 00343 generateWidgetCode(label, varname, sig); 00344 00345 } else { 00346 00347 fprintf(stderr, "error in user interface generation 2\n"); 00348 exit(1); 00349 00350 } 00351 } 00352 00353 void Compiler::generateUserInterfaceElements(Tree elements) 00354 { 00355 while (!isNil(elements)) { 00356 generateUserInterfaceTree(right(hd(elements))); 00357 elements = tl(elements); 00358 } 00359 } 00360 */ 00361 00362 /***************************************************************************** 00363 TABLES 00364 *****************************************************************************/ 00365 00366 00367 00368 /*---------------------------------------------------------------------------- 00369 sigGen : initial table content 00370 ----------------------------------------------------------------------------*/ 00371 /* 00372 string Compiler::generateSigGen(Tree tEnv, Tree sig, Tree content) 00373 { 00374 string klassname = getFreshID("SIG"); 00375 string signame = getFreshID("sig"); 00376 00377 fClass->addSubKlass(signal2klass(klassname, content)); 00378 fClass->addInitCode(subst("$0 $1;", klassname, signame)); 00379 00380 return signame; 00381 } 00382 */ 00383 00384 /*---------------------------------------------------------------------------- 00385 sigTable : table declaration 00386 ----------------------------------------------------------------------------*/ 00387 /* 00388 string Compiler::generateTable(Tree tEnv, Tree sig, Tree tsize, Tree content) 00389 { 00390 string generator(CS(tEnv, content)); 00391 string ctype, vname; 00392 int size; 00393 00394 if (!isSigInt(tsize, &size)) { fprintf(stderr, "error\n"); exit(1); } 00395 // definition du nom et du type de la table 00396 // A REVOIR !!!!!!!!! 00397 Type t = getSigType(content, tEnv); 00398 if (t->nature() == kInt) { 00399 vname = getFreshID("itbl"); 00400 ctype = "int"; 00401 } else { 00402 vname = getFreshID("ftbl"); 00403 ctype = "float"; 00404 } 00405 00406 // declaration de la table 00407 fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(size))); 00408 00409 // initialisation du generateur de contenu 00410 fClass->addInitCode(subst("$0.init(samplingRate);", generator)); 00411 // remplissage de la table 00412 fClass->addInitCode(subst("$0.fill($1,$2);", generator, T(size), vname)); 00413 00414 // on retourne le nom de la table 00415 return vname; 00416 } 00417 */ 00418 00419 /*---------------------------------------------------------------------------- 00420 sigWRTable : table assignement 00421 ----------------------------------------------------------------------------*/ 00422 /* 00423 string Compiler::generateWRTbl(Tree tEnv, Tree sig, Tree tbl, Tree idx, Tree data) 00424 { 00425 string tblName(CS(tEnv, tbl)); 00426 fClass->addExecCode(subst("$0[$1] = $2;", tblName, CS(tEnv, idx), CS(tEnv, data))); 00427 return tblName; 00428 } 00429 */ 00430 00431 /*---------------------------------------------------------------------------- 00432 sigRDTable : table access 00433 ----------------------------------------------------------------------------*/ 00434 /* 00435 string Compiler::generateRDTbl(Tree tEnv, Tree sig, Tree tbl, Tree idx) 00436 { 00437 return subst("$0[$1]", CS(tEnv, tbl), CS(tEnv, idx)); 00438 } 00439 00440 */ 00441 00442 /***************************************************************************** 00443 RECURSIONS 00444 *****************************************************************************/ 00445 00446 00447 /*--------------------------------------------------------------------------- 00448 fonctions auxilliaires 00449 ----------------------------------------------------------------------------*/ 00450 /* 00451 // Genere le nom d'une variable recursive permanente 00452 static string makeRecVarPermName(const string& groupID, int i) 00453 { 00454 return subst("$0_$1", groupID, T(i)); 00455 } 00456 00457 // Genere le nom d'une variable recursive temporaire 00458 static string makeRecVarTempName(const string& groupID, int i) 00459 { 00460 return subst("$0temp$1", groupID, T(i)); 00461 } 00462 00463 // Donne le nom du type C correspondant à la nature d'un signal 00464 static string cType (Type t) 00465 { 00466 return (t->nature() == kInt) ? "int" : "float"; 00467 } 00468 00469 // Donne le nom zero correspondant à la nature d'un signal 00470 static string cZero (Type t) 00471 { 00472 return (t->nature() == kInt) ? "0" : "0.0"; 00473 } 00474 00475 // Clef de proprieté associant un nom au label d'un groupe recursif 00476 Tree RECNAMEPROP = tree(symbol("sigRecNameProp")); 00477 00478 */ 00479 /*-------------------------------------------------------------------------- 00480 Fonctions de génération 00481 ----------------------------------------------------------------------------*/ 00482 00483 // Groupe de signaux mutuellement recursifs 00484 00485 /* 00486 string Compiler::generateRecGroup(Tree tEnv, Tree sig, Tree var, Tree le) 00487 { 00488 Type t = getSigType(sig, tEnv); 00489 int n = len(le); 00490 string ID = getFreshID("R"); 00491 00492 00493 // prepare the environments for the subtermes 00494 Tree tEnv2 = addEnv(var,t,tEnv); 00495 00496 // store the variable name associated with this recursive group 00497 setProperty(ref(var), fCompileKey, tree(ID.c_str())); 00498 00499 00500 if (n==1) { 00501 00502 Tree e = nth(le, 0); 00503 Type te = getSigType(e, tEnv2); 00504 00505 00506 string vperm = makeRecVarPermName(ID, 0); 00507 string type = cType(te); 00508 string zero = cZero(te); 00509 fClass->addDeclCode(subst("$0 \t$1;", type, vperm)); 00510 fClass->addInitCode(subst("$0 = $1;", vperm, zero)); 00511 fClass->addExecCode(subst("$0 = $1;", vperm, CS(tEnv2, e))); 00512 00513 } else { 00514 00515 for (int i=0; i<n; i++) { 00516 Tree e = nth(le, i); 00517 Type te = getSigType(e, tEnv2); 00518 string vperm = makeRecVarPermName(ID, i); 00519 string vtemp = makeRecVarTempName(ID, i); 00520 string type = cType(te); 00521 string zero = cZero(te); 00522 fClass->addDeclCode(subst("$0 \t$1;", type, vperm)); 00523 fClass->addInitCode(subst("$0 = $1;", vperm, zero)); 00524 fClass->addExecCode(subst("$0 $1 = $2;", type, vtemp, CS(tEnv2, e))); 00525 } 00526 00527 for (int i=0; i<n; i++) { 00528 fClass->addExecCode(subst("$0 = $1;", makeRecVarPermName(ID, i), makeRecVarTempName(ID, i))); 00529 } 00530 } 00531 return ID; 00532 } 00533 00534 00535 // Projection : selection du ième signal d'un groupe recursif 00536 string Compiler::generateRecProj(Tree tEnv, Tree sig, const string& ID, int i) 00537 { 00538 return makeRecVarPermName(ID, i); 00539 } 00540 00541 00542 //--------------a supprimer 00543 // Variable : référence au ième signal d'un groupe recursif englobant 00544 string Compiler::generateRecRef(Tree tEnv, Tree sig, Tree var) 00545 { 00546 Tree code; 00547 if (!getProperty(var, fCompileKey, code)) { 00548 fprintf(stderr, "ERROR in generateRecRef\n"); 00549 exit(1); 00550 } 00551 return name(code->node().getSym()); 00552 } 00553 00554 */ 00555 /***************************************************************************** 00556 1-SAMPLE DELAY 00557 *****************************************************************************/ 00558 /* 00559 string Compiler::generateDelay1 (Tree tEnv, Tree sig, Tree e) 00560 { 00561 Type te = getSigType(e, tEnv); 00562 00563 string vperm = getFreshID("M"); 00564 string vtemp = getFreshID("T"); 00565 00566 string type = cType(te); 00567 string zero = cZero(te); 00568 00569 fClass->addDeclCode(subst("$0 \t$1;", type, vperm)); 00570 fClass->addInitCode(subst("$0 = $1;", vperm, zero)); 00571 00572 fClass->addExecCode(subst("$0 $1 = $2;", type, vtemp, vperm)); 00573 fClass->addExecCode(subst("$0 = $1;", vperm, CS(tEnv, e))); 00574 return vtemp; 00575 } 00576 00577 00578 00579 // a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs 00580 // il faudrait egalement tenir compte de la computability et de la variability 00581 00582 string Compiler::generateSelect2 (Tree tEnv, Tree sig, Tree sel, Tree s1, Tree s2) 00583 { 00584 Type t = getSigType(sig, tEnv); 00585 00586 string type = cType(t); 00587 string var = getFreshID("S"); 00588 00589 fClass->addExecCode(subst("$0 \t$1[2];", type, var)); 00590 fClass->addExecCode(subst("$0[0] = $1;", var, CS(tEnv, s1))); 00591 fClass->addExecCode(subst("$0[1] = $1;", var, CS(tEnv, s2))); 00592 return subst("$0[$1]", var, CS(tEnv, sel)); 00593 } 00594 00595 string Compiler::generateSelect3 (Tree tEnv, Tree sig, Tree sel, Tree s1, Tree s2, Tree s3) 00596 { 00597 Type t = getSigType(sig, tEnv); 00598 00599 string type = cType(t); 00600 string var = getFreshID("S"); 00601 00602 fClass->addExecCode(subst("$0 \t$1[3];", type, var)); 00603 fClass->addExecCode(subst("$0[0] = $1;", var, CS(tEnv, s1))); 00604 fClass->addExecCode(subst("$0[1] = $2;", var, CS(tEnv, s2))); 00605 fClass->addExecCode(subst("$0[2] = $3;", var, CS(tEnv, s3))); 00606 return subst("$0[$1]", var, CS(tEnv, sel)); 00607 } 00608 */