CompileDES 3.14
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
20CodeGenerator implementation: source data organisation
21
22******************************************************************
23******************************************************************
24******************************************************************
25*/
26
27
28// CodeGenerator(void)
29CodeGenerator::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
45std::map< std::string, CodeGenerator* (*)(void) >* CodeGenerator::mpsRegistry=0;
46
47// Register(type)
48void 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)
54std::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)
63CodeGenerator* 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)
79void 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)
93void 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()
104Idx CodeGenerator::Size(void) const {
105 return (Idx) mGenerators.size();
106}
107
108//DoReadTargetConfiguration(rTr)
110 (void) rTr;
111}
112
113
114//DoReadGenerators(rTr)
115void 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(PrependPath(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)
151void 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)
196void CodeGenerator::DoWriteTargetConfiguration(TokenWriter& rTw) const {
197 (void) rTw;
198}
199
200//DoWriteGenerators(rTr,rLabel)
201void 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);
219void 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
239 std::stringstream res;
240 res << COMPILEDES_VERSION << " (using " << faudes::VersionString() << ")";
241 return res.str();
242}
243
244/*
245******************************************************************
246******************************************************************
247******************************************************************
248
249CodeGenerator 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();
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
501int 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
514std::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
528std::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
549CodeGenerator::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
559std::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
571const std::vector<int>& CodeGenerator::TransitionVector(size_t git) {
572 return mTransitionVector[git];
573}
574
575// default target state index refers to vector representation
576int 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
585Idx 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
597
598// access compiled data
602
603// access compiled data
607
608// access compiled data
612
613// access compiled data
617
618// access compiled data
622
623// access compiled data
627
628// access compiled data
632
633// access compiled data
637
638// access compiled data
642
643
644// control error out
645void CodeGenerator::Verbose(int level, std::ostream* altout) {
646 mVerbLevel=level;
647 if(altout!=0) pErrStream=altout;
648}
649
650/*
651******************************************************************
652******************************************************************
653******************************************************************
654
655CodeGenerator 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
691std::ostream& CodeGenerator::Output(void) {
692 return *pOutStream;
693}
694
695const std::string& CodeGenerator::OutputString(void) {
696 static std::string ems("");
697 if(!pOutBuffer) return ems;
698 return pOutBuffer->Buffer();
699}
700
701void 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
708void CodeGenerator::MuteMode(char mode) {
709 mMuteMode=mode;
710 if(!pOutBuffer) return;
711 pOutBuffer->Mute(mode!='*');
712};
713
714
715// generate output
716void 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
727void 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)
760void CodeGenerator::Comment(const std::string& text) {
761 if(mMuteComments)
763 if(pOutBuffer)
764 if(pOutBuffer->Mute())
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
790CodeGenerator::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
829CodeGenerator::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)
838std::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
887void 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
904const std::string& CodeGenerator::cgp_streambuf::Buffer(){
905 return mBuffer;
906}
907
908// implement output buffer
909void CodeGenerator::cgp_streambuf::Clear(void){
910 Flush();
911 mLines=0;
912 mBeginOfLine=true;
913 mBuffer.clear();
914}
915
916 // implementation of output buffer
917int CodeGenerator::cgp_streambuf::LineCount() {
918 Flush();
919 return mLines;
920};
921
922
923// implementation of output buffer
924void CodeGenerator::cgp_streambuf::IndentInc() {
925 mIndent+=2;
926};
927
928// implementation of output buffer
929void CodeGenerator::cgp_streambuf::IndentDec() {
930 mIndent-=2;
931};
932
933// implementation of output buffer
934void CodeGenerator::cgp_streambuf::XmlTextEscape(bool on) {
935 Flush();
936 mCdataEscape=false;
937 mTextEscape=on;
938};
939
940// implementation of output buffer
941void CodeGenerator::cgp_streambuf::XmlCdataEscape(bool on) {
942 Flush();
943 mTextEscape=false;
944 mCdataEscape=on;
945};
946
947// implementation of output buffer
948void CodeGenerator::cgp_streambuf::Mute(bool on) {
949 Flush();
950 mMute=on;
951};
952
953// implementation of output buffer
954bool CodeGenerator::cgp_streambuf::Mute() {
955 return mMute;
956};
957
958// implementation of output buffer
959void 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)
std::vector< OutputAction > mActions
List of actions to perform (output events only)
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 "]]>")
virtual const std::string & Name(void) const
Get objects's name (reimplementing base faudes::Type)
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)
const TimedGenerator & At(int i) const
Direct access for read-only access of generators.
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, ActionAddress >::iterator ActionAddressIterator
Access to action record 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, 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.
std::map< std::string, TimerConfiguration >::iterator TimerIterator
Access to timer records by iterator.
virtual std::ostream & Output(void)
Output stream.
std::map< std::string, TimerAction > mTimerActions
timer actions by event name
virtual void MuteCond(char mode)
Set mode condition.
std::vector< word_t > WordVectorFromBitVector(const std::vector< bool > &vect)
Convert boolean vector to word array.
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
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.
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.
std::map< std::string, FlagExpression >::iterator FlagIterator
Access to flag records by iterator.
virtual void IndentDec()
Indentation (convenience support for derived classes)
ActionAddressIterator ActionAddressesEnd()
Access to action addresses 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.