CompileDES  3.13
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 
Code-generator common base class.
Event attributes for the purpose of code generation.
TimeConstraint mTimeConstraint
Timer definition (indicate timer event iff mInitialValue non-empty)
EventSet mResetEvents
Events that reset this timer.
std::string mInitialValue
Initial value (literal to allow for advanced units, empty string for "not a timer")
EventSet mStopEvents
Events that stop this timer.
EventSet mStartEvents
Events that start this timer.
Code-generation common base.
std::string mOutMode
output file name (base)
virtual std::string LineCount(void)
LineFeed (convenience support for derived classes)
char mMuteMode
current output mode
std::string EventName(Idx index) const
Faudes-event name lookup.
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
virtual void XmlCdataEscape(bool on)
XmlCdataEscape (escape "]]>")
std::map< Idx, int > mEventBitAddress
mapping from faudes event idx to bit address (descending priority, range 0 .
int EventBitAddress(Idx idx)
Get event bit-address from faudes Idx (consecutive, starts at 0)
LineIterator LinesEnd()
Access to line records by iterator.
static std::vector< std::string > Registry(void)
Access registry contents.
std::vector< bool > EventBitMask(Idx idx)
Get vector representation for a single faudes event Idx.
std::vector< int > mWordAddressVector
Look-up table to map a bit-address to the word-index.
std::vector< word_t > mBitMaskVector
Look-up table to map a bit-address to the word-bitmask.
int mLastInputEvent
highest bit-address with input (or timer) event (-1 for none)
virtual void XmlTextEscape(bool on)
XmlTextEscape (escape "<", ">", "&", "\"" and "'")
virtual void MuteComments(bool on)
Mute comments (convenience support for derived classes)
std::vector< std::map< int, Idx > > mStateFaudesIndex
mapping from vector state idx to faudes index
virtual void DoReadTargetConfiguration(TokenReader &rTr)
Reads global configuration from TokenReader, excl.
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
virtual void DoGenerate(void)=0
pure virtual interface to code generation
std::ostream * pErrStream
error stream
std::string mRecentMutedComment
recent muted comment
std::vector< std::vector< int > > mTransitionVector
compiled transition-sets, represented as vectors of integers with 0 as separator
EventSet mInternalEvents
used events that are configured as internal events (excl.
int mLastOutputEvent
highest bit-address with output event (-1 for none)
FlagIterator FlagsBegin()
Access to flag records by iterator.
int EventBitMaskSize(void)
Get overall number of events.
static CodeGenerator * New(const std::string &type)
Instantiate by identifier (returns 0 on unknown class)
TimerIterator TimersBegin()
Access to timer records by iterator.
static void Register(const std::string &type, CodeGenerator *(*newcg)(void))
Insert derived class in the registry.
virtual void IndentInc()
Indentation (convenience support for derived classes)
virtual ~CodeGenerator(void)
Destructor.
EventSet mOutputEvents
used events that are configured as outputs
TimerIterator TimersEnd()
Access to timer records by iterator.
Idx EventIndex(const std::string &rName) const
Faudes-event index lookup.
std::map< std::string, TimerConfiguration >::iterator TimerIterator
Access to timer records by iterator.
std::map< std::string, LineAddress > mLines
input event generation
Idx EventFaudesIdx(int idx)
Get faudes Idx from target Idx (aka from bit-address + 1)
TimerActionIterator TimerActionsBegin()
Access to timer records by iterator.
int mWordSize
compressed boolean capacity of target type word
std::map< int, Idx > mEventFaudesIdx
mapping from bit address to faudes event idx
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.
virtual void MuteMode(char mode)
Set current mute mode.
virtual void DoRead(TokenReader &rTr, const std::string &rLabel="", const Type *pContext=0)
Read the configuration from TokenReader, see faudes Type for public wrappers.
std::ostream * pOutStream
output stream
std::vector< TimedGenerator > mGenerators
list of executors
bool mMuteComments
mute comments
virtual Idx StateFaudesIdx(size_t git, int idx)
Get faudes state index (refer to vector representation as default, overload in CodePrimitives)
virtual int EventTargetIdx(Idx idx)
Get target event Idx from faudes Idx (use bit-address + 1)
LineIterator LinesBegin()
Access to line records by iterator.
int mVerbLevel
diagnpstic-output level
void Insert(const std::string &file)
Add a Generator from file.
int mIntegerSize
compressed boolean capacity of target type integer
std::map< std::string, ActionAddress > mActionAddresses
action addresses
EventSet mInputEvents
used events that are configured as inputs (incl timer)
FlagIterator FlagsEnd()
Access to flag records by iterator.
virtual std::ostream & Output(void)
Output stream.
std::map< std::string, TimerAction > mTimerActions
timer actions by event name
std::map< std::string, FlagExpression >::iterator FlagIterator
Access to flag records by iterator.
virtual void MuteCond(char mode)
Set mode condition.
std::vector< word_t > WordVectorFromBitVector(const std::vector< bool > &vect)
Convert boolean vector to word array.
void Verbose(int level, std::ostream *altout=0)
Set verbosity level.
virtual void MuteVspace(bool on)
Mute empty lines (convenience support for derived classes)
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
virtual void DoCompile(void)
virtual hook to input parameter compilation
std::vector< std::map< Idx, int > > mStateVectorAddress
mapping from faudes state idx to vector index
virtual void Compile(void)
Compile input data for alternative representation.
cgEventSet mAlphabet
event configuration by attributes
virtual void Comment(const std::string &text)
Write a comment (reimplement in derived classes, call base)
word_t WordFromBitVector(const std::vector< bool > &vect, int wordindex)
Extract individual word from boolean vector.
CodeGenerator(void)
Constructor.
virtual const std::string & Name(void) const
Get objects's name (reimplementing base faudes::Type)
const std::string & OutputString(void)
Get accumulated output as string.
virtual void Clear(void)
Clear all data.
const std::vector< int > & TransitionVector(size_t git)
Get target state index (refer to vector representation as default, overload in CodePrimitives)
std::vector< std::string > mGeneratorNames
list of filenames when generator are read from file
std::vector< bool > mUsingVectorAddressStates
configuration of state indexing per generator
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, TimerConfiguration > mTimers
timer definitions
virtual void Generate(void)
Generate code.
const TimedGenerator & At(int i) const
Direct access for read-only access of generators.
virtual void IndentDec()
Indentation (convenience support for derived classes)
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record by iterator.
TimerActionIterator TimerActionsEnd()
Access to timer records by iterator.
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
Write global configuration to TokenWriter, excl.
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
std::map< std::string, FlagExpression > mFlags
input event generation
unsigned long word_t
Code-generator internal data type of target words.
EventSet mUsedEvents
configured events that are referred to by some generator
std::map< std::string, TimerAction >::iterator TimerActionIterator
Access to timer records by iterator.