CompileDES  3.12
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  // default to vector addresses as state indices
262  mUsingVectorAddressStates.assign(Size(),true);
263  // virtual compile
264  DoCompile();
265  FCG_VERB0("CodeGenerator::Compile(): done");
266 }
267 
268 
269 // base class do compile: organize events and transitionrelations
271  FD_DCG("CodeGenerator::DoCompile()");
272  // check that all events have specified attributes
273  mUsedEvents.Clear();
274  for(size_t git=0; git<Size(); ++git) {
275  EventSet::Iterator eit=At(git).AlphabetBegin();
276  for(; eit!=At(git).AlphabetEnd(); ++eit) {
277  if(!mAlphabet.Exists(*eit)) {
278  FCG_ERR("CodeGenerator::Compile(): event [" << EventName(*eit) << "] has unspecified execution semantics")
279  }
280  mUsedEvents.Insert(*eit);
281  }
282  }
284  FCG_VERB0("CodeGenerator::Compile(): event configuration mismatch: #" << (mAlphabet-mUsedEvents).Size() << " unused events");
285  // compose event sets by type
286  mOutputEvents.Clear();
287  EventSet::Iterator eit;
288  for(eit=mUsedEvents.Begin();eit!=mUsedEvents.End();++eit)
289  if(mAlphabet.Attribute(*eit).Output()) mOutputEvents.Insert(*eit);
290  mInputEvents.Clear();
291  for(eit=mUsedEvents.Begin();eit!=mUsedEvents.End();++eit) {
292  if(mAlphabet.Attribute(*eit).Input()) mInputEvents.Insert(*eit);
293  if(mAlphabet.Attribute(*eit).Timer()) mInputEvents.Insert(*eit);
294  }
295  mInternalEvents.Clear();
296  for(eit=mUsedEvents.Begin();eit!=mUsedEvents.End();++eit) {
297  if(mAlphabet.Attribute(*eit).Input()) continue;
298  if(mAlphabet.Attribute(*eit).Timer()) continue;
299  if(mAlphabet.Attribute(*eit).Output()) continue;
300  mInternalEvents.Insert(*eit);
301  }
302  FCG_VERB0("CodeGenerator::Compile(): event statistics: overall used events: #" << mUsedEvents.Size());
303  FCG_VERB0("CodeGenerator::Compile(): event statistics: input events incl timer: #" << mInputEvents.Size());
304  FCG_VERB0("CodeGenerator::Compile(): event statistics: output events: #" << mOutputEvents.Size());
305  FCG_VERB0("CodeGenerator::Compile(): event statistics: internal events excl timer: #" << mInternalEvents.Size());
306  // sort events by priority (highest first)
307  FD_DCG("CodeGenerator::DoCompile(): sorting events");
308  std::multimap<int, Idx> sortev;
309  for(eit=mUsedEvents.Begin(); eit!=mUsedEvents.End(); eit++) {
310  const AttributeCodeGeneratorEvent& attr = mAlphabet.Attribute(*eit);
311  int prio = attr.mPriority;
312  if((prio<0) || (prio > 10000)) {
313  FCG_ERR("CodeGenerator::Compile(): priority out of range [0, 10000] for event [" << EventName(*eit) << "]");
314  prio=0;
315  }
316  // map timer-events to high priority
317  if(attr.Timer() || attr.Input()) prio+=10001;
318  // effectively sort to: first inputs/timers then others
319  sortev.insert(std::pair<int,Idx>(-prio,*eit));
320  }
321  // install bit addresses
322  FD_DCG("CodeGenerator::DoCompile(): set up bitaddress");
323  mEventBitAddress.clear();
324  mEventFaudesIdx.clear();
325  mLastInputEvent=-1;
326  mLastOutputEvent=-1;
327  std::multimap<int, Idx>::iterator sit;
328  int bitaddr=0;
329  for(sit=sortev.begin(); sit!=sortev.end(); sit++) {
330  if(mAlphabet.Attribute(sit->second).Input()) mLastInputEvent=bitaddr;
331  if(mAlphabet.Attribute(sit->second).Timer()) mLastInputEvent=bitaddr;
332  if(mAlphabet.Attribute(sit->second).Output()) mLastOutputEvent=bitaddr;
333  mEventBitAddress[sit->second]=bitaddr;
334  mEventFaudesIdx[bitaddr]=sit->second;
335  bitaddr++;
336  }
337  // report
338  if(mVerbLevel>=2) {
339  for(int i=0; i<EventBitMaskSize(); ++i)
340  FCG_VERB2("CodeGenerator::Compile(): bit-address " << i << " event [" << EventName(mEventFaudesIdx[i]) << "]");
341  }
342  FCG_VERB1("CodeGenerator::Compile(): bitmask size #" << EventBitMaskSize() << " bits");
343  // represent transitionrelation as integer records
344  FD_DCG("CodeGenerator::DoCompie(): set up transition vector");
345  mTransitionVector.resize(Size());
346  //mStateVector.resize(Size());
347  mStateVectorAddress.resize(Size());
348  mStateFaudesIndex.resize(Size());
349  for(Idx gid=0; gid< Size(); gid++) {
350  FD_DCG("CodeGenerator::DoCompile(): set up transition vector " << gid);
351  std::vector<int>& transvect = mTransitionVector[gid];
352  std::map<Idx,int>& vectoraddr = mStateVectorAddress[gid];
353  std::map<int,Idx>& faudesindex = mStateFaudesIndex[gid];
354  bool usingvectoraddr = mUsingVectorAddressStates[gid];
355  transvect.clear();
356  vectoraddr.clear();
357  faudesindex.clear();
358  const Generator gen = At(gid);
359  if(gen.Size()==0) {
360  FCG_ERR("CodeGenerator::Complie(): generator must not be empty [" << gen.Name() << "]");
361  continue;
362  }
363  // scan all transitions
364  IndexSet::Iterator sit= gen.StatesBegin();
365  for(;sit!=gen.StatesEnd();++sit) {
366  vectoraddr[*sit]= (int) transvect.size();
367  faudesindex[(int) transvect.size()]= *sit;
368  TransSet::Iterator tit = gen.TransRelBegin(*sit);
369  TransSet::Iterator tit_end = gen.TransRelEnd(*sit);
370  for(;tit!=tit_end;++tit) {
371  transvect.push_back((int) tit->Ev);
372  transvect.push_back((int) tit->X2);
373  }
374  transvect.push_back(0);
375  }
376  // convert to target index
377  for(size_t vit=0; vit< transvect.size(); ++vit) {
378  int ev = transvect[vit];
379  if(ev==0) continue;
380  transvect[vit]=EventTargetIdx(ev);
381  int x2 = transvect[++vit];
382  if(usingvectoraddr)
383  transvect[vit]=vectoraddr[x2];
384  }
385  FCG_VERB0("CodeGenerator::Compile(): [" << gen.Name() << "] raw data for transition array #"
386  << (mIntegerSize/8)*transvect.size() << " bytes");
387  if(!usingvectoraddr) {
388  FCG_VERB0("CodeGenerator::Compile(): [" << gen.Name() << "] raw data for state-address array #"
389  << (mIntegerSize/8)*gen.MaxStateIndex() << " bytes");
390  } else {
391  FCG_VERB0("CodeGenerator::Compile(): [" << gen.Name() << "] using vector addresses as state indices");
392  }
393  }
394 
395  // record line levels and input expressions to monitor
396  mLines.clear();
397  mFlags.clear();
398  for(eit=mAlphabet.Begin(); eit!=mAlphabet.End(); ++eit) {
399  if(!mUsedEvents.Exists(*eit)) continue;
400  if(!mAlphabet.Attribute(*eit).Input()) continue;
401  const std::vector<AttributeCodeGeneratorEvent::InputTrigger>& triggers = mAlphabet.Attribute(*eit).mTriggers;
402  for(size_t i=0; i<triggers.size(); i++) {
403  if(triggers[i].mExe) {
404  std::string flagaddr=triggers[i].mAddress;
405  mFlags[flagaddr].mEvents.Insert(*eit);
406  mFlags[flagaddr].mAddress=flagaddr;
407  }
408  if((triggers[i].mNeg) || (triggers[i].mPos)) {
409  std::string lineaddr=triggers[i].mAddress;
410  if(mLines.find(lineaddr)!=mLines.end()) {
411  if(mLines[lineaddr].mStatic != triggers[i].mStatic)
412  FCG_ERR("CodeGenerator::Compile(): inconsistent static option on input line [" << lineaddr << "]");
413  }
414  mLines[lineaddr].mAddress=lineaddr;
415  if(triggers[i].mNeg) mLines[lineaddr].mNegEvents.Insert(*eit);
416  if(triggers[i].mPos) mLines[lineaddr].mPosEvents.Insert(*eit);
417  if(triggers[i].mNeg && triggers[i].mStatic) mLines[lineaddr].mNegStatics.Insert(*eit);
418  if(triggers[i].mPos && triggers[i].mStatic) mLines[lineaddr].mPosStatics.Insert(*eit);
419  mLines[lineaddr].mStatic=triggers[i].mStatic;
420  }
421  }
422  }
423  std::map<std::string, LineAddress>::iterator lit= mLines.begin();
424  int linecnt=0;
425  for(;lit!=mLines.end();++lit) lit->second.mBitAddress=linecnt++;
426  FCG_VERB1("CodeGenerator::Compile(): monitoring #" << mLines.size() << " lines for edge detection");
427  // record timer definitions
428  EventSet evcnt;
429  mTimers.clear();
430  mTimerActions.clear();
431  for(eit=mAlphabet.Begin(); eit!=mAlphabet.End(); ++eit) {
432  if(!mUsedEvents.Exists(*eit)) continue;
433  const AttributeCodeGeneratorEvent& attr = mAlphabet.Attribute(*eit);
434  if(!attr.Timer()) continue;
435  std::string timerev=EventName(*eit);
436  const EventSet& starts = attr.mTimeConstraint.mStartEvents;
437  const EventSet& stops = attr.mTimeConstraint.mStopEvents;
438  const EventSet& resets = attr.mTimeConstraint.mResetEvents;
439  mTimers[timerev].mAddress= timerev;
440  mTimers[timerev].mElapseEvent= timerev;
441  mTimers[timerev].mInitialValue= attr.mTimeConstraint.mInitialValue;
442  mTimers[timerev].mStartEvents= starts;
443  mTimers[timerev].mStopEvents= stops;
444  mTimers[timerev].mResetEvents= resets;
445  EventSet::Iterator ait;
446  ait = starts.Begin();
447  for(;ait!=starts.End();++ait)
448  mTimerActions[EventName(*ait)].mTimerStarts.insert(timerev);
449  ait = stops.Begin();
450  for(;ait!=stops.End();++ait)
451  mTimerActions[EventName(*ait)].mTimerStops.insert(timerev);
452  ait = resets.Begin();
453  for(;ait!=resets.End();++ait)
454  mTimerActions[EventName(*ait)].mTimerResets.insert(timerev);
455  }
456  FCG_VERB1("CodeGenerator::Compile(): operating #" << mTimers.size() << " timers controlled by #" << mTimerActions.size() << " events");
457  // record actions
458  int evcn=0;
459  mActionAddresses.clear();
460  for(eit=mAlphabet.Begin(); eit!=mAlphabet.End(); ++eit) {
461  if(!mUsedEvents.Exists(*eit)) continue;
462  const AttributeCodeGeneratorEvent& attr = mAlphabet.Attribute(*eit);
463  if(!attr.Output()) continue;
464  evcn++;
465  const std::vector<AttributeCodeGeneratorEvent::OutputAction>& actions = mAlphabet.Attribute(*eit).mActions;
466  for(size_t i=0; i<actions.size(); i++) {
467  std::string actaddr=actions[i].mAddress;
468  mActionAddresses[actaddr].mAddress= actions[i].mAddress;
469  mActionAddresses[actaddr].mSetClr= actions[i].mSet || actions[i].mClr;
470  mActionAddresses[actaddr].mExe= actions[i].mExe;
471  }
472  }
473  FCG_VERB1("CodeGenerator::Compile(): operating #" << mActionAddresses.size() << " action primitives controlled by #" << evcn << " events");
474  // bitmaks vectors
475  mWordAddressVector.clear();
476  mBitMaskVector.clear();
477  for(int bitaddr=0; bitaddr<EventBitMaskSize(); ++bitaddr) {
478  int baddr = bitaddr % mWordSize;
479  int waddr = bitaddr / mWordSize;
480  mWordAddressVector.push_back(waddr);
481  mBitMaskVector.push_back((1ULL << baddr));
482  }
483  FD_DCG("CodeGenerator::DoCompile(): ok");
484 }
485 
486 
487 // access bit address, ranging from 0
489  std::map<Idx,int>::const_iterator sit;
490  sit=mEventBitAddress.find(idx);
491  if(sit==mEventBitAddress.end()) return -1;
492  return sit->second;
493 }
494 
495 // access target index, ranging from 1
497  return EventBitAddress(idx)+1;
498 }
499 
500 // access target index, ranging from 1
501 int CodeGenerator::EventTargetIdx(const std::string& ev){
502  return EventTargetIdx(EventIndex(ev));
503 }
504 
505 // access faudes index by target index
507  std::map<int,Idx>::const_iterator sit;
508  sit=mEventFaudesIdx.find(idx-1);
509  if(sit==mEventFaudesIdx.end()) return -1;
510  return sit->second;
511 }
512 
513 // generate bit mask from event index
514 std::vector<bool> CodeGenerator::EventBitMask(Idx idx) {
515  // prepare result
516  std::vector<bool> res;
517  size_t vsize= mEventBitAddress.size();
518  while(res.size()< vsize) res.push_back(false);
519  // get bit address
520  int baddr=EventBitAddress(idx);
521  if(baddr<0) return res;
522  // set the bit
523  res[baddr] = true;
524  return res;
525 }
526 
527 // generate bit mask from event set
528 std::vector<bool> CodeGenerator::EventBitMask(const EventSet& eset) {
529  // prepare result
530  std::vector<bool> res;
531  size_t vsize= mEventBitAddress.size();
532  while(res.size()< vsize) res.push_back(false);
533  // merge bit addresses for each event
534  EventSet::Iterator eit;
535  for(eit=eset.Begin(); eit!=eset.End(); eit++) {
536  int baddr=EventBitAddress(*eit);
537  if(baddr<0) continue;
538  res[baddr] = true;
539  }
540  return res;
541 }
542 
543 // access bit-address map
545  return (int) mEventBitAddress.size();
546 }
547 
548 // access word in bit vector
549 CodeGenerator::word_t CodeGenerator::WordFromBitVector(const std::vector<bool>& vect, int wordindex) {
550  word_t res=0;
551  size_t bidx= wordindex*mWordSize;
552  int shift=0;
553  for(;(shift<mWordSize) && (bidx<vect.size()); shift++,bidx++)
554  if(vect[bidx]) res |= (1UL<<shift);
555  return res;
556 }
557 
558 // conver bit vector to word vector
559 std::vector< CodeGenerator::word_t > CodeGenerator::WordVectorFromBitVector(const std::vector<bool>& vect) {
560  std::vector< word_t > res;
561  res.resize((vect.size()+mWordSize - 1) / mWordSize, 0);
562  for(size_t vidx=0; vidx < vect.size(); ++vidx) {
563  if(!vect[vidx]) continue;
564  res[vidx/mWordSize] |= (1UL << (vidx % mWordSize) );
565  }
566  return res;
567 }
568 
569 
570 // access transition vector
571 const std::vector<int>& CodeGenerator::TransitionVector(size_t git) {
572  return mTransitionVector[git];
573 }
574 
575 // default target state index refers to vector representation
576 int CodeGenerator::StateTargetIdx(size_t git, Idx idx) {
577  if(!mUsingVectorAddressStates[git]) return idx;
578  std::map<Idx,int>::const_iterator sit;
579  sit=mStateVectorAddress[git].find(idx);
580  if(sit==mStateVectorAddress[git].end()) return -1;
581  return sit->second;
582 }
583 
584 // default faudes state index refers to vector representation
585 Idx CodeGenerator::StateFaudesIdx(size_t git, int idx) {
586  if(!mUsingVectorAddressStates[git]) return idx;
587  std::map<int,Idx>::const_iterator sit;
588  sit=mStateFaudesIndex[git].find(idx);
589  if(sit==mStateFaudesIndex[git].end()) return -1;
590  return sit->second;
591 }
592 
593 // access compiled data
595  return mLines.begin();
596 }
597 
598 // access compiled data
600  return mLines.end();
601 }
602 
603 // access compiled data
605  return mFlags.begin();
606 }
607 
608 // access compiled data
610  return mFlags.end();
611 }
612 
613 // access compiled data
615  return mTimers.begin();
616 }
617 
618 // access compiled data
620  return mTimers.end();
621 }
622 
623 // access compiled data
625  return mActionAddresses.begin();
626 }
627 
628 // access compiled data
630  return mActionAddresses.end();
631 }
632 
633 // access compiled data
635  return mTimerActions.begin();
636 }
637 
638 // access compiled data
640  return mTimerActions.end();
641 }
642 
643 
644 // control error out
645 void CodeGenerator::Verbose(int level, std::ostream* altout) {
646  mVerbLevel=level;
647  if(altout!=0) pErrStream=altout;
648 }
649 
650 /*
651 ******************************************************************
652 ******************************************************************
653 ******************************************************************
654 
655 CodeGenerator implementation: generate / outstream
656 
657 ******************************************************************
658 ******************************************************************
659 ******************************************************************
660 */
661 
662 
663 // base class: prepare main out stream and call virtual hook
664 // to let derived classes generate code
666  // report on output
667  FCG_VERB0("CodeGenerator::Generate(): generating code to \"[" << mOutMode <<"]\"");
668  // have stream
669  bool tmpstream=false;
670  if(pOutStream==0) {
671  tmpstream=true;
672  if(pOutBuffer!=0) delete pOutBuffer;
673  pOutBuffer = new cgp_streambuf(mOutMode);
674  pOutStream = new std::ostream(pOutBuffer);
675  }
676  // set default output mode to "no mute"
677  mMuteMode='*';
678  // generate code
679  DoGenerate();
680  // report
681  FCG_VERB0("CodeGenerator::Generate(): generated " << LineCount() << " lines of code.");
682  // delete/flush managed stream
683  if(tmpstream) {
684  delete pOutStream;
685  pOutStream=0;
686  }
687 }
688 
689 
690 // generate output
691 std::ostream& CodeGenerator::Output(void) {
692  return *pOutStream;
693 }
694 
695 const std::string& CodeGenerator::OutputString(void) {
696  static std::string ems("");
697  if(!pOutBuffer) return ems;
698  return pOutBuffer->Buffer();
699 }
700 
701 void CodeGenerator::OutputString(const std::string& strbuf){
702  if(!pOutBuffer) return;
703  pOutBuffer->Clear();
704  if(!strbuf.empty()) FCG_VERB1("CodeGenerator::OutputString(): setting non-trivial not implemented")
705 }
706 
707 // generate output
708 void CodeGenerator::MuteMode(char mode) {
709  mMuteMode=mode;
710  if(!pOutBuffer) return;
711  pOutBuffer->Mute(mode!='*');
712 };
713 
714 
715 // generate output
716 void CodeGenerator::MuteCond(char mode) {
717  if(!pOutBuffer) return;
718  bool mute = (mode!=mMuteMode) && (mode!='*') && (mMuteMode!='*');
719  pOutBuffer->Mute(mute);
720  if((!mMuteComments) && (!mute) && (mRecentMutedComment!="")) {
723  }
724 }
725 
726 // generate output
727 void CodeGenerator::LineFeed(int lines) {
728  if(!Output()) return;
729  while(lines>0) {
730  Output() << std::endl;
731  --lines;
732  }
733 }
734 
735 // generate output
737  if(!pOutBuffer) return;
738  pOutBuffer->IndentInc();
739 }
740 
741 // generate output
743  if(!pOutBuffer) return;
744  pOutBuffer->IndentDec();
745 }
746 
747 // generate output
749  if(!pOutBuffer) return;
750  pOutBuffer->XmlTextEscape(on);
751 }
752 
753 // generate output
755  if(!pOutBuffer) return;
756  pOutBuffer->XmlCdataEscape(on);
757 }
758 
759 // comment (need to reimplement and pass on)
760 void CodeGenerator::Comment(const std::string& text) {
761  if(mMuteComments)
762  mRecentMutedComment=text;
763  if(pOutBuffer)
764  if(pOutBuffer->Mute())
765  mRecentMutedComment=text;
766 }
767 
768 // generate output
770  mMuteComments=on;
771 }
772 
773 // generate output
775  if(!pOutBuffer) return;
776  pOutBuffer->MuteVspace(on);
777 }
778 
779 
780 // generate output
782  if(!pOutBuffer) return std::string();
783  std::stringstream res;
784  res << "#" << pOutBuffer->LineCount();
785  return std::string(res.str());
786 }
787 
788 
789 // implementation of output buffer
790 CodeGenerator::cgp_streambuf::cgp_streambuf(std::string mode) :
791  std::streambuf(),
792  mpFOutStream(0),
793  mLines(0),
794  mBeginOfLine(true),
795  mIndent(0),
796  mMute(false),
797  mMuteVspace(false),
798  mTextEscape(false),
799  mCdataEscape(false)
800 {
801  // case a) using string buffer only
802  if(mode == "std::string") {
803  mMode = "std::string";
804  pOutStream=0;
805  }
806  // case b) using cout
807  else if(mode=="std::cout") {
808  mMode="std::cout";
809  pOutStream=&std::cout;
810  } else
811  // case c) flush to specified file
812  {
813  mMode=mode;
814  mpFOutStream = new std::ofstream();
815  mpFOutStream->exceptions(std::ios::badbit|std::ios::failbit);
816  try{
817  mpFOutStream->open(mode.c_str(), std::ios::out|std::ios::trunc);
818  }
819  catch (std::ios::failure&) {
820  std::stringstream errstr;
821  errstr << "Exception opening/writing file \""<< mode << "\"";
822  throw Exception("CodeGenerator::Generate()", errstr.str(), 1);
823  }
824  pOutStream = mpFOutStream;
825  }
826 };
827 
828 // implementation of output buffer
829 CodeGenerator::cgp_streambuf::~cgp_streambuf() {
830  Flush();
831  if(mpFOutStream) {
832  mpFOutStream->close();
833  delete mpFOutStream;
834  }
835 }
836 
837 // implementation of output buffer (hook on virtual function)
838 std::streambuf::int_type CodeGenerator::cgp_streambuf::overflow (int_type c) {
839  //FD_WARN("cgp_steambuf::overflow(): " << c);
840  // pass on EOF
841  if(c == EOF) return EOF;
842  // ignore on mute
843  if(mMute) return c;
844  // ignore vspace
845  if(mMuteVspace && (c=='\n') && (mBuffer.size()==0)) return c;
846  // sense eol
847  if(c=='\n') {
848  mBuffer.push_back(c);
849  Flush();
850  mLines++;
851  mBeginOfLine=true;
852  return c;
853  }
854  // prepend indent
855  if(mBeginOfLine) {
856  int scnt=mIndent;
857  for(;scnt>0;--scnt) mBuffer.push_back(' ');
858  mBeginOfLine=false;
859  }
860  // escape xml (substitute indicators by enteties)
861  if(mTextEscape) {
862  if(c=='<')
863  { mBuffer += "&lt;"; return c;}
864  if(c=='>')
865  { mBuffer += "&gt;"; return c;}
866  if(c=='&')
867  { mBuffer += "&amp;"; return c;}
868  if(c=='\'')
869  { mBuffer += "&apos;"; return c;}
870  if(c=='"')
871  { mBuffer += "&quot;"; return c;}
872  }
873  // escape xml (insert "]]><![CDATA[" betwwen "]]" and ">")
874  if(mCdataEscape) {
875  if((c=='>') && (mBuffer.size()>=2))
876  if(mBuffer.at(mBuffer.size()-1) == ']')
877  if(mBuffer.at(mBuffer.size()-2) == ']')
878  mBuffer += "]]><![CDATA[";
879  }
880  // plain append
881  mBuffer.push_back(c);
882  return c;
883 }
884 
885 
886 // implementation of output buffer
887 void CodeGenerator::cgp_streambuf::Flush() {
888  // keep in buffer on std::string-mode
889  if(!pOutStream) return;
890  // try to flush
891  try {
892  (*pOutStream) << mBuffer;
893  (*pOutStream) << std::flush;
894  } catch(std::ios::failure&) {
895  std::stringstream errstr;
896  errstr << "Exception writing to file \""<< mMode << "\"";
897  throw Exception("CodeGenerator::Generate()", errstr.str(), 1);
898  }
899  // clear buffer
900  mBuffer.clear();
901 }
902 
903 // implement output buffer
904 const std::string& CodeGenerator::cgp_streambuf::Buffer(){
905  return mBuffer;
906 }
907 
908 // implement output buffer
909 void CodeGenerator::cgp_streambuf::Clear(void){
910  Flush();
911  mLines=0;
912  mBeginOfLine=true;
913  mBuffer.clear();
914 }
915 
916  // implementation of output buffer
917 int CodeGenerator::cgp_streambuf::LineCount() {
918  Flush();
919  return mLines;
920 };
921 
922 
923 // implementation of output buffer
924 void CodeGenerator::cgp_streambuf::IndentInc() {
925  mIndent+=2;
926 };
927 
928 // implementation of output buffer
929 void CodeGenerator::cgp_streambuf::IndentDec() {
930  mIndent-=2;
931 };
932 
933 // implementation of output buffer
934 void CodeGenerator::cgp_streambuf::XmlTextEscape(bool on) {
935  Flush();
936  mCdataEscape=false;
937  mTextEscape=on;
938 };
939 
940 // implementation of output buffer
941 void CodeGenerator::cgp_streambuf::XmlCdataEscape(bool on) {
942  Flush();
943  mTextEscape=false;
944  mCdataEscape=on;
945 };
946 
947 // implementation of output buffer
948 void CodeGenerator::cgp_streambuf::Mute(bool on) {
949  Flush();
950  mMute=on;
951 };
952 
953 // implementation of output buffer
954 bool CodeGenerator::cgp_streambuf::Mute() {
955  return mMute;
956 };
957 
958 // implementation of output buffer
959 void CodeGenerator::cgp_streambuf::MuteVspace(bool on) {
960  Flush();
961  mMuteVspace=on;
962 };
963 
virtual std::string LineCount(void)
LineFeed (convenience support for derived classes)
Idx Size(void) const
Number of generators.
virtual int StateTargetIdx(size_t git, Idx idx)
Get target state index (refer to vector representation as default, overload in CodePrimitives) ...
std::map< std::string, FlagExpression > mFlags
input event generation
virtual void MuteMode(char mode)
Set current mute mode.
EventSet mStartEvents
Events that start this timer.
virtual void DoGenerate(void)=0
pure virtual interface to code generation
Event attributes for the purpose of code generation.
std::vector< std::string > mGeneratorNames
list of filenames when generator are read from file
LineIterator LinesEnd()
Access to line records by iterator.
virtual void XmlCdataEscape(bool on)
XmlCdataEscape (escape "]]>")
TimeConstraint mTimeConstraint
Timer definition (indicate timer event iff mInitialValue non-empty)
virtual std::ostream & Output(void)
Output stream.
EventSet mUsedEvents
configured events that are referred to by some generator
EventSet mResetEvents
Events that reset this timer.
virtual void DoRead(TokenReader &rTr, const std::string &rLabel="", const Type *pContext=0)
Read the configuration from TokenReader, see faudes Type for public wrappers.
virtual void DoReadTargetConfiguration(TokenReader &rTr)
Reads global configuration from TokenReader, excl.
static CodeGenerator * New(const std::string &type)
Instantiate by identifier (returns 0 on unknown class)
std::string mOutMode
output file name (base)
std::vector< bool > EventBitMask(Idx idx)
Get vector representation for a single faudes event Idx.
int mWordSize
compressed boolean capacity of target type word
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
void Verbose(int level, std::ostream *altout=0)
Set verbosity level.
virtual void MuteComments(bool on)
Mute comments (convenience support for derived classes)
std::string mRecentMutedComment
recent muted comment
std::vector< bool > mUsingVectorAddressStates
configuration of state indexing per generator
std::ostream * pOutStream
output stream
cgEventSet mAlphabet
event configuration by attributes
Idx EventFaudesIdx(int idx)
Get faudes Idx from target Idx (aka from bit-address + 1)
virtual Idx StateFaudesIdx(size_t git, int idx)
Get faudes state index (refer to vector representation as default, overload in CodePrimitives) ...
int EventBitAddress(Idx idx)
Get event bit-address from faudes Idx (consecutive, starts at 0)
const std::string & OutputString(void)
Get accumulated output as string.
EventSet mOutputEvents
used events that are configured as outputs
TimerActionIterator TimerActionsBegin()
Access to timer records by iterator.
std::vector< word_t > WordVectorFromBitVector(const std::vector< bool > &vect)
Convert boolean vector to word array.
std::map< std::string, TimerConfiguration >::iterator TimerIterator
Access to timer records by iterator.
const std::vector< int > & TransitionVector(size_t git)
Get target state index (refer to vector representation as default, overload in CodePrimitives) ...
virtual void IndentInc()
Indentation (convenience support for derived classes)
FlagIterator FlagsBegin()
Access to flag records by iterator.
const TimedGenerator & At(int i) const
Direct access for read-only access of generators.
virtual void DoWrite(TokenWriter &rTw, const std::string &rLabel="", const Type *pContext=0) const
Writes the configuration to TokenWriter, see faudes Type for public wrappers.
std::vector< word_t > mBitMaskVector
Look-up table to map a bit-address to the word-bitmask.
std::vector< int > mWordAddressVector
Look-up table to map a bit-address to the word-index.
Idx EventIndex(const std::string &rName) const
Faudes-event index lookup.
std::map< std::string, TimerAction >::iterator TimerActionIterator
Access to timer records by iterator.
TimerActionIterator TimerActionsEnd()
Access to timer records by iterator.
std::map< std::string, FlagExpression >::iterator FlagIterator
Access to flag records by iterator.
std::map< std::string, TimerAction > mTimerActions
timer actions by event name
std::vector< std::map< Idx, int > > mStateVectorAddress
mapping from faudes state idx to vector index
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
std::map< Idx, int > mEventBitAddress
mapping from faudes event idx to bit address (descending priority, range 0 .
virtual const std::string & Name(void) const
Get objects&#39;s name (reimplementing base faudes::Type)
int mIntegerSize
compressed boolean capacity of target type integer
std::ostream * pErrStream
error stream
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
Write global configuration to TokenWriter, excl.
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record by iterator.
CodeGenerator(void)
Constructor.
static std::vector< std::string > Registry(void)
Access registry contents.
int mVerbLevel
diagnpstic-output level
int mLastInputEvent
highest bit-address with input (or timer) event (-1 for none)
virtual void XmlTextEscape(bool on)
XmlTextEscape (escape "<", ">", "&", "\"" and "&#39;")
virtual void MuteCond(char mode)
Set mode condition.
std::vector< std::map< int, Idx > > mStateFaudesIndex
mapping from vector state idx to faudes index
unsigned long word_t
Code-generator internal data type of target words.
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
std::vector< std::vector< int > > mTransitionVector
compiled transition-sets, represented as vectors of integers with 0 as separator
virtual void Comment(const std::string &text)
Write a comment (reimplement in derived classes, call base)
void Insert(const std::string &file)
Add a Generator from file.
EventSet mInputEvents
used events that are configured as inputs (incl timer)
FlagIterator FlagsEnd()
Access to flag records by iterator.
virtual void Generate(void)
Generate code.
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
char mMuteMode
current output mode
virtual void Clear(void)
Clear all data.
std::map< std::string, ActionAddress > mActionAddresses
action addresses
virtual void Compile(void)
Compile input data for alternative representation.
virtual void IndentDec()
Indentation (convenience support for derived classes)
EventSet mStopEvents
Events that stop this timer.
word_t WordFromBitVector(const std::vector< bool > &vect, int wordindex)
Extract individual word from boolean vector.
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
TimerIterator TimersBegin()
Access to timer records by iterator.
EventSet mInternalEvents
used events that are configured as internal events (excl.
std::map< int, Idx > mEventFaudesIdx
mapping from bit address to faudes event idx
Code-generator common base class.
virtual void DoCompile(void)
virtual hook to input parameter compilation
std::map< std::string, TimerConfiguration > mTimers
timer definitions
std::string EventName(Idx index) const
Faudes-event name lookup.
std::map< std::string, LineAddress > mLines
input event generation
LineIterator LinesBegin()
Access to line records by iterator.
Code-generation common base.
virtual void MuteVspace(bool on)
Mute empty lines (convenience support for derived classes)
std::string mInitialValue
Initial value (literal to allow for advanced units, empty string for "not a timer") ...
static void Register(const std::string &type, CodeGenerator *(*newcg)(void))
Insert derived class in the registry.
int mLastOutputEvent
highest bit-address with output event (-1 for none)
bool mMuteComments
mute comments
virtual int EventTargetIdx(Idx idx)
Get target event Idx from faudes Idx (use bit-address + 1)
virtual ~CodeGenerator(void)
Destructor.
std::vector< TimedGenerator > mGenerators
list of executors
int EventBitMaskSize(void)
Get overall number of events.
TimerIterator TimersEnd()
Access to timer records by iterator.