1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 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 #ifndef _TEXT_INSTRUCTIONS_H
23 #define _TEXT_INSTRUCTIONS_H
24 
25 #include <fstream>
26 #include <iostream>
27 #include <sstream>
28 #include <string>
29 #include <map>
30 
31 #include "Text.hh"
32 #include "fir_to_fir.hh"
33 #include "instructions.hh"
34 #include "type_manager.hh"
35 
36 class TextInstVisitor : public InstVisitor {
37    protected:
38     int                fTab;
39     std::ostream*      fOut;
40     bool               fFinishLine;
41     std::string        fObjectAccess;
42     StringTypeManager* fTypeManager;
43 
EndLine(char end_line=';')44     virtual void EndLine(char end_line = ';')
45     {
46         if (fFinishLine) {
47             *fOut << end_line;
48             tab(fTab, *fOut);
49         }
50     }
51 
52     // To be adapted in subclasses
visitCond(ValueInst * cond)53     virtual void visitCond(ValueInst* cond)
54     {
55         cond->accept(this);
56     }
57 
58    public:
59     using InstVisitor::visit;
60 
TextInstVisitor(std::ostream * out,const std::string & object_access,int tab=0)61     TextInstVisitor(std::ostream* out, const std::string& object_access, int tab = 0)
62         : fTab(tab), fOut(out), fFinishLine(true), fObjectAccess(object_access)
63     {
64         fTypeManager = new CStringTypeManager(xfloat(), "*");
65     }
66 
TextInstVisitor(std::ostream * out,const std::string & object_access,const std::string & float_macro_name,const std::string & ptr_postfix,int tab=0)67     TextInstVisitor(std::ostream* out, const std::string& object_access, const std::string& float_macro_name,
68                     const std::string& ptr_postfix, int tab = 0)
69         : fTab(tab), fOut(out), fFinishLine(true), fObjectAccess(object_access)
70     {
71         fTypeManager = new CStringTypeManager(float_macro_name, ptr_postfix);
72     }
73 
TextInstVisitor(std::ostream * out,const std::string & object_access,StringTypeManager * manager,int tab=0)74     TextInstVisitor(std::ostream* out, const std::string& object_access, StringTypeManager* manager, int tab = 0)
75         : fTab(tab), fOut(out), fFinishLine(true), fObjectAccess(object_access), fTypeManager(manager)
76     {
77     }
78 
~TextInstVisitor()79     virtual ~TextInstVisitor() { delete fTypeManager; }
80 
Tab(int n)81     void Tab(int n) { fTab = n; }
82 
visit(LabelInst * inst)83     virtual void visit(LabelInst* inst)
84     {
85         *fOut << inst->fLabel;
86         tab(fTab, *fOut);
87     }
88 
visit(DeclareVarInst * inst)89     virtual void visit(DeclareVarInst* inst) { faustassert(false); }
90 
visit(RetInst * inst)91     virtual void visit(RetInst* inst) { visitAux(inst, true); }
92 
visitAux(RetInst * inst,bool gen_empty)93     virtual void visitAux(RetInst* inst, bool gen_empty)
94     {
95         if (inst->fResult) {
96             *fOut << "return ";
97             inst->fResult->accept(this);
98             EndLine();
99         } else if (gen_empty) {
100             *fOut << "return";
101             EndLine();
102         }
103     }
104 
visit(DropInst * inst)105     virtual void visit(DropInst* inst)
106     {
107         if (inst->fResult) {
108             inst->fResult->accept(this);
109             EndLine();
110         }
111     }
112 
visit(DeclareFunInst * inst)113     virtual void visit(DeclareFunInst* inst) { faustassert(false); }
114 
visit(NamedAddress * named)115     virtual void visit(NamedAddress* named) { *fOut << named->fName; }
116 
117     /*
118      Indexed address can actually be values in an array or fields in a struct type
119      */
visit(IndexedAddress * indexed)120     virtual void visit(IndexedAddress* indexed)
121     {
122         indexed->fAddress->accept(this);
123         DeclareStructTypeInst* struct_type = isStructType(indexed->getName());
124         if (struct_type) {
125             Int32NumInst* field_index = static_cast<Int32NumInst*>(indexed->fIndex);
126             *fOut << "->" << struct_type->fType->getName(field_index->fNum);
127         } else {
128             *fOut << "[";
129             indexed->fIndex->accept(this);
130             *fOut << "]";
131         }
132     }
133 
visit(LoadVarInst * inst)134     virtual void visit(LoadVarInst* inst) { inst->fAddress->accept(this); }
135 
visit(LoadVarAddressInst * inst)136     virtual void visit(LoadVarAddressInst* inst) { faustassert(false); }
137 
visit(StoreVarInst * inst)138     virtual void visit(StoreVarInst* inst)
139     {
140         inst->fAddress->accept(this);
141         *fOut << " = ";
142         inst->fValue->accept(this);
143         EndLine();
144     }
145 
visit(FloatNumInst * inst)146     virtual void visit(FloatNumInst* inst) { *fOut << checkFloat(inst->fNum); }
147 
visit(FloatArrayNumInst * inst)148     virtual void visit(FloatArrayNumInst* inst)
149     {
150         char sep = '{';
151         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
152             *fOut << sep << checkFloat(inst->fNumTable[i]);
153             sep = ',';
154         }
155         *fOut << '}';
156     }
157 
visit(Int32NumInst * inst)158     virtual void visit(Int32NumInst* inst) { *fOut << inst->fNum; }
159 
visit(Int64NumInst * inst)160     virtual void visit(Int64NumInst* inst) { *fOut << inst->fNum; }
161 
visit(Int32ArrayNumInst * inst)162     virtual void visit(Int32ArrayNumInst* inst)
163     {
164         char sep = '{';
165         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
166             *fOut << sep << inst->fNumTable[i];
167             sep = ',';
168         }
169         *fOut << '}';
170     }
171 
visit(BoolNumInst * inst)172     virtual void visit(BoolNumInst* inst) { *fOut << ((inst->fNum) ? "true" : "false"); }
173 
visit(DoubleNumInst * inst)174     virtual void visit(DoubleNumInst* inst) { *fOut << checkDouble(inst->fNum); }
175 
visit(DoubleArrayNumInst * inst)176     virtual void visit(DoubleArrayNumInst* inst)
177     {
178         char sep = '{';
179         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
180             *fOut << sep << checkDouble(inst->fNumTable[i]);
181             sep = ',';
182         }
183         *fOut << '}';
184     }
185 
visit(BinopInst * inst)186     virtual void visit(BinopInst* inst)
187     {
188         *fOut << "(";
189         inst->fInst1->accept(this);
190         *fOut << " ";
191         *fOut << gBinOpTable[inst->fOpcode]->fName;
192         *fOut << " ";
193         inst->fInst2->accept(this);
194         *fOut << ")";
195     }
196 
visit(::CastInst * inst)197     virtual void visit(::CastInst* inst) { faustassert(false); }
198 
generateFunName(const std::string & name)199     virtual std::string generateFunName(const std::string& name)
200     {
201         // If function is actually a method (that is "xx::name"), then keep "xx::name" in gGlobalTable but print "name"
202         size_t pos;
203         if ((pos = name.find("::")) != std::string::npos) {
204             return name.substr(pos + 2);  // After the "::"
205         } else {
206             return name;
207         }
208     }
209 
generateFunCallArgs(list<ValueInst * >::const_iterator beg,list<ValueInst * >::const_iterator end,size_t size)210     virtual void generateFunCallArgs(list<ValueInst*>::const_iterator beg,
211                                      list<ValueInst*>::const_iterator end,
212                                      size_t size)
213     {
214         list<ValueInst*>::const_iterator it = beg;
215         size_t                           i  = 0;
216         for (it = beg; it != end; it++, i++) {
217             // Compile argument
218             (*it)->accept(this);
219             if (i < size - 1) *fOut << ", ";
220         }
221     }
222 
generateFunDefArgs(DeclareFunInst * inst)223     virtual void generateFunDefArgs(DeclareFunInst* inst)
224     {
225         *fOut << "(";
226 
227         list<NamedTyped*>::const_iterator it;
228 
229         size_t size = inst->fType->fArgsTypes.size(), i = 0;
230         for (it = inst->fType->fArgsTypes.begin(); it != inst->fType->fArgsTypes.end(); it++, i++) {
231             *fOut << fTypeManager->generateType((*it));
232             if (i < size - 1) *fOut << ", ";
233         }
234     }
235 
generateFunDefBody(DeclareFunInst * inst)236     virtual void generateFunDefBody(DeclareFunInst* inst)
237     {
238         if (inst->fCode->fCode.size() == 0) {
239             *fOut << ");" << endl;  // Pure prototype
240         } else {
241             // Function body
242             *fOut << ") {";
243             fTab++;
244             tab(fTab, *fOut);
245             inst->fCode->accept(this);
246             fTab--;
247             back(1, *fOut);
248             *fOut << "}";
249             tab(fTab, *fOut);
250         }
251     }
252 
generateFunCall(FunCallInst * inst,const std::string & fun_name)253     virtual void generateFunCall(FunCallInst* inst, const std::string& fun_name)
254     {
255         if (inst->fMethod) {
256             list<ValueInst*>::const_iterator it = inst->fArgs.begin();
257             // Compile object arg
258             (*it)->accept(this);
259             // Compile parameters
260             *fOut << fObjectAccess << fun_name << "(";
261             generateFunCallArgs(++it, inst->fArgs.end(), int(inst->fArgs.size()) - 1);
262         } else {
263             *fOut << fun_name << "(";
264             // Compile parameters
265             generateFunCallArgs(inst->fArgs.begin(), inst->fArgs.end(), int(inst->fArgs.size()));
266         }
267         *fOut << ")";
268     }
269 
visit(FunCallInst * inst)270     virtual void visit(FunCallInst* inst) { faustassert(false); }
271 
visit(Select2Inst * inst)272     virtual void visit(Select2Inst* inst)
273     {
274         *fOut << "(";
275         visitCond(inst->fCond);
276         *fOut << " ? ";
277         inst->fThen->accept(this);
278         *fOut << " : ";
279         inst->fElse->accept(this);
280         *fOut << ")";
281     }
282 
visit(IfInst * inst)283     virtual void visit(IfInst* inst)
284     {
285         *fOut << "if (";
286         visitCond(inst->fCond);
287         *fOut << ") {";
288         fTab++;
289         tab(fTab, *fOut);
290         inst->fThen->accept(this);
291         fTab--;
292         back(1, *fOut);
293         if (inst->fElse->fCode.size() > 0) {
294             *fOut << "} else {";
295             fTab++;
296             tab(fTab, *fOut);
297             inst->fElse->accept(this);
298             fTab--;
299             back(1, *fOut);
300             *fOut << "}";
301         } else {
302             *fOut << "}";
303         }
304         tab(fTab, *fOut);
305     }
306 
visit(ForLoopInst * inst)307     virtual void visit(ForLoopInst* inst)
308     {
309         // Don't generate empty loops...
310         if (inst->fCode->size() == 0) return;
311 
312         *fOut << "for (";
313         fFinishLine = false;
314         inst->fInit->accept(this);
315         *fOut << "; ";
316         inst->fEnd->accept(this);
317         *fOut << "; ";
318         inst->fIncrement->accept(this);
319         fFinishLine = true;
320         *fOut << ") {";
321         fTab++;
322         tab(fTab, *fOut);
323         inst->fCode->accept(this);
324         fTab--;
325         back(1, *fOut);
326         *fOut << "}";
327         tab(fTab, *fOut);
328     }
329 
visit(WhileLoopInst * inst)330     virtual void visit(WhileLoopInst* inst)
331     {
332         *fOut << "while (";
333         visitCond(inst->fCond);
334         *fOut << ") {";
335         fTab++;
336         tab(fTab, *fOut);
337         inst->fCode->accept(this);
338         fTab--;
339         back(1, *fOut);
340         *fOut << "}";
341         tab(fTab, *fOut);
342     }
343 
visit(BlockInst * inst)344     virtual void visit(BlockInst* inst)
345     {
346         if (inst->fIndent) {
347             *fOut << "{";
348             fTab++;
349             tab(fTab, *fOut);
350         }
351         RetInst* ret_inst = nullptr;
352         for (const auto& it : inst->fCode) {
353             // Special case for "return" as last instruction
354             if ((it == *inst->fCode.rbegin()) && (ret_inst = dynamic_cast<RetInst*>(it))) {
355                 visitAux(ret_inst, false);
356             } else {
357                 it->accept(this);
358             }
359         }
360         if (inst->fIndent) {
361             fTab--;
362             back(1, *fOut);
363             *fOut << "}";
364             tab(fTab, *fOut);
365         }
366     }
367 
visit(::SwitchInst * inst)368     virtual void visit(::SwitchInst* inst)
369     {
370         *fOut << "switch (";
371         inst->fCond->accept(this);
372         *fOut << ") {";
373         fTab++;
374         tab(fTab, *fOut);
375         list<pair<int, BlockInst*> >::const_iterator it;
376         for (it = inst->fCode.begin(); it != inst->fCode.end(); it++) {
377             if ((*it).first == -1) {  // -1 used to code "default" case
378                 *fOut << "default: {";
379             } else {
380                 *fOut << "case " << (*it).first << ": {";
381             }
382             fTab++;
383             tab(fTab, *fOut);
384             ((*it).second)->accept(this);
385             if (!((*it).second)->hasReturn()) {
386                 *fOut << "break;";
387             }
388             fTab--;
389             tab(fTab, *fOut);
390             *fOut << "}";
391             tab(fTab, *fOut);
392         }
393         fTab--;
394         back(1, *fOut);
395         *fOut << "}";
396         tab(fTab, *fOut);
397     }
398 
getTypeManager()399     StringTypeManager* getTypeManager() { return fTypeManager; }
400 
401 };
402 
403 // Mathematical functions are declared as variables, they have to be generated before any other function (like
404 // 'faustpower')
405 struct sortDeclareFunctions {
406     std::map<std::string, std::string> fMathLibTable;
407 
sortDeclareFunctionssortDeclareFunctions408     sortDeclareFunctions(const std::map<std::string, std::string>& table) : fMathLibTable(table) {}
409 
operator ()sortDeclareFunctions410     bool operator()(StatementInst* a, StatementInst* b)
411     {
412         DeclareFunInst* inst1 = dynamic_cast<DeclareFunInst*>(a);
413         DeclareFunInst* inst2 = dynamic_cast<DeclareFunInst*>(b);
414 
415         if (inst1) {
416             if (inst2) {
417                 if (fMathLibTable.find(inst1->fName) != fMathLibTable.end()) {
418                     if (fMathLibTable.find(inst2->fName) != fMathLibTable.end()) {
419                         return inst1->fName < inst2->fName;
420                     } else {
421                         return true;
422                     }
423                 }
424             }
425         }
426         return false;
427     }
428 };
429 
430 #endif
431