Merge branch 'libsndfile'
[Faustine.git] / interpretor / preprocessor / faust-0.9.47mr3 / compiler / preprocess / preprocess.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
21
22 #include "preprocess.hh"
23
24
25
26
27 /****************************************************************
28 Parser variables
29 *****************************************************************/
30
31
32 int yyparse();
33
34 int yyerr;
35 extern int yydebug;
36 extern FILE* yyin;
37 Tree gResult;
38 Tree gResult2;
39
40 SourceReader gReader;
41
42 map<Tree, set<Tree> > gMetaDataSet;
43 extern vector<Tree> gDocVector;
44 extern string gDocLang;
45
46
47 /****************************************************************
48 Command line tools and arguments
49 *****************************************************************/
50
51 //-- globals
52 string gFaustSuperSuperDirectory;
53 string gFaustSuperDirectory;
54 string gFaustDirectory;
55 string gMasterDocument;
56 string gMasterDirectory;
57 string gMasterName;
58 string gDocName;
59 Tree gExpandedDefList;
60
61 //-- command line arguments
62
63 bool gHelpSwitch = false;
64 bool gVersionSwitch = false;
65 bool gDetailsSwitch = false;
66 bool gDrawSignals = false;
67 bool gShadowBlur = false; // note: svg2pdf doesn't like the blur filter
68 bool gGraphSwitch = false;
69 bool gDrawPSSwitch = false;
70 bool gDrawSVGSwitch = false;
71 bool gPrintXMLSwitch = false;
72 bool gPrintDocSwitch = false;
73 bool gLatexDocSwitch = true; // Only LaTeX outformat is handled for the moment.
74 bool gStripDocSwitch = false; // Strip <mdoc> content from doc listings.
75 int gBalancedSwitch = 0;
76 int gFoldThreshold = 25;
77 int gMaxNameSize = 40;
78 bool gSimpleNames = false;
79 bool gSimplifyDiagrams = false;
80 bool gLessTempSwitch = false;
81 int gMaxCopyDelay = 16;
82 string gArchFile;
83 string gOutputFile;
84 list<string> gInputFiles;
85
86 bool gPatternEvalMode = false;
87
88 bool gVectorSwitch = false;
89 bool gDeepFirstSwitch= false;
90 int gVecSize = 32;
91 int gVectorLoopVariant = 0;
92
93 bool gOpenMPSwitch = false;
94 bool gOpenMPLoop = false;
95 bool gSchedulerSwitch = false;
96 bool gGroupTaskSwitch= false;
97
98 bool gUIMacroSwitch = false;
99 bool gDumpNorm = false;
100
101 int gTimeout = 120; // time out to abort compiler (in seconds)
102
103 int gFloatSize = 1;
104
105 bool gPrintFileListSwitch = false;
106
107 string gClassName = "mydsp";
108
109 //-- command line tools
110
111 static bool isCmd(const char* cmd, const char* kw1)
112 {
113 return (strcmp(cmd, kw1) == 0);
114 }
115
116 static bool isCmd(const char* cmd, const char* kw1, const char* kw2)
117 {
118 return (strcmp(cmd, kw1) == 0) || (strcmp(cmd, kw2) == 0);
119 }
120
121 bool process_cmdline(int argc, char* argv[])
122 {
123 int i=1; int err=0;
124
125 while (i<argc) {
126
127 if (isCmd(argv[i], "-h", "--help")) {
128 gHelpSwitch = true;
129 i += 1;
130
131 } else if (isCmd(argv[i], "-v", "--version")) {
132 gVersionSwitch = true;
133 i += 1;
134
135 } else if (isCmd(argv[i], "-d", "--details")) {
136 gDetailsSwitch = true;
137 i += 1;
138
139 } else if (isCmd(argv[i], "-a", "--architecture")) {
140 gArchFile = argv[i+1];
141 i += 2;
142
143 } else if (isCmd(argv[i], "-o")) {
144 gOutputFile = argv[i+1];
145 i += 2;
146
147 } else if (isCmd(argv[i], "-ps", "--postscript")) {
148 gDrawPSSwitch = true;
149 i += 1;
150
151 } else if (isCmd(argv[i], "-xml", "--xml")) {
152 gPrintXMLSwitch = true;
153 i += 1;
154
155 } else if (isCmd(argv[i], "-tg", "--task-graph")) {
156 gGraphSwitch = true;
157 i += 1;
158
159 } else if (isCmd(argv[i], "-sg", "--signal-graph")) {
160 gDrawSignals = true;
161 i += 1;
162
163 } else if (isCmd(argv[i], "-blur", "--shadow-blur")) {
164 gShadowBlur = true;
165 i += 1;
166
167 } else if (isCmd(argv[i], "-svg", "--svg")) {
168 gDrawSVGSwitch = true;
169 i += 1;
170
171 } else if (isCmd(argv[i], "-f", "--fold")) {
172 gFoldThreshold = atoi(argv[i+1]);
173 i += 2;
174
175 } else if (isCmd(argv[i], "-mns", "--max-name-size")) {
176 gMaxNameSize = atoi(argv[i+1]);
177 i += 2;
178
179 } else if (isCmd(argv[i], "-sn", "--simple-names")) {
180 gSimpleNames = true;
181 i += 1;
182
183 } else if (isCmd(argv[i], "-lb", "--left-balanced")) {
184 gBalancedSwitch = 0;
185 i += 1;
186
187 } else if (isCmd(argv[i], "-mb", "--mid-balanced")) {
188 gBalancedSwitch = 1;
189 i += 1;
190
191 } else if (isCmd(argv[i], "-rb", "--right-balanced")) {
192 gBalancedSwitch = 2;
193 i += 1;
194
195 } else if (isCmd(argv[i], "-lt", "--less-temporaries")) {
196 gLessTempSwitch = true;
197 i += 1;
198
199 } else if (isCmd(argv[i], "-mcd", "--max-copy-delay")) {
200 gMaxCopyDelay = atoi(argv[i+1]);
201 i += 2;
202
203 } else if (isCmd(argv[i], "-sd", "--simplify-diagrams")) {
204 gSimplifyDiagrams = true;
205 i += 1;
206
207 } else if (isCmd(argv[i], "-vec", "--vectorize")) {
208 gVectorSwitch = true;
209 i += 1;
210
211 } else if (isCmd(argv[i], "-dfs", "--deepFirstScheduling")) {
212 gDeepFirstSwitch = true;
213 i += 1;
214
215 } else if (isCmd(argv[i], "-vs", "--vec-size")) {
216 gVecSize = atoi(argv[i+1]);
217 i += 2;
218
219 } else if (isCmd(argv[i], "-lv", "--loop-variant")) {
220 gVectorLoopVariant = atoi(argv[i+1]);
221 i += 2;
222
223 } else if (isCmd(argv[i], "-omp", "--openMP")) {
224 gOpenMPSwitch = true;
225 i += 1;
226
227 } else if (isCmd(argv[i], "-pl", "--par-loop")) {
228 gOpenMPLoop = true;
229 i += 1;
230
231 } else if (isCmd(argv[i], "-sch", "--scheduler")) {
232 gSchedulerSwitch = true;
233 i += 1;
234
235 } else if (isCmd(argv[i], "-g", "--groupTasks")) {
236 gGroupTaskSwitch = true;
237 i += 1;
238
239 } else if (isCmd(argv[i], "-uim", "--user-interface-macros")) {
240 gUIMacroSwitch = true;
241 i += 1;
242
243 } else if (isCmd(argv[i], "-t", "--timeout")) {
244 gTimeout = atoi(argv[i+1]);
245 i += 2;
246
247 // double float options
248 } else if (isCmd(argv[i], "-single", "--single-precision-floats")) {
249 gFloatSize = 1;
250 i += 1;
251
252 } else if (isCmd(argv[i], "-double", "--double-precision-floats")) {
253 gFloatSize = 2;
254 i += 1;
255
256 } else if (isCmd(argv[i], "-quad", "--quad-precision-floats")) {
257 gFloatSize = 3;
258 i += 1;
259
260 } else if (isCmd(argv[i], "-mdoc", "--mathdoc")) {
261 gPrintDocSwitch = true;
262 i += 1;
263
264 } else if (isCmd(argv[i], "-mdlang", "--mathdoc-lang")) {
265 gDocLang = argv[i+1];
266 i += 2;
267
268 } else if (isCmd(argv[i], "-stripmdoc", "--strip-mdoc-tags")) {
269 gStripDocSwitch = true;
270 i += 1;
271
272 } else if (isCmd(argv[i], "-flist", "--file-list")) {
273 gPrintFileListSwitch = true;
274 i += 1;
275
276 } else if (isCmd(argv[i], "-norm", "--normalized-form")) {
277 gDumpNorm = true;
278 i += 1;
279
280 } else if (isCmd(argv[i], "-cn", "--class-name")) {
281 gClassName = argv[i+1];
282 i += 2;
283
284 } else if (argv[i][0] != '-') {
285 if (check_file(argv[i])) {
286 gInputFiles.push_back(argv[i]);
287 }
288 i++;
289
290 } else {
291 cerr << "faust: unrecognized option \"" << argv[i] <<"\"" << endl;
292 i++;
293 err++;
294 }
295 }
296
297 // adjust related options
298 if (gOpenMPSwitch || gSchedulerSwitch) gVectorSwitch = true;
299
300 return err == 0;
301 }
302
303
304
305 /****************************************************************
306 Help and Version information
307 *****************************************************************/
308
309
310
311 void printversion()
312 {
313 cout << "FAUST, DSP to C++ compiler, Version " << FAUSTVERSION << "\n";
314 cout << "Copyright (C) 2002-2012, GRAME - Centre National de Creation Musicale. All rights reserved. \n\n";
315 }
316
317
318 void printhelp()
319 {
320 printversion();
321 cout << "usage: faust [options] file1 [file2 ...]\n";
322 cout << "\twhere options represent zero or more compiler options \n\tand fileN represents a faust source file (.dsp extension).\n";
323
324 cout << "\noptions :\n";
325 cout << "---------\n";
326
327 cout << "-h \t\tprint this --help message\n";
328 cout << "-v \t\tprint compiler --version information\n";
329 cout << "-d \t\tprint compilation --details\n";
330 cout << "-tg \t\tprint the internal --task-graph in dot format file\n";
331 cout << "-sg \t\tprint the internal --signal-graph in dot format file\n";
332 cout << "-ps \t\tprint block-diagram --postscript file\n";
333 cout << "-svg \tprint block-diagram --svg file\n";
334 cout << "-mdoc \tprint --mathdoc of a Faust program in LaTeX format in a -mdoc directory\n";
335 cout << "-mdlang <l>\t\tload --mathdoc-lang <l> if translation file exists (<l> = en, fr, ...)\n";
336 cout << "-stripdoc \t\tapply --strip-mdoc-tags when printing Faust -mdoc listings\n";
337 cout << "-sd \t\ttry to further --simplify-diagrams before drawing them\n";
338 cout << "-f <n> \t\t--fold <n> threshold during block-diagram generation (default 25 elements) \n";
339 cout << "-mns <n> \t--max-name-size <n> threshold during block-diagram generation (default 40 char)\n";
340 cout << "-sn \t\tuse --simple-names (without arguments) during block-diagram generation\n";
341 cout << "-xml \t\tgenerate an --xml description file\n";
342 cout << "-blur \t\tadd a --shadow-blur to SVG boxes\n";
343 cout << "-lb \t\tgenerate --left-balanced expressions\n";
344 cout << "-mb \t\tgenerate --mid-balanced expressions (default)\n";
345 cout << "-rb \t\tgenerate --right-balanced expressions\n";
346 cout << "-lt \t\tgenerate --less-temporaries in compiling delays\n";
347 cout << "-mcd <n> \t--max-copy-delay <n> threshold between copy and ring buffer implementation (default 16 samples)\n";
348 cout << "-a <file> \tC++ architecture file\n";
349 cout << "-cn <name> \t--class-name <name> specify the name of the dsp class to be used instead of mydsp \n";
350 cout << "-t <sec> \t--timeout <sec>, abort compilation after <sec> seconds (default 120)\n";
351 cout << "-o <file> \tC++ output file\n";
352 cout << "-vec \t--vectorize generate easier to vectorize code\n";
353 cout << "-vs <n> \t--vec-size <n> size of the vector (default 32 samples)\n";
354 cout << "-lv <n> \t--loop-variant [0:fastest (default), 1:simple] \n";
355 cout << "-omp \t--openMP generate OpenMP pragmas, activates --vectorize option\n";
356 cout << "-pl \t--par-loop generate parallel loops in --openMP mode\n";
357 cout << "-sch \t--scheduler generate tasks and use a Work Stealing scheduler, activates --vectorize option\n";
358 cout << "-dfs \t--deepFirstScheduling schedule vector loops in deep first order\n";
359 cout << "-g \t\t--groupTasks group single-threaded sequential tasks together when -omp or -sch is used\n";
360 cout << "-uim \t--user-interface-macros add user interface macro definitions in the C++ code\n";
361 cout << "-single \tuse --single-precision-floats for internal computations (default)\n";
362 cout << "-double \tuse --double-precision-floats for internal computations\n";
363 cout << "-quad \t\tuse --quad-precision-floats for internal computations\n";
364 cout << "-flist \t\tuse --file-list used to eval process\n";
365 cout << "-norm \t\t--normalized-form prints signals in normalized form and exits\n";
366
367 cout << "\nexample :\n";
368 cout << "---------\n";
369
370 cout << "faust -a jack-gtk.cpp -o myfx.cpp myfx.dsp\n";
371 }
372
373
374 void printheader(ostream& dst)
375 {
376 // defines the metadata we want to print as comments at the begin of in the C++ file
377 set<Tree> selectedKeys;
378 selectedKeys.insert(tree("name"));
379 selectedKeys.insert(tree("author"));
380 selectedKeys.insert(tree("copyright"));
381 selectedKeys.insert(tree("license"));
382 selectedKeys.insert(tree("version"));
383
384 dst << "//-----------------------------------------------------" << endl;
385 for (map<Tree, set<Tree> >::iterator i = gMetaDataSet.begin(); i != gMetaDataSet.end(); i++) {
386 if (selectedKeys.count(i->first)) {
387 dst << "// " << *(i->first);
388 const char* sep = ": ";
389 for (set<Tree>::iterator j = i->second.begin(); j != i->second.end(); ++j) {
390 dst << sep << **j;
391 sep = ", ";
392 }
393 dst << endl;
394 }
395 }
396
397 dst << "//" << endl;
398 dst << "// Code generated with Faust " << FAUSTVERSION << " (http://faust.grame.fr)" << endl;
399 dst << "//-----------------------------------------------------" << endl;
400 }
401
402
403
404
405 /****************************************************************
406 MAIN
407 *****************************************************************/
408
409
410
411 /**
412 * transform a filename "faust/example/noise.dsp" into
413 * the corresponding fx name "noise"
414 */
415 static string fxname(const string& filename)
416 {
417 // determine position right after the last '/' or 0
418 unsigned int p1 = 0;
419 for (unsigned int i=0; i<filename.size(); i++) {
420 if (filename[i] == '/') { p1 = i+1; }
421 }
422
423 // determine position of the last '.'
424 unsigned int p2 = filename.size();
425 for (unsigned int i=p1; i<filename.size(); i++) {
426 if (filename[i] == '.') { p2 = i; }
427 }
428
429 return filename.substr(p1, p2-p1);
430 }
431
432
433 static void initFaustDirectories()
434 {
435 char s[1024];
436 getFaustPathname(s, 1024);
437
438 gFaustDirectory = filedirname(s);
439 gFaustSuperDirectory = filedirname(gFaustDirectory);
440 gFaustSuperSuperDirectory = filedirname(gFaustSuperDirectory);
441 if (gInputFiles.empty()) {
442 gMasterDocument = "Unknown";
443 gMasterDirectory = ".";
444 gMasterName = "faustfx";
445 gDocName = "faustdoc";
446 } else {
447 gMasterDocument = *gInputFiles.begin();
448 gMasterDirectory = filedirname(gMasterDocument);
449 gMasterName = fxname(gMasterDocument);
450 gDocName = fxname(gMasterDocument);
451 }
452 }
453
454 char* preProcess (char* file_route)
455 {
456
457 /****************************************************************
458 1 - process command line
459 *****************************************************************/
460 int argc = 3;
461 char* argv[3];
462 argv[0] = "faust";
463 argv[1] = "-d";
464 argv[2] = file_route;
465
466 process_cmdline(argc, argv);
467
468 if (gHelpSwitch) { printhelp(); exit(0); }
469 if (gVersionSwitch) { printversion(); exit(0); }
470
471 initFaustDirectories();
472 #ifndef WIN32
473 alarm(gTimeout);
474 #endif
475
476
477 /****************************************************************
478 2 - parse source files
479 *****************************************************************/
480
481 startTiming("parser");
482
483
484 list<string>::iterator s;
485 gResult2 = nil;
486 yyerr = 0;
487
488 if (gInputFiles.begin() == gInputFiles.end()) {
489 cerr << "ERROR: no files specified;" << endl;
490 cerr << "interpreter <program.dsp> [input.wav]." << endl;
491 exit(1);
492 }
493 for (s = gInputFiles.begin(); s != gInputFiles.end(); s++) {
494 if (s == gInputFiles.begin()) gMasterDocument = *s;
495 gResult2 = cons(importFile(tree(s->c_str())), gResult2);
496 }
497 if (yyerr > 0) {
498 //fprintf(stderr, "Erreur de parsing 2, count = %d \n", yyerr);
499 exit(1);
500 }
501 gExpandedDefList = gReader.expandlist(gResult2);
502
503 endTiming("parser");
504
505 /****************************************************************
506 3 - evaluate 'process' definition
507 *****************************************************************/
508
509 startTiming("evaluation");
510
511 Tree process = evalprocess(gExpandedDefList);
512
513 if (gErrorCount > 0) {
514 // cerr << "Total of " << gErrorCount << " errors during evaluation of : process = " << boxpp(process) << ";\n";
515 cerr << "Total of " << gErrorCount << " errors during the compilation of " << gMasterDocument << ";\n";
516 exit(1);
517 }
518
519 endTiming("evaluation");
520
521 ostringstream result_stream;
522 result_stream << boxpp(process);
523 string result_string = result_stream.str();
524 char* result_char = new char [result_string.length()+1];
525 strcpy(result_char, result_string.c_str());;
526
527 //cout << result_string.length() << endl;
528 //cout << result_char << endl;
529
530 // Karim Barkati: printing globals value
531 //list<string> faustGlobals = {
532 //cout << "gFaustSuperSuperDirectory = " << gFaustSuperSuperDirectory << endl;
533 //cout << "gFaustSuperDirectory = " << gFaustSuperDirectory << endl;
534 //cout << "gFaustDirectory = " << gFaustDirectory << endl;
535 //cout << "gMasterDocument = " << gMasterDocument << endl;
536 //cout << "gMasterDirectory = " << gMasterDirectory << endl;
537 //cout << "gMasterName = " << gMasterName << endl;
538
539 return result_char;
540 }