stage4/generate_cc/plciec.h
changeset 0 fb772792efd1
child 16 e8b99f896416
equal deleted inserted replaced
-1:000000000000 0:fb772792efd1
       
     1 /*
       
     2  * (c) 2003 Mario de Sousa
       
     3  *
       
     4  * Offered to the public under the terms of the GNU General Public License
       
     5  * as published by the Free Software Foundation; either version 2 of the
       
     6  * License, or (at your option) any later version.
       
     7  *
       
     8  * This program is distributed in the hope that it will be useful, but
       
     9  * WITHOUT ANY WARRANTY; without even the implied warranty of
       
    10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
       
    11  * Public License for more details.
       
    12  *
       
    13  * This code is made available on the understanding that it will not be
       
    14  * used in safety-critical situations without a full and competent review.
       
    15  */
       
    16 
       
    17 /*
       
    18  * An IEC 61131-3 IL and ST compiler.
       
    19  *
       
    20  * Based on the
       
    21  * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
       
    22  *
       
    23  */
       
    24 
       
    25 
       
    26 /*
       
    27  * Code to be included into the code generated by the 4th stage.
       
    28  *
       
    29  * This is part of the 4th stage that generates
       
    30  * a c++ source program equivalent to the IL and ST
       
    31  * code.
       
    32  */
       
    33 
       
    34 
       
    35 #ifndef __PLCIEC_H
       
    36 #define __PLCIEC_H
       
    37 
       
    38 //#include <stdio.h>
       
    39 #include "plc.h"
       
    40 #include <math.h>
       
    41 #include <time.h>
       
    42 
       
    43 
       
    44 
       
    45 /* function that generates an IEC runtime error */
       
    46 void IEC_error(void) {
       
    47   /* TODO... */
       
    48   fprintf(stderr, "IEC 61131-3 runtime error.\n");
       
    49   exit(1);
       
    50 }
       
    51 
       
    52 
       
    53 
       
    54 typedef bool	BOOL;
       
    55 #define TRUE true
       
    56 #define FALSE false
       
    57 
       
    58 typedef i8	SINT;
       
    59 typedef i16	INT;
       
    60 typedef i32	DINT;
       
    61 typedef i64	LINT;
       
    62 
       
    63 typedef u8	USINT;
       
    64 typedef u16	UINT;
       
    65 typedef u32	UDINT;
       
    66 typedef u64	ULINT;
       
    67 
       
    68 typedef u8	BYTE;
       
    69 typedef u16	WORD;
       
    70 typedef u32	DWORD;
       
    71 typedef u64	LWORD;
       
    72 
       
    73 typedef f32	REAL;
       
    74 typedef f64	LREAL;
       
    75 
       
    76 
       
    77 
       
    78 
       
    79 
       
    80 
       
    81 /*********************************************/
       
    82 /*     TIME AND DATE data trypes             */
       
    83 /*********************************************/
       
    84 
       
    85 /* NOTE: All the time and date data types use a struct timespec
       
    86  * internally to store the time and date. This is so as to ease all the
       
    87  * operations (add, subtract, multiply and division) the standard defines
       
    88  * on these same data types.
       
    89  * However, in order to ease the implementation of the comparison operators
       
    90  * (==, =>, <=, <, >, <>), the two elements in the timespec structure
       
    91  * must be handled in such a way as to guarantee the following:
       
    92  *  - The stored time is always the result of the operation tv_sec + tv_nsec*1e-9
       
    93  *  - tv_sec and tv_nsec will always have the same sign
       
    94  *      (i.e. either both positive or both negative)
       
    95  *  - tv_nsec always holds a value in the range ]-1, +1[ seconds.
       
    96  *      (note that -1 and +1 are excluded form the range)
       
    97  */
       
    98 
       
    99 
       
   100 /* NOTE: According to the C++ standard, the result of the % and / operations is implementation dependent
       
   101  *    when the at least one of the operands is negative! However, whatever the result of the operations, we are
       
   102  *    guaranteed that (a/b)*b + (a%b) is always equal to a.
       
   103  *    This means that, even knowing that both tv_sec and tv_sec always have the same sign (we make it so this is true),
       
   104  *    we must still re-normailze the result for both the addition and subtraction operations!
       
   105  */
       
   106 
       
   107 static inline void __normalizesign_timespec (struct timespec *ts) {
       
   108   if ((ts->tv_sec > 0) && (ts->tv_nsec < 0)) {
       
   109     ts->tv_sec--;
       
   110     ts->tv_nsec += 1000000000;
       
   111   }
       
   112   if ((ts->tv_sec < 0) && (ts->tv_nsec > 0)) {
       
   113     ts->tv_sec++;
       
   114     ts->tv_nsec -= 1000000000;
       
   115   }
       
   116 }
       
   117 
       
   118 
       
   119 static inline struct timespec __add_timespec (const struct timespec &t1, const struct timespec &t2) {
       
   120   /* NOTE the following sum works correctly because a long can hold a litle more than 2 seconds expressed in nano seconds! */
       
   121   long nsec;
       
   122   nsec = t1.tv_nsec + t2.tv_nsec;
       
   123   struct timespec ts;
       
   124   ts.tv_sec = t1.tv_sec + t2.tv_sec + (nsec / 1000000000);
       
   125   ts.tv_nsec = nsec % 1000000000;
       
   126 
       
   127   __normalizesign_timespec(&ts);
       
   128 
       
   129 return ts;
       
   130 }
       
   131 
       
   132 
       
   133 static inline struct timespec __sub_timespec (const struct timespec &t1, const struct timespec &t2) {
       
   134   /* NOTE the following subtraction works correctly because a long can hold a litle more than 2 seconds expressed in nano seconds! */
       
   135   long nsec = t1.tv_nsec - t2.tv_nsec;
       
   136   struct timespec ts;
       
   137   ts.tv_sec = t1.tv_sec - t2.tv_sec + nsec / 1000000000;
       
   138   ts.tv_nsec = nsec % 1000000000;
       
   139 
       
   140   __normalizesign_timespec(&ts);
       
   141 
       
   142   return ts;
       
   143 }
       
   144 
       
   145 
       
   146 static inline struct timespec __mul_timespec (const struct timespec &t1, const long double value) {
       
   147 #if 0
       
   148   /* A simple implementation that risks reducing the precision of the TIME value */
       
   149   long double sec_d1 = t1.tv_nsec / (long double)1e9 * value;
       
   150   long double sec_d2 = t1.tv_sec * value;
       
   151   long int sec = (long int)truncl(sec_d1 + sec_d2);
       
   152   struct timespec ts;
       
   153   ts.tv_sec = sec;
       
   154   ts.tv_nsec = (long int)((sec_d1 + sec_d2 - sec)*1e9);
       
   155   return ts;
       
   156 #else
       
   157   /* A more robust implementation that reduces the loss of precision of the TIME value */
       
   158   /* NOTE: The following assumes that the value stored in tv_nsec is never larger than 1 sec
       
   159    *  and is also based on the fact that tv_nsec can safely store slighlty more thanb 2 sec.
       
   160    */
       
   161   long double sec_d1 = t1.tv_nsec / (long double)1e9 * value;
       
   162   long double sec_d2 = t1.tv_sec * value;
       
   163   long int sec1 = (long int)sec_d1;
       
   164   long int sec2 = (long int)sec_d2;
       
   165   struct timespec ts;
       
   166   ts.tv_sec = sec1 + sec2;
       
   167   ts.tv_nsec = (long int)(((sec_d1 - sec1) + (sec_d2 - sec2))*1e9);
       
   168   /* re-normalize the value of tv_nsec */
       
   169   /* i.e. guarantee that it falls in the range ]-1, +1[ seconds. */
       
   170   if (ts.tv_nsec >=  1000000000) {ts.tv_nsec -= 1000000000; ts.tv_sec += 1;}
       
   171   if (ts.tv_nsec <= -1000000000) {ts.tv_nsec += 1000000000; ts.tv_sec -= 1;}
       
   172   /* We don't need to re-normalize the sign, since we are guaranteed that tv_sec and tv_nsec
       
   173    * will still both have the same sign after being multiplied by the same value.
       
   174    */
       
   175   return ts;
       
   176 #endif
       
   177 }
       
   178 
       
   179 /* Helper Macro for the comparison operators... */
       
   180 #define __compare_timespec(CMP, t1, t2) ((t1.tv_sec == t2.tv_sec)? t1.tv_nsec CMP t2.tv_nsec : t1.tv_sec CMP t2.tv_sec)
       
   181 
       
   182 
       
   183 
       
   184 /* Some necessary forward declarations... */
       
   185 class TIME;
       
   186 class TOD;
       
   187 class DT;
       
   188 class DATE;
       
   189 
       
   190 typedef struct timespec __timebase_t;
       
   191 
       
   192 
       
   193 
       
   194 class TIME{
       
   195   private:
       
   196     /* private variable that contains the value of time. */
       
   197     /* NOTE: The stored value is _always_ (time.tv_sec + time.tv_nsec),
       
   198        no matter whether tv_sec is positive or negative, or tv_nsec is positive or negative.
       
   199     */
       
   200     __timebase_t time;
       
   201 
       
   202   public:
       
   203     /* conversion to __timebase_t */
       
   204     operator __timebase_t(void) {return time;}
       
   205 
       
   206     /* constructors... */
       
   207     TIME (void) {time.tv_sec = 0; time.tv_nsec = 0;}
       
   208     TIME (__timebase_t time) {this->time = time;}
       
   209     TIME (const TIME &time) {this->time = time.time;}  /* copy constructor */
       
   210     TIME(int sign, double mseconds, double seconds=0, double minutes=0, double hours=0, double days=0) {
       
   211       /* sign is 1 for positive values, -1 for negative time... */
       
   212       long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3;
       
   213       if (sign >= 0) sign = 1; else sign = -1;
       
   214       time.tv_sec = sign * (long int)total_sec;
       
   215       time.tv_nsec = sign * (long int)((total_sec - time.tv_sec)*1e9);
       
   216     }
       
   217 
       
   218     /* used in plciec.cc to set the value of the __CURRENT_TIME variable without having to call a
       
   219      * TIME((__timebase_t time) constructor followed by the copy constructor.
       
   220      */
       
   221     void operator= (__timebase_t time) {this->time = time;}
       
   222 
       
   223     /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
       
   224     TIME operator+ (const TIME &time) {return TIME(__add_timespec(this->time, time.time));}
       
   225     TIME operator- (const TIME &time) {return TIME(__sub_timespec(this->time, time.time));}
       
   226 
       
   227     friend  TOD operator+ (const TIME &time, const TOD &tod);
       
   228     friend  TOD operator+ (const TOD &tod, const TIME &time);
       
   229     friend  TOD operator- (const TOD &tod, const TIME &time);
       
   230 
       
   231     friend  DT  operator+ (const TIME &time, const DT &dt);
       
   232     friend  DT  operator+ (const DT &dt, const TIME &time);
       
   233     friend  DT operator- (const DT &dt, const TIME &time);
       
   234 
       
   235     friend  TIME operator* (const TIME &time, const long double value);
       
   236     friend  TIME operator* (const long double value, const TIME &time);
       
   237     friend  TIME operator/ (const TIME &time, const long double value);
       
   238 
       
   239     /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
       
   240     BOOL operator>  (const TIME &time) {return  __compare_timespec(>,  this->time, time.time);}
       
   241     BOOL operator>= (const TIME &time) {return  __compare_timespec(>=, this->time, time.time);}
       
   242     BOOL operator<  (const TIME &time) {return  __compare_timespec(<,  this->time, time.time);}
       
   243     BOOL operator<= (const TIME &time) {return  __compare_timespec(<=, this->time, time.time);}
       
   244     BOOL operator== (const TIME &time) {return  __compare_timespec(==, this->time, time.time);}
       
   245     BOOL operator!= (const TIME &time) {return !__compare_timespec(==, this->time, time.time);}
       
   246 };
       
   247 
       
   248 
       
   249 
       
   250 /* Time of Day */
       
   251 class TOD {
       
   252   private:
       
   253     __timebase_t time;
       
   254 
       
   255   public:
       
   256     /* conversion to __timebase_t */
       
   257     operator __timebase_t(void) {return time;}
       
   258 
       
   259     /* constructors... */
       
   260     TOD (void) {time.tv_sec = 0; time.tv_nsec = 0;}
       
   261     TOD (__timebase_t time) {this->time = time;}
       
   262     TOD (const TOD &tod) {this->time = tod.time;}  /* copy constructor */
       
   263     TOD (double seconds, double minutes=0, double hours=0) {
       
   264       long double total_sec = (hours*60 + minutes)*60 + seconds;
       
   265       time.tv_sec = (long int)total_sec;
       
   266       time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9);
       
   267     }
       
   268 
       
   269     /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
       
   270     TIME operator- (const TOD &tod) {return TIME(__sub_timespec(this->time, tod.time));}
       
   271 
       
   272     friend  TOD operator+ (const TIME &time, const TOD &tod);
       
   273     friend  TOD operator+ (const TOD &tod, const TIME &time);
       
   274     friend  TOD operator- (const TOD &tod, const TIME &time);
       
   275 
       
   276     /* The following operation is not in the standard,
       
   277      * but will ease the implementation of the default function CONCAT_DATE_TOD
       
   278      */
       
   279     friend  DT operator+ (const DATE &date, const TOD &tod);
       
   280     friend  DT operator+ (const TOD &tod, const DATE &date);
       
   281 
       
   282     /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
       
   283     BOOL operator>  (const TOD &tod) {return  __compare_timespec(>,  this->time, tod.time);}
       
   284     BOOL operator>= (const TOD &tod) {return  __compare_timespec(>=, this->time, tod.time);}
       
   285     BOOL operator<  (const TOD &tod) {return  __compare_timespec(<,  this->time, tod.time);}
       
   286     BOOL operator<= (const TOD &tod) {return  __compare_timespec(<=, this->time, tod.time);}
       
   287     BOOL operator== (const TOD &tod) {return  __compare_timespec(==, this->time, tod.time);}
       
   288     BOOL operator!= (const TOD &tod) {return !__compare_timespec(==, this->time, tod.time);}
       
   289 };
       
   290 
       
   291 
       
   292 
       
   293 //typedef DATE;
       
   294 class DATE {
       
   295   private:
       
   296     __timebase_t time;
       
   297 
       
   298   public:
       
   299     /* conversion to __timebase_t */
       
   300     operator __timebase_t(void) {return time;}
       
   301 
       
   302     /* constructors... */
       
   303     DATE (void) {time.tv_sec = 0; time.tv_nsec = 0;}
       
   304     DATE (__timebase_t time) {this->time = time;}
       
   305     DATE (const DATE &date) {this->time = date.time;}  /* copy constructor */
       
   306     DATE (int day, int month, int year) {
       
   307       struct tm broken_down_time;
       
   308 
       
   309       broken_down_time.tm_sec = 0;
       
   310       broken_down_time.tm_min = 0;
       
   311       broken_down_time.tm_hour = 0;
       
   312       broken_down_time.tm_mday = day;  /* day of month, from 1 to 31 */
       
   313       broken_down_time.tm_mon = month - 1;   /* month since January, in the range 0 to 11 */
       
   314       broken_down_time.tm_year = year - 1900;  /* number of years since 1900 */
       
   315 
       
   316       time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
       
   317 
       
   318       if ((time_t)(-1) == epoch_seconds)
       
   319         IEC_error();
       
   320 
       
   321       time.tv_sec = epoch_seconds;
       
   322       time.tv_nsec = 0;
       
   323     }
       
   324 
       
   325     /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
       
   326     TIME operator- (const DATE &date) {return TIME(__sub_timespec(this->time, date.time));}
       
   327     /* The following operation is not in the standard,
       
   328      * but will ease the implementation of the default function CONCAT_DATE_TOD
       
   329      */
       
   330     friend  DT operator+ (const DATE &date, const TOD &tod);
       
   331     friend  DT operator+ (const TOD &tod, const DATE &date);
       
   332 
       
   333     /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
       
   334     BOOL operator>  (const DATE &date) {return  __compare_timespec(>,  this->time, date.time);}
       
   335     BOOL operator>= (const DATE &date) {return  __compare_timespec(>=, this->time, date.time);}
       
   336     BOOL operator<  (const DATE &date) {return  __compare_timespec(<,  this->time, date.time);}
       
   337     BOOL operator<= (const DATE &date) {return  __compare_timespec(<=, this->time, date.time);}
       
   338     BOOL operator== (const DATE &date) {return  __compare_timespec(==, this->time, date.time);}
       
   339     BOOL operator!= (const DATE &date) {return !__compare_timespec(==, this->time, date.time);}
       
   340 };
       
   341 
       
   342 
       
   343 
       
   344 
       
   345 
       
   346 class DT {
       
   347   private:
       
   348     __timebase_t time;
       
   349 
       
   350   public:
       
   351     /* conversion to __timebase_t */
       
   352     operator __timebase_t(void) {return time;}
       
   353 
       
   354     /* constructors... */
       
   355     DT (void) {time.tv_sec = 0; time.tv_nsec = 0;}
       
   356     DT (__timebase_t time) {this->time = time;}
       
   357     DT (const DT &dt) {this->time = dt.time;}  /* copy constructor */
       
   358     DT (double seconds,  double minutes, double hours, int day, int month, int year) {
       
   359       long double total_sec = (hours*60 + minutes)*60 + seconds;
       
   360       time.tv_sec = (long int)total_sec;
       
   361       time.tv_nsec = (long int)((total_sec - time.tv_sec)*1e9);
       
   362 
       
   363       struct tm broken_down_time;
       
   364       broken_down_time.tm_sec = 0;
       
   365       broken_down_time.tm_min = 0;
       
   366       broken_down_time.tm_hour = 0;
       
   367       broken_down_time.tm_mday = day;  /* day of month, from 1 to 31 */
       
   368       broken_down_time.tm_mon = month - 1;   /* month since January, in the range 0 to 11 */
       
   369       broken_down_time.tm_year = year - 1900;  /* number of years since 1900 */
       
   370 
       
   371       time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
       
   372       if ((time_t)(-1) == epoch_seconds)
       
   373         IEC_error();
       
   374 
       
   375       time.tv_sec += epoch_seconds;
       
   376       if (time.tv_sec < epoch_seconds)
       
   377         /* since the TOD is always positive, if the above happens then we had an overflow */
       
   378 	IEC_error();
       
   379     }
       
   380 
       
   381     /* Helpers to conversion operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
       
   382     DATE __to_DATE(void) {
       
   383 #if 0
       
   384       /* slow version */
       
   385       struct tm broken_down_time;
       
   386       time_t seconds = time.tv_sec;
       
   387       if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */
       
   388         IEC_error();
       
   389       return DATE(broken_down_time.tm_mday, broken_down_time.tm_mon, broken_down_time.tm_year);
       
   390 #else
       
   391       /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds,
       
   392        * and that the value of tv_nsec falls in the range ]-1, +1[
       
   393        */
       
   394       /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */
       
   395       struct timespec date_time = {time.tv_sec - (time.tv_sec % (24*60*60)), 0};
       
   396       return DATE(date_time);
       
   397 #endif
       
   398     }
       
   399 
       
   400     TOD __to_TOD(void) {
       
   401 #if 0
       
   402       /* slow version */
       
   403       struct tm broken_down_time;
       
   404       time_t seconds = time.tv_sec;
       
   405       if (NULL == gmtime_r(seconds, &broken_down_time)) /* get the UTC (GMT) broken down time */
       
   406         IEC_error();
       
   407       return TOD(broken_down_time.tm_sec, broken_down_time.tm_min, broken_down_time.tm_hour);
       
   408 #else
       
   409       /* Faster version, based on the fact that the date will always be a multiple of 60*60*24 seconds
       
   410        * and that the value of tv_nsec falls in the range ]-1, +1[
       
   411        */
       
   412       /* The above is true since the Unix function mktime() seems to ignore all leap seconds! */
       
   413       struct timespec time_time = {time.tv_sec % (24*60*60), time.tv_nsec};
       
   414       return TOD(time_time);
       
   415 #endif
       
   416     }
       
   417 
       
   418     /* Arithmetic operators (section 2.5.1.5.6. of version 2 of the IEC 61131-3 standard) */
       
   419     TIME operator- (const DT &dt) {return TIME(__sub_timespec(this->time, dt.time));}
       
   420 
       
   421     friend  DT operator+ (const TIME &time, const DT &dt);
       
   422     friend  DT operator+ (const DT &dt, const TIME &time);
       
   423     friend  DT operator- (const DT &dt, const TIME &time);
       
   424 
       
   425     /* Comparison operators (section 2.5.1.5.4. of version 2 of the IEC 61131-3 standard) */
       
   426     BOOL operator>  (const DT &dt) {return  __compare_timespec(>,  this->time, dt.time);}
       
   427     BOOL operator>= (const DT &dt) {return  __compare_timespec(>=, this->time, dt.time);}
       
   428     BOOL operator<  (const DT &dt) {return  __compare_timespec(<,  this->time, dt.time);}
       
   429     BOOL operator<= (const DT &dt) {return  __compare_timespec(<=, this->time, dt.time);}
       
   430     BOOL operator== (const DT &dt) {return  __compare_timespec(==, this->time, dt.time);}
       
   431     BOOL operator!= (const DT &dt) {return !__compare_timespec(==, this->time, dt.time);}
       
   432 };
       
   433 
       
   434 
       
   435 /* The operations on time and data types... */
       
   436 TOD operator+ (const TIME &time, const TOD &tod) {return TOD(__add_timespec(tod.time, time.time));};
       
   437 TOD operator+ (const TOD &tod, const TIME &time) {return TOD(__add_timespec(tod.time, time.time));};
       
   438 TOD operator- (const TOD &tod, const TIME &time) {return TOD(__sub_timespec(tod.time, time.time));};
       
   439 
       
   440 DT  operator+ (const TIME &time, const DT &dt) {return DT(__add_timespec(dt.time, time.time));};
       
   441 DT  operator+ (const DT &dt, const TIME &time) {return DT(__add_timespec(dt.time, time.time));};
       
   442 DT  operator- (const DT &dt, const TIME &time) {return DT(__sub_timespec(dt.time, time.time));};
       
   443 
       
   444 TIME operator* (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, value));}
       
   445 TIME operator* (const long double value, const TIME &time) {return TIME(__mul_timespec(time.time, value));}
       
   446 TIME operator/ (const TIME &time, const long double value) {return TIME(__mul_timespec(time.time, 1.0/value));}
       
   447 
       
   448 /* The following operation is not in the standard,
       
   449  * but will ease the implementation of the default function CONCAT_DATE_TOD
       
   450  */
       
   451 DT operator+ (const DATE &date, const TOD &tod) {return DT(__add_timespec(date.time, tod.time));};
       
   452 DT operator+ (const TOD &tod, const DATE &date) {return DT(__add_timespec(date.time, tod.time));};
       
   453 
       
   454 
       
   455 /* global variable that will be used to implement the timers TON, TOFF and TP */
       
   456 extern TIME __CURRENT_TIME;
       
   457 
       
   458 
       
   459 
       
   460 //typedef STRING;
       
   461 //typedef WSTRING;
       
   462 
       
   463 
       
   464 
       
   465 typedef union __IL_DEFVAR_T {
       
   466 	BOOL	BOOLvar;
       
   467 
       
   468 	SINT	SINTvar;
       
   469 	INT 	INTvar;
       
   470 	DINT	DINTvar;
       
   471 	LINT	LINTvar;
       
   472 
       
   473 	USINT	USINTvar;
       
   474 	UINT	UINTvar;
       
   475 	UDINT	UDINTvar;
       
   476 	ULINT	ULINTvar;
       
   477 
       
   478 	BYTE	BYTEvar;
       
   479 	WORD	WORDvar;
       
   480 	DWORD	DWORDvar;
       
   481 	LWORD	LWORDvar;
       
   482 
       
   483 	REAL	REALvar;
       
   484 	LREAL	LREALvar;
       
   485 
       
   486 	/* NOTE: since the TIME, DATE, ... classes all have constructors,
       
   487 	 *   C++ does not allow them to be used as members of a union.
       
   488 	 *   The workaround is to use a base data type (in this case __timebase_t) that
       
   489 	 *   contains all the internal data these classes require, and then add an operator
       
   490 	 *   member function to each class that allows it to be converted to that same base data type,
       
   491 	 *   acompanied by a constructor using that data type.
       
   492 	 */
       
   493 	/*
       
   494 	TIME	TIMEvar;
       
   495 	TOD	TODvar;
       
   496 	DT	DTvar;
       
   497 	DATE	DATEvar;
       
   498 	*/
       
   499 	__timebase_t	TIMEvar;
       
   500 	__timebase_t	TODvar;
       
   501 	__timebase_t	DTvar;
       
   502 	__timebase_t	DATEvar;
       
   503 } __IL_DEFVAR_T;
       
   504   /*TODO TODO TODO TODO TODO TODO TODO TODO TODO
       
   505    * How do we add support for the possibility of storing
       
   506    * data values of derived data types into the default register,
       
   507    * to be later used for calling functions, stroing in another
       
   508    * variable, etc...?
       
   509    *
       
   510    * For example:
       
   511    *  TYPE
       
   512    *    point_t : STRUCT
       
   513    *                x : INT;
       
   514    *                y : INT;
       
   515    *              END_STRUCT;
       
   516    *  END_TYPE
       
   517    *
       
   518    *  VAR p1, p2, p3 : point_t;
       
   519    *
       
   520    *  LD p1
       
   521    *  ST p2
       
   522    *
       
   523    *
       
   524    * We could do it with a pointer to void, that would contain not
       
   525    * the value itself, but rather the address in which the value
       
   526    * is currently stored.
       
   527    * For example, we could add a
       
   528    *    void *generic_ptr
       
   529    * to this union, and then have the above LD and ST instructions
       
   530    * converted to:
       
   531    *   __IL_DEFVAR.generic_ptr = (void *)(&p1);
       
   532    *   p2 = *((point_t *)__IL_DEFVAR.generic_ptr);
       
   533    *
       
   534    * Unfortunately the above will only work as long as the p1 variable
       
   535    * does not get a chance to change its value before the default register
       
   536    * gets loaded with something esle (and therefore the value is no
       
   537    * longer needed).
       
   538    * Additionally, a scenario where the value of p1 may change before the
       
   539    * default register gets a new value is if p1 is used in a function block
       
   540    * call for an output parameter!
       
   541    * For example:
       
   542    *
       
   543    *  LD p1
       
   544    *  CAL funcblock(
       
   545    *         param1 => p1
       
   546    *      )
       
   547    *  ST p2
       
   548    *
       
   549    * In the above scenario, p1 gets a new value when the function block
       
   550    * funcblock is called. When we get to copy the default register to
       
   551    * p2, we will no longer be copying the value that got stored in the default
       
   552    * register when we did 'LD p1', but rather the value returned by the
       
   553    * function block call!!!
       
   554    *
       
   555    * How the do we implement this???
       
   556    * We will probably need to declare a default variable of the correct data
       
   557    * type whenever we get these values stored to the default register.
       
   558    * For example
       
   559    *   LD p1
       
   560    *   ST p2
       
   561    *
       
   562    * would be converted to:
       
   563    *   union {
       
   564    *     point_tvar point_t;
       
   565    *   } __IL_DEFVAR_special ;
       
   566    *
       
   567    *   __IL_DEFVAR_special.point_tvar = p1;
       
   568    *   p2 = __IL_DEFVAR_special.point_tvar;
       
   569    *
       
   570    * The above requires that we iterate through the whole Instruction list
       
   571    * before we start the conversion, in order to first determine if we need
       
   572    * to declare that new variable for the default register.
       
   573    *
       
   574    * Since we have to do this, it would probaly be a better idea to simply
       
   575    * do away with the __IL_DEFVAR_T data type we declare here, and
       
   576    * declare the __IL_DEFVAR at the begining of each IL code segment
       
   577    * with all the data types that get used in that segment!
       
   578    */
       
   579 
       
   580 
       
   581 /* Names start with double underscore so as not to clash with
       
   582  * names in ST or IL source code! Names including a double underscore are
       
   583  * ilegal under IL and ST!
       
   584  */
       
   585 
       
   586 /* This is an abstract base class, that cannot be instantiated... */
       
   587 template<typename value_type> class __ext_ref_c {
       
   588   public:
       
   589     virtual void operator= (value_type value) = 0;
       
   590     virtual operator value_type(void) = 0;
       
   591 };
       
   592 
       
   593 
       
   594 
       
   595 
       
   596 
       
   597 
       
   598 /* Names start with double underscore so as not to clash with
       
   599  * names in ST or IL source code! Names including a double underscore are
       
   600  * ilegal under IL and ST!
       
   601  */
       
   602 template<typename value_type> class __ext_element_c
       
   603   : public __ext_ref_c<value_type> {
       
   604 //{
       
   605 
       
   606   private:
       
   607     value_type value;
       
   608 
       
   609   public:
       
   610     virtual void operator= (value_type value) {
       
   611       this->value = value;
       
   612     }
       
   613 
       
   614     virtual operator value_type(void) {
       
   615       return value;
       
   616     }
       
   617 
       
   618     __ext_element_c(void) {}
       
   619 
       
   620     __ext_element_c(value_type value) {
       
   621       this->value = value;
       
   622     }
       
   623 };
       
   624 
       
   625 
       
   626 /* Names start with double underscore so as not to clash with
       
   627  * names in ST or IL source code! Names including a double underscore are
       
   628  * ilegal under IL and ST!
       
   629  */
       
   630 template<typename value_type, int size = 8 * sizeof(value_type) /* in bits */> class __plc_pt_c
       
   631   : public __ext_ref_c<value_type> {
       
   632 
       
   633   private:
       
   634     plc_pt_t plc_pt;
       
   635     bool valid_plc_pt;
       
   636 
       
   637   private:
       
   638     void init_name(const char *pt_name) {
       
   639       /* assume error! */
       
   640       valid_plc_pt = false;
       
   641       plc_pt = plc_pt_by_name(pt_name);
       
   642       if (plc_pt.valid == 0) {
       
   643         plc_pt = plc_pt_null();
       
   644 	return;
       
   645       }
       
   646       /* We can't have this check here, otherwise the boolean variables won't work correctly,
       
   647        * since MatPLC uses 1 bit for boolean variables, whereas g++ uses 8 bits.
       
   648        */
       
   649       /*
       
   650       if (plc_pt_len(plc_pt) != size) {
       
   651         plc_pt = plc_pt_null();
       
   652 	return;
       
   653       }
       
   654       */
       
   655       valid_plc_pt = true;
       
   656     }
       
   657 
       
   658   public:
       
   659     virtual void operator= (value_type value) {
       
   660       plc_set(plc_pt, *((u32 *)&value));
       
   661     }
       
   662 
       
   663     virtual operator value_type(void) {
       
   664       u32 tmp_val = plc_get(plc_pt);
       
   665       return *((value_type *)&tmp_val);
       
   666     }
       
   667 
       
   668     __plc_pt_c(const char *pt_name) {
       
   669       init_name(pt_name);
       
   670     }
       
   671 
       
   672     __plc_pt_c(const char *pt_name, value_type init_value) {
       
   673       init_name(pt_name);
       
   674       *this = init_value;
       
   675     }
       
   676 
       
   677     bool valid(void) {return valid_plc_pt;}
       
   678 };
       
   679 
       
   680 
       
   681 
       
   682 #define DEFAULT_MODULE_NAME "iec"
       
   683 
       
   684 
       
   685 
       
   686 #endif /* __PLCIEC_H */
       
   687 
       
   688