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