1 %{
2 #define YYDEBUG 1
3 #define YYERROR_VERBOSE 1
4 #include <string.h> // for error reporting
5 
6 #include "fpconfig.hh"
7 #include "fparser.hh"
8 #include "extrasrc/fptypes.hh"
9 
10 #include "../fpoptimizer/grammar.hh"
11 #include "../fpoptimizer/consts.hh"
12 
13 #include "../fpoptimizer/grammar.cc"
14 /* ^Note: including .cc file here in order to be able
15  *  to instantiate DumpParam and DumpParams for complex types.
16  */
17 
18 #include <cstdio>
19 #include <cctype>
20 #include <cstdlib>
21 #include <iostream>
22 #include <sstream>
23 #include <complex>
24 #include <map>
25 #include <set>
26 #include <algorithm>
27 #include <assert.h>
28 
29 #include "../lib/crc32.hh"
30 
31 #ifdef __GNUC__
32 # define likely(x)       __builtin_expect(!!(x), 1)
33 # define unlikely(x)     __builtin_expect(!!(x), 0)
34 #else
35 # define likely(x)   (x)
36 # define unlikely(x) (x)
37 #endif
38 
39 static const unsigned PARAM_INDEX_BITS = 10;
40 
41 /*********/
42 using namespace FPoptimizer_Grammar;
43 
44 class GrammarDumper;
45 
46 static void yyerror(const char* msg);
47 static int yylex(union YYSTYPE* lval);
48 
49 namespace
50 {
51     /* This function generated with make_identifier_parser.cc */
readOpcode(const char * input)52     unsigned readOpcode(const char* input)
53     {
54         using namespace FUNCTIONPARSERTYPES;
55 #include "extrasrc/fp_identifier_parser.inc"
56         return 0;
57     }
58 }
59 
60 namespace
61 {
62     struct mycomplex
63     {
64         double real, imag;
65     };
66     mycomplex operator -(const mycomplex& v)
67         { mycomplex res = {-v.real, -v.imag }; return res; }
68 
69     typedef std::complex<double> stdcomplex;
70 }
71 
72 namespace GrammarData
73 {
74     class ParamSpec;
75 
76     class MatchedParams
77     {
78     public:
79         ParamMatchingType Type;
80         std::vector<ParamSpec*> Params;
81         unsigned RestHolderIndex;
82 
83     public:
MatchedParams()84         MatchedParams()                    : Type(PositionalParams), Params(), RestHolderIndex(0) { }
MatchedParams(ParamMatchingType t)85         MatchedParams(ParamMatchingType t) : Type(t),                Params(), RestHolderIndex(0) { }
MatchedParams(ParamSpec * p)86         MatchedParams(ParamSpec* p)        : Type(PositionalParams), Params(), RestHolderIndex(0) { Params.push_back(p); }
87 
SetType(ParamMatchingType t)88         MatchedParams* SetType(ParamMatchingType t) { Type=t; return this; }
AddParam(ParamSpec * p)89         MatchedParams* AddParam(ParamSpec* p) { Params.push_back(p); return this; }
90 
GetParams()91         const std::vector<ParamSpec*>& GetParams() const { return Params; }
92 
93         void RecursivelySetDefaultParamMatchingType();
94         bool EnsureNoRepeatedNamedHolders(std::set<unsigned>& used) const;
95         bool EnsureNoRepeatedNamedHolders() const;
96         bool EnsureNoVariableCoverageParams_InPositionalParamLists();
97 
98         unsigned CalcRequiredParamsCount() const;
99 
100         unsigned BuildDepMask();
101         void BuildFinalDepMask();
102     };
103 
104     class FunctionType
105     {
106     public:
107         FUNCTIONPARSERTYPES::OPCODE Opcode;
108         MatchedParams Params;
109     public:
FunctionType(FUNCTIONPARSERTYPES::OPCODE o,const MatchedParams & p)110         FunctionType(FUNCTIONPARSERTYPES::OPCODE o, const MatchedParams& p)
111             : Opcode(o), Params(p) { }
112 
RecursivelySetDefaultParamMatchingType()113         void RecursivelySetDefaultParamMatchingType()
114         {
115             using namespace FUNCTIONPARSERTYPES;
116             Params.RecursivelySetDefaultParamMatchingType();
117             if((Opcode == cAdd || Opcode == cMul
118             || Opcode == cAnd || Opcode == cOr
119             || Opcode == cAbsAnd || Opcode == cAbsOr)
120             && Params.Type == PositionalParams)
121                 Params.Type = SelectedParams;
122         }
123 
EnsureNoRepeatedNamedHolders()124         bool EnsureNoRepeatedNamedHolders() const
125             { return Params.EnsureNoRepeatedNamedHolders(); }
126     };
127 
128     class ParamSpec
129     {
130     public:
131         unsigned DepMask;
132 
133         SpecialOpcode Opcode;      // specifies the type of the function
134         union
135         {
136             mycomplex ConstantValue;// for NumConstant
137             unsigned Index;                 // for ParamHolder
138             FunctionType* Func;             // for SubFunction
139         };
140         unsigned ImmedConstraint;
141         bool     IsConst;                   // when SubFunction
142 
143     public:
144         struct ParamHolderTag{};
145 
ParamSpec(FunctionType * f)146         ParamSpec(FunctionType* f)
147             : DepMask(),
148               Opcode(SubFunction),
149               Func(f),
150               ImmedConstraint(0),
151               IsConst(false)
152         {
153         }
154 
ParamSpec(mycomplex d,unsigned constraints)155         ParamSpec(mycomplex d, unsigned constraints)
156             : DepMask(),
157               Opcode(NumConstant),
158               ConstantValue(d),
159               ImmedConstraint(constraints),
160               IsConst(true)
161         {
162         }
163 
ParamSpec(FUNCTIONPARSERTYPES::OPCODE o,const std::vector<ParamSpec * > & p)164         ParamSpec(FUNCTIONPARSERTYPES::OPCODE o, const std::vector<ParamSpec*>& p)
165             : DepMask(),
166               Opcode(SubFunction),
167               Func(new FunctionType(o, MatchedParams(PositionalParams))),
168               ImmedConstraint(0),
169               IsConst(true)
170         {
171             if(o == FUNCTIONPARSERTYPES::cNeg && p[0]->Opcode == NumConstant)
172             {
173                 delete Func;
174                 Opcode        = NumConstant;
175                 ConstantValue  = -p[0]->ConstantValue;
176                 ImmedConstraint = p[0]->ImmedConstraint;
177             }
178             else
179             {
180                 Func->Params.Params = p;
181                 /*
182                 if(o == cAdd && p[1]->Opcode == SubFunction
183                              && p[1]->Func->Opcode == cNeg
184                              && p.size() == 2)
185                 {
186                     Func->Opcode = cSub;
187                     Func->Params.Params[1] = p[1]->Func->Params.Params[0];
188                 } -- not done because ConstantFolding() cannot handle cSub
189                 */
190             }
191         }
192 
ParamSpec(unsigned i,ParamHolderTag)193         ParamSpec(unsigned i, ParamHolderTag)
194             : DepMask(),
195               Opcode(ParamHolder), Index(i),
196               ImmedConstraint(0),
197               IsConst(true)
198         {
199         }
200 
201 /*
202         // Order:
203         //  NumConstant { ConstantValue }
204         //  ParamHolder { Index }
205         //  SubFunction { Opcode, IsConst }
206         bool operator< (const ParamSpec& b) const
207         {
208             if(Opcode == NumConstant)
209                 return (b.Opcode == NumConstant)
210                         ? ConstantValue < b.ConstantValue
211                         : true;
212             if(Opcode == ParamHolder)
213                 return (b.Opcode == ParamHolder)
214                         ? Index < b.Index
215                         : (b.Opcode == SubFunction)
216                             ? true
217                             : false;
218             if(Opcode == SubFunction)
219                 return (b.Opcode == SubFunction)
220                     ? (Func->Opcode != b.Func->Opcode
221                          ? Func->Opcode < b.Func->Opcode
222                          : IsConst < b.IsConst
223                       )
224                     : false;
225             return false;
226         }
227         bool operator!= (const ParamSpec& b) const { return !operator==(b); }
228         bool operator== (const ParamSpec& b) const
229         {
230             switch(Opcode)
231             {
232                 case NumConstant:
233                     return b.Opcode == Opcode && fp_equal(ConstantValue, b.ConstantValue);
234                 case ParamHolder:
235                     return b.Opcode == Opcode && ImmedConstraint == b.ImmedConstraint
236                         && b.DepMask == DepMask && Index == b.Index;
237                 case SubFunction:
238                     if(b.Opcode != SubFunction) return false;
239                     if(Func->Opcode != b.Func->Opcode) return false;
240                     if(ImmedConstraint != b.ImmedConstraint) return false;
241                     if(DepMask != b.DepMask) return false;
242                     if(IsConst != b.IsConst) return false;
243                     if(Func->Params.Type != b.Func->Params.Type
244                     || Func->Params.RestHolderIndex != b.Func->Params.RestHolderIndex
245                     || Func->Params.Params.size() != b.Func->Params.Params.size())
246                         return false;
247                     for(size_t a=0; a<Func->Params.Params.size(); ++a)
248                         if(*Func->Params.Params[a] != *b.Func->Params.Params[a])
249                             return false;
250             }
251             return true;
252         }
253 */
SetConstraint(unsigned mask)254         ParamSpec* SetConstraint(unsigned mask)
255             { ImmedConstraint |= mask; return this; }
256 
257         unsigned BuildDepMask();
258 
RecursivelySetDefaultParamMatchingType()259         void RecursivelySetDefaultParamMatchingType()
260         {
261             if(Opcode == SubFunction)
262                 Func->RecursivelySetDefaultParamMatchingType();
263         }
VerifyIsConstant()264         bool VerifyIsConstant()
265         {
266             switch(Opcode)
267             {
268                 case NumConstant: return true;
269                 case ParamHolder: return
270                     (ImmedConstraint & ConstnessMask) == Constness_Const;
271                 case SubFunction:
272                     if(!IsConst) return false; // subfunctions are not constant
273             }
274             // For const-subfunctions, all params must be const.
275             for(size_t a=0; a<Func->Params.Params.size(); ++a)
276                 if(!Func->Params.Params[a]->VerifyIsConstant()) return false;
277             return true;
278         }
279 
EnsureNoRepeatedNamedHolders()280         bool EnsureNoRepeatedNamedHolders() const
281         {
282             if(Opcode != SubFunction) return true;
283             MatchedParams tmp;
284             tmp.Params = Func->Params.Params;
285             return tmp.EnsureNoRepeatedNamedHolders();
286         }
287 
288     private:
289         ParamSpec(const ParamSpec&);
290         ParamSpec& operator= (const ParamSpec&);
291     };
292 
293     class Rule
294     {
295     public:
296         friend class GrammarDumper;
297         RuleType Type;
298 
299         FunctionType  Input;
300         MatchedParams Replacement; // length should be 1 if ProduceNewTree is used
301         unsigned SituationFlags;
302     public:
Rule(RuleType t,const FunctionType & f,const MatchedParams & r)303         Rule(RuleType t, const FunctionType& f, const MatchedParams& r)
304             : Type(t), Input(f), Replacement(r), SituationFlags(0)
305         { }
306 
Rule(RuleType t,const FunctionType & f,ParamSpec * p)307         Rule(RuleType t, const FunctionType& f, ParamSpec* p)
308             : Type(t), Input(f), Replacement(), SituationFlags(0)
309         { Replacement.AddParam(p); }
310 
BuildFinalDepMask()311         void BuildFinalDepMask()
312         {
313             Input.Params.BuildFinalDepMask();
314             //Replacement.BuildFinalDepMask(); -- not needed, though not wrong either.
315         }
SetSituationFlags(unsigned flags)316         void SetSituationFlags(unsigned flags)
317         {
318             SituationFlags = flags;
319         }
320     };
321 
322     class Grammar
323     {
324     public:
325         std::vector<Rule> rules;
326     public:
Grammar()327         Grammar(): rules() { }
328 
AddRule(const Rule & r)329         void AddRule(const Rule& r) { rules.push_back(r); }
BuildFinalDepMask()330         void BuildFinalDepMask()
331         {
332             for(size_t a=0; a<rules.size(); ++a)
333                 rules[a].BuildFinalDepMask();
334         }
335     };
336 
337     ////////////////////
338 
RecursivelySetDefaultParamMatchingType()339     void MatchedParams::RecursivelySetDefaultParamMatchingType()
340     {
341         Type = PositionalParams;
342         if(RestHolderIndex != 0)
343             Type = AnyParams;
344 
345         for(size_t a=0; a<Params.size(); ++a)
346             Params[a]->RecursivelySetDefaultParamMatchingType();
347     }
348 
EnsureNoRepeatedNamedHolders(std::set<unsigned> & used)349     bool MatchedParams::EnsureNoRepeatedNamedHolders(std::set<unsigned>& used) const
350     {
351         for(size_t a=0; a<Params.size(); ++a)
352         {
353             if(Params[a]->Opcode == ParamHolder)
354             {
355                 unsigned index = Params[a]->Index;
356                 std::set<unsigned>::iterator i = used.lower_bound(index);
357                 if(i != used.end() && *i == index)
358                     return false;
359                 used.insert(i, index);
360             }
361             if(Params[a]->Opcode == SubFunction)
362                 if(!Params[a]->Func->Params.EnsureNoRepeatedNamedHolders(used))
363                     return false;
364         }
365         return true;
366     }
367 
EnsureNoRepeatedNamedHolders()368     bool MatchedParams::EnsureNoRepeatedNamedHolders() const
369     {
370         std::set<unsigned> used;
371         return EnsureNoRepeatedNamedHolders(used);
372     }
373 
EnsureNoVariableCoverageParams_InPositionalParamLists()374     bool MatchedParams::EnsureNoVariableCoverageParams_InPositionalParamLists()
375     {
376         if(Type != PositionalParams
377         && Type != SelectedParams) return true;
378 
379         if(RestHolderIndex != 0) return false;
380 
381         for(size_t a=0; a<Params.size(); ++a)
382         {
383             if(Params[a]->Opcode == SubFunction)
384                 if(!Params[a]->Func->Params.EnsureNoVariableCoverageParams_InPositionalParamLists())
385                     return false;
386         }
387         return true;
388     }
CalcRequiredParamsCount()389     unsigned MatchedParams::CalcRequiredParamsCount() const
390     {
391         return (unsigned)Params.size();
392     }
393 
BuildDepMask()394     unsigned MatchedParams::BuildDepMask()
395     {
396         unsigned result = 0;
397         for(size_t a=0; a<Params.size(); ++a)
398             result |= Params[a]->BuildDepMask();
399         return result;
400     }
401 
BuildFinalDepMask()402     void MatchedParams::BuildFinalDepMask()
403     {
404         unsigned all_bits = BuildDepMask();
405 
406         // For each bit that is set in all_bits, unset
407         // all of them that are only set in one of the parameters.
408         for(unsigned bit=1; all_bits >= bit; bit <<= 1)
409             if(all_bits & bit)
410             {
411                 unsigned count_found = 0;
412                 for(size_t a=0; a<Params.size(); ++a)
413                 {
414                     unsigned param_bitmask = Params[a]->DepMask;
415                     if(param_bitmask & bit) ++count_found;
416                 }
417                 if(count_found <= 1)
418                 {
419                     for(size_t a=0; a<Params.size(); ++a)
420                         Params[a]->DepMask &= ~bit;
421                 }
422             }
423 
424         // Recurse
425         for(size_t a=0; a<Params.size(); ++a)
426             if(Params[a]->Opcode == SubFunction)
427                 Params[a]->Func->Params.BuildFinalDepMask();
428     }
429 }
430 
431 namespace FPoptimizer_Grammar
432 {
433     template<typename Value_t> // Used only by tree_grammar_parser.y
ParamSpec_Compare(const void * aa,const void * bb,SpecialOpcode type)434     bool ParamSpec_Compare(const void* aa, const void* bb, SpecialOpcode type)
435     {
436         switch(type)
437         {
438             case ParamHolder:
439             {
440                 ParamSpec_ParamHolder& a = *(ParamSpec_ParamHolder*) aa;
441                 ParamSpec_ParamHolder& b = *(ParamSpec_ParamHolder*) bb;
442                 return a.constraints == b.constraints
443                     && a.index       == b.index
444                     && a.depcode     == b.depcode;
445             }
446             case NumConstant:
447             {
448                 ParamSpec_NumConstant<Value_t>& a = *(ParamSpec_NumConstant<Value_t>*) aa;
449                 ParamSpec_NumConstant<Value_t>& b = *(ParamSpec_NumConstant<Value_t>*) bb;
450                 return a.constvalue == b.constvalue
451                     && a.modulo == b.modulo;
452             }
453             case SubFunction:
454             {
455                 ParamSpec_SubFunction& a = *(ParamSpec_SubFunction*) aa;
456                 ParamSpec_SubFunction& b = *(ParamSpec_SubFunction*) bb;
457                 return a.constraints    == b.constraints
458                     && a.data.subfunc_opcode   == b.data.subfunc_opcode
459                     && a.data.match_type       == b.data.match_type
460                     && a.data.param_count      == b.data.param_count
461                     && a.data.param_list       == b.data.param_list
462                     && a.data.restholder_index == b.data.restholder_index
463                     && a.depcode               == b.depcode;
464             }
465         }
466         return true;
467     }
468 }
469 
470 GrammarData::Grammar grammar;
471 std::vector<ParamSpec> plist;
472 std::vector<Rule>      rlist;
473 
474 struct RuleComparer
475 {
operatorRuleComparer476     bool operator() (const Rule& a, const Rule& b) const
477     {
478         if(a.match_tree.subfunc_opcode != b.match_tree.subfunc_opcode)
479             return a.match_tree.subfunc_opcode < b.match_tree.subfunc_opcode;
480 
481         // Other rules to break ties
482         if(a.situation_flags != b.situation_flags)
483             return a.situation_flags < b.situation_flags;
484 
485         if(a.ruletype != b.ruletype)
486             return a.ruletype < b.ruletype;
487 
488         if(a.match_tree.match_type != b.match_tree.match_type)
489             return a.match_tree.match_type < b.match_tree.match_type;
490 
491         if(a.match_tree.param_count != b.match_tree.param_count)
492             return a.match_tree.param_count < b.match_tree.param_count;
493 
494         if(a.repl_param_count != b.repl_param_count)
495             return a.repl_param_count < b.repl_param_count;
496 
497         if(a.match_tree.param_list != b.match_tree.param_list)
498             return a.match_tree.param_list < b.match_tree.param_list;
499 
500         if(a.repl_param_list != b.repl_param_list)
501             return a.repl_param_list < b.repl_param_list;
502 
503         return false;
504     }
505 
operatorRuleComparer506     bool operator() (unsigned a, unsigned b) const
507     {
508         return this->operator() ( rlist[a], rlist[b] );
509     }
510 };
511 
512 class GrammarDumper
513 {
514 private:
GenName(const char * prefix)515     std::string GenName(const char* prefix)
516     {
517         static unsigned counter = 0;
518         std::ostringstream tmp;
519         tmp << prefix << ++counter;
520         return tmp.str();
521     }
522 private:
523     std::map<std::string, size_t> n_index;
524 
525     std::vector<std::string>        nlist;
526     std::map<std::string, Grammar>  glist;
527 public:
GrammarDumper()528     GrammarDumper():
529         n_index(),
530         nlist(),glist()
531     {
532         plist.reserve(16384);
533         nlist.reserve(16);
534         rlist.reserve(16384);
535     }
536 
ConvertNamedHolderNameIntoIndex(const std::string & n)537     unsigned ConvertNamedHolderNameIntoIndex(const std::string& n)
538     {
539         std::map<std::string, size_t>::const_iterator i = n_index.find(n);
540         if(i != n_index.end()) return i->second;
541         nlist.push_back(n);
542         return n_index[n] = (unsigned)(nlist.size()-1);
543     }
GetNumNamedHolderNames()544     size_t GetNumNamedHolderNames() const { return nlist.size(); }
545 
DumpParamList(const std::vector<GrammarData::ParamSpec * > & Params,unsigned & param_count,unsigned & param_list)546     void DumpParamList(const std::vector<GrammarData::ParamSpec*>& Params,
547                        unsigned&       param_count,
548                        unsigned&       param_list)
549     {
550         param_count = (unsigned)Params.size();
551         param_list  = 0;
552         for(unsigned a=0; a<param_count; ++a)
553         {
554             ParamSpec p = CreateParam(*Params[a]);
555 
556             unsigned paramno = (unsigned)plist.size();
557 
558             for(size_t b = 0; b < plist.size(); ++b)
559                 if(plist[b].first == p.first
560                 && ParamSpec_Compare<stdcomplex>(plist[b].second, p.second, p.first))
561                 {
562                     paramno = (unsigned)b;
563                     break;
564                 }
565 
566             if(paramno == plist.size()) plist.push_back(p);
567 
568             param_list |= paramno << (a * PARAM_INDEX_BITS);
569         }
570     }
571 
CreateParam(const GrammarData::ParamSpec & p)572     ParamSpec CreateParam(const GrammarData::ParamSpec& p)
573     {
574         unsigned    pcount;
575         unsigned    plist;
576         switch(p.Opcode)
577         {
578             case SubFunction:
579             {
580                 ParamSpec_SubFunction* result = new ParamSpec_SubFunction;
581                 result->constraints    = p.ImmedConstraint;
582                 result->data.subfunc_opcode = p.Func->Opcode;
583                 result->data.match_type     = p.Func->Params.Type;
584                 DumpParamList(p.Func->Params.Params, pcount, plist);
585                 result->data.param_count = pcount;
586                 result->data.param_list  = plist;
587                 result->depcode        = p.DepMask;
588                 result->data.restholder_index = p.Func->Params.RestHolderIndex;
589                 if(p.IsConst)
590                 {
591                     result->data.match_type = GroupFunction;
592                     result->constraints |= Constness_Const;
593                 }
594                 return std::make_pair(SubFunction, (void*)result);
595             }
596             case NumConstant:
597             {
598                 typedef stdcomplex v;
599                 ParamSpec_NumConstant<v>* result = new ParamSpec_NumConstant<v>;
600                 result->constvalue     = v(p.ConstantValue.real, p.ConstantValue.imag);
601                 result->modulo         = p.ImmedConstraint;
602                 return std::make_pair(NumConstant, (void*)result);
603             }
604             case ParamHolder:
605             {
606                 ParamSpec_ParamHolder* result = new ParamSpec_ParamHolder;
607                 result->constraints    = p.ImmedConstraint;
608                 result->index          = p.Index;
609                 result->depcode        = p.DepMask;
610                 return std::make_pair(ParamHolder, (void*)result);
611             }
612         }
613         std::cout << "???\n";
614         return std::make_pair(SubFunction, (void*) 0);
615     }
616 
CreateRule(const GrammarData::Rule & r)617     Rule CreateRule(const GrammarData::Rule& r)
618     {
619         //unsigned min_params = r.Input.Params.CalcRequiredParamsCount();
620 
621         Rule ritem;
622         memset(&ritem, 0, sizeof(ritem));
623         //ritem.n_minimum_params          = min_params;
624         ritem.ruletype                  = r.Type;
625         ritem.situation_flags           = r.SituationFlags;
626         ritem.match_tree.subfunc_opcode = r.Input.Opcode;
627         ritem.match_tree.match_type     = r.Input.Params.Type;
628         ritem.match_tree.restholder_index = r.Input.Params.RestHolderIndex;
629         unsigned         pcount;
630         unsigned         plist;
631         DumpParamList(r.Input.Params.Params, pcount, plist);
632         ritem.match_tree.param_count = pcount;
633         ritem.match_tree.param_list  = plist;
634 
635         DumpParamList(r.Replacement.Params,  pcount, plist);
636         ritem.repl_param_count = pcount;
637         ritem.repl_param_list  = plist;
638         return ritem;
639     }
640 
RegisterGrammar(const std::vector<GrammarData::Grammar> & gset)641     void RegisterGrammar(const std::vector<GrammarData::Grammar>& gset)
642     {
643         using namespace FUNCTIONPARSERTYPES;
644         std::vector<Rule> this_rules;
645 
646         for(size_t a=0; a<gset.size(); ++a)
647         {
648             const GrammarData::Grammar& g = gset[a];
649 
650             for(size_t a=0; a<g.rules.size(); ++a)
651             {
652                 if(g.rules[a].Input.Opcode == cNop) continue;
653                 this_rules.push_back( CreateRule(g.rules[a]) );
654             }
655         }
656 
657         std::sort(this_rules.begin(), this_rules.end(),
658                   RuleComparer());
659 
660         for(size_t a=0; a<this_rules.size(); ++a)
661         {
662             const Rule& r = this_rules[a];
663 
664             // Add to global rule list, unless it's already there
665             bool dup=false;
666             for(size_t c=0; c<rlist.size(); ++c)
667                 if(memcmp(&r, &rlist[c], sizeof(r)) == 0)
668                 {
669                     // Already in global rule list...
670                     dup = true;
671                     break;
672                 }
673             if(!dup)
674                 rlist.push_back(r);
675         }
676     }
677 
DumpGrammar(const std::string & grammarname,const std::vector<GrammarData::Grammar> & gset)678     void DumpGrammar(const std::string& grammarname,
679                      const std::vector<GrammarData::Grammar>& gset)
680     {
681         using namespace FUNCTIONPARSERTYPES;
682         std::vector<unsigned> rule_list;
683 
684         std::vector<Rule> this_rules;
685 
686         for(size_t a=0; a<gset.size(); ++a)
687         {
688             const GrammarData::Grammar& g = gset[a];
689 
690             for(size_t a=0; a<g.rules.size(); ++a)
691             {
692                 if(g.rules[a].Input.Opcode == cNop) continue;
693                 this_rules.push_back( CreateRule(g.rules[a]) );
694             }
695         }
696 
697         std::sort(this_rules.begin(), this_rules.end(),
698                   RuleComparer());
699 
700         for(size_t a=0; a<this_rules.size(); ++a)
701         {
702             const Rule& r = this_rules[a];
703 
704             // Add to global rule list, unless it's already there
705             bool dup=false;
706             for(size_t c=0; c<rlist.size(); ++c)
707                 if(memcmp(&r, &rlist[c], sizeof(r)) == 0)
708                 {
709                     // Already in global rule list...
710                     // Add to grammar's rule list unless it's already there
711                     dup = false;
712                     for(size_t b=0; b<rule_list.size(); ++b)
713                         if(c == rule_list[b])
714                         {
715                             dup = true;
716                             break;
717                         }
718                     if(!dup)
719                     {
720                         // Global duplicate, but not yet in grammar.
721                         rule_list.push_back(c);
722                     }
723                     dup = true;
724                     break;
725                 }
726             if(!dup)
727             {
728                 // Not in global rule list. Add there and in grammar.
729                 rule_list.push_back( (unsigned) rlist.size() );
730                 rlist.push_back(r);
731             }
732         }
733 
734         Grammar& gitem = glist[grammarname];
735 
736         gitem.rule_count = (unsigned) rule_list.size();
737 
738         std::sort(rule_list.begin(), rule_list.end(),
739                   RuleComparer());
740 
741         for(size_t a=0; a<rule_list.size(); ++a)
742             gitem.rule_list[a] = rule_list[a];
743     }
744 
ConstraintsToString(unsigned constraints)745     static std::string ConstraintsToString(unsigned constraints)
746     {
747         std::ostringstream result;
748         const char* sep = "";
749         static const char s[] = " | ";
750         switch( ImmedConstraint_Value( constraints & ValueMask ) )
751         {
752             case ValueMask: case Value_AnyNum: break;
753             case Value_EvenInt: result << sep << "Value_EvenInt"; sep=s; break;
754             case Value_OddInt: result << sep << "Value_OddInt"; sep=s; break;
755             case Value_IsInteger: result << sep << "Value_IsInteger"; sep=s; break;
756             case Value_NonInteger: result << sep << "Value_NonInteger"; sep=s; break;
757             case Value_Logical: result << sep << "Value_Logical"; sep=s; break;
758         }
759         switch( ImmedConstraint_Sign( constraints & SignMask ) )
760         {
761             /*case SignMask:*/ case Sign_AnySign: break;
762             case Sign_Positive: result << sep << "Sign_Positive"; sep=s; break;
763             case Sign_Negative: result << sep << "Sign_Negative"; sep=s; break;
764             case Sign_NoIdea:   result << sep << "Sign_NoIdea"; sep=s; break;
765         }
766         switch( ImmedConstraint_Oneness( constraints & OnenessMask ) )
767         {
768             case OnenessMask: case Oneness_Any: break;
769             case Oneness_One: result << sep << "Oneness_One"; sep=s; break;
770             case Oneness_NotOne: result << sep << "Oneness_NotOne"; sep=s; break;
771         }
772         switch( ImmedConstraint_Constness( constraints & ConstnessMask ) )
773         {
774             case ConstnessMask: case Oneness_Any: break;
775             case Constness_Const: result << sep << "Constness_Const"; sep=s; break;
776             case Constness_NotConst: result << sep << "Constness_NotConst"; sep=s; break;
777         }
778         if(!*sep) result << "0";
779         return result.str();
780     }
ModuloToString(unsigned constraints)781     static std::string ModuloToString(unsigned constraints)
782     {
783         std::ostringstream result;
784         const char* sep = "";
785         static const char s[] = " | ";
786         switch( Modulo_Mode(constraints) )
787         {
788             case Modulo_None: break;
789             case Modulo_Radians: result << sep << "Modulo_Radians"; sep=s; break;
790         }
791         if(!*sep) result << "0";
792         return result.str();
793     }
794 
ConstValueToString(const stdcomplex & value)795     static std::string ConstValueToString(const stdcomplex& value)
796     {
797         using namespace FUNCTIONPARSERTYPES;
798         std::ostringstream result;
799         result.precision(50);
800         double dvalue = value.real();
801         if(value.imag() != 0.0) goto NotAnyKnownConstant;
802         #define Value_t double
803         #define if_const(n) \
804             if((dvalue)==(n)) result << #n; \
805             else if((dvalue)==(-n)) result << "-" #n;
806         if_const(fp_const_e<Value_t>())
807         else if_const(fp_const_einv<Value_t>())
808         else if_const(fp_const_twoe<Value_t>())
809         else if_const(fp_const_twoeinv<Value_t>())
810         else if_const(fp_const_pi<Value_t>())
811         else if_const(fp_const_pihalf<Value_t>())
812         else if_const(fp_const_twopi<Value_t>())
813         else if_const(fp_const_log2<Value_t>())
814         else if_const(fp_const_log2inv<Value_t>())
815         else if_const(fp_const_log10<Value_t>())
816         else if_const(fp_const_log10inv<Value_t>())
817         else if_const(fp_const_rad_to_deg<Value_t>())
818         else if_const(fp_const_deg_to_rad<Value_t>())
819         #undef if_const
820         #undef Value_t
821         else
822         {
823         NotAnyKnownConstant:
824             result << "Value_t(" << value.real() << ")";
825             if(value.imag() != 0.0)
826                 result << " + fp_make_imag(Value_t(" << value.imag() << "))";
827         }
828         return result.str();
829     }
830 
831     struct ParamCollection
832     {
833         std::vector<ParamSpec_ParamHolder>           plist_p;
834         std::vector<ParamSpec_NumConstant<stdcomplex> >  plist_n;
835         std::vector<ParamSpec_SubFunction>           plist_s;
836 
PopulateParamCollection837         void Populate(const ParamSpec& param)
838         {
839             #define set(when, type, list, code) \
840                 case when: \
841                   { for(size_t a=0; a<list.size(); ++a) \
842                         if(ParamSpec_Compare<stdcomplex>(param.second, (const void*) &list[a], when)) \
843                             return; \
844                     list.push_back( *(type*) param.second ); \
845                     code; \
846                     break; }
847             switch(param.first)
848             {
849                 set(ParamHolder, ParamSpec_ParamHolder,         plist_p, {} );
850                 set(NumConstant, ParamSpec_NumConstant<stdcomplex>, plist_n, {} );
851                 set(SubFunction, ParamSpec_SubFunction,         plist_s,
852                      ParamSpec_SubFunction* p = (ParamSpec_SubFunction*)param.second;
853                      for(size_t a=0; a<p->data.param_count; ++a)
854                          Populate( ParamSpec_Extract<stdcomplex>( p->data.param_list, a) );
855                     );
856             }
857             #undef set
858         }
859 
kindParamCollection::p_compare860         struct p_compare { int kind(
861             const ParamSpec_ParamHolder& a,
862             const ParamSpec_ParamHolder& b) const
863         {
864             if((a.index^2) != (b.index^2)) return (a.index^2) < (b.index^2) ? -1 : 1;
865             // xor-2 is here to tweak the sorting order such that
866             // the most used parameters (x,y) are first in the list,
867             // resulting in smaller numbers for the parameter indexes,
868             // and thus a smaller source code size for grammar data.
869             return 0;
870         } };
kindParamCollection::n_compare871         struct n_compare { int kind(
872             const ParamSpec_NumConstant<stdcomplex>& a,
873             const ParamSpec_NumConstant<stdcomplex>& b) const
874         {
875             if(a.modulo != b.modulo) return a.modulo < b.modulo ? -1 : 1;
876             double av = std::norm(a.constvalue), bv = std::norm(b.constvalue);
877             if(a.constvalue.real() < 0) av = -av;
878             if(b.constvalue.real() < 0) bv = -bv;
879             if(av != bv) return av < bv ? -1 : 1;
880             return 0;
881         } };
kindParamCollection::s_compare882         struct s_compare { int kind(
883             const ParamSpec_SubFunction& a,
884             const ParamSpec_SubFunction& b) const
885         {
886             unsigned a_opcode = a.data.subfunc_opcode;
887             unsigned b_opcode = b.data.subfunc_opcode;
888 
889             if(a_opcode == FUNCTIONPARSERTYPES::cAdd) a_opcode = 2;
890             else if(a_opcode == FUNCTIONPARSERTYPES::cMul) a_opcode = 3;
891             else if(a_opcode == FUNCTIONPARSERTYPES::cPow) a_opcode = 4;
892             else if(a_opcode == FUNCTIONPARSERTYPES::cNeg) a_opcode = 0;
893             else if(a_opcode == FUNCTIONPARSERTYPES::cInv) a_opcode = 1;
894             else a_opcode += 5;
895             if(b_opcode == FUNCTIONPARSERTYPES::cAdd) b_opcode = 2;
896             else if(b_opcode == FUNCTIONPARSERTYPES::cMul) b_opcode = 3;
897             else if(b_opcode == FUNCTIONPARSERTYPES::cPow) b_opcode = 4;
898             else if(b_opcode == FUNCTIONPARSERTYPES::cNeg) b_opcode = 0;
899             else if(b_opcode == FUNCTIONPARSERTYPES::cInv) b_opcode = 1;
900             else b_opcode += 5;
901 
902             if(a_opcode != b_opcode)
903                 return a_opcode < b_opcode ? -1 : 1;
904             if(a.constraints != b.constraints)
905                 return a.constraints < b.constraints ? -1 : 1;
906             if(a.data.match_type != b.data.match_type)
907                 return a.data.match_type < b.data.match_type ? -1 : 1;
908 
909             size_t min_param_count = std::min(a.data.param_count, b.data.param_count);
910 
911             for(size_t c=0; c< min_param_count; ++c)
912             {
913                 ParamSpec aa = ParamSpec_Extract<stdcomplex>(a.data.param_list, (unsigned)c);
914                 ParamSpec bb = ParamSpec_Extract<stdcomplex>(b.data.param_list, (unsigned)c);
915                 if(aa.first != bb.first)
916                     return aa.first < bb.first;
917                 switch(aa.first)
918                 {
919                     case ParamHolder: {
920                         int k = p_compare().kind
921                             (*(const ParamSpec_ParamHolder*)aa.second,
922                              *(const ParamSpec_ParamHolder*)bb.second);
923                         if(k) return k;
924                         break;
925                    }case NumConstant: {
926                         int k = n_compare().kind
927                             (*(const ParamSpec_NumConstant<stdcomplex>*)aa.second,
928                              *(const ParamSpec_NumConstant<stdcomplex>*)bb.second);
929                         if(k) return k;
930                         break;
931                    }case SubFunction:{
932                         int k = s_compare().kind
933                             (*(const ParamSpec_SubFunction*)aa.second,
934                              *(const ParamSpec_SubFunction*)bb.second);
935                         if(k) return k;
936                         break;
937                 }  }
938             }
939             if(a.data.param_count != b.data.param_count)
940                 return a.data.param_count < b.data.param_count ? -1 : 1;
941             return 0;
942         } };
943         template<typename T>
944         struct kind_compare
945         {
946             template<typename K>
operatorParamCollection::kind_compare947             bool operator() (const K& a, const K& b) const
948             {
949                 return T().kind(a,b) < 0;
950             }
951         };
952 
SortParamCollection953         void Sort()
954         {
955             std::stable_sort(plist_p.begin(), plist_p.end(), kind_compare<p_compare>());
956             std::stable_sort(plist_n.begin(), plist_n.end(), kind_compare<n_compare>());
957             std::stable_sort(plist_s.begin(), plist_s.end(), kind_compare<s_compare>());
958         }
959 
ParamPtrToParamIndexParamCollection960         unsigned ParamPtrToParamIndex(unsigned paramlist, unsigned index) const
961         {
962             const ParamSpec& p = ParamSpec_Extract<stdcomplex> (paramlist, index);
963             if(p.second)
964             {
965                 #define set(when, list, c) \
966                     case when: \
967                         for(size_t a=0; a<list.size(); ++a) \
968                             if(ParamSpec_Compare<stdcomplex> (p.second, (const void*)&list[a], when)) \
969                                 return (a + c##offset); \
970                         break;
971                 unsigned Poffset = 0;
972                 unsigned Noffset = plist_p.size();
973                 unsigned Soffset = plist_n.size() + Noffset;
974                 switch(p.first)
975                 {
976                     set(ParamHolder, plist_p, P);
977                     set(NumConstant, plist_n, N);
978                     set(SubFunction, plist_s, S);
979                 }
980                 #undef set
981             }
982             return (1 << 10)-1;
983         }
984 
ParamListToStringParamCollection985         std::string ParamListToString(unsigned paramlist, unsigned paramcount) const
986         {
987             std::ostringstream result, comment;
988             unsigned value = 0;
989             for(unsigned p=0; p<paramcount; ++p)
990             {
991                 unsigned index = ParamPtrToParamIndex(paramlist, p);
992                 if(p) comment << ',';
993                 comment << index;
994                 value += index << (p*PARAM_INDEX_BITS);
995             }
996             std::string commentstr = comment.str();
997             commentstr.resize(3*3+2, ' ');
998             result << "/*" << commentstr << "*/" << value;
999 
1000             std::string res = result.str();
1001             if(res.size() < 25) res.resize(25, ' ');
1002             /* 999*x+999*x+999 = 15 characters */
1003             /* (*999,999,999*)1048551399 = 25 characters */
1004             return res;
1005         }
ParamHolderToStringParamCollection1006         std::string ParamHolderToString(const ParamSpec_ParamHolder& i) const
1007         {
1008             std::ostringstream result;
1009             result << "{" << i.index
1010                    << ", " << ConstraintsToString(i.constraints)
1011                    << ", 0x" << i.depcode
1012                    << "}";
1013             return result.str();
1014         }
1015 
NumConstantToStringParamCollection1016         std::string NumConstantToString(const ParamSpec_NumConstant<stdcomplex>& i) const
1017         {
1018             std::ostringstream result;
1019             result << "{" << ConstValueToString(i.constvalue)
1020                    << ", " << ModuloToString(i.modulo)
1021                    << "}";
1022             return result.str();
1023         }
1024 
SubFunctionDataToStringParamCollection1025         std::string SubFunctionDataToString(const ParamSpec_SubFunctionData& i) const
1026         {
1027             std::ostringstream result;
1028             result << "{"  << i.param_count
1029                    <<  "," << ParamListToString(i.param_list, i.param_count)
1030                    << ", " << FP_GetOpcodeName(i.subfunc_opcode, true)
1031                    << ","  << (i.match_type == PositionalParams ? "PositionalParams"
1032                             :  i.match_type == SelectedParams   ? "SelectedParams  "
1033                             :  i.match_type == AnyParams        ? "AnyParams       "
1034                             :/*i.match_type == GroupFunction  ?*/ "GroupFunction   "
1035                             )
1036                    << "," << i.restholder_index
1037                    << "}";
1038             return result.str();
1039         }
1040 
SubFunctionToStringParamCollection1041         std::string SubFunctionToString(const ParamSpec_SubFunction& i) const
1042         {
1043             std::ostringstream result;
1044             result << "{" << SubFunctionDataToString(i.data)
1045                    << ", " << ConstraintsToString(i.constraints)
1046                    << ", 0x" << i.depcode
1047                    << "}";
1048             return result.str();
1049         }
1050     };
1051 
1052     ParamCollection collection;
1053 
Flush()1054     void Flush()
1055     {
1056         for(size_t a=0; a<rlist.size(); ++a)
1057         {
1058             for(unsigned b=0; b < rlist[a].match_tree.param_count; ++b)
1059                 collection.Populate( ParamSpec_Extract<stdcomplex>(rlist[a].match_tree.param_list, b) );
1060             for(unsigned b=0; b < rlist[a].repl_param_count; ++b)
1061                 collection.Populate( ParamSpec_Extract<stdcomplex>(rlist[a].repl_param_list, b) );
1062         }
1063         collection.Sort();
1064 
1065         std::cout << "/* BEGIN_EXPLICIT_INSTANTATIONS */\n";
1066         for(std::map<std::string, Grammar>::const_iterator
1067              i = glist.begin(); i != glist.end(); ++i)
1068             std::cout << "#define grammar_" << i->first << " grammar_" << i->first << "_tweak\n";
1069         std::cout <<
1070             "#include \"../fpoptimizer/grammar.hh\"\n";
1071         for(std::map<std::string, Grammar>::const_iterator
1072              i = glist.begin(); i != glist.end(); ++i)
1073             std::cout << "#undef grammar_" << i->first << "\n";
1074         std::cout << "/* END_EXPLICIT_INSTANTATIONS */\n";
1075 
1076         std::cout <<
1077             "\n"
1078             "using namespace FPoptimizer_Grammar;\n"
1079             "using namespace FUNCTIONPARSERTYPES;\n"
1080             "\n"
1081             "namespace\n"
1082             "{\n";
1083 
1084         {
1085 
1086         #define set(type, listprefix, list, c) \
1087             std::cout << \
1088             "    const ParamSpec_" #type " " listprefix #list "[" << collection.list.size() << "] =\n" \
1089             "    {\n"; \
1090             for(size_t a=0; a<collection.list.size(); ++a) \
1091             { \
1092                 std::cout << "    /* " << offset++ << "\t*/ " \
1093                           << collection.type##ToString(collection.list[a]) \
1094                           << ", /* "; \
1095                 FPoptimizer_Grammar::DumpParam<stdcomplex>( ParamSpec(type, (const void*) &collection.list[a]), std::cout); \
1096                 std::cout << " */\n"; \
1097             } \
1098             std::cout << \
1099             "    };\n" \
1100             "\n";
1101 
1102         unsigned offset = 0;
1103         set(ParamHolder, "", plist_p, P) // Must be first one
1104         std::cout <<
1105             "    template<typename Value_t>\n"
1106             "    struct plist_n_container\n"
1107             "    {\n"
1108             "        static const ParamSpec_NumConstant<Value_t> plist_n[" << collection.plist_n.size() << "];\n"
1109             "    };\n"
1110             "    template<typename Value_t>\n";
1111         set(NumConstant, "<Value_t> plist_n_container<Value_t>::", plist_n, N)
1112         set(SubFunction, "", plist_s, S)
1113 
1114         std::cout <<
1115             "}\n";
1116         }
1117 
1118         #undef set
1119 
1120         std::cout <<
1121             "namespace FPoptimizer_Grammar\n"
1122             "{\n";
1123         std::cout <<
1124             "    const Rule grammar_rules[" << rlist.size() << "] =\n"
1125             "    {\n";
1126         for(size_t a=0; a<rlist.size(); ++a)
1127         {
1128             std::cout <<
1129             "        /* " << a << ":\t";
1130             ParamSpec_SubFunction tmp = {rlist[a].match_tree,0,0};
1131             if(rlist[a].situation_flags & OnlyForComplex)
1132                 std::cout << "@C ";
1133             if(rlist[a].situation_flags & NotForComplex)
1134                 std::cout << "@R ";
1135             if(rlist[a].situation_flags & LogicalContextOnly)
1136                 std::cout << "@L ";
1137             if(rlist[a].situation_flags & NotForIntegers)
1138                 std::cout << "@F ";
1139             if(rlist[a].situation_flags & OnlyForIntegers)
1140                 std::cout << "@I ";
1141             FPoptimizer_Grammar::DumpParam<stdcomplex>
1142                 ( ParamSpec(SubFunction, (const void*) &tmp) );
1143             switch(rlist[a].ruletype)
1144             {
1145                 case ProduceNewTree:
1146                     std::cout <<
1147                     "\n"
1148                     "         *\t->\t";
1149                     FPoptimizer_Grammar::DumpParam<stdcomplex>(
1150                         ParamSpec_Extract<stdcomplex>(rlist[a].repl_param_list, 0) );
1151                     break;
1152                 case ReplaceParams: default:
1153                     std::cout <<
1154                     "\n"
1155                     "         *\t:\t";
1156                     FPoptimizer_Grammar::DumpParams<stdcomplex>
1157                         ( rlist[a].repl_param_list, rlist[a].repl_param_count);
1158                     break;
1159             }
1160             std::cout <<
1161             "\n"
1162             "         */\t\t "
1163                         "{"
1164                         << (rlist[a].ruletype == ProduceNewTree  ? "ProduceNewTree"
1165                          :/*rlist[a].ruletype == ReplaceParams ?*/ "ReplaceParams "
1166                            )
1167                         << ", " << rlist[a].situation_flags
1168                         << ", " << rlist[a].repl_param_count
1169                         <<  "," << collection.ParamListToString(rlist[a].repl_param_list, rlist[a].repl_param_count)
1170                         << ", " << collection.SubFunctionDataToString(rlist[a].match_tree)
1171                         << "},\n";
1172         }
1173         std::cout <<
1174             "    };\n"
1175             <<
1176             "\n";
1177         for(std::map<std::string, Grammar>::const_iterator
1178              i = glist.begin(); i != glist.end(); ++i)
1179         {
1180             std::cout << "    struct grammar_" << i->first << "_type\n"
1181                          "    {\n"
1182                          "        unsigned c;\n"
1183                          "        unsigned short l[" << i->second.rule_count << "];\n"
1184                          "    };\n"
1185                          "    extern \"C\"\n"
1186                          "    {\n"
1187                          "        grammar_" << i->first << "_type grammar_" << i->first << " =\n"
1188                          "        {\n"
1189                          "            " << i->second.rule_count << ",\n"
1190                          "            { ";
1191             for(size_t p=0; p<i->second.rule_count; ++p)
1192             {
1193                 std::cout << (unsigned) i->second.rule_list[p];
1194                 if(p+1 == i->second.rule_count) std::cout << "\n";
1195                 else
1196                 {
1197                     std::cout << ',';
1198                     if(p%10 == 9)
1199                         std::cout << "\n              ";
1200                 }
1201             }
1202             std::cout << "    }   };  }\n";
1203         }
1204         std::cout <<
1205             "}\n";
1206     }
1207 private:
1208 };
1209 
1210 static GrammarDumper dumper;
1211 
1212 %}
1213 
1214 %pure_parser
1215 
1216 %union {
1217     /* Note: Because bison's token type is an union or a simple type,
1218      *       anything that has constructors and destructors must be
1219      *       carried behind pointers here.
1220      */
1221     GrammarData::Rule*          r;
1222     GrammarData::FunctionType*  f;
1223     GrammarData::MatchedParams* p;
1224     GrammarData::ParamSpec*     a;
1225 
1226     mycomplex         num;
1227     unsigned                     index;
1228     FUNCTIONPARSERTYPES::OPCODE  opcode;
1229 }
1230 
1231 /* See documentation about syntax and token meanings in fpoptimizer.dat */
1232 %token <num>       NUMERIC_CONSTANT
1233 %token <index>     NAMEDHOLDER_TOKEN
1234 %token <index>     RESTHOLDER_TOKEN
1235 %token <index>     IMMEDHOLDER_TOKEN
1236 %token <opcode>    BUILTIN_FUNC_NAME
1237 %token <opcode>    OPCODE_TOKEN
1238 %token <opcode>    UNARY_TRANSFORMATION
1239 %token <index>     PARAM_CONSTRAINT
1240 %token <index>     CONST_CONSTRAINT
1241 %token NEWLINE
1242 
1243 %token SUBST_OP_COLON /* ':' */
1244 %token SUBST_OP_ARROW /* '->'  */
1245 
1246 %type <r> substitution
1247 %type <f> function function_match
1248 %type <p> paramlist
1249 %type <a> param
1250 %type <index> param_constraints const_constraints rule_constraints
1251 
1252 %%
1253     grammar:
1254       grammar substitution
1255       {
1256         grammar.AddRule(*$2);
1257         delete $2;
1258       }
1259     | grammar rule_constraints substitution
1260       {
1261         $3->SetSituationFlags($2);
1262         grammar.AddRule(*$3);
1263         delete $3;
1264       }
1265     | grammar NEWLINE
1266     | /* empty */
1267     ;
1268 
1269     rule_constraints:
1270       rule_constraints PARAM_CONSTRAINT
1271       {
1272         // Translate constraint flags to Rule Constraints.
1273         // They were lexed as param constraints, which
1274         // is why they have a different value.
1275         if($2 == Value_Logical)         // @L
1276           $$ = $1 | LogicalContextOnly;
1277         else if($2 == Value_NonInteger) // @F
1278           $$ = $1 | NotForIntegers;
1279         else if($2 == Value_IsInteger) // @I
1280           $$ = $1 | OnlyForIntegers;
1281         else if($2 == Constness_Const)
1282           $$ = $1 | OnlyForComplex;
1283         else
1284         {
1285           char msg[] = "Only @L, @F, @I, @C and @R rule constraints are allowed for now";
1286           yyerror(msg); YYERROR;
1287         }
1288       }
1289     | rule_constraints CONST_CONSTRAINT
1290       {
1291         if($2 == Modulo_Radians)
1292           $$ = $1 | NotForComplex;
1293         else
1294         {
1295           char msg[] = "Only @L, @F, @I, @C and @R rule constraints are allowed for now";
1296           yyerror(msg); YYERROR;
1297         }
1298       }
1299     |  /* empty */
1300       {
1301         $$ = 0;
1302       }
1303     ;
1304 
1305     substitution:
1306       function_match SUBST_OP_ARROW param NEWLINE
1307       /* Entire function is changed into the particular param */
1308       {
1309         $3->RecursivelySetDefaultParamMatchingType();
1310 
1311         $$ = new GrammarData::Rule(ProduceNewTree, *$1, $3);
1312         delete $1;
1313       }
1314 
1315     | function_match SUBST_OP_ARROW function NEWLINE
1316       /* Entire function changes, the param_notinv_list is rewritten */
1317       /* NOTE: "p x -> o y"  is a shortcut for "p x -> (o y)"  */
1318       {
1319         GrammarData::ParamSpec* p = new GrammarData::ParamSpec($3);
1320         p->RecursivelySetDefaultParamMatchingType();
1321         /*if(!$3->Params.EnsureNoRepeatedNamedHolders())
1322         {
1323             char msg[] = "The replacement function may not specify the same variable twice";
1324             yyerror(msg); YYERROR;
1325         }*/
1326 
1327         $$ = new GrammarData::Rule(ProduceNewTree, *$1, p);
1328 
1329         //std::cout << GrammarDumper().Dump(*new GrammarData::ParamSpec($3)) << "\n";
1330         delete $1;
1331       }
1332 
1333     | function_match SUBST_OP_COLON  paramlist NEWLINE
1334       /* The params provided are replaced with the new param_maybeinv_list */
1335       {
1336         /*if($1->Params.RestHolderIndex != 0)
1337         {
1338             char msg[] = "Restholder is not valid in the outermost function when ReplaceParams is used";
1339             yyerror(msg); YYERROR;
1340         }*/
1341         $3->RecursivelySetDefaultParamMatchingType();
1342         /*if(!$3->EnsureNoRepeatedNamedHolders())
1343         {
1344             char msg[] = "The replacement function may not specify the same variable twice";
1345             yyerror(msg); YYERROR;
1346         }*/
1347 
1348         $$ = new GrammarData::Rule(ReplaceParams, *$1, *$3);
1349         delete $1;
1350         delete $3;
1351       }
1352     ;
1353 
1354     function_match:
1355        function
1356        {
1357            if(!$1->Params.EnsureNoVariableCoverageParams_InPositionalParamLists())
1358            {
1359                char msg[] = "Restholders such as <1>, must not occur in bracketed param lists on the matching side";
1360                yyerror(msg); YYERROR;
1361            }
1362            $$ = $1;
1363        }
1364     ;
1365 
1366     function:
1367        OPCODE_TOKEN '[' paramlist ']'
1368        /* Match a function with opcode=opcode,
1369         * and the exact parameter list as specified
1370         */
1371        {
1372          $$ = new GrammarData::FunctionType($1, *$3);
1373          delete $3;
1374        }
1375     |  OPCODE_TOKEN '{' paramlist '}'
1376        /* Match a function with opcode=opcode,
1377         * and the exact parameter list in any order
1378         */
1379        {
1380          $$ = new GrammarData::FunctionType($1, *$3->SetType(SelectedParams));
1381          delete $3;
1382        }
1383     |  OPCODE_TOKEN paramlist
1384        /* Match a function with opcode=opcode and the given way of matching params */
1385        /* There may be more parameters, don't care about them */
1386        {
1387          $$ = new GrammarData::FunctionType($1, *$2->SetType(AnyParams));
1388          delete $2;
1389        }
1390     ;
1391 
1392     paramlist: /* left-recursive list of 0-n params with no delimiter */
1393         paramlist param    /* param */
1394         {
1395           $$ = $1->AddParam($2);
1396         }
1397       | paramlist RESTHOLDER_TOKEN /* a placeholder for all remaining params */
1398         {
1399           if($1->RestHolderIndex != 0)
1400           {
1401               char msg[] = "Illegal attempt to specify two restholders for the same param list";
1402               yyerror(msg); YYERROR;
1403           }
1404           $1->RestHolderIndex = $2;
1405           $$ = $1;
1406         }
1407       | /* empty */
1408         {
1409           $$ = new GrammarData::MatchedParams;
1410         }
1411     ;
1412 
1413     param:
1414        NUMERIC_CONSTANT const_constraints /* particular immed */
1415        {
1416          $$ = new GrammarData::ParamSpec($1, $2);
1417        }
1418     |  IMMEDHOLDER_TOKEN param_constraints  /* a placeholder for some immed */
1419        {
1420          $$ = new GrammarData::ParamSpec($1, GrammarData::ParamSpec::ParamHolderTag());
1421          $$->SetConstraint($2 | Constness_Const);
1422        }
1423     |  BUILTIN_FUNC_NAME '(' paramlist ')'  /* literal logarithm/sin/etc. of the provided immed-type params -- also sum/product/minimum/maximum */
1424        {
1425          /* Verify that $3 consists of constants */
1426          $$ = new GrammarData::ParamSpec($1, $3->GetParams() );
1427          if(!$$->VerifyIsConstant())
1428          {
1429              char msg[] = "Not constant";
1430              yyerror(msg); YYERROR;
1431          }
1432          delete $3;
1433        }
1434     |  NAMEDHOLDER_TOKEN param_constraints /* any expression, indicated by "x", "a" etc. */
1435        {
1436          $$ = new GrammarData::ParamSpec($1 + 2, GrammarData::ParamSpec::ParamHolderTag());
1437          $$->SetConstraint($2);
1438        }
1439     |  '(' function ')' param_constraints    /* a subtree */
1440        {
1441          $$ = new GrammarData::ParamSpec($2);
1442          $$->SetConstraint($4);
1443        }
1444     |  UNARY_TRANSFORMATION param   /* the negated/inverted literal value of the param */
1445        {
1446          /* Verify that $2 is constant */
1447          if(!$2->VerifyIsConstant())
1448          {
1449              char msg[] = "Not constant";
1450              yyerror(msg); YYERROR;
1451          }
1452          std::vector<GrammarData::ParamSpec*> tmp;
1453          tmp.push_back($2);
1454          $$ = new GrammarData::ParamSpec($1, tmp);
1455        }
1456     ;
1457 
1458     param_constraints: /* List of possible constraints to the given param, eg. odd,int,etc */
1459        param_constraints PARAM_CONSTRAINT
1460        {
1461          $$ = $1 | $2;
1462        }
1463     |  /* empty */
1464        {
1465          $$ = 0;
1466        }
1467     ;
1468 
1469     const_constraints: /* List of possible constraints to the given param */
1470        const_constraints CONST_CONSTRAINT
1471        {
1472          $$ = $1 | $2;
1473        }
1474     |  /* empty */
1475        {
1476          $$ = 0;
1477        }
1478     ;
1479 %%
1480 
1481 #ifndef FP_SUPPORT_OPTIMIZER
1482 enum { cVar,cFetch,cPopNMov };
1483 #endif
1484 
yyerror(const char * msg)1485 static void yyerror(const char* msg)
1486 {
1487     std::cerr << msg << std::endl;
1488     for(;;)
1489     {
1490         int c = std::fgetc(stdin);
1491         if(c == EOF) break;
1492         std::fputc(c, stderr);
1493     }
1494     exit(1);
1495 }
1496 
yylex(YYSTYPE * lval)1497 static int yylex(YYSTYPE* lval)
1498 {
1499     int c = std::fgetc(stdin);
1500     switch(c)
1501     {
1502         case EOF: break;
1503         case '#':
1504             while(c != EOF && c != '\n') c = std::fgetc(stdin);
1505             return NEWLINE;
1506         case '\n':
1507         {
1508             c = std::fgetc(stdin);
1509             std::ungetc(c, stdin);
1510             if(c == '['
1511             || c == '$')
1512                 return EOF;
1513             return NEWLINE;
1514         }
1515         case '+':
1516         {
1517             c = std::fgetc(stdin);
1518             std::ungetc(c, stdin);
1519             if(c == '(') { lval->opcode = FUNCTIONPARSERTYPES::cAdd; return BUILTIN_FUNC_NAME; }
1520             return '+';
1521         }
1522         case '*':
1523         {
1524             c = std::fgetc(stdin);
1525             std::ungetc(c, stdin);
1526             if(c == '(') { lval->opcode = FUNCTIONPARSERTYPES::cMul; return BUILTIN_FUNC_NAME; }
1527             return '*';
1528         }
1529         case '-':
1530         {
1531             int c2 = std::fgetc(stdin);
1532             if(c2 == '>') return SUBST_OP_ARROW;
1533             std::ungetc(c2, stdin);
1534             if(c2 >= '0' && c2 <= '9')
1535             {
1536                 goto GotNumeric;
1537             }
1538             lval->opcode = FUNCTIONPARSERTYPES::cNeg;
1539             return UNARY_TRANSFORMATION;
1540         }
1541         case '/':
1542             lval->opcode = FUNCTIONPARSERTYPES::cInv;
1543             return UNARY_TRANSFORMATION;
1544 
1545         case '=':
1546         {
1547             int c2 = std::fgetc(stdin);
1548             std::ungetc(c2, stdin);
1549             return '=';
1550         }
1551         case '[': case '{':
1552         case ']': case '}':
1553         case '(':
1554         case ')':
1555             return c;
1556         case ' ':
1557         case '\t':
1558         case '\v':
1559         case '\r':
1560             return yylex(lval); // Counts as tail recursion, I hope
1561         case ':':
1562             return SUBST_OP_COLON;
1563         case '%': { lval->index = 0; return IMMEDHOLDER_TOKEN; }
1564         case '&': { lval->index = 1; return IMMEDHOLDER_TOKEN; }
1565 
1566         case '@':
1567         {
1568             int c2 = std::fgetc(stdin);
1569             switch(c2)
1570             {
1571                 case 'E': { lval->index = Value_EvenInt; return PARAM_CONSTRAINT; }
1572                 case 'O': { lval->index = Value_OddInt; return PARAM_CONSTRAINT; }
1573                 case 'I': { lval->index = Value_IsInteger; return PARAM_CONSTRAINT; }
1574                 case 'F': { lval->index = Value_NonInteger; return PARAM_CONSTRAINT; }
1575                 case 'L': { lval->index = Value_Logical; return PARAM_CONSTRAINT; }
1576                 case 'P': { lval->index = Sign_Positive; return PARAM_CONSTRAINT; }
1577                 case 'N': { lval->index = Sign_Negative; return PARAM_CONSTRAINT; }
1578                 case 'Q': { lval->index = Sign_NoIdea; return PARAM_CONSTRAINT; }
1579                 case '1': { lval->index = Oneness_One; return PARAM_CONSTRAINT; }
1580                 case 'M': { lval->index = Oneness_NotOne; return PARAM_CONSTRAINT; }
1581                 case 'C': { lval->index = Constness_Const; return PARAM_CONSTRAINT; }
1582                 case 'V': { lval->index = Constness_NotConst; return PARAM_CONSTRAINT; }
1583                 case 'R': { lval->index = Modulo_Radians; return CONST_CONSTRAINT; }
1584             }
1585             std::ungetc(c2, stdin);
1586             return '@';
1587         }
1588         case '<':
1589         {
1590             lval->index  = 0;
1591             for(;;)
1592             {
1593                 c = std::fgetc(stdin);
1594                 if(c < '0' || c > '9') { std::ungetc(c, stdin); break; }
1595                 lval->index = lval->index * 10 + (c-'0');
1596             }
1597             c = std::fgetc(stdin);
1598             if(c != '>') std::ungetc(c, stdin);
1599             return RESTHOLDER_TOKEN;
1600         }
1601         case '0': case '1': case '2': case '3': case '4':
1602         case '5': case '6': case '7': case '8': case '9':
1603         {
1604         GotNumeric:;
1605             std::string NumBuf;
1606             NumBuf += (char)c;
1607             bool had_comma = false;
1608             for(;;)
1609             {
1610                 c = std::fgetc(stdin);
1611                 if(c >= '0' && c <= '9')  { NumBuf += (char)c; continue; }
1612                 if(c == '.' && !had_comma){ had_comma = true; NumBuf += (char)c; continue; }
1613                 std::ungetc(c, stdin);
1614                 break;
1615             }
1616             lval->num.real = std::strtod(NumBuf.c_str(), 0);
1617             lval->num.imag = 0.0;
1618             if(c == 'i')
1619             {
1620                 std::fgetc(stdin);
1621                 lval->num.imag = lval->num.real;
1622                 lval->num.real = 0.0;
1623             }
1624             else if(c == '-' || c == '+')
1625             {
1626                 NumBuf.clear();
1627                 NumBuf += (char)c;
1628                 bool had_comma = false;
1629                 for(;;)
1630                 {
1631                     c = std::fgetc(stdin);
1632                     if(c >= '0' && c <= '9')  { NumBuf += (char)c; continue; }
1633                     if(c == '.' && !had_comma){ had_comma = true; NumBuf += (char)c; continue; }
1634                     std::ungetc(c, stdin);
1635                     break;
1636                 }
1637                 if(c == 'i')
1638                 {
1639                     lval->num.imag = std::strtod(NumBuf.c_str(), 0);
1640                     std::fgetc(stdin);
1641                 }
1642             }
1643             return NUMERIC_CONSTANT;
1644         }
1645         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1646         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
1647         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
1648         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
1649         case 'Y': case 'Z': case '_':
1650         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1651         case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
1652         case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
1653         case 's': case 't': case 'u': case 'v': case 'w': case 'x':
1654         case 'y': case 'z':
1655         {
1656             std::string IdBuf;
1657             IdBuf += (char)c;
1658             for(;;)
1659             {
1660                 c = std::fgetc(stdin);
1661                 if((c >= '0' && c <= '9')
1662                 || c == '_'
1663                 || (c >= 'a' && c <= 'z')
1664                 || (c >= 'A' && c <= 'Z')) { IdBuf += (char)c; continue; }
1665                 std::ungetc(c, stdin);
1666                 break;
1667             }
1668             lval->num.real = 0;
1669             lval->num.imag = 0;
1670 
1671             /* This code figures out if this is a named constant,
1672                an opcode, or a parse-time function name,
1673                or just an identifier
1674              */
1675 
1676             /* Detect named constants */
1677             if(IdBuf == "i")          { lval->num.imag = 1.0; return NUMERIC_CONSTANT; }
1678             if(IdBuf == "CONSTANT_E") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_e<double>(); return NUMERIC_CONSTANT; }
1679             if(IdBuf == "CONSTANT_EI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_einv<double>(); return NUMERIC_CONSTANT; }
1680             if(IdBuf == "CONSTANT_2E") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twoe<double>(); return NUMERIC_CONSTANT; }
1681             if(IdBuf == "CONSTANT_2EI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twoeinv<double>(); return NUMERIC_CONSTANT; }
1682             if(IdBuf == "CONSTANT_RD") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_rad_to_deg<double>(); return NUMERIC_CONSTANT; }
1683             if(IdBuf == "CONSTANT_DR") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_deg_to_rad<double>(); return NUMERIC_CONSTANT; }
1684             if(IdBuf == "CONSTANT_PI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_pi<double>(); return NUMERIC_CONSTANT; }
1685             if(IdBuf == "CONSTANT_PIHALF") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_pihalf<double>(); return NUMERIC_CONSTANT; }
1686             if(IdBuf == "CONSTANT_TWOPI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twopi<double>(); return NUMERIC_CONSTANT; }
1687             if(IdBuf == "CONSTANT_L2I") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log2inv<double>(); return NUMERIC_CONSTANT; }
1688             if(IdBuf == "CONSTANT_L10I") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log10inv<double>(); return NUMERIC_CONSTANT; }
1689             if(IdBuf == "CONSTANT_L2") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log2<double>(); return NUMERIC_CONSTANT; }
1690             if(IdBuf == "CONSTANT_L10") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log10<double>(); return NUMERIC_CONSTANT; }
1691 
1692             /* Detect opcodes */
1693             if(IdBuf == "cAdd") { lval->opcode = FUNCTIONPARSERTYPES::cAdd; return OPCODE_TOKEN; }
1694             if(IdBuf == "cAnd") { lval->opcode = FUNCTIONPARSERTYPES::cAnd; return OPCODE_TOKEN; }
1695             if(IdBuf == "cMul") { lval->opcode = FUNCTIONPARSERTYPES::cMul; return OPCODE_TOKEN; }
1696             if(IdBuf == "cOr")  { lval->opcode = FUNCTIONPARSERTYPES::cOr; return OPCODE_TOKEN; }
1697 
1698             if(IdBuf == "cNeg") { lval->opcode = FUNCTIONPARSERTYPES::cNeg; return OPCODE_TOKEN; }
1699             if(IdBuf == "cSub") { lval->opcode = FUNCTIONPARSERTYPES::cSub; return OPCODE_TOKEN; }
1700             if(IdBuf == "cDiv") { lval->opcode = FUNCTIONPARSERTYPES::cDiv; return OPCODE_TOKEN; }
1701             if(IdBuf == "cMod") { lval->opcode = FUNCTIONPARSERTYPES::cMod; return OPCODE_TOKEN; }
1702             if(IdBuf == "cEqual") { lval->opcode = FUNCTIONPARSERTYPES::cEqual; return OPCODE_TOKEN; }
1703             if(IdBuf == "cNEqual") { lval->opcode = FUNCTIONPARSERTYPES::cNEqual; return OPCODE_TOKEN; }
1704             if(IdBuf == "cLess") { lval->opcode = FUNCTIONPARSERTYPES::cLess; return OPCODE_TOKEN; }
1705             if(IdBuf == "cLessOrEq") { lval->opcode = FUNCTIONPARSERTYPES::cLessOrEq; return OPCODE_TOKEN; }
1706             if(IdBuf == "cGreater") { lval->opcode = FUNCTIONPARSERTYPES::cGreater; return OPCODE_TOKEN; }
1707             if(IdBuf == "cGreaterOrEq") { lval->opcode = FUNCTIONPARSERTYPES::cGreaterOrEq; return OPCODE_TOKEN; }
1708             if(IdBuf == "cNot") { lval->opcode = FUNCTIONPARSERTYPES::cNot; return OPCODE_TOKEN; }
1709             if(IdBuf == "cNotNot") { lval->opcode = FUNCTIONPARSERTYPES::cNotNot; return OPCODE_TOKEN; }
1710             if(IdBuf == "cAbsNot") { lval->opcode = FUNCTIONPARSERTYPES::cAbsNot; return OPCODE_TOKEN; }
1711             if(IdBuf == "cAbsNotNot") { lval->opcode = FUNCTIONPARSERTYPES::cAbsNotNot; return OPCODE_TOKEN; }
1712             if(IdBuf == "cAbsAnd") { lval->opcode = FUNCTIONPARSERTYPES::cAbsAnd; return OPCODE_TOKEN; }
1713             if(IdBuf == "cAbsOr") { lval->opcode = FUNCTIONPARSERTYPES::cAbsOr; return OPCODE_TOKEN; }
1714             if(IdBuf == "cAbsIf") { lval->opcode = FUNCTIONPARSERTYPES::cAbsIf; return OPCODE_TOKEN; }
1715             if(IdBuf == "cDeg")  { lval->opcode = FUNCTIONPARSERTYPES::cDeg; return OPCODE_TOKEN; }
1716             if(IdBuf == "cRad")  { lval->opcode = FUNCTIONPARSERTYPES::cRad; return OPCODE_TOKEN; }
1717             if(IdBuf == "cInv")  { lval->opcode = FUNCTIONPARSERTYPES::cInv; return OPCODE_TOKEN; }
1718             if(IdBuf == "cSqr")  { lval->opcode = FUNCTIONPARSERTYPES::cSqr; return OPCODE_TOKEN; }
1719             if(IdBuf == "cRDiv") { lval->opcode = FUNCTIONPARSERTYPES::cRDiv; return OPCODE_TOKEN; }
1720             if(IdBuf == "cRSub") { lval->opcode = FUNCTIONPARSERTYPES::cRSub; return OPCODE_TOKEN; }
1721             if(IdBuf == "cRSqrt") { lval->opcode = FUNCTIONPARSERTYPES::cRSqrt; return OPCODE_TOKEN; }
1722 #ifdef FP_SUPPORT_OPTIMIZER
1723             if(IdBuf == "cLog2by") { lval->opcode = FUNCTIONPARSERTYPES::cLog2by; return OPCODE_TOKEN; }
1724 #else
1725             if(IdBuf == "cLog2by") { lval->opcode = FUNCTIONPARSERTYPES::cNop; return OPCODE_TOKEN; }
1726 #endif
1727 
1728             /* Detect other function opcodes */
1729             if(IdBuf[0] == 'c' && std::isupper(IdBuf[1]))
1730             {
1731                 // This has a chance of being an opcode token
1732                 std::string opcodetoken = IdBuf.substr(1);
1733                 opcodetoken[0] = (char) std::tolower( opcodetoken[0] );
1734 
1735                 unsigned nameLength = readOpcode(opcodetoken.c_str());
1736                 if(nameLength & 0x80000000U)
1737                 {
1738                     lval->opcode = FUNCTIONPARSERTYPES::OPCODE(
1739                         (nameLength >> 16) & 0x7FFF );
1740                     return OPCODE_TOKEN;
1741                 }
1742                 std::cerr <<
1743                     "Warning: Unrecognized opcode '" << IdBuf << "' interpreted as cNop\n";
1744                 lval->opcode = FUNCTIONPARSERTYPES::cNop;
1745                 return OPCODE_TOKEN;
1746             }
1747 
1748             // If it is typed entirely in capitals, it has a chance of being
1749             // a group token
1750             if(true)
1751             {
1752                 std::string grouptoken = IdBuf;
1753                 for(size_t a=0; a<grouptoken.size(); ++a)
1754                 {
1755                     if(std::islower(grouptoken[a])) goto NotAGroupToken;
1756                     grouptoken[a] = (char) std::tolower(grouptoken[a]);
1757                 }
1758                 if(1) // scope
1759                 {
1760                     unsigned nameLength = readOpcode(grouptoken.c_str());
1761                     if(nameLength & 0x80000000U)
1762                     {
1763                         lval->opcode = FUNCTIONPARSERTYPES::OPCODE(
1764                             (nameLength >> 16) & 0x7FFF );
1765                         return BUILTIN_FUNC_NAME;
1766                     }
1767                     if(IdBuf == "MOD")
1768                     {
1769                         lval->opcode = FUNCTIONPARSERTYPES::cMod;
1770                         return BUILTIN_FUNC_NAME;
1771                     }
1772                     if(IdBuf == "DIV")
1773                     {
1774                         lval->opcode = FUNCTIONPARSERTYPES::cDiv;
1775                         return BUILTIN_FUNC_NAME;
1776                     }
1777                     if(IdBuf == "SUB")
1778                     {
1779                         lval->opcode = FUNCTIONPARSERTYPES::cSub;
1780                         return BUILTIN_FUNC_NAME;
1781                     }
1782 
1783                     std::cerr << "Warning: Unrecognized constant function '" << IdBuf
1784                               << "' interpreted as cNop\n";
1785                     lval->opcode = FUNCTIONPARSERTYPES::cNop;
1786                     return BUILTIN_FUNC_NAME;
1787                 }
1788             NotAGroupToken:;
1789             }
1790             // Anything else is an identifier
1791             lval->index = dumper.ConvertNamedHolderNameIntoIndex(IdBuf);
1792             // std::cerr << "'" << IdBuf << "'' interpreted as PARAM\n";
1793 
1794             return NAMEDHOLDER_TOKEN;
1795         }
1796         default:
1797         {
1798             std::cerr << "Ignoring unidentifier character '" << char(c) << "'\n";
1799             return yylex(lval); // tail recursion
1800         }
1801     }
1802     return EOF;
1803 }
1804 
BuildDepMask()1805 unsigned GrammarData::ParamSpec::BuildDepMask()
1806 {
1807     DepMask = 0;
1808     switch(Opcode)
1809     {
1810         case ParamHolder:
1811             DepMask |= 1 << Index;
1812             break;
1813         case SubFunction:
1814             DepMask = Func->Params.BuildDepMask();
1815             break;
1816         default: break;
1817     }
1818     return DepMask;
1819 }
1820 
1821 namespace FPoptimizer_Grammar
1822 {
1823     template<typename Value_t>
ParamSpec_Extract(unsigned paramlist,unsigned index)1824     ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index)
1825     {
1826         unsigned plist_index = (paramlist >> (index*PARAM_INDEX_BITS))
1827                                % (1 << PARAM_INDEX_BITS);
1828         return plist[plist_index];
1829     }
1830     template ParamSpec ParamSpec_Extract<stdcomplex>(unsigned paramlist, unsigned index);
1831 }
1832 
main()1833 int main()
1834 {
1835     std::map<std::string, GrammarData::Grammar> sections;
1836 
1837     std::string sectionname;
1838 
1839     for(;;)
1840     {
1841         grammar = GrammarData::Grammar();
1842 
1843         yyparse();
1844 
1845         grammar.BuildFinalDepMask();
1846         sections[sectionname] = grammar;
1847 
1848         int c = std::fgetc(stdin);
1849         if(c != '[')
1850         {
1851             std::ungetc(c, stdin);
1852             break;
1853         }
1854 
1855         sectionname.clear();
1856         for(;;)
1857         {
1858             c = std::fgetc(stdin);
1859             if(c == ']' || c == EOF) break;
1860             sectionname += (char)c;
1861         }
1862         std::cerr << "Parsing [" << sectionname << "]\n";
1863     }
1864 
1865     std::map<std::string, std::vector<std::string> > grammar_components;
1866     sectionname = "";
1867     for(;;)
1868     {
1869         int c = std::fgetc(stdin);
1870         if(c == ' ' || c == '\t' || c == '\r' || c == '\n') continue;
1871         if(c == '#')
1872             { do { c = std::fgetc(stdin); } while(!(c == '\n' || c == EOF));
1873               continue; }
1874         if(c == '$')
1875         {
1876             sectionname = "";
1877             for(;;)
1878             {
1879                 c = std::fgetc(stdin);
1880                 if(c == EOF) break;
1881                 if(c == ' ' || c == '\t' || c == '\r' || c == '\n') break;
1882                 if(c == ':') break;
1883                 sectionname += char(c);
1884             }
1885             std::cerr << "Parsing $" << sectionname << "\n";
1886             continue;
1887         }
1888         if((c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9'))
1889         {
1890             std::string componentname;
1891             for(;;)
1892             {
1893                 if(c == EOF) break;
1894                 if(c == ' ' || c == '\t' || c == '\r' || c == '\n') break;
1895                 componentname += char(c);
1896                 c = std::fgetc(stdin);
1897             }
1898             std::cerr << "- Has [" << componentname << "]\n";
1899             grammar_components[sectionname].push_back(componentname);
1900             //dumper.AddRulesFrom(sections[componentname]);
1901         }
1902         else break;
1903     }
1904 
1905     std::cout <<
1906         "/* This file is automatically generated. Do not edit... */\n"
1907         "#include \"../fpoptimizer/consts.hh\"\n"
1908         "#include \"fpconfig.hh\"\n"
1909         "#include \"extrasrc/fptypes.hh\"\n"
1910         "#include <algorithm>\n"
1911         "\n";
1912 
1913     std::vector<GrammarData::Grammar> components;
1914     for(std::map<std::string, std::vector<std::string> >::const_iterator
1915         i = grammar_components.begin();
1916         i != grammar_components.end();
1917         ++i)
1918     {
1919         for(size_t a=0; a<i->second.size(); ++a)
1920             components.push_back(sections[ i->second[a] ]);
1921     }
1922     dumper.RegisterGrammar(components);
1923 
1924     for(std::map<std::string, std::vector<std::string> >::const_iterator
1925         i = grammar_components.begin();
1926         i != grammar_components.end();
1927         ++i)
1928     {
1929         components.clear();
1930         for(size_t a=0; a<i->second.size(); ++a)
1931             components.push_back(sections[ i->second[a] ]);
1932         dumper.DumpGrammar(i->first, components);
1933     }
1934     dumper.Flush();
1935 
1936     unsigned mask = (1 << PARAM_INDEX_BITS)-1;
1937     const unsigned p_begin = 0;
1938     const unsigned n_begin = p_begin + dumper.collection.plist_p.size();
1939     const unsigned s_begin = n_begin + dumper.collection.plist_n.size();
1940     std::cout <<
1941         "namespace FPoptimizer_Grammar\n"
1942         "{\n"
1943         "    template<typename Value_t>\n"
1944         "    ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index)\n"
1945         "    {\n"
1946         "        index = (paramlist >> (index * " << PARAM_INDEX_BITS << ")) & " << mask << " /* % (1 << " << PARAM_INDEX_BITS << ") */;\n"
1947         "        if(index >= " << s_begin << ")\n"
1948         "            return ParamSpec(SubFunction,(const void*)&plist_s[index-" << s_begin << "]);\n"
1949         "        if(index >= " << n_begin << ")\n"
1950         "            return ParamSpec(NumConstant,(const void*)&plist_n_container<Value_t>::plist_n[index-" << n_begin << "]);\n"
1951         "        return ParamSpec(ParamHolder,(const void*)&plist_p[index"/*"-" << p_begin << */"]);\n"
1952         "    }\n"
1953         "}\n"
1954         "/* BEGIN_EXPLICIT_INSTANTATION */\n"
1955         "#include \"instantiate.hh\"\n"
1956         "namespace FPoptimizer_Grammar\n"
1957         "{\n"
1958         "#define FP_INSTANTIATE(type) \\\n"
1959         "    template ParamSpec ParamSpec_Extract<type>(unsigned paramlist, unsigned index);\n"
1960         "    FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE)\n"
1961         "#undef FP_INSTANTIATE\n"
1962         "}\n"
1963         "/* END_EXPLICIT_INSTANTATION */\n";
1964 
1965     return 0;
1966 }
1967