X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/c7f552fd8888da2f0d8cfb228fe0f28d3df3a12c..b4b6f2ea75b9f0f3ca918f5b84016610bf7a4d4f:/interpretor/faust-0.9.47mr3/compiler/draw/drawschema.cpp diff --git a/interpretor/faust-0.9.47mr3/compiler/draw/drawschema.cpp b/interpretor/faust-0.9.47mr3/compiler/draw/drawschema.cpp deleted file mode 100644 index 6e3624c..0000000 --- a/interpretor/faust-0.9.47mr3/compiler/draw/drawschema.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/************************************************************************ - ************************************************************************ - 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. - ************************************************************************ - ************************************************************************/ - - /** - * @file drawschema.cpp - * Implement block-diagram schema generation in svg or postscript format. - * The result is a folder containing one or more schema files in svg or - * ps format. Complex block-diagrams are automatically splitted. - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "boxes.hh" -#include "ppbox.hh" -#include "prim2.hh" - -#include -#include "devLib.h" -#include "ppbox.hh" -#include "xtended.hh" -#include "occurrences.hh" -#include "boxcomplexity.h" - -#include "schema.h" -#include "drawschema.hh" -#include "compatibility.hh" -#include "names.hh" -#include "description.hh" -#include "property.hh" - - - -#if 0 -#define linkcolor "#b3d1dc" -#define normalcolor "#ffeaa2" -#define uicolor "#F1CFA1" -#define slotcolor "#ffffd7" -#define numcolor "#ffffff" -#endif - -#if 0 -#define linkcolor "#F57900" -#define normalcolor "#4B71A1" -#define uicolor "#47945E" -#define slotcolor "#EDD400" -#define numcolor "#4B71A1" -#endif - -#if 0 -#define linkcolor "#47945E" -#define normalcolor "#4B71A1" -#define uicolor "#f44800" -#define slotcolor "#EDD400" -#define numcolor "#f44800" -#endif - -#if 0 -#define linkcolor "#47945E" -#define normalcolor "#4B71A1" -#define uicolor "#816647" -#define slotcolor "#EDD400" -#define numcolor "#f44800" -#endif - -#if 0 -#define linkcolor "#003366" -#define normalcolor "#4B71A1" -#define uicolor "#816647" -#define slotcolor "#EDD400" -#define numcolor "#f44800" -#endif - -#if 0 -#define linkcolor "#003366" -#define normalcolor "#4B71A1" -#define uicolor "#477881" -#define slotcolor "#816647" -#define numcolor "#f44800" -#endif - - -#if 1 -#define linkcolor "#003366" -#define normalcolor "#4B71A1" -#define uicolor "#477881" -#define slotcolor "#47945E" -#define numcolor "#f44800" -#define invcolor "#ffffff" -#endif - -using namespace std; - -// external parameters -extern int gFoldThreshold; // max diagram complexity before folding - - -// internal state during drawing -static Occurrences* gOccurrences; -static bool sFoldingFlag; // true with complex block-diagrams -static stack gPendingExp; // Expressions that need to be drawn -static set gDrawnExp; // Expressions drawn or scheduled so far -static const char* gDevSuffix; // .svg or .ps used to choose output device -static char gCurrentDir[512]; // room to save current directory name -static string gSchemaFileName; // name of schema file beeing generated -static map gBackLink; // link to enclosing file for sub schema - -// prototypes of internal functions -static void writeSchemaFile(Tree bd); -static schema* generateDiagramSchema (Tree bd); -static schema* generateInsideSchema(Tree t); -static void scheduleDrawing(Tree t); -static bool pendingDrawing(Tree& t); -static schema* generateAbstractionSchema(schema* x, Tree t); -static schema* generateOutputSlotSchema(Tree a); -static schema* generateInputSlotSchema(Tree a); -static schema* generateBargraphSchema(Tree t); -static schema* generateUserInterfaceSchema(Tree t); -static char* legalFileName(Tree t, int n, char* dst); -static int cholddir (); -static int mkchdir(const char* dirname); - - - - -/** - *The entry point to generate from a block diagram as a set of - *svg files stored in the directory "-svg/" or - *"-ps/" depending of . - */ -void drawSchema(Tree bd, const char* projname, const char* dev) -{ - gDevSuffix = dev; - sFoldingFlag = boxComplexity(bd) > gFoldThreshold; - - mkchdir(projname); // create a directory to store files - - scheduleDrawing(bd); // schedule the initial drawing - - Tree t; while (pendingDrawing(t)) { - writeSchemaFile(t); // generate all the pending drawing - } - - cholddir(); // return to current directory -} - - -/************************************************************************ - ************************************************************************ - IMPLEMENTATION - ************************************************************************ - ************************************************************************/ - - -//------------------- to schedule and retreive drawing ------------------ - -/** - * Schedule a makeBlockSchema diagram to be drawn. - */ -static void scheduleDrawing(Tree t) -{ - if (gDrawnExp.find(t) == gDrawnExp.end()) { - gDrawnExp.insert(t); - gBackLink.insert(make_pair(t,gSchemaFileName)); // remember the enclosing filename - gPendingExp.push(t); - } -} - -/** - * Retrieve next block diagram that must be drawn - */ -static bool pendingDrawing(Tree& t) -{ - if (gPendingExp.empty()) return false; - t = gPendingExp.top(); - gPendingExp.pop(); - return true; -} - - - -//------------------------ dealing with files ------------------------- - -/** - * Write a top level diagram. A top level diagram - * is decorated with its definition name property - * and is drawn in an individual file - */ -static void writeSchemaFile(Tree bd) -{ - Tree id; - schema* ts; - - char temp[1024]; - - gOccurrences = new Occurrences(bd); - - bool hasname = getDefNameProperty(bd, id); - - //assert(hasname); - if (!hasname) { - // create an arbitrary name - id = tree(Node(unique("diagram_"))); - } - - // generate legal file name for the schema - stringstream s1; s1 << legalFileName(bd, 1024, temp) << "." << gDevSuffix; - gSchemaFileName = s1.str(); - - // generate the label of the schema - stringstream s2; s2 << tree2str(id); - string link = gBackLink[bd]; - ts = makeTopSchema(generateInsideSchema(bd), 20, s2.str(), link); - // draw to the device defined by gDevSuffix - if (strcmp(gDevSuffix, "svg") == 0) { - SVGDev dev(s1.str().c_str(), ts->width(), ts->height()); - ts->place(0,0, kLeftRight); - ts->draw(dev); - { collector c; ts->collectTraits(c); c.draw(dev); } - } else { - PSDev dev(s1.str().c_str(), ts->width(), ts->height()); - ts->place(0,0, kLeftRight); - ts->draw(dev); - { - collector c; - ts->collectTraits(c); - c.draw(dev); - } - } -} - - - -/** - * Create a new directory in the current one to store the diagrams. - * The current directory is saved to be later restaured. - */ -static int mkchdir(const char* dirname) -{ - //cerr << "mkchdir of " << dirname << endl; - if (getcwd(gCurrentDir, 512) != 0) { - int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if (status == 0 || errno == EEXIST) { - if (chdir(dirname) == 0) { - return 0; - } - } - } - perror("mkchdir"); - exit(errno); - //return errno; -} - - -/** - *Switch back to the previously stored current directory - */ -static int cholddir () -{ - if (chdir(gCurrentDir) == 0) { - return 0; - } else { - perror("cholddir"); - exit(errno); - } -} - - -/** - * Transform the definition name property of tree into a - * legal file name. The resulting file name is stored in - * a table of at least chars. Returns the pointer - * for convenience. - */ -static char* legalFileName(Tree t, int n, char* dst) -{ - Tree id; - int i=0; - if (getDefNameProperty(t, id)) { - const char* src = tree2str(id); - for (i=0; isalnum(src[i]) && i<16; i++) { - dst[i] = src[i]; - } - } - dst[i] = 0; - if (strcmp(dst, "process") != 0) { - // if it is not process add the hex address to make the name unique - snprintf(&dst[i], n-i, "-%p", t); - } - return dst; -} - - - -//------------------------ generating the schema ------------------------- - - -/** - * isInverter(t) returns true if t == '*(-1)'. This test is used - * to simplify diagram by using a special symbol for inverters. - */ -Tree gInverter[6]; - -static bool isInverter(Tree t) -{ - // init gInverted table. For some reason doesn't work if done outside - if (gInverter[0] == 0) { - gInverter[0] = boxSeq(boxPar(boxWire(), boxInt(-1)),boxPrim2(sigMul)); - gInverter[1] = boxSeq(boxPar(boxInt(-1), boxWire()),boxPrim2(sigMul)); - gInverter[2] = boxSeq(boxPar(boxWire(), boxReal(-1.0)),boxPrim2(sigMul)); - gInverter[3] = boxSeq(boxPar(boxReal(-1.0), boxWire()),boxPrim2(sigMul)); - gInverter[4] = boxSeq(boxPar(boxInt(0), boxWire()),boxPrim2(sigSub)); - gInverter[5] = boxSeq(boxPar(boxReal(0.0), boxWire()),boxPrim2(sigSub)); - }; - - //cerr << "isInverter " << t << '$' << boxpp(t) << endl; - for (int i=0; i<6; i++) { - if (t == gInverter[i]) return true; - } - return false; -} - - -/** - * Compute the Pure Routing property, that is expressions - * only made of cut, wires and slots. No labels will be - * dispayed for pure routing expressions. - */ -property gPureRoutingProperty; - -static bool isPureRouting(Tree t) -{ - bool r; - int ID; - Tree x,y; - - if (gPureRoutingProperty.get(t,r)) { - return r; - } else if ( isBoxCut(t) - || isBoxWire(t) - || isInverter(t) - || isBoxSlot(t, &ID) - || (isBoxPar(t,x,y) && isPureRouting(x) && isPureRouting(y)) - || (isBoxSeq(t,x,y) && isPureRouting(x) && isPureRouting(y)) - || (isBoxSplit(t,x,y) && isPureRouting(x) && isPureRouting(y)) - || (isBoxMerge(t,x,y) && isPureRouting(x) && isPureRouting(y)) - ) { - gPureRoutingProperty.set(t,true); - return true; - } else { - gPureRoutingProperty.set(t,false); - return false; - } -} - - -/** - * Generate an appropriate schema according to - * the type of block diagram. When folding is requiered, - * instead of going down block-diagrams with a name, - * schedule them for an individual file. - */ -static schema* generateDiagramSchema(Tree t) -{ - Tree id; - int ins, outs; - - //cerr << t << " generateDiagramSchema " << boxpp(t)<< endl; - - if (getDefNameProperty(t, id)) { - stringstream s; s << tree2str(id); - //cerr << t << "\tNAMED : " << s.str() << endl; - } - - if ( sFoldingFlag && /*(gOccurrences->getCount(t) > 0) &&*/ - (boxComplexity(t) > 2) && getDefNameProperty(t, id)) { - char temp[1024]; - getBoxType(t, &ins, &outs); - stringstream s, l; - s << tree2str(id); - l << legalFileName(t,1024,temp) << "." << gDevSuffix; - scheduleDrawing(t); - return makeBlockSchema(ins, outs, s.str(), linkcolor, l.str()); - - } else if (getDefNameProperty(t, id) && ! isPureRouting(t)) { - // named case : not a slot, with a name - // draw a line around the object with its name - stringstream s; s << tree2str(id); - return makeDecorateSchema(generateInsideSchema(t), 10, s.str()); - - } else { - // normal case - return generateInsideSchema(t); - } -} - - - -/** - * Generate the inside schema of a block diagram - * according to its type - */ -static schema* generateInsideSchema(Tree t) -{ - Tree a, b, ff, l, type,name,file; - int i; - double r; - prim0 p0; - prim1 p1; - prim2 p2; - prim3 p3; - prim4 p4; - prim5 p5; - - - xtended* xt = (xtended*)getUserData(t); - - if (xt) { return makeBlockSchema(xt->arity(), 1, xt->name(), normalcolor, ""); } - - else if (isInverter(t)) { return makeInverterSchema(invcolor); } - - else if (isBoxInt(t, &i)) { stringstream s; s << i; return makeBlockSchema(0, 1, s.str(), numcolor, "" ); } - else if (isBoxReal(t, &r)) { stringstream s; s << r; return makeBlockSchema(0, 1, s.str(), numcolor, "" ); } - else if (isBoxWire(t)) { return makeCableSchema(); } - else if (isBoxCut(t)) { return makeCutSchema(); } - - else if (isBoxPrim0(t, &p0)) { return makeBlockSchema(0, 1, prim0name(p0), normalcolor, ""); } - else if (isBoxPrim1(t, &p1)) { return makeBlockSchema(1, 1, prim1name(p1), normalcolor, ""); } - else if (isBoxPrim2(t, &p2)) { return makeBlockSchema(2, 1, prim2name(p2), normalcolor, ""); } - else if (isBoxPrim3(t, &p3)) { return makeBlockSchema(3, 1, prim3name(p3), normalcolor, ""); } - else if (isBoxPrim4(t, &p4)) { return makeBlockSchema(4, 1, prim4name(p4), normalcolor, ""); } - else if (isBoxPrim5(t, &p5)) { return makeBlockSchema(5, 1, prim5name(p5), normalcolor, ""); } - - else if (isBoxFFun(t, ff)) { return makeBlockSchema(ffarity(ff), 1, ffname(ff), normalcolor, ""); } - else if (isBoxFConst(t, type,name,file)) { return makeBlockSchema(0, 1, tree2str(name), normalcolor, ""); } - else if (isBoxFVar (t, type, name,file)) { return makeBlockSchema(0, 1, tree2str(name), normalcolor, ""); } - - else if (isBoxButton(t)) { return generateUserInterfaceSchema(t); } - else if (isBoxCheckbox(t)) { return generateUserInterfaceSchema(t); } - else if (isBoxVSlider(t)) { return generateUserInterfaceSchema(t); } - else if (isBoxHSlider(t)) { return generateUserInterfaceSchema(t); } - else if (isBoxNumEntry(t)) { return generateUserInterfaceSchema(t); } - else if (isBoxVBargraph(t)) { return generateBargraphSchema(t); } - else if (isBoxHBargraph(t)) { return generateBargraphSchema(t); } - - // don't draw group rectangle when labels are empty (ie "") - else if (isBoxVGroup(t,l,a)) { stringstream s; s << "vgroup(" << extractName(l) << ")"; - schema* r = generateDiagramSchema(a); - return makeDecorateSchema(r, 10, s.str()); } - else if (isBoxHGroup(t,l,a)) { stringstream s; s << "hgroup(" << extractName(l) << ")"; - schema* r = generateDiagramSchema(a); - return makeDecorateSchema(r, 10, s.str()); } - else if (isBoxTGroup(t,l,a)) { stringstream s; s << "tgroup(" << extractName(l) << ")"; - schema* r = generateDiagramSchema(a); - return makeDecorateSchema(r, 10, s.str()); } - - else if (isBoxSeq(t, a, b)) { return makeSeqSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } - else if (isBoxPar(t, a, b)) { return makeParSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } - else if (isBoxSplit(t, a, b)) { return makeSplitSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } - else if (isBoxMerge(t, a, b)) { return makeMergeSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } - else if (isBoxRec(t, a, b)) { return makeRecSchema(generateDiagramSchema(a), generateDiagramSchema(b)); } - - else if (isBoxSlot(t, &i)) { return generateOutputSlotSchema(t); } - else if (isBoxSymbolic(t,a,b)) { - Tree id; - if (getDefNameProperty(t, id)) { - return generateAbstractionSchema(generateInputSlotSchema(a), b); - } else { - return makeDecorateSchema(generateAbstractionSchema(generateInputSlotSchema(a), b), 10, "Abstraction"); - } - } - - else { - - fprintf(stderr, "Internal Error, box expression not recognized : "); print(t, stderr); fprintf(stderr, "\n"); - exit(1); - - } -} - -/** - * Convert User interface element into a textual representation - */ -static void UserInterfaceDescription(Tree box, string& d) -{ - Tree t1, label, cur, min, max, step; - stringstream fout; - // user interface - if (isBoxButton(box, label)) fout << "button(" << extractName(label) << ')'; - else if (isBoxCheckbox(box, label)) fout << "checkbox(" << extractName(label) << ')'; - else if (isBoxVSlider(box, label, cur, min, max, step)) { - fout << "vslider(" - << extractName(label) << ", " - << boxpp(cur) << ", " - << boxpp(min) << ", " - << boxpp(max) << ", " - << boxpp(step)<< ')'; - } - else if (isBoxHSlider(box, label, cur, min, max, step)) { - fout << "hslider(" - << extractName(label) << ", " - << boxpp(cur) << ", " - << boxpp(min) << ", " - << boxpp(max) << ", " - << boxpp(step)<< ')'; - } - else if (isBoxVGroup(box, label, t1)) { - fout << "vgroup(" << extractName(label) << ", " << boxpp(t1, 0) << ')'; - } - else if (isBoxHGroup(box, label, t1)) { - fout << "hgroup(" << extractName(label) << ", " << boxpp(t1, 0) << ')'; - } - else if (isBoxTGroup(box, label, t1)) { - fout << "tgroup(" << extractName(label) << ", " << boxpp(t1, 0) << ')'; - } - else if (isBoxHBargraph(box, label, min, max)) { - fout << "hbargraph(" - << extractName(label) << ", " - << boxpp(min) << ", " - << boxpp(max) << ')'; - } - else if (isBoxVBargraph(box, label, min, max)) { - fout << "vbargraph(" - << extractName(label) << ", " - << boxpp(min) << ", " - << boxpp(max) << ')'; - } - else if (isBoxNumEntry(box, label, cur, min, max, step)) { - fout << "nentry(" - << extractName(label) << ", " - << boxpp(cur) << ", " - << boxpp(min) << ", " - << boxpp(max) << ", " - << boxpp(step)<< ')'; - } - else { - cerr << "INTERNAL ERROR : unknow user interface element " << endl; - exit(0); - } - d = fout.str(); -} - - -/** - * Generate a 0->1 block schema for a user interface element - */ -static schema* generateUserInterfaceSchema(Tree t) -{ - string s; UserInterfaceDescription(t,s); - return makeBlockSchema(0, 1, s, uicolor, ""); -} - - -/** - * Generate a 1->1 block schema for a user interface bargraph - */ -static schema* generateBargraphSchema(Tree t) -{ - string s; UserInterfaceDescription(t,s); - return makeBlockSchema(1, 1, s, uicolor, ""); -} - - - -/** - * Generate a 1->0 block schema for an input slot - */ -static schema* generateInputSlotSchema(Tree a) -{ - Tree id; assert(getDefNameProperty(a, id)); - stringstream s; s << tree2str(id); - return makeBlockSchema(1, 0, s.str(), slotcolor, ""); -} - - - -/** - * Generate a 0->1 block schema for an output slot - */ -static schema* generateOutputSlotSchema(Tree a) -{ - Tree id; assert(getDefNameProperty(a, id)); - stringstream s; s << tree2str(id); - return makeBlockSchema(0, 1, s.str(), slotcolor, ""); -} - - - -/** - * Generate an abstraction schema by placing in sequence - * the input slots and the body - */ -static schema* generateAbstractionSchema(schema* x, Tree t) -{ - Tree a,b; - - while (isBoxSymbolic(t,a,b)) { - x = makeParSchema(x, generateInputSlotSchema(a)); - t = b; - } - return makeSeqSchema(x, generateDiagramSchema(t)); -} -