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]" <<
";";
273 Output() << ToStringInteger(gid) <<
": "
274 <<
mPrefix <<
"state_lookup_f" <<
" := CONCAT('s'," <<
mIntegerType <<
"_TO_STRING(IDX))" <<
";";
279 Output() <<
"END_FUNCTION";
288 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::StateReset()");
303 Comment(
"elapsed time since last invokation");
318 std::string lineaddr= lit->second.mAddress;
319 if(lineaddr.size()<1)
continue;
320 if(lineaddr.at(0)==
'%') iocnt++;
324 if(!ait->second.mSetClr)
continue;
325 std::string actaddr= ait->second.mAddress;
326 if(actaddr.size()<1)
continue;
327 if(actaddr.at(0)==
'%') ++iocnt;
334 Comment(
"import physical i/o addresses");
337 std::string lineaddr= lit->second.mAddress;
338 if(lineaddr.size()<1)
continue;
339 if(lineaddr.at(0)==
'%') {
340 Output() <<
"AT " << lineaddr <<
" : BOOL;";
346 if(!ait->second.mSetClr)
continue;
347 std::string actaddr= ait->second.mAddress;
348 if(actaddr.size()<1)
continue;
349 if(actaddr.at(0)==
'%') {
350 Output() <<
"AT " << actaddr <<
" : BOOL;";
363 std::string lineaddr= lit->second.mAddress;
364 if(lineaddr.size()<1)
continue;
365 if(lineaddr.at(0)!=
'%') iocnt++;
369 if(!ait->second.mSetClr)
continue;
370 std::string actaddr= ait->second.mAddress;
371 if(actaddr.size()<1)
continue;
372 if(actaddr.at(0)!=
'%') ++iocnt;
378 Comment(
"import i/o variables and addresses");
381 std::string lineaddr= lit->second.mAddress;
382 if(lineaddr.size()<1)
continue;
383 if(lineaddr.at(0)!=
'%') {
390 if(!ait->second.mSetClr)
continue;
391 std::string actaddr= ait->second.mAddress;
392 if(actaddr.size()<1)
continue;
393 if(actaddr.at(0)!=
'%') {
405 Comment(
"************************************************");
406 Comment(
"* extra cyclic code from configuration *");
410 Comment(
"* end of extra code from configuration *");
411 Comment(
"************************************************");
437 Comment(
"************************************************");
438 Comment(
"* update timer states *");
445 AA cnt(
"timer_" + tit->second.mAddress +
"_cnt");
446 AA run(
"timer_" + tit->second.mAddress +
"_run");
482 Comment(
"iec timer to simulate system time");
492 Comment(
"do reset/track systime");
493 Output() <<
"IF " <<
mPrefix <<
"exec_event = -1 " <<
" THEN" << std::endl;
494 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=false);" << std::endl;
495 Output() <<
" " <<
mPrefix <<
"systime_recent := TIME#0ms;" << std::endl;
496 Output() <<
"END_IF;" << std::endl;
497 Output() <<
mPrefix <<
"systime_ton(IN:=true, PT:=TIME#2h, ET=>" <<
mPrefix <<
"systime_now);" << std::endl;
503 Output() <<
"IF " <<
mPrefix <<
"systime_now < TIME#1h THEN" << std::endl;
505 Output() <<
"ELSE" << std::endl;
506 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=false, PT:=TIME#2h);" << std::endl;
507 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=true, PT:=TIME#2h);" << std::endl;
508 Output() <<
" " <<
mPrefix <<
"systime_recent := TIME#0ms;" << std::endl;
509 Output() <<
"END_IF;" << std::endl;
532 Output() <<
"(* " << text <<
" *)";
541 if((ltype !=
mIntegerType) && (ltype !=
mWordType) && (ltype !=
"BOOL") && (ltype !=
"STRING") && (ltype !=
"TIME") && (ltype !=
"TON"))
542 FCG_ERR(
"Iec61131stCodeGenerator::VariableDeclare(): unsupported type [" << ltype <<
"]");
543 Output() << laddr <<
" : " << ltype <<
";";
548 if((ltype !=
mIntegerType) && (ltype !=
mWordType) && (ltype !=
"BOOL") && (ltype !=
"STRING") && (ltype !=
"TIME"))
549 FCG_ERR(
"Iec61131stCodeGenerator::VariableDeclare(): unsupported type [" << ltype <<
"]");
550 Output() << laddr <<
" : " << ltype <<
" := " << lval <<
";";
558 if(address==
"reset") res=
"RESET";
559 if(address==
"status") res=
"STATUS";
561 if(address==
"recent_event") res=
"RECENT_EVENT";
562 if(address.find(
"pending_events")==0)
563 if(address!=
"pending_events_t")
564 res=
"PENDING_EVENTS"+address.substr(14);
565 if(address.find(
"enabled_events")==0)
566 if(address!=
"enabled_events_t")
567 res=
"ENABLED_EVENTS"+address.substr(14);
570 if(address.find(
"parallel_state")==0)
571 if(address!=
"parallel_state_t")
572 res=
"PARALLEL_STATE"+address.substr(14);
575 if(res==
"") res=
mPrefix+address;
628 return AX(
"SHL( IN:=" +
WordConstant(1) +
" , N:=" + expression +
" )" );
638 std::string res(ToStringInteger(val));
642 FCG_ERR(
"Iec61131stCodeGenerator: unsupported integer data type");
785 std::stringstream sstr;
786 sstr <<
mWordType <<
"#16#" << std::setbase(16) << std::setfill(
'0');
787 if(
mWordType ==
"BYTE") sstr << std::setw(2) << (val & 0xff);
788 else if(
mWordType ==
"WORD") sstr << std::setw(4) << (val & 0xffff);
789 else if(
mWordType ==
"DWORD") sstr << std::setw(8) << (val & 0xffffffff);
790 else if(
mWordType ==
"LWORD") sstr << std::setw(16) << (val & 0xffffffffffffffff);
791 else FCG_ERR(
"Iec61131stCodeGenerator: unsupported word data type");
805 if(val) valstr=
"true";
else valstr=
"false";
812 if(val) valstr=
"true";
else valstr=
"false";
836 std::stringstream strstr;
838 if(val.size()<25) newline=25;
842 if(vit==val.size())
break;
845 if(vit==val.size())
break;
849 strstr << std::endl <<
" ";
854 return AX(strstr.str());
860 FCG_ERR(
"Iec61131stCodeGenerator::Cintarray(): ignoring empty const vector");
864 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): const vector exceeds address range");
879 return AA(address +
"[" + ToStringInteger(index) +
"]");
895 std::stringstream strstr;
897 if(val.size()<11) newline=15;
901 if(vit==val.size())
break;
904 if(vit==val.size())
break;
908 strstr << std::endl <<
" ";
913 return AX(strstr.str());
919 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): ignoring empty const vector");
923 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): const vector exceeds addres range");
938 return AA(address +
"[" + ToStringInteger(index) +
"]");
955 for(std::size_t i=0; i<val.length(); ++i) {
960 if(c==
'\'') { res.append(
"$'");
continue; }
962 if(c==
'$') { res.append(
"$$");
continue; }
964 if((c>=0x20) && (c<0x7f)) { res.append(1,c);
continue; };
966 FCG_ERR(
"EmbeddedcCodeGenerator: non-printable ascii or other encoding unsupported [" << val <<
"]");
974 std::stringstream strstr;
981 strstr <<
"[ " << std::endl;
985 if(vit==val.size())
break;
988 if(vit==val.size())
break;
997 return AX(strstr.str());
1004 FCG_ERR(
"Iec61131stCodeGenerator::Cstrarray(): ignoring empty const vector");
1008 FCG_ERR(
"Iec61131stCodeGenerator::Cstrarray(): const vector exceeds addres range");
1013 for(
size_t i=0; i<val.size(); ++i)
1014 if(val[i].size()>len) len=val[i].size();
1016 Output() <<
TargetAddress(address) <<
" : ARRAY[0.." << val.size()-1 <<
"] OF STRING[" << ToStringInteger(len) <<
"] := ";
1027 return AA(address +
"[" + ToStringInteger(index) +
"]");
1043 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): ignoring empty const vector");
1047 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): const vector exceeds addres range");
1063 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): ignoring empty const vector");
1067 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): const vector exceeds addres range");
1076 return AA(address +
"[" + ToStringInteger(index) +
"]");
1093 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): ignoring empty const vector");
1097 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): const vector exceeds addres range");
1113 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): ignoring empty const vector");
1117 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): const vector exceeds addres range");
1126 return AA(address +
"[" + ToStringInteger(index) +
"]");
1151 Output() <<
"IF " << expression <<
" THEN";
1158 Output() <<
"IF NOT " << expression <<
" THEN";
1181 Output() <<
"ELSIF " << expression <<
" THEN";
1211 FCG_VERB0(
"CodeGenerator: WARNING: inconsistent empty range of switch-cases");
1230 FCG_VERB0(
"CodeGenerator: WARNING: inconsistent empty range of switch-cases");
1235 int from=*vals.begin();
1236 int to= *(--vals.end());
1237 if(to+1-from== (
int) vals.size()) {
1242 std::set< int >::const_iterator vit=vals.begin();
1243 for(; vit!=vals.end(); ++ vit) {
1244 if(vit!=vals.begin())
Output() <<
", ";
1270 Output() <<
"WHILE true DO";
1277 Output() <<
"IF " << expression <<
" THEN EXIT; END_IF;";
1284 Output() <<
"END_WHILE;";
1320 std::string res(
"TIME#" + ToStringInteger(val) +
"ms");
1327 Output() << address <<
" := true;" ;
1331 Output() << address <<
" := false;" ;
1335 Output() << expression <<
";";
1339 Iec61131stCodeGenerator::IECVariableType Iec61131stCodeGenerator::CurrentVariableType(
void) {
1340 return mCurrentVariableType;
1343 void Iec61131stCodeGenerator::CurrentVariableType(
const IECVariableType & type) {
1344 mCurrentVariableType = type;