33 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::Iec61131stCodeGenerator()");
39 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::~Iec61131stCodeGenerator()");
45 FD_DCG(
"Iec61131stCodeGenerator::Clear()");
60 FD_DCG(
"Iec61131stCodeGenerator::DoReadTargetConfiguration()");
65 if(rTr.ExistsBegin(
"IecDeclarePhysical")) {
66 rTr.ReadBegin(
"IecDeclarePhysical",token);
68 rTr.ReadEnd(
"IecDeclarePhysical");
71 if(rTr.ExistsBegin(
"IncludeCyclic"))
73 if(rTr.ExistsBegin(
"IecTimeOperators")) {
74 rTr.ReadBegin(
"IecTimeOperators",token);
76 rTr.ReadEnd(
"IecTimeOperators");
82 FD_DCG(
"Iec61131stCodeGenerator::DoWriteTargetConfiguration()");
87 token.SetEmpty(
"IecDeclarePhysical");
93 token.SetEmpty(
"IecTimeOperators");
118 FCG_VERB1(
"Iec61131stCodeGenerator::Compile(): prefer compiled bitmasks over bit-address maths");
123 FCG_VERB1(
"Iec61131stCodeGenerator::Compile(): using array for state as return value datatype");
134 Comment(
"************************************************");
135 Comment(
"CodeGenerator: Target IEC 61131 Structured Text ");
136 Comment(
"************************************************");
149 Comment(
"************************************************");
150 Comment(
"CodeGenerator: Generated Code Ends Here ");
151 Comment(
"************************************************");
158 Comment(
"************************************************");
159 Comment(
"* function block to host cyclic code *");
160 Comment(
"************************************************");
191 Output() <<
"VAR_EXTERNAL";
209 Comment(
"************************************************");
210 Comment(
"* end of cyclic function block *");
212 Output() <<
"END_FUNCTION_BLOCK";
221 Comment(
"************************************************");
222 Comment(
"* function to host the event name loopup table *");
223 Comment(
"************************************************");
225 Output() <<
"FUNCTION " <<
mPrefix <<
"event_lookup_f" <<
" : STRING";
233 Output() <<
"VAR CONSTANT";
240 Output() <<
"END_FUNCTION";
245 Comment(
"************************************************");
246 Comment(
"* function to host state name loopup tables *");
247 Comment(
"************************************************");
249 Output() <<
"FUNCTION " <<
mPrefix <<
"state_lookup_f" <<
" : STRING";
259 Output() <<
"VAR CONSTANT";
266 Output() <<
"CASE GID OF";
268 for(
size_t gid=0; gid<
Size(); ++gid) {
270 Output() << ToStringInteger(gid) <<
": "
271 <<
mPrefix <<
"state_lookup_f" <<
" := " <<
mPrefix <<
"state_lookup_" << ToStringInteger(gid) <<
"[IDX]" <<
";";
276 Output() <<
"IF LEN(" <<
mPrefix <<
"state_lookup_f) = 0 THEN";
282 Output() <<
"END_FUNCTION";
291 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::StateReset()");
306 Comment(
"elapsed time since last invokation");
321 std::string lineaddr= lit->second.mAddress;
322 if(lineaddr.size()<1)
continue;
323 if(lineaddr.at(0)==
'%') iocnt++;
327 if(!ait->second.mSetClr)
continue;
328 std::string actaddr= ait->second.mAddress;
329 if(actaddr.size()<1)
continue;
330 if(actaddr.at(0)==
'%') ++iocnt;
337 Comment(
"import physical i/o addresses");
340 std::string lineaddr= lit->second.mAddress;
341 if(lineaddr.size()<1)
continue;
342 if(lineaddr.at(0)==
'%') {
343 Output() <<
"AT " << lineaddr <<
" : BOOL;";
349 if(!ait->second.mSetClr)
continue;
350 std::string actaddr= ait->second.mAddress;
351 if(actaddr.size()<1)
continue;
352 if(actaddr.at(0)==
'%') {
353 Output() <<
"AT " << actaddr <<
" : BOOL;";
366 std::string lineaddr= lit->second.mAddress;
367 if(lineaddr.size()<1)
continue;
368 if(lineaddr.at(0)!=
'%') iocnt++;
372 if(!ait->second.mSetClr)
continue;
373 std::string actaddr= ait->second.mAddress;
374 if(actaddr.size()<1)
continue;
375 if(actaddr.at(0)!=
'%') ++iocnt;
381 Comment(
"import i/o variables and addresses");
384 std::string lineaddr= lit->second.mAddress;
385 if(lineaddr.size()<1)
continue;
386 if(lineaddr.at(0)!=
'%') {
393 if(!ait->second.mSetClr)
continue;
394 std::string actaddr= ait->second.mAddress;
395 if(actaddr.size()<1)
continue;
396 if(actaddr.at(0)!=
'%') {
408 Comment(
"************************************************");
409 Comment(
"* extra cyclic code from configuration *");
413 Comment(
"* end of extra code from configuration *");
414 Comment(
"************************************************");
440 Comment(
"************************************************");
441 Comment(
"* update timer states *");
448 AA cnt(
"timer_" + tit->second.mAddress +
"_cnt");
449 AA run(
"timer_" + tit->second.mAddress +
"_run");
485 Comment(
"iec timer to simulate system time");
495 Comment(
"do reset/track systime");
496 Output() <<
"IF " <<
mPrefix <<
"exec_event = -1 " <<
" THEN" << std::endl;
497 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=false);" << std::endl;
498 Output() <<
" " <<
mPrefix <<
"systime_recent := TIME#0ms;" << std::endl;
499 Output() <<
"END_IF;" << std::endl;
500 Output() <<
mPrefix <<
"systime_ton(IN:=true, PT:=TIME#2h, ET=>" <<
mPrefix <<
"systime_now);" << std::endl;
506 Output() <<
"IF " <<
mPrefix <<
"systime_now < TIME#1h THEN" << std::endl;
508 Output() <<
"ELSE" << std::endl;
509 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=false, PT:=TIME#2h);" << std::endl;
510 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=true, PT:=TIME#2h);" << std::endl;
511 Output() <<
" " <<
mPrefix <<
"systime_recent := TIME#0ms;" << std::endl;
512 Output() <<
"END_IF;" << std::endl;
535 Output() <<
"(* " << text <<
" *)";
544 if((ltype !=
mIntegerType) && (ltype !=
mWordType) && (ltype !=
"BOOL") && (ltype !=
"STRING") && (ltype !=
"TIME") && (ltype !=
"TON"))
545 FCG_ERR(
"Iec61131stCodeGenerator::VariableDeclare(): unsupported type [" << ltype <<
"]");
546 Output() << laddr <<
" : " << ltype <<
";";
551 if((ltype !=
mIntegerType) && (ltype !=
mWordType) && (ltype !=
"BOOL") && (ltype !=
"STRING") && (ltype !=
"TIME"))
552 FCG_ERR(
"Iec61131stCodeGenerator::VariableDeclare(): unsupported type [" << ltype <<
"]");
553 Output() << laddr <<
" : " << ltype <<
" := " << lval <<
";";
561 if(address==
"reset") res=
"RESET";
562 if(address==
"status") res=
"STATUS";
564 if(address==
"recent_event") res=
"RECENT_EVENT";
565 if(address.find(
"pending_events")==0)
566 if(address!=
"pending_events_t")
567 res=
"PENDING_EVENTS"+address.substr(14);
568 if(address.find(
"enabled_events")==0)
569 if(address!=
"enabled_events_t")
570 res=
"ENABLED_EVENTS"+address.substr(14);
573 if(address.find(
"parallel_state")==0)
574 if(address!=
"parallel_state_t")
575 res=
"PARALLEL_STATE"+address.substr(14);
578 if(res==
"") res=
mPrefix+address;
631 return AX(
"SHL( IN:=" +
WordConstant(1) +
" , N:=" + expression +
" )" );
641 std::string res(ToStringInteger(val));
645 FCG_ERR(
"Iec61131stCodeGenerator: unsupported integer data type");
788 std::stringstream sstr;
789 sstr <<
mWordType <<
"#16#" << std::setbase(16) << std::setfill(
'0');
790 if(
mWordType ==
"BYTE") sstr << std::setw(2) << (val & 0xff);
791 else if(
mWordType ==
"WORD") sstr << std::setw(4) << (val & 0xffff);
792 else if(
mWordType ==
"DWORD") sstr << std::setw(8) << (val & 0xffffffff);
793 else if(
mWordType ==
"LWORD") sstr << std::setw(16) << (val & 0xffffffffffffffff);
794 else FCG_ERR(
"Iec61131stCodeGenerator: unsupported word data type");
808 if(val) valstr=
"true";
else valstr=
"false";
815 if(val) valstr=
"true";
else valstr=
"false";
839 std::stringstream strstr;
841 if(val.size()<25) newline=25;
845 if(vit==val.size())
break;
848 if(vit==val.size())
break;
852 strstr << std::endl <<
" ";
857 return AX(strstr.str());
863 FCG_ERR(
"Iec61131stCodeGenerator::Cintarray(): ignoring empty const vector");
867 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): const vector exceeds address range");
882 return AA(address +
"[" + ToStringInteger(index) +
"]");
898 std::stringstream strstr;
900 if(val.size()<11) newline=15;
904 if(vit==val.size())
break;
907 if(vit==val.size())
break;
911 strstr << std::endl <<
" ";
916 return AX(strstr.str());
922 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): ignoring empty const vector");
926 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): const vector exceeds addres range");
941 return AA(address +
"[" + ToStringInteger(index) +
"]");
958 for(std::size_t i=0; i<val.length(); ++i) {
963 if(c==
'\'') { res.append(
"$'");
continue; }
965 if(c==
'$') { res.append(
"$$");
continue; }
967 if((c>=0x20) && (c<0x7f)) { res.append(1,c);
continue; };
969 FCG_ERR(
"EmbeddedcCodeGenerator: non-printable ascii or other encoding unsupported [" << val <<
"]");
977 std::stringstream strstr;
984 strstr <<
"[ " << std::endl;
988 if(vit==val.size())
break;
991 if(vit==val.size())
break;
1000 return AX(strstr.str());
1007 FCG_ERR(
"Iec61131stCodeGenerator::Cstrarray(): ignoring empty const vector");
1011 FCG_ERR(
"Iec61131stCodeGenerator::Cstrarray(): const vector exceeds addres range");
1016 for(
size_t i=0; i<val.size(); ++i)
1017 if(val[i].size()>len) len=val[i].size();
1019 Output() <<
TargetAddress(address) <<
" : ARRAY[" << offset <<
".." << val.size()+offset-1 <<
"] OF STRING[" << ToStringInteger(len) <<
"] := ";
1030 return AA(address +
"[" + ToStringInteger(index) +
"]");
1046 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): ignoring empty const vector");
1050 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): const vector exceeds addres range");
1066 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): ignoring empty const vector");
1070 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): const vector exceeds addres range");
1079 return AA(address +
"[" + ToStringInteger(index) +
"]");
1096 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): ignoring empty const vector");
1100 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): const vector exceeds addres range");
1116 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): ignoring empty const vector");
1120 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): const vector exceeds addres range");
1129 return AA(address +
"[" + ToStringInteger(index) +
"]");
1154 Output() <<
"IF " << expression <<
" THEN";
1161 Output() <<
"IF NOT " << expression <<
" THEN";
1184 Output() <<
"ELSIF " << expression <<
" THEN";
1214 FCG_VERB0(
"CodeGenerator: WARNING: inconsistent empty range of switch-cases");
1233 FCG_VERB0(
"CodeGenerator: WARNING: inconsistent empty range of switch-cases");
1238 int from=*vals.begin();
1239 int to= *(--vals.end());
1240 if(to+1-from== (
int) vals.size()) {
1245 std::set< int >::const_iterator vit=vals.begin();
1246 for(; vit!=vals.end(); ++ vit) {
1247 if(vit!=vals.begin())
Output() <<
", ";
1273 Output() <<
"WHILE true DO";
1280 Output() <<
"IF " << expression <<
" THEN EXIT; END_IF;";
1287 Output() <<
"END_WHILE;";
1323 std::string res(
"TIME#" + ToStringInteger(val) +
"ms");
1330 Output() << address <<
" := true;" ;
1334 Output() << address <<
" := false;" ;
1338 Output() << expression <<
";";
1342 Iec61131stCodeGenerator::IECVariableType Iec61131stCodeGenerator::CurrentVariableType(
void) {
1343 return mCurrentVariableType;
1346 void Iec61131stCodeGenerator::CurrentVariableType(
const IECVariableType & type) {
1347 mCurrentVariableType = type;
#define FAUDES_REGISTERCODEGENERATOR(ftype, ctype)
Class registration macro.
Code-generator for target IEC 61131-3 ST.
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
LineIterator LinesEnd()
Access to line records by iterator.
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
TimerIterator TimersBegin()
Access to timer records by iterator.
virtual void IndentInc()
Indentation (convenience support for derived classes)
TimerIterator TimersEnd()
Access to timer records by iterator.
std::map< std::string, TimerConfiguration >::iterator TimerIterator
Access to timer records by iterator.
int mWordSize
compressed boolean capacity of target type word
bool mMuteComments
mute comments
LineIterator LinesBegin()
Access to line records by iterator.
int mIntegerSize
compressed boolean capacity of target type integer
virtual std::ostream & Output(void)
Output stream.
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
virtual const std::string & Name(void) const
Get objects's name (reimplementing base faudes::Type)
Idx Size(void) const
Number 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.
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
unsigned long word_t
Code-generator internal data type of target words.
Abstract address; see also Absstract_Addresses.
Abstract expression; see also Absstract_Addresses.
Execution semantics in terms of code primitives.
virtual void DeclareTimers(void)
Use target implementation to declare timers, typically "timer_run_*" and "timer_cnt_*".
bool mBitAddressArithmetic
code option: compute bit and word address on target
std::string mStateUpdateHook
code option: state change hook
virtual void DeclareSmallCarray(void)
Declare bit-mask loop-ups.
virtual void DoGenerateResetCode(void)
cut-and-paste template for code snippet assembly
bool mArrayForState
code option: use int arrays to represent that overall state
virtual void DeclareReset(void)
Declare "reset".
virtual void LiteralAppend(void)
Cosmetic: append literally from configuration.
virtual void DeclareStatus(void)
Declare "status".
virtual void DeclareRecentEvent(void)
Declare "recent_event".
virtual void Comment(const std::string &text)
Target comments (see EmbeddedcCodeGenerator for consistent reimplementation pattern)
virtual void DeclareAux(void)
Declare variables local to the provided snippets, e.g. helpers for bit-mask computation.
bool mEventNameLookup
code option: event name lookup
virtual void DeclareEventNameLookup(void)
Declare symbolic name lookup tables.
std::map< std::string, bitarray_rec > mBitarrays
Record of all declared bit-arrays.
bool mStateNameLookup
code option: state name lookup
virtual void DoReadTargetConfiguration(TokenReader &rTr)
re-implement token i/o for extra configuration
virtual void DeclareParallelState(void)
Declare "parallel_state".
std::string mIntegerType
target data type for integer
virtual void DeclareLoopState(void)
Declare loop state, i.e. line levels, loop flag.
virtual void DoGenerateCyclicCode(void)
cut-and-paste template for code snippet assembly
virtual void Clear(void)
Clear all data.
std::string mWordType
target data type for word
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
re-implement token i/o for extra configuration
virtual void DeclareLargeCarray(void)
Declare compiled transition relations.
virtual void ResetState(void)
Reset state.
bool mArrayForBitmasks
code option: use const array to represent bit-masks
virtual void DeclareStateNameLookup(void)
Declare symbolic name lookup tables.
virtual void DoCompile(void)
virtual hook to extend compiled data
virtual void LiteralPrepend(void)
Cosmetic: prepend literally from configuration data.
std::vector< bool > mHasStateNames
record per generator whether there is a lookup table
virtual void DeclarePendingEvents(void)
Declare "pending_events" and "enabled_events".
std::string mPrefix
universal prefix (pseudo name space)
std::string mEventExecutionHook
code option: event exec hook
Implementation of primitives by IEC 61131 ST.
virtual void WordNand(const AA &address, const AX &expression)
generate code: conditionals
virtual AX IntegerIsEq(const AA &address, int val)
generate code: conditionals
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
virtual void RunActionSet(const std::string &address)
generate code: conditionals
virtual void IfElseIfTrue(const AX &expression)
generate code: conditionals
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
virtual AX IntegerIsLess(const AA &address, int val)
generate code: conditionals
virtual void DeclareImportPhysicalIo(void)
generate code: conditionals
virtual void UpdateSystime(void)
generate code: conditionals
virtual AX BooleanIsNotEq(const AA &op1, const AA &op2)
generate code: conditionals
virtual void CintarrayDeclare(const AA &address, int offset, const std::vector< int > &val)
generate code: conditionals
virtual void IfFalse(const AX &expression)
generate code: conditionals
virtual bool HasCintarray(void)
generate code: conditionals
virtual void WordDeclare(const AA &address)
generate code: conditionals
virtual bool HasWordarray(void)
generate code: conditionals
virtual void IfTrue(const AX &expression)
generate code: conditionals
virtual void BooleanDeclare(const AA &address)
generate code: conditionals
virtual ~Iec61131stCodeGenerator(void)
Explicit destructor.
virtual AX BooleanIsEq(const AA &op1, const AA &op2)
generate code: conditionals
virtual void BooleanAssign(const AA &address, int val)
generate code: conditionals
virtual void IfWord(const AX &expression)
generate code: conditionals
virtual AX WordIsEq(const AA &address, word_t val)
generate code: conditionals
virtual void InsertExecHooks(void)
generate code: conditionals
virtual void TimerDeclare(const AA &address, const std::string &val)
generate code: conditionals
void DoGenerate(void)
code generation hook (overall)
virtual void Clear(void)
Clear all data.
virtual void SwitchEnd(void)
generate code: conditionals
virtual void LoopEnd(void)
generate code: conditionals
virtual AX WordarrayConstant(const std::vector< word_t > &val)
generate code: conditionals
virtual AX StrarrayConstant(const std::vector< std::string > &val)
generate code: conditionals
virtual void TimerStart(const AA &address)
generate code: conditionals
virtual void WordAssign(const AA &address, word_t val)
generate code: conditionals
virtual AA CstrarrayAccess(const AA &address, int index)
generate code: conditionals
virtual void DeclareSystime(void)
generate code: conditionals
virtual AX WordIsNotEq(const AA &address, word_t val)
generate code: conditionals
virtual void WordarrayDeclare(const AA &address, int offset, int len)
generate code: conditionals
virtual AX StringConstant(const std::string &val)
generate code: conditionals
virtual void Comment(const std::string &text)
generate code: conditionals
virtual void TimerReset(const AA &address, const std::string &val)
generate code: conditionals
virtual AX IntegerConstant(int val)
generate code: conditionals
virtual void DecrementTimers(void)
code snippet
virtual AX IntegerRemainder(const AX &expression, int val)
generate code: conditionals
std::string mLiteralCyclic
option: extra cyclic code
virtual void IfEnd(void)
generate code: conditionals
virtual bool HasIntarray(void)
generate code: conditionals
virtual AA CintarrayAccess(const AA &address, int index)
generate code: conditionals
void DoCompile(void)
add my preferences to DoCompile
virtual void DeclareImportSymbolicIo(void)
generate code: conditionals
virtual AX IntarrayConstant(const std::vector< int > &val)
generate code: conditionals
virtual AX WordIsMaskSet(const AA &address, word_t mask)
generate code: conditionals
virtual std::string TargetAddress(const AA &address)
abstract address conversion
virtual bool HasCwordarray(void)
generate code: conditionals
virtual int CountImportPhysicalIo(void)
generate code: conditionals
virtual AX IntegerIsGreater(const AA &address, int val)
generate code: conditionals
virtual void RunActionClr(const std::string &address)
generate code: conditionals
virtual AX TimeConstant(int val)
generate code: conditionals
virtual AX WordIsBitSet(const AA &address, int idx)
generate code: conditionals
virtual bool HasIntmaths(void)
generate code: conditionals
virtual AA WordarrayAccess(const AA &address, int index)
generate code: conditionals
virtual void DoGenerateLookups(void)
code generation hook (lookup functions)
virtual AX TimerIsElapsed(const AA &address)
generate code: conditionals
virtual void LoopBegin(void)
generate code: conditionals
virtual void WordOr(const AA &address, word_t val)
generate code: conditionals
virtual void ResetState(void)
generate code: conditionals
virtual void SwitchBegin(const AA &address)
generate code: conditionals
virtual void RunActionExe(const AX &expression)
generate code: conditionals
virtual void CstrarrayDeclare(const AA &address, int offset, const std::vector< std::string > &val)
generate code: conditionals
virtual AX WordIsBitClr(const AA &address, int idx)
generate code: conditionals
virtual void LoopBreak(const AX &expression)
generate code: conditionals
virtual void SwitchBreak(void)
generate code: conditionals
virtual AA IntarrayAccess(const AA &address, int index)
generate code: conditionals
virtual AX IntegerIsNotEq(const AA &address, int val)
generate code: conditionals
virtual void IntegerAssign(const AA &address, int val)
generate code: conditionals
virtual void IfElse(void)
generate code: conditionals
virtual void WordAnd(const AA &address, word_t val)
generate code: conditionals
virtual void IntegerDeclare(const AA &address)
generate code: conditionals
virtual void SwitchCases(const AA &address, int from, int to)
generate code: conditionals
virtual void DeclareTimers(void)
generate code: conditionals
bool mHasIecTimeOperators
option: overloaded operators for time maths
virtual void VariableDeclare(const std::string &laddr, const std::string <ype)
generate code: conditionals
virtual AX IntegerBitmask(const AX &expression)
generate code: conditionals
virtual void IntegerIncrement(const AA &address, int val)
generate code: conditionals
Iec61131stCodeGenerator(void)
Constructor.
virtual bool HasMultiCase(void)
generate code: conditionals
virtual void CwordarrayDeclare(const AA &address, int offset, const std::vector< word_t > &val)
generate code: conditionals
virtual AX WordConstant(word_t val)
generate code: conditionals
virtual bool HasCstrarray(void)
generate code: conditionals
virtual AA CwordarrayAccess(const AA &address, int index)
generate code: conditionals
virtual void IntarrayDeclare(const AA &address, int offset, int len)
generate code: conditionals
virtual void SwitchCase(const AA &address, int val)
generate code: conditionals
virtual void DoGenerateFunction(void)
code generation hook (function block)
virtual void TimerStop(const AA &address)
generate code: conditionals
virtual int CountImportSymbolicIo(void)
generate code: conditionals
virtual void FunctionReturn(void)
generate code: conditionals
virtual AX TargetExpression(const AA &address)
abstract address conversion
std::string mIecDeclarePhysical
option: formal declaration of io lines
virtual AX IntegerQuotient(const AX &expression, int val)
generate code: conditionals
virtual void LiteralCyclic(void)
generate code: conditionals