|
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 00030 #include <stdio.h> 00031 #include <ctype.h> 00032 #include <sys/stat.h> 00033 #include <sys/types.h> 00034 #include <errno.h> 00035 #include <string.h> 00036 00037 #include <ostream> 00038 #include <sstream> 00039 #include <set> 00040 #include <utility> 00041 #include <map> 00042 #include <stack> 00043 #include <string> 00044 00045 #include "boxes.hh" 00046 #include "ppbox.hh" 00047 #include "prim2.hh" 00048 00049 #include <vector> 00050 #include "devLib.h" 00051 #include "ppbox.hh" 00052 #include "xtended.hh" 00053 #include "occurrences.hh" 00054 #include "boxcomplexity.h" 00055 00056 #include "schema.h" 00057 #include "drawschema.hh" 00058 #include "compatibility.hh" 00059 #include "names.hh" 00060 #include "description.hh" 00061 #include "property.hh" 00062 00063 00064 00065 #if 0 00066 #define linkcolor "#b3d1dc" 00067 #define normalcolor "#ffeaa2" 00068 #define uicolor "#F1CFA1" 00069 #define slotcolor "#ffffd7" 00070 #define numcolor "#ffffff" 00071 #endif 00072 00073 #if 0 00074 #define linkcolor "#F57900" 00075 #define normalcolor "#4B71A1" 00076 #define uicolor "#47945E" 00077 #define slotcolor "#EDD400" 00078 #define numcolor "#4B71A1" 00079 #endif 00080 00081 #if 0 00082 #define linkcolor "#47945E" 00083 #define normalcolor "#4B71A1" 00084 #define uicolor "#f44800" 00085 #define slotcolor "#EDD400" 00086 #define numcolor "#f44800" 00087 #endif 00088 00089 #if 0 00090 #define linkcolor "#47945E" 00091 #define normalcolor "#4B71A1" 00092 #define uicolor "#816647" 00093 #define slotcolor "#EDD400" 00094 #define numcolor "#f44800" 00095 #endif 00096 00097 #if 0 00098 #define linkcolor "#003366" 00099 #define normalcolor "#4B71A1" 00100 #define uicolor "#816647" 00101 #define slotcolor "#EDD400" 00102 #define numcolor "#f44800" 00103 #endif 00104 00105 #if 0 00106 #define linkcolor "#003366" 00107 #define normalcolor "#4B71A1" 00108 #define uicolor "#477881" 00109 #define slotcolor "#816647" 00110 #define numcolor "#f44800" 00111 #endif 00112 00113 00114 #if 1 00115 #define linkcolor "#003366" 00116 #define normalcolor "#4B71A1" 00117 #define uicolor "#477881" 00118 #define slotcolor "#47945E" 00119 #define numcolor "#f44800" 00120 #define invcolor "#ffffff" 00121 #endif 00122 00123 using namespace std; 00124 00125 // external parameters 00126 extern int gFoldThreshold; // max diagram complexity before folding 00127 00128 00129 // internal state during drawing 00130 static Occurrences* gOccurrences; 00131 static bool sFoldingFlag; // true with complex block-diagrams 00132 static stack<Tree> gPendingExp; // Expressions that need to be drawn 00133 static set<Tree> gDrawnExp; // Expressions drawn or scheduled so far 00134 static const char* gDevSuffix; // .svg or .ps used to choose output device 00135 static char gCurrentDir[512]; // room to save current directory name 00136 static string gSchemaFileName; // name of schema file beeing generated 00137 static map<Tree,string> gBackLink; // link to enclosing file for sub schema 00138 00139 // prototypes of internal functions 00140 static void writeSchemaFile(Tree bd); 00141 static schema* generateDiagramSchema (Tree bd); 00142 static schema* generateInsideSchema(Tree t); 00143 static void scheduleDrawing(Tree t); 00144 static bool pendingDrawing(Tree& t); 00145 static schema* generateAbstractionSchema(schema* x, Tree t); 00146 static schema* generateOutputSlotSchema(Tree a); 00147 static schema* generateInputSlotSchema(Tree a); 00148 static schema* generateBargraphSchema(Tree t); 00149 static schema* generateUserInterfaceSchema(Tree t); 00150 static char* legalFileName(Tree t, int n, char* dst); 00151 static int cholddir (); 00152 static int mkchdir(const char* dirname); 00153 00154 00155 00156 00162 void drawSchema(Tree bd, const char* projname, const char* dev) 00163 { 00164 gDevSuffix = dev; 00165 sFoldingFlag = boxComplexity(bd) > gFoldThreshold; 00166 00167 mkchdir(projname); // create a directory to store files 00168 00169 scheduleDrawing(bd); // schedule the initial drawing 00170 00171 Tree t; while (pendingDrawing(t)) { 00172 writeSchemaFile(t); // generate all the pending drawing 00173 } 00174 00175 cholddir(); // return to current directory 00176 } 00177 00178 00179 /************************************************************************ 00180 ************************************************************************ 00181 IMPLEMENTATION 00182 ************************************************************************ 00183 ************************************************************************/ 00184 00185 00186 //------------------- to schedule and retreive drawing ------------------ 00187 00191 static void scheduleDrawing(Tree t) 00192 { 00193 if (gDrawnExp.find(t) == gDrawnExp.end()) { 00194 gDrawnExp.insert(t); 00195 gBackLink.insert(make_pair(t,gSchemaFileName)); // remember the enclosing filename 00196 gPendingExp.push(t); 00197 } 00198 } 00199 00203 static bool pendingDrawing(Tree& t) 00204 { 00205 if (gPendingExp.empty()) return false; 00206 t = gPendingExp.top(); 00207 gPendingExp.pop(); 00208 return true; 00209 } 00210 00211 00212 00213 //------------------------ dealing with files ------------------------- 00214 00220 static void writeSchemaFile(Tree bd) 00221 { 00222 Tree id; 00223 schema* ts; 00224 00225 char temp[1024]; 00226 00227 gOccurrences = new Occurrences(bd); 00228 00229 bool hasname = getDefNameProperty(bd, id); 00230 00231 //assert(hasname); 00232 if (!hasname) { 00233 // create an arbitrary name 00234 id = tree(Node(unique("diagram_"))); 00235 } 00236 00237 // generate legal file name for the schema 00238 stringstream s1; s1 << legalFileName(bd, 1024, temp) << "." << gDevSuffix; 00239 gSchemaFileName = s1.str(); 00240 00241 // generate the label of the schema 00242 stringstream s2; s2 << tree2str(id); 00243 string link = gBackLink[bd]; 00244 ts = makeTopSchema(generateInsideSchema(bd), 20, s2.str(), link); 00245 // draw to the device defined by gDevSuffix 00246 if (strcmp(gDevSuffix, "svg") == 0) { 00247 SVGDev dev(s1.str().c_str(), ts->width(), ts->height()); 00248 ts->place(0,0, kLeftRight); 00249 ts->draw(dev); 00250 { collector c; ts->collectTraits(c); c.draw(dev); } 00251 } else { 00252 PSDev dev(s1.str().c_str(), ts->width(), ts->height()); 00253 ts->place(0,0, kLeftRight); 00254 ts->draw(dev); 00255 { 00256 collector c; 00257 ts->collectTraits(c); 00258 c.draw(dev); 00259 } 00260 } 00261 } 00262 00263 00264 00269 static int mkchdir(const char* dirname) 00270 { 00271 //cerr << "mkchdir of " << dirname << endl; 00272 if (getcwd(gCurrentDir, 512) != 0) { 00273 int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 00274 if (status == 0 || errno == EEXIST) { 00275 if (chdir(dirname) == 0) { 00276 return 0; 00277 } 00278 } 00279 } 00280 perror("mkchdir"); 00281 exit(errno); 00282 //return errno; 00283 } 00284 00285 00289 static int cholddir () 00290 { 00291 if (chdir(gCurrentDir) == 0) { 00292 return 0; 00293 } else { 00294 perror("cholddir"); 00295 exit(errno); 00296 } 00297 } 00298 00299 00306 static char* legalFileName(Tree t, int n, char* dst) 00307 { 00308 Tree id; 00309 int i=0; 00310 if (getDefNameProperty(t, id)) { 00311 const char* src = tree2str(id); 00312 for (i=0; isalnum(src[i]) && i<16; i++) { 00313 dst[i] = src[i]; 00314 } 00315 } 00316 dst[i] = 0; 00317 if (strcmp(dst, "process") != 0) { 00318 // if it is not process add the hex address to make the name unique 00319 snprintf(&dst[i], n-i, "-%p", t); 00320 } 00321 return dst; 00322 } 00323 00324 00325 00326 //------------------------ generating the schema ------------------------- 00327 00328 00333 Tree gInverter[6]; 00334 00335 static bool isInverter(Tree t) 00336 { 00337 // init gInverted table. For some reason doesn't work if done outside 00338 if (gInverter[0] == 0) { 00339 gInverter[0] = boxSeq(boxPar(boxWire(), boxInt(-1)),boxPrim2(sigMul)); 00340 gInverter[1] = boxSeq(boxPar(boxInt(-1), boxWire()),boxPrim2(sigMul)); 00341 gInverter[2] = boxSeq(boxPar(boxWire(), boxReal(-1.0)),boxPrim2(sigMul)); 00342 gInverter[3] = boxSeq(boxPar(boxReal(-1.0), boxWire()),boxPrim2(sigMul)); 00343 gInverter[4] = boxSeq(boxPar(boxInt(0), boxWire()),boxPrim2(sigSub)); 00344 gInverter[5] = boxSeq(boxPar(boxReal(0.0), boxWire()),boxPrim2(sigSub)); 00345 }; 00346 00347 //cerr << "isInverter " << t << '$' << boxpp(t) << endl; 00348 for (int i=0; i<6; i++) { 00349 if (t == gInverter[i]) return true; 00350 } 00351 return false; 00352 } 00353 00354 00360 property<bool> gPureRoutingProperty; 00361 00362 static bool isPureRouting(Tree t) 00363 { 00364 bool r; 00365 int ID; 00366 Tree x,y; 00367 00368 if (gPureRoutingProperty.get(t,r)) { 00369 return r; 00370 } else if ( isBoxCut(t) 00371 || isBoxWire(t) 00372 || isInverter(t) 00373 || isBoxSlot(t, &ID) 00374 || (isBoxPar(t,x,y) && isPureRouting(x) && isPureRouting(y)) 00375 || (isBoxSeq(t,x,y) && isPureRouting(x) && isPureRouting(y)) 00376 || (isBoxSplit(t,x,y) && isPureRouting(x) && isPureRouting(y)) 00377 || (isBoxMerge(t,x,y) && isPureRouting(x) && isPureRouting(y)) 00378 ) { 00379 gPureRoutingProperty.set(t,true); 00380 return true; 00381 } else { 00382 gPureRoutingProperty.set(t,false); 00383 return false; 00384 } 00385 } 00386 00387 00394 static schema* generateDiagramSchema(Tree t) 00395 { 00396 Tree id; 00397 int ins, outs; 00398 00399 //cerr << t << " generateDiagramSchema " << boxpp(t)<< endl; 00400 00401 if (getDefNameProperty(t, id)) { 00402 stringstream s; s << tree2str(id); 00403 //cerr << t << "\tNAMED : " << s.str() << endl; 00404 } 00405 00406 if ( sFoldingFlag && /*(gOccurrences->getCount(t) > 0) &&*/ 00407 (boxComplexity(t) > 2) && getDefNameProperty(t, id)) { 00408 char temp[1024]; 00409 getBoxType(t, &ins, &outs); 00410 stringstream s, l; 00411 s << tree2str(id); 00412 l << legalFileName(t,1024,temp) << "." << gDevSuffix; 00413 scheduleDrawing(t); 00414 return makeBlockSchema(ins, outs, s.str(), linkcolor, l.str()); 00415 00416 } else if (getDefNameProperty(t, id) && ! isPureRouting(t)) { 00417 // named case : not a slot, with a name 00418 // draw a line around the object with its name 00419 stringstream s; s << tree2str(id); 00420 return makeDecorateSchema(generateInsideSchema(t), 10, s.str()); 00421 00422 } else { 00423 // normal case 00424 return generateInsideSchema(t); 00425 } 00426 } 00427 00428 00429 00434 static schema* generateInsideSchema(Tree t) 00435 { 00436 Tree a, b, ff, l, type,name,file; 00437 int i; 00438 double r; 00439 prim0 p0; 00440 prim1 p1; 00441 prim2 p2; 00442 prim3 p3; 00443 prim4 p4; 00444 prim5 p5; 00445 00446 00447 xtended* xt = (xtended*)getUserData(t); 00448 00449 if (xt) { return makeBlockSchema(xt->arity(), 1, xt->name(), normalcolor, ""); } 00450 00451 else if (isInverter(t)) { return makeInverterSchema(invcolor); } 00452 00453 else if (isBoxInt(t, &i)) { stringstream s; s << i; return makeBlockSchema(0, 1, s.str(), numcolor, "" ); } 00454 else if (isBoxReal(t, &r)) { stringstream s; s << r; return makeBlockSchema(0, 1, s.str(), numcolor, "" ); } 00455 else if (isBoxWire(t)) { return makeCableSchema(); } 00456 else if (isBoxCut(t)) { return makeCutSchema(); } 00457 00458 else if (isBoxPrim0(t, &p0)) { return makeBlockSchema(0, 1, prim0name(p0), normalcolor, ""); } 00459 else if (isBoxPrim1(t, &p1)) { return makeBlockSchema(1, 1, prim1name(p1), normalcolor, ""); } 00460 else if (isBoxPrim2(t, &p2)) { return makeBlockSchema(2, 1, prim2name(p2), normalcolor, ""); } 00461 else if (isBoxPrim3(t, &p3)) { return makeBlockSchema(3, 1, prim3name(p3), normalcolor, ""); } 00462 else if (isBoxPrim4(t, &p4)) { return makeBlockSchema(4, 1, prim4name(p4), normalcolor, ""); } 00463 else if (isBoxPrim5(t, &p5)) { return makeBlockSchema(5, 1, prim5name(p5), normalcolor, ""); } 00464 00465 else if (isBoxFFun(t, ff)) { return makeBlockSchema(ffarity(ff), 1, ffname(ff), normalcolor, ""); } 00466 else if (isBoxFConst(t, type,name,file)) { return makeBlockSchema(0, 1, tree2str(name), normalcolor, ""); } 00467 else if (isBoxFVar (t, type, name,file)) { return makeBlockSchema(0, 1, tree2str(name), normalcolor, ""); } 00468 00469 else if (isBoxButton(t)) { return generateUserInterfaceSchema(t); } 00470 else if (isBoxCheckbox(t)) { return generateUserInterfaceSchema(t); } 00471 else if (isBoxVSlider(t)) { return generateUserInterfaceSchema(t); } 00472 else if (isBoxHSlider(t)) { return generateUserInterfaceSchema(t); } 00473 else if (isBoxNumEntry(t)) { return generateUserInterfaceSchema(t); } 00474 else if (isBoxVBargraph(t)) { return generateBargraphSchema(t); } 00475 else if (isBoxHBargraph(t)) { return generateBargraphSchema(t); } 00476 00477 // don't draw group rectangle when labels are empty (ie "") 00478 else if (isBoxVGroup(t,l,a)) { stringstream s; s << "vgroup(" << extractName(l) << ")"; 00479 schema* r = generateDiagramSchema(a); 00480 return makeDecorateSchema(r, 10, s.str()); } 00481 else if (isBoxHGroup(t,l,a)) { stringstream s; s << "hgroup(" << extractName(l) << ")"; 00482 schema* r = generateDiagramSchema(a); 00483 return makeDecorateSchema(r, 10, s.str()); } 00484 else if (isBoxTGroup(t,l,a)) { stringstream s; s << "tgroup(" << extractName(l) << ")"; 00485 schema* r = generateDiagramSchema(a); 00486 return makeDecorateSchema(r, 10, s.str()); } 00487 00488 else if (isBoxSeq(t, a, b)) { return makeSeqSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } 00489 else if (isBoxPar(t, a, b)) { return makeParSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } 00490 else if (isBoxSplit(t, a, b)) { return makeSplitSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } 00491 else if (isBoxMerge(t, a, b)) { return makeMergeSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } 00492 else if (isBoxRec(t, a, b)) { return makeRecSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } 00493 00494 else if (isBoxSlot(t, &i)) { return generateOutputSlotSchema(t); } 00495 else if (isBoxSymbolic(t,a,b)) { 00496 Tree id; 00497 if (getDefNameProperty(t, id)) { 00498 return generateAbstractionSchema(generateInputSlotSchema(a), b); 00499 } else { 00500 return makeDecorateSchema(generateAbstractionSchema(generateInputSlotSchema(a), b), 10, "Abstraction"); 00501 } 00502 } 00503 00504 else { 00505 00506 fprintf(stderr, "Internal Error, box expression not recognized : "); print(t, stderr); fprintf(stderr, "\n"); 00507 exit(1); 00508 00509 } 00510 } 00511 00515 static void UserInterfaceDescription(Tree box, string& d) 00516 { 00517 Tree t1, label, cur, min, max, step; 00518 stringstream fout; 00519 // user interface 00520 if (isBoxButton(box, label)) fout << "button(" << extractName(label) << ')'; 00521 else if (isBoxCheckbox(box, label)) fout << "checkbox(" << extractName(label) << ')'; 00522 else if (isBoxVSlider(box, label, cur, min, max, step)) { 00523 fout << "vslider(" 00524 << extractName(label) << ", " 00525 << boxpp(cur) << ", " 00526 << boxpp(min) << ", " 00527 << boxpp(max) << ", " 00528 << boxpp(step)<< ')'; 00529 } 00530 else if (isBoxHSlider(box, label, cur, min, max, step)) { 00531 fout << "hslider(" 00532 << extractName(label) << ", " 00533 << boxpp(cur) << ", " 00534 << boxpp(min) << ", " 00535 << boxpp(max) << ", " 00536 << boxpp(step)<< ')'; 00537 } 00538 else if (isBoxVGroup(box, label, t1)) { 00539 fout << "vgroup(" << extractName(label) << ", " << boxpp(t1, 0) << ')'; 00540 } 00541 else if (isBoxHGroup(box, label, t1)) { 00542 fout << "hgroup(" << extractName(label) << ", " << boxpp(t1, 0) << ')'; 00543 } 00544 else if (isBoxTGroup(box, label, t1)) { 00545 fout << "tgroup(" << extractName(label) << ", " << boxpp(t1, 0) << ')'; 00546 } 00547 else if (isBoxHBargraph(box, label, min, max)) { 00548 fout << "hbargraph(" 00549 << extractName(label) << ", " 00550 << boxpp(min) << ", " 00551 << boxpp(max) << ')'; 00552 } 00553 else if (isBoxVBargraph(box, label, min, max)) { 00554 fout << "vbargraph(" 00555 << extractName(label) << ", " 00556 << boxpp(min) << ", " 00557 << boxpp(max) << ')'; 00558 } 00559 else if (isBoxNumEntry(box, label, cur, min, max, step)) { 00560 fout << "nentry(" 00561 << extractName(label) << ", " 00562 << boxpp(cur) << ", " 00563 << boxpp(min) << ", " 00564 << boxpp(max) << ", " 00565 << boxpp(step)<< ')'; 00566 } 00567 else { 00568 cerr << "INTERNAL ERROR : unknow user interface element " << endl; 00569 exit(0); 00570 } 00571 d = fout.str(); 00572 } 00573 00574 00578 static schema* generateUserInterfaceSchema(Tree t) 00579 { 00580 string s; UserInterfaceDescription(t,s); 00581 return makeBlockSchema(0, 1, s, uicolor, ""); 00582 } 00583 00584 00588 static schema* generateBargraphSchema(Tree t) 00589 { 00590 string s; UserInterfaceDescription(t,s); 00591 return makeBlockSchema(1, 1, s, uicolor, ""); 00592 } 00593 00594 00595 00599 static schema* generateInputSlotSchema(Tree a) 00600 { 00601 Tree id; assert(getDefNameProperty(a, id)); 00602 stringstream s; s << tree2str(id); 00603 return makeBlockSchema(1, 0, s.str(), slotcolor, ""); 00604 } 00605 00606 00607 00611 static schema* generateOutputSlotSchema(Tree a) 00612 { 00613 Tree id; assert(getDefNameProperty(a, id)); 00614 stringstream s; s << tree2str(id); 00615 return makeBlockSchema(0, 1, s.str(), slotcolor, ""); 00616 } 00617 00618 00619 00624 static schema* generateAbstractionSchema(schema* x, Tree t) 00625 { 00626 Tree a,b; 00627 00628 while (isBoxSymbolic(t,a,b)) { 00629 x = makeParSchema(x, generateInputSlotSchema(a)); 00630 t = b; 00631 } 00632 return makeSeqSchema(x, generateDiagramSchema(t)); 00633 } 00634
1.8.0