CompileDES  3.09
Executable-Code Generation from Synchronised libFAUDES Automata
cgp_codegenerator.cpp
Go to the documentation of this file.
1 
3 /*
4 
5  FAU Discrete Event Systems Library (libFAUDES)
6 
7  Copyright (C) 2010, 2016, Thomas Moor
8 
9 */
10 
11 // my includes
12 #include "cgp_codegenerator.h"
13 #include <cctype>
14 
15 /*
16 ******************************************************************
17 ******************************************************************
18 ******************************************************************
19 
20 CodeGenerator implementation: source data organisation
21 
22 ******************************************************************
23 ******************************************************************
24 ******************************************************************
25 */
26 
27 
28 // CodeGenerator(void)
29 CodeGenerator::CodeGenerator(void) : Type(), pOutStream(0), pOutBuffer(0) {
30  FD_DCG("CodeGenerator()::CodeGenerator()");
31  pErrStream=&std::cerr;
32  mOutMode="std::cout";
33  mVerbLevel=1;
34  mMuteComments=false;
35  mMuteMode='*';
36 }
37 
38 // CodeGenerator(void)
40  FD_DCG("CodeGenerator()::~CodeGenerator()");
41  if(pOutBuffer) delete pOutBuffer;
42 }
43 
44 // mRegistry
45 std::map< std::string, CodeGenerator* (*)(void) >* CodeGenerator::mpsRegistry=0;
46 
47 // Register(type)
48 void CodeGenerator::Register(const std::string& type, CodeGenerator* (*newcg)(void) ) {
49  if(!mpsRegistry) mpsRegistry = new std::map< std::string, CodeGenerator* (*)(void) >;
50  (*mpsRegistry)[type]=newcg;
51 }
52 
53 // CodeGeneratorTypes(void)
54 std::vector< std::string > CodeGenerator::Registry(void) {
55  std::vector< std::string > res;
56  std::map< std::string, CodeGenerator* (*)(void) >::iterator rit;
57  for(rit=mpsRegistry->begin(); rit != mpsRegistry->end(); ++rit)
58  res.push_back(rit->first);
59  return res;
60 }
61 
62 // New(type)
63 CodeGenerator* CodeGenerator::New(const std::string& type) {
64  if(mpsRegistry->find(type)==mpsRegistry->end()) return 0;
65  return (*mpsRegistry)[type]();
66 }
67 
68 // Clear()
70  FD_DCG("CodeGenerator()::Clear()");
71  mGenerators.clear();
72  mAlphabet.Clear();
73  mUsedEvents.Clear();
74  mWordSize=8;
75  mIntegerSize=16;
76 }
77 
78 // Insert(rFileName)
79 void CodeGenerator::Insert(const std::string& rFileName) {
80  FCG_VERB2("CodeGenerator::Generator(): from file " << rFileName);
81  TokenReader tr(rFileName);
82  // create executor and read generator
83  mGenerators.push_back(TimedGenerator());
84  mGeneratorNames.push_back(rFileName);
85  // read generator
86  mGenerators.back().Read(tr);
87  // report
88  FCG_VERB2("CodeGenerator::Generator(): found [" << mGenerators.back().Name() << "] " <<
89  "with #" << mGenerators.back().TransRelSize() << " transitions");
90 }
91 
92 // Insert(rGen)
93 void CodeGenerator::Insert(const TimedGenerator& rGen) {
94  FCG_VERB2("CodeGenerator::Generator(): generator by reference");
95  mGenerators.push_back(TimedGenerator(rGen));
96  mGeneratorNames.push_back("");
97  // report
98  FCG_VERB2("CodeGenerator::Generator(): found [" << mGenerators.back().Name() << "] " <<
99  "with #" << mGenerators.back().TransRelSize() << " transitions");
100 }
101 
102 
103 // Size()
104 Idx CodeGenerator::Size(void) const {
105  return (Idx) mGenerators.size();
106 }
107 
108 //DoReadTargetConfiguration(rTr)
110  (void) rTr;
111 }
112 
113 
114 //DoReadGenerators(rTr)
115 void CodeGenerator::DoReadGenerators(TokenReader& rTr) {
116  // get relevant directory
117  std::string dirname="";
118  if(rTr.SourceMode()==TokenReader::File)
119  dirname=ExtractDirectory(rTr.FileName());
120  // report
121  FD_DCG("CodeGenerator()::DoReadGenerators(tr): dirname " << dirname);
122  // read section
123  rTr.ReadBegin("Generators");
124  Token token;
125  while(!rTr.Eos("Generators")) {
126  rTr.Peek(token);
127  // is it a file name?
128  if(token.Type()==Token::String) {
129  Insert(PrependDirectory(dirname,token.StringValue()));
130  rTr.Get(token);
131  continue;
132  }
133  // is it a generator?
134  if(token.Type()==Token::Begin)
135  if(token.StringValue()=="Generator") {
136  TimedGenerator gen;
137  gen.Read(rTr);
138  Insert(gen);
139  continue;
140  }
141  // else report error
142  std::stringstream errstr;
143  errstr << "Invalid token" << rTr.FileLine();
144  throw Exception("CodeGenerator::DoReadGenerators", errstr.str(), 502);
145  }
146  rTr.ReadEnd("Generators");
147 }
148 
149 
150 //DoRead(rTr)
151 void CodeGenerator::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
152  (void) pContext;
153  FD_DCG("CodeGenerator::DoRead()");
154  std::string label=rLabel;
155  if(label=="") label="CodeGenerator";
156  // read my section
157  Token token;
158  rTr.ReadBegin(label,token);
159  if(token.ExistsAttributeString("name"))
160  Name(token.AttributeStringValue("name"));
161  // loop to end
162  while(!rTr.Eos(label)) {
163  rTr.Peek(token);
164  // global conf
165  if(token.Type()==Token::Begin)
166  if(token.StringValue()=="TargetConfiguration") {
167  rTr.ReadBegin("TargetConfiguration");
169  rTr.ReadEnd("TargetConfiguration");
170  continue;
171  }
172  // generators
173  if(token.Type()==Token::Begin)
174  if(token.StringValue()=="Generators") {
175  DoReadGenerators(rTr);
176  FCG_VERB1("CodeGenerator::Generator(): found #" << Size() << " generators");
177  continue;
178  }
179  // alphabet
180  if(token.Type()==Token::Begin)
181  if(token.StringValue()=="EventConfiguration") {
182  mAlphabet.Read(rTr,"EventConfiguration");
183  FCG_VERB1("CodeGenerator::Events(): found event configuration for #" << mAlphabet.Size() << " events");
184  continue;
185  }
186  // else report error
187  std::stringstream errstr;
188  errstr << "Invalid token" << rTr.FileLine();
189  throw Exception("CodeGenerator::DoRead", errstr.str(), 502);
190  }
191  // done
192  rTr.ReadEnd(label);
193 }
194 
195 //DoWriteTargetConfiguration(rTr,rLabel)
196 void CodeGenerator::DoWriteTargetConfiguration(TokenWriter& rTw) const {
197  (void) rTw;
198 }
199 
200 //DoWriteGenerators(rTr,rLabel)
201 void CodeGenerator::DoWriteGenerators(TokenWriter& rTw) const {
202  rTw.WriteBegin("Generators");
203  for(Idx i=0; i<Size(); i++) {
204  // write filename
205  if(mGeneratorNames.at(i)!="") {
206  rTw.WriteString(mGeneratorNames.at(i));
207  }
208  // write generator
209  if(mGeneratorNames.at(i)=="") {
210  mGenerators.at(i).Write(rTw);
211  }
212  }
213  rTw.WriteEnd("Generators");
214 }
215 
216 
217 
218 //DoWrite(rTw);
219 void CodeGenerator::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
220  (void) pContext;
221  std::string label=rLabel;
222  if(label=="") label="CodeGenerator";
223  rTw.WriteBegin(label);
224  // global conf
225  rTw.WriteBegin("TargetConfiguration");
227  rTw.WriteEnd("TargetConfiguration");
228  // alphabet
229  mAlphabet.Write(rTw,"EventConfiguration");
230  // generators
231  DoWriteGenerators(rTw);
232  // done
233  rTw.WriteEnd(label);
234 }
235 
236 
237 // report version
238 std::string CodeGenerator::VersionString(void) {
239  std::stringstream res;
240  res << COMPILEDES_VERSION << " (using " << faudes::VersionString() << ")";
241  return res.str();
242 }
243 
244 /*
245 ******************************************************************
246 ******************************************************************
247 ******************************************************************
248 
249 CodeGenerator implementation: internal data organisation
250 
251 ******************************************************************
252 ******************************************************************
253 ******************************************************************
254 */
255 
256 
257 
258 // base class: prepare main out stream and compile
260  FCG_VERB0("CodeGenerator::Compile(): compile to internal representation");
261  // virtual compile
262  DoCompile();
263  FCG_VERB0("CodeGenerator::Compile(): done");
264 }
265 
266 
267 // base class do compile: organize events and transitionrelations
269  FD_DCG("CodeGenerator::DoCompile()");
270  // check that all events have specified attributes
271  mUsedEvents.Clear();
272  for(size_t git=0; git<Size(); ++git) {
273  EventSet::Iterator eit=At(git).AlphabetBegin();
274  for(; eit!=At(git).AlphabetEnd(); ++eit) {
275  if(!mAlphabet.Exists(*eit)) {
276  FCG_ERR("CodeGenerator::Compile(): event [" << EventName(*eit) << "] has unspecified execution semantics")
277  }
278  mUsedEvents.Insert(*eit);
279  }
280  }
282  FCG_VERB0("CodeGenerator::Compile(): event configuration mismatch: #" << (mAlphabet-mUsedEvents).Size() << " unused events");
283  // compose event sets by type
284  mOutputEvents.Clear();
285  EventSet::Iterator eit;
286  for(eit=mUsedEvents.Begin();eit!=mUsedEvents.End();++eit)
287  if(mAlphabet.Attribute(*eit).Output()) mOutputEvents.Insert(*eit);
288  mInputEvents.Clear();
289  for(eit=mUsedEvents.Begin();eit!=mUsedEvents.End();++eit) {
290  if(mAlphabet.Attribute(*eit).Input()) mInputEvents.Insert(*eit);
291  if(mAlphabet.Attribute(*eit).Timer()) mInputEvents.Insert(*eit);
292  }
293  mInternalEvents.Clear();
294  for(eit=mUsedEvents.Begin();eit!=mUsedEvents.End();++eit) {
295  if(mAlphabet.Attribute(*eit).Input()) continue;
296  if(mAlphabet.Attribute(*eit).Timer()) continue;
297  if(mAlphabet.Attribute(*eit).Output()) continue;
298  mInternalEvents.Insert(*eit);
299  }
300  FCG_VERB0("CodeGenerator::Compile(): event statistics: overall used events: #" << mUsedEvents.Size());
301  FCG_VERB0("CodeGenerator::Compile(): event statistics: input events incl timer: #" << mInputEvents.Size());
302  FCG_VERB0("CodeGenerator::Compile(): event statistics: output events: #" << mOutputEvents.Size());
303  FCG_VERB0("CodeGenerator::Compile(): event statistics: internal events excl timer: #" << mInternalEvents.Size());
304  // sort events by priority (highest first)
305  FD_DCG("CodeGenerator::DoCompile(): sorting events");
306  std::multimap<int, Idx> sortev;
307  for(eit=mUsedEvents.Begin(); eit!=mUsedEvents.End(); eit++) {
308  const AttributeCodeGeneratorEvent& attr = mAlphabet.Attribute(*eit);
309  int prio = attr.mPriority;
310  if((prio<0) || (prio > 10000)) {
311  FCG_ERR("CodeGenerator::Compile(): priority out of range [0, 10000] for event [" << EventName(*eit) << "]");
312  prio=0;
313  }
314  // map timer-events to high priority
315  if(attr.Timer() || attr.Input()) prio+=10001;
316  // effectively sort to: first inputs/timers then others
317  sortev.insert(std::pair<int,Idx>(-prio,*eit));
318  }
319  // install bit addresses
320  FD_DCG("CodeGenerator::DoCompile(): set up bitaddress");
321  mEventBitAddress.clear();
322  mEventFaudesIdx.clear();
323  mLastInputEvent=-1;
324  mLastOutputEvent=-1;
325  std::multimap<int, Idx>::iterator sit;
326  int bitaddr=0;
327  for(sit=sortev.begin(); sit!=sortev.end(); sit++) {
328  if(mAlphabet.Attribute(sit->second).Input()) mLastInputEvent=bitaddr;
329  if(mAlphabet.Attribute(sit->second).Timer()) mLastInputEvent=bitaddr;
330  if(mAlphabet.Attribute(sit->second).Output()) mLastOutputEvent=bitaddr;
331  mEventBitAddress[sit->second]=bitaddr;
332  mEventFaudesIdx[bitaddr]=sit->second;
333  bitaddr++;
334  }
335  // report
336  if(mVerbLevel>=2) {
337  for(int i=0; i<EventBitMaskSize(); ++i)
338  FCG_VERB2("CodeGenerator::Compile(): bit-address " << i << " event [" << EventName(mEventFaudesIdx[i]) << "]");
339  }
340  FCG_VERB1("CodeGenerator::Compile(): bitmask size #" << EventBitMaskSize() << " bits");
341  // represent transitionrelation as integer records
342  FD_DCG("CodeGenerator::DoCompie(): set up transition vector");
343  mTransitionVector.resize(Size());
344  mStateVector.resize(Size());
345  mStateVectorAddress.resize(Size());
346  mStateFaudesIndex.resize(Size());
347  for(Idx gid=0; gid< Size(); gid++) {
348  FD_DCG("CodeGenerator::DoCompile(): set up transition vector " << gid);
349  std::vector<int>& transvect = mTransitionVector[gid];
350  std::vector<int>& statevect = mStateVector[gid];
351  std::map<Idx,int>& targetindex = mStateVectorAddress[gid];
352  std::map<int,Idx>& faudesindex = mStateFaudesIndex[gid];
353  transvect.clear();
354  statevect.clear();
355  const Generator gen = At(gid);
356  if(gen.Size()==0) {
357  FCG_ERR("CodeGenerator::Complie(): generator must not be empty [" << gen.Name() << "]");
358  continue;
359  }
360  // scan all transitions
361  statevect.resize(gen.MaxStateIndex()+1,0);
362  IndexSet::Iterator sit= gen.StatesBegin();
363  for(;sit!=gen.StatesEnd();++sit) {
364  targetindex[*sit]= (int) transvect.size();
365  statevect[*sit] = (int) transvect.size();
366  faudesindex[(int) transvect.size()]= *sit;
367  TransSet::Iterator tit = gen.TransRelBegin(*sit);
368  TransSet::Iterator tit_end = gen.TransRelEnd(*sit);
369  for(;tit!=tit_end;++tit) {
370  transvect.push_back((int) tit->Ev);
371  transvect.push_back((int) tit->X2);
372  }
373  transvect.push_back(0);
374  }
375  // convert to target index
376  for(size_t vit=0; vit< transvect.size(); ++vit) {
377  int ev = transvect[vit];
378  if(ev==0) continue;
379  transvect[vit]=EventTargetIdx(ev);
380  int x2 = transvect[++vit];
381  transvect[vit]=targetindex[x2];
382  }
383  FCG_VERB0("CodeGenerator::Compile(): raw data for generator [" << gen.Name() << "] amounts to #"
384  << (mIntegerSize/8)*transvect.size() << " bytes");
385  }
386  // record line levels and input expressions to monitor
387  mLines.clear();
388  mFlags.clear();
389  for(eit=mAlphabet.Begin(); eit!=mAlphabet.End(); ++eit) {
390  if(!mUsedEvents.Exists(*eit)) continue;
391  if(!mAlphabet.Attribute(*eit).Input()) continue;
392  const std::vector<AttributeCodeGeneratorEvent::InputTrigger>& triggers = mAlphabet.Attribute(*eit).mTriggers;
393  for(size_t i=0; i<triggers.size(); i++) {
394  if(triggers[i].mExe) {
395  std::string flagaddr=triggers[i].mAddress;
396  mFlags[flagaddr].mEvents.Insert(*eit);
397  mFlags[flagaddr].mAddress=flagaddr;
398  }
399  if((triggers[i].mNeg) || (triggers[i].mPos)) {
400  std::string lineaddr=triggers[i].mAddress;
401  if(mLines.find(lineaddr)!=mLines.end()) {
402  if(mLines[lineaddr].mStatic != triggers[i].mStatic)
403  FCG_ERR("CodeGenerator::Compile(): inconsistent static option on input line [" << lineaddr << "]");
404  }
405  mLines[lineaddr].mAddress=lineaddr;
406  if(triggers[i].mNeg) mLines[lineaddr].mNegEvents.Insert(*eit);
407  if(triggers[i].mPos) mLines[lineaddr].mPosEvents.Insert(*eit);
408  if(triggers[i].mNeg && triggers[i].mStatic) mLines[lineaddr].mNegStatics.Insert(*eit);
409  if(triggers[i].mPos && triggers[i].mStatic) mLines[lineaddr].mPosStatics.Insert(*eit);
410  mLines[lineaddr].mStatic=triggers[i].mStatic;
411  }
412  }
413  }
414  std::map<std::string, LineAddress>::iterator lit= mLines.begin();
415  int linecnt=0;
416  for(;lit!=mLines.end();++lit) lit->second.mBitAddress=linecnt++;
417  FCG_VERB1("CodeGenerator::Compile(): monitoring #" << mLines.size() << " lines for edge detection");
418  // record timer definitions
419  EventSet evcnt;
420  mTimers.clear();
421  mTimerActions.clear();
422  for(eit=mAlphabet.Begin(); eit!=mAlphabet.End(); ++eit) {
423  if(!mUsedEvents.Exists(*eit)) continue;
424  const AttributeCodeGeneratorEvent& attr = mAlphabet.Attribute(*eit);
425  if(!attr.Timer()) continue;
426  std::string timerev=EventName(*eit);
427  const EventSet& starts = attr.mTimeConstraint.mStartEvents;
428  const EventSet& stops = attr.mTimeConstraint.mStopEvents;
429  const EventSet& resets = attr.mTimeConstraint.mResetEvents;
430  mTimers[timerev].mAddress= timerev;
431  mTimers[timerev].mElapseEvent= timerev;
432  mTimers[timerev].mInitialValue= attr.mTimeConstraint.mInitialValue;
433  mTimers[timerev].mStartEvents= starts;
434  mTimers[timerev].mStopEvents= stops;
435  mTimers[timerev].mResetEvents= resets;
436  EventSet::Iterator ait;
437  ait = starts.Begin();
438  for(;ait!=starts.End();++ait)
439  mTimerActions[EventName(*ait)].mTimerStarts.insert(timerev);
440  ait = stops.Begin();
441  for(;ait!=stops.End();++ait)
442  mTimerActions[EventName(*ait)].mTimerStops.insert(timerev);
443  ait = resets.Begin();
444  for(;ait!=resets.End();++ait)
445  mTimerActions[EventName(*ait)].mTimerResets.insert(timerev);
446  }
447  FCG_VERB1("CodeGenerator::Compile(): operating #" << mTimers.size() << " timers controlled by #" << mTimerActions.size() << " events");
448  // record actions
449  int evcn=0;
450  mActionAddresses.clear();
451  for(eit=mAlphabet.Begin(); eit!=mAlphabet.End(); ++eit) {
452  if(!mUsedEvents.Exists(*eit)) continue;
453  const AttributeCodeGeneratorEvent& attr = mAlphabet.Attribute(*eit);
454  if(!attr.Output()) continue;
455  evcn++;
456  const std::vector<AttributeCodeGeneratorEvent::OutputAction>& actions = mAlphabet.Attribute(*eit).mActions;
457  for(size_t i=0; i<actions.size(); i++) {
458  std::string actaddr=actions[i].mAddress;
459  mActionAddresses[actaddr].mAddress= actions[i].mAddress;
460  mActionAddresses[actaddr].mSetClr= actions[i].mSet || actions[i].mClr;
461  mActionAddresses[actaddr].mExe= actions[i].mExe;
462  }
463  }
464  FCG_VERB1("CodeGenerator::Compile(): operating #" << mActionAddresses.size() << " action primitives controlled by #" << evcn << " events");
465  // bitmaks vectors
466  mWordAddressVector.clear();
467  mBitMaskVector.clear();
468  for(int bitaddr=0; bitaddr<EventBitMaskSize(); ++bitaddr) {
469  int baddr = bitaddr % mWordSize;
470  int waddr = bitaddr / mWordSize;
471  mWordAddressVector.push_back(waddr);
472  mBitMaskVector.push_back((1ULL << baddr));
473  }
474  FD_DCG("CodeGenerator::DoCompile(): ok");
475 }
476 
477 
478 // access bit address, ranging from 0
480  std::map<Idx,int>::const_iterator sit;
481  sit=mEventBitAddress.find(idx);
482  if(sit==mEventBitAddress.end()) return -1;
483  return sit->second;
484 }
485 
486 // access target index, ranging from 1
488  return EventBitAddress(idx)+1;
489 }
490 
491 // access target index, ranging from 1
492 int CodeGenerator::EventTargetIdx(const std::string& ev){
493  return EventTargetIdx(EventIndex(ev));
494 }
495 
496 // access faudes index by target index
498  std::map<int,Idx>::const_iterator sit;
499  sit=mEventFaudesIdx.find(idx-1);
500  if(sit==mEventFaudesIdx.end()) return -1;
501  return sit->second;
502 }
503 
504 // generate bit mask from event index
505 std::vector<bool> CodeGenerator::EventBitMask(Idx idx) {
506  // prepare result
507  std::vector<bool> res;
508  size_t vsize= mEventBitAddress.size();
509  while(res.size()< vsize) res.push_back(false);
510  // get bit address
511  int baddr=EventBitAddress(idx);
512  if(baddr<0) return res;
513  // set the bit
514  res[baddr] = true;
515  return res;
516 }
517 
518 // generate bit mask from event set
519 std::vector<bool> CodeGenerator::EventBitMask(const EventSet& eset) {
520  // prepare result
521  std::vector<bool> res;
522  size_t vsize= mEventBitAddress.size();
523  while(res.size()< vsize) res.push_back(false);
524  // merge bit addresses for each event
525  EventSet::Iterator eit;
526  for(eit=eset.Begin(); eit!=eset.End(); eit++) {
527  int baddr=EventBitAddress(*eit);
528  if(baddr<0) continue;
529  res[baddr] = true;
530  }
531  return res;
532 }
533 
534 // access bit-address map
536  return (int) mEventBitAddress.size();
537 }
538 
539 // access word in bit vector
540 CodeGenerator::word_t CodeGenerator::WordFromBitVector(const std::vector<bool>& vect, int wordindex) {
541  word_t res=0;
542  size_t bidx= wordindex*mWordSize;
543  int shift=0;
544  for(;(shift<mWordSize) && (bidx<vect.size()); shift++,bidx++)
545  if(vect[bidx]) res |= (1UL<<shift);
546  return res;
547 }
548 
549 // conver bit vector to word vector
550 std::vector< CodeGenerator::word_t > CodeGenerator::WordVectorFromBitVector(const std::vector<bool>& vect) {
551  std::vector< word_t > res;
552  res.resize((vect.size()+mWordSize - 1) / mWordSize, 0);
553  for(size_t vidx=0; vidx < vect.size(); ++vidx) {
554  if(!vect[vidx]) continue;
555  res[vidx/mWordSize] |= (1UL << (vidx % mWordSize) );
556  }
557  return res;
558 }
559 
560 
561 // access transition vector
562 const std::vector<int>& CodeGenerator::TransitionVector(size_t git) {
563  return mTransitionVector[git];
564 }
565 
566 // default target state index refers to vector representation
567 int CodeGenerator::StateTargetIdx(size_t git, Idx idx) {
568  std::map<Idx,int>::const_iterator sit;
569  sit=mStateVectorAddress[git].find(idx);
570  if(sit==mStateVectorAddress[git].end()) return -1;
571  return sit->second;
572 }
573 
574 // default faudes state index refers to vector representation
575 Idx CodeGenerator::StateFaudesIdx(size_t git, int idx) {
576  std::map<int,Idx>::const_iterator sit;
577  sit=mStateFaudesIndex[git].find(idx);
578  if(sit==mStateFaudesIndex[git].end()) return -1;
579  return sit->second;
580 }
581 
582 // access compiled data
584  return mLines.begin();
585 }
586 
587 // access compiled data
589  return mLines.end();
590 }
591 
592 // access compiled data
594  return mFlags.begin();
595 }
596 
597 // access compiled data
599  return mFlags.end();
600 }
601 
602 // access compiled data
604  return mTimers.begin();
605 }
606 
607 // access compiled data
609  return mTimers.end();
610 }
611 
612 // access compiled data
614  return mActionAddresses.begin();
615 }
616 
617 // access compiled data
619  return mActionAddresses.end();
620 }
621 
622 // access compiled data
624  return mTimerActions.begin();
625 }
626 
627 // access compiled data
629  return mTimerActions.end();
630 }
631 
632 
633 // control error out
634 void CodeGenerator::Verbose(int level, std::ostream* altout) {
635  mVerbLevel=level;
636  if(altout!=0) pErrStream=altout;
637 }
638 
639 /*
640 ******************************************************************
641 ******************************************************************
642 ******************************************************************
643 
644 CodeGenerator implementation: generate / outstream
645 
646 ******************************************************************
647 ******************************************************************
648 ******************************************************************
649 */
650 
651 
652 // base class: prepare main out stream and call virtual hook
653 // to let derived classes generate code
655  // report on output
656  FCG_VERB0("CodeGenerator::Generate(): generating code to \"[" << mOutMode <<"]\"");
657  // have stream
658  bool tmpstream=false;
659  if(pOutStream==0) {
660  tmpstream=true;
661  if(pOutBuffer!=0) delete pOutBuffer;
662  pOutBuffer = new cgp_streambuf(mOutMode);
663  pOutStream = new std::ostream(pOutBuffer);
664  }
665  // set default output mode to "no mute"
666  mMuteMode='*';
667  // generate code
668  DoGenerate();
669  // report
670  FCG_VERB0("CodeGenerator::Generate(): generated " << LineCount() << " lines of code.");
671  // delete/flush managed stream
672  if(tmpstream) {
673  delete pOutStream;
674  pOutStream=0;
675  }
676 }
677 
678 
679 // generate output
680 std::ostream& CodeGenerator::Output(void) {
681  return *pOutStream;
682 }
683 
684 const std::string& CodeGenerator::OutputString(void) {
685  static std::string ems("");
686  if(!pOutBuffer) return ems;
687  return pOutBuffer->Buffer();
688 }
689 
690 void CodeGenerator::OutputString(const std::string& strbuf){
691  if(!pOutBuffer) return;
692  pOutBuffer->Clear();
693  if(!strbuf.empty()) FCG_VERB1("CodeGenerator::OutputString(): setting non-trivial not implemented")
694 }
695 
696 // generate output
697 void CodeGenerator::MuteMode(char mode) {
698  mMuteMode=mode;
699  if(!pOutBuffer) return;
700  pOutBuffer->Mute(mode!='*');
701 };
702 
703 
704 // generate output
705 void CodeGenerator::MuteCond(char mode) {
706  if(!pOutBuffer) return;
707  bool mute = (mode!=mMuteMode) && (mode!='*') && (mMuteMode!='*');
708  pOutBuffer->Mute(mute);
709  if((!mMuteComments) && (!mute) && (mRecentMutedComment!="")) {
712  }
713 }
714 
715 // generate output
716 void CodeGenerator::LineFeed(int lines) {
717  if(!Output()) return;
718  while(lines>0) {
719  Output() << std::endl;
720  --lines;
721  }
722 }
723 
724 // generate output
726  if(!pOutBuffer) return;
727  pOutBuffer->IndentInc();
728 }
729 
730 // generate output
732  if(!pOutBuffer) return;
733  pOutBuffer->IndentDec();
734 }
735 
736 // generate output
738  if(!pOutBuffer) return;
739  pOutBuffer->XmlTextEscape(on);
740 }
741 
742 // generate output
744  if(!pOutBuffer) return;
745  pOutBuffer->XmlCdataEscape(on);
746 }
747 
748 // comment (need to reimplement and pass on)
749 void CodeGenerator::Comment(const std::string& text) {
750  if(mMuteComments)
751  mRecentMutedComment=text;
752  if(pOutBuffer)
753  if(pOutBuffer->Mute())
754  mRecentMutedComment=text;
755 }
756 
757 // generate output
759  mMuteComments=on;
760 }
761 
762 // generate output
764  if(!pOutBuffer) return;
765  pOutBuffer->MuteVspace(on);
766 }
767 
768 
769 // generate output
771  if(!pOutBuffer) return std::string();
772  std::stringstream res;
773  res << "#" << pOutBuffer->LineCount();
774  return std::string(res.str());
775 }
776 
777 
778 // implementation of output buffer
779 CodeGenerator::cgp_streambuf::cgp_streambuf(std::string mode) :
780  std::streambuf(),
781  mpFOutStream(0),
782  mLines(0),
783  mBeginOfLine(true),
784  mIndent(0),
785  mMute(false),
786  mMuteVspace(false),
787  mTextEscape(false),
788  mCdataEscape(false)
789 {
790  // case a) using string buffer only
791  if(mode == "std::string") {
792  mMode = "std::string";
793  pOutStream=0;
794  }
795  // case b) using cout
796  else if(mode=="std::cout") {
797  mMode="std::cout";
798  pOutStream=&std::cout;
799  } else
800  // case c) flush to specified file
801  {
802  mMode=mode;
803  mpFOutStream = new std::ofstream();
804  mpFOutStream->exceptions(std::ios::badbit|std::ios::failbit);
805  try{
806  mpFOutStream->open(mode.c_str(), std::ios::out|std::ios::trunc);
807  }
808  catch (std::ios::failure&) {
809  std::stringstream errstr;
810  errstr << "Exception opening/writing file \""<< mode << "\"";
811  throw Exception("CodeGenerator::Generate()", errstr.str(), 1);
812  }
813  pOutStream = mpFOutStream;
814  }
815 };
816 
817 // implementation of output buffer
818 CodeGenerator::cgp_streambuf::~cgp_streambuf() {
819  Flush();
820  if(mpFOutStream) {
821  mpFOutStream->close();
822  delete mpFOutStream;
823  }
824 }
825 
826 // implementation of output buffer (hook on virtual function)
827 std::streambuf::int_type CodeGenerator::cgp_streambuf::overflow (int_type c) {
828  //FD_WARN("cgp_steambuf::overflow(): " << c);
829  // pass on EOF
830  if(c == EOF) return EOF;
831  // ignore on mute
832  if(mMute) return c;
833  // ignore vspace
834  if(mMuteVspace && (c=='\n') && (mBuffer.size()==0)) return c;
835  // sense eol
836  if(c=='\n') {
837  mBuffer.push_back(c);
838  Flush();
839  mLines++;
840  mBeginOfLine=true;
841  return c;
842  }
843  // prepend indent
844  if(mBeginOfLine) {
845  int scnt=mIndent;
846  for(;scnt>0;--scnt) mBuffer.push_back(' ');
847  mBeginOfLine=false;
848  }
849  // escape xml (substitute indicators by enteties)
850  if(mTextEscape) {
851  if(c=='<')
852  { mBuffer += "&lt;"; return c;}
853  if(c=='>')
854  { mBuffer += "&gt;"; return c;}
855  if(c=='&')
856  { mBuffer += "&amp;"; return c;}
857  if(c=='\'')
858  { mBuffer += "&apos;"; return c;}
859  if(c=='"')
860  { mBuffer += "&quot;"; return c;}
861  }
862  // escape xml (insert "]]><![CDATA[" betwwen "]]" and ">")
863  if(mCdataEscape) {
864  if((c=='>') && (mBuffer.size()>=2))
865  if(mBuffer.at(mBuffer.size()-1) == ']')
866  if(mBuffer.at(mBuffer.size()-2) == ']')
867  mBuffer += "]]><![CDATA[";
868  }
869  // plain append
870  mBuffer.push_back(c);
871  return c;
872 }
873 
874 
875 // implementation of output buffer
876 void CodeGenerator::cgp_streambuf::Flush() {
877  // keep in buffer on std::string-mode
878  if(!pOutStream) return;
879  // try to flush
880  try {
881  (*pOutStream) << mBuffer;
882  (*pOutStream) << std::flush;
883  } catch(std::ios::failure&) {
884  std::stringstream errstr;
885  errstr << "Exception writing to file \""<< mMode << "\"";
886  throw Exception("CodeGenerator::Generate()", errstr.str(), 1);
887  }
888  // clear buffer
889  mBuffer.clear();
890 }
891 
892 // implement output buffer
893 const std::string& CodeGenerator::cgp_streambuf::Buffer(){
894  return mBuffer;
895 }
896 
897 // implement output buffer
899  Flush();
900  mLines=0;
901  mBeginOfLine=true;
902  mBuffer.clear();
903 }
904 
905  // implementation of output buffer
907  Flush();
908  return mLines;
909 };
910 
911 
912 // implementation of output buffer
914  mIndent+=2;
915 };
916 
917 // implementation of output buffer
919  mIndent-=2;
920 };
921 
922 // implementation of output buffer
924  Flush();
925  mCdataEscape=false;
926  mTextEscape=on;
927 };
928 
929 // implementation of output buffer
931  Flush();
932  mTextEscape=false;
933  mCdataEscape=on;
934 };
935 
936 // implementation of output buffer
937 void CodeGenerator::cgp_streambuf::Mute(bool on) {
938  Flush();
939  mMute=on;
940 };
941 
942 // implementation of output buffer
943 bool CodeGenerator::cgp_streambuf::Mute() {
944  return mMute;
945 };
946 
947 // implementation of output buffer
949  Flush();
950  mMuteVspace=on;
951 };
952