|
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 /* Determine the size, in bits, of the data type. |
|
26 * |
|
27 * NOTE: Currently, only elementary data types with well defined sizes (in the standard) are supported. |
|
28 * - derived data types are not supported, and these will return 0 |
|
29 * - TIME, DATE, TIME_OF_DAY, and DATE_AND_TIME are not supported, and will return 0 |
|
30 * - STRING and WSTRING are not supported, and the standard merely defines bit per character, |
|
31 * and not the maximum number of characters, so these will return 0 |
|
32 * |
|
33 * We also support the 'Numeric Literals' Data types. |
|
34 * i.e., numeric literals are considerd basic data types |
|
35 * as their data type is undefined (e.g. the datat type of '30' |
|
36 * could be 'INT' or 'SINT' or 'LINT' or 'USINT' or ... |
|
37 * NOTE: for base 10 numeric literals, any number taking up more than 64 bits |
|
38 * will only return a bitsize of 1024! |
|
39 * |
|
40 * For numeric literals, we return the minimum number of bits |
|
41 * required to store the value. |
|
42 * |
|
43 * E.g. TYPE new_int_t : INT; END_TYPE; |
|
44 * TYPE new_int2_t : INT = 2; END_TYPE; |
|
45 * TYPE new_subr_t : INT (4..5); END_TYPE; |
|
46 * |
|
47 * sizeof(SINT) -> 8 |
|
48 * sizeof(INT) -> 16 |
|
49 * sizeof(DINT) -> 32 |
|
50 * sizeof(LINT) -> 64 |
|
51 * |
|
52 * sizeof('1') -> 1 |
|
53 * sizeof('015') -> 4 # Leading zeros are ignored! |
|
54 * sizeof('0') -> 1 # This is a special case! Even the value 0 needs at least 1 bit to store! |
|
55 * sizeof('16') -> 5 |
|
56 * sizeof('2#00101') -> 3 |
|
57 * sizeof('8#334') -> 9 |
|
58 * sizeof('16#2A') -> 8 |
|
59 * |
|
60 * sizeof('7.4') -> 32 # all real literals return 32 bits, the size of a 'REAL' |
|
61 * # TODO: study IEC 60559 for the range of values that may be |
|
62 * # stored in a REAL (basic single width floating point format) |
|
63 * # and in a LREAL (basic double width floating point format) |
|
64 * # and see if some real literals need to return 64 instead! |
|
65 */ |
|
66 |
|
67 #include "get_sizeof_datatype.hh" |
|
68 |
|
69 #include <stdlib.h> |
|
70 #include <string.h> |
|
71 #include <limits.h> // get definition of ULLONG_MAX |
|
72 /* tell stdint.h we want the definition of UINT64_MAX */ |
|
73 #define __STDC_LIMIT_MACROS |
|
74 #include <stdint.h> // get definition of uint64_t and UINT64_MAX |
|
75 |
|
76 |
|
77 #define ERROR error_exit(__FILE__,__LINE__) |
|
78 /* function defined in main.cc */ |
|
79 extern void error_exit(const char *file_name, int line_no); |
|
80 |
|
81 |
|
82 /* This class is a singleton. |
|
83 * So we need a pointer to the singe instance... |
|
84 */ |
|
85 get_sizeof_datatype_c *get_sizeof_datatype_c::singleton = NULL; |
|
86 |
|
87 |
|
88 #define _encode_int(value) ((void *)(((char *)NULL) + value)) |
|
89 #define _decode_int(ptr) (((char *)ptr) - ((char *)NULL)) |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 /* divide a base 10 literal in a string by 2 */ |
|
95 /* returns remainder of division (0 or 1) */ |
|
96 static int strdivby2(char **strptr) { |
|
97 char *str = *strptr; |
|
98 int carry = 0; |
|
99 |
|
100 while (*str != '\0') { |
|
101 /* Assumes ASCII */ |
|
102 int newcarry; |
|
103 // newcarry = ((*str-'0') mod 2); |
|
104 newcarry = ((*str-'0') - ((*str-'0')/2)*2); |
|
105 *str = (((*str-'0') + 10*carry)/2) + '0'; |
|
106 carry = newcarry; |
|
107 str++; |
|
108 } |
|
109 |
|
110 /* ignore leading zeros in result... */ |
|
111 while (**strptr == '0') |
|
112 (*strptr)++; |
|
113 |
|
114 return carry; |
|
115 } |
|
116 |
|
117 |
|
118 /* Constructor for the singleton class */ |
|
119 int get_sizeof_datatype_c::getsize(symbol_c *data_type_symbol) { |
|
120 if (NULL == singleton) { |
|
121 singleton = new get_sizeof_datatype_c; |
|
122 if (NULL == singleton) |
|
123 ERROR; |
|
124 } |
|
125 return _decode_int(data_type_symbol->accept(*singleton)); |
|
126 } |
|
127 |
|
128 /* Destructor for the singleton class */ |
|
129 get_sizeof_datatype_c::~get_sizeof_datatype_c(void) { |
|
130 if (NULL != singleton) delete singleton; |
|
131 singleton = NULL; |
|
132 } |
|
133 |
|
134 |
|
135 /*********************/ |
|
136 /* B 1.2 - Constants */ |
|
137 /*********************/ |
|
138 |
|
139 /******************************/ |
|
140 /* B 1.2.1 - Numeric Literals */ |
|
141 /******************************/ |
|
142 /* Numeric literals without any explicit type cast have unknown data type, |
|
143 * so we continue considering them as their own basic data types until |
|
144 * they can be resolved (for example, when using '30+x' where 'x' is a LINT variable, the |
|
145 * numeric literal '30' must then be considered a LINT so the ADD function may be called |
|
146 * with all inputs of the same data type. |
|
147 * If 'x' were a SINT, then the '30' would have to be a SINT too! |
|
148 */ |
|
149 |
|
150 /* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-') |
|
151 * due to the way the source code is parsed by iec.flex. |
|
152 */ |
|
153 void *get_sizeof_datatype_c::visit(real_c *symbol) { |
|
154 return _encode_int(32); |
|
155 } |
|
156 |
|
157 /* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-') |
|
158 * due to the way the source code is parsed by iec.flex. |
|
159 */ |
|
160 void *get_sizeof_datatype_c::visit(integer_c *symbol) { |
|
161 int bitsize = 0; |
|
162 |
|
163 if (NULL == symbol->value ) ERROR; |
|
164 if ('\0' == *(symbol->value)) ERROR; |
|
165 |
|
166 #if 0 |
|
167 char *endptr; |
|
168 /* Convert the string to an unsigned 64 bit integer */ |
|
169 /* We can use strtoull(), but we are not guaranteed that an unsigned long long int |
|
170 * is 64 bits wide. First make sure that it is... |
|
171 * |
|
172 * We could also use the strtouq() instead, which converts |
|
173 * to a quad word (64 bits). However, this requires either GCC or BSD extensions. |
|
174 */ |
|
175 #ifdef strtoull // this ifdef does not work!! |
|
176 /* we have long long int, use it... */ |
|
177 #define ival_MAX ULLONG_MAX |
|
178 unsigned long long int ival = 0; |
|
179 ival = strtoull (symbol->value, &endptr, 10 /* base */); |
|
180 #else |
|
181 /* use long int ... */ |
|
182 #define ival_MAX ULONG_MAX |
|
183 unsigned long int ival = 0; |
|
184 ival = strtoul (symbol->value, &endptr, 10 /* base */); |
|
185 #endif |
|
186 |
|
187 #if (ival_MAX < UINT64_MAX) |
|
188 #error Largest strtoint() conversion function converts to an int less than 64 bits wide! |
|
189 #endif |
|
190 |
|
191 if (NULL == endptr) ERROR; |
|
192 if ('\0' != *endptr) ERROR; |
|
193 // TODO: return _encode_int(1024) if value takes up more than 64 bits! |
|
194 |
|
195 /* determine the number of bits used... */ |
|
196 for (bitsize = 0; ival > 0; ival /= 2, bitsize++); |
|
197 |
|
198 /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */ |
|
199 if (0 == bitsize) bitsize = 1; |
|
200 |
|
201 return _encode_int(bitsize); |
|
202 #endif |
|
203 /* We could first convert from string to some kind of integer, and then |
|
204 * determine the the bitsize using integer aritmetic. |
|
205 * However, we are then limited to the bit size of the widest available integer |
|
206 * (usually 64 bits), which is not good at all! |
|
207 */ |
|
208 /* Let's try to determine bitsize by converting directly from the string!! */ |
|
209 char *sval = strdup(symbol->value); |
|
210 char *oval = sval; |
|
211 if (NULL == sval) ERROR; |
|
212 if ('\0' == *sval) ERROR; |
|
213 |
|
214 for (bitsize = 0; *sval != '\0'; strdivby2(&sval), bitsize ++); |
|
215 |
|
216 /* Even for (value == 0), the above loop will return bitsize == 1!, |
|
217 * so we don't need to handle the special case... |
|
218 */ |
|
219 /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */ |
|
220 // if (0 == bitsize) bitsize = 1; |
|
221 |
|
222 free(oval); |
|
223 return _encode_int(bitsize); |
|
224 } |
|
225 |
|
226 |
|
227 /* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-') |
|
228 * due to the way the source code is parsed by iec.flex. |
|
229 */ |
|
230 void *get_sizeof_datatype_c::visit(binary_integer_c *symbol) { |
|
231 const char *sval = symbol->value; |
|
232 int bitsize = 0; |
|
233 |
|
234 /* first 2 characters had better be "2#" ! */ |
|
235 if (NULL == sval) ERROR; |
|
236 if ('\0' == *sval) ERROR; |
|
237 if ( '2' != *sval) ERROR; |
|
238 sval++; |
|
239 if ('\0' == *sval) ERROR; |
|
240 if ( '#' != *sval) ERROR; |
|
241 sval++; |
|
242 if ('\0' == *sval) ERROR; |
|
243 |
|
244 /* determine the number of bits used... */ |
|
245 for (bitsize = 0; '\0' != *sval; sval++, bitsize++) { |
|
246 /* consistency check: make sure we only have binary digits! */ |
|
247 if (('0' != *sval) && ('1' != *sval)) |
|
248 ERROR; |
|
249 } |
|
250 |
|
251 /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */ |
|
252 if (0 == bitsize) bitsize = 1; |
|
253 |
|
254 return _encode_int(bitsize); |
|
255 } |
|
256 |
|
257 |
|
258 /* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-') |
|
259 * due to the way the source code is parsed by iec.flex. |
|
260 */ |
|
261 void *get_sizeof_datatype_c::visit(octal_integer_c *symbol) { |
|
262 const char *sval = symbol->value; |
|
263 int bitsize = 0; |
|
264 |
|
265 /* first 2 characters had better be "8#" ! */ |
|
266 if (NULL == sval) ERROR; |
|
267 if ('\0' == *sval) ERROR; |
|
268 if ( '8' != *sval) ERROR; |
|
269 sval++; |
|
270 if ('\0' == *sval) ERROR; |
|
271 if ( '#' != *sval) ERROR; |
|
272 sval++; |
|
273 if ('\0' == *sval) ERROR; |
|
274 |
|
275 /* determine the number of bits used... */ |
|
276 for (bitsize = 0; '\0' != *sval; sval++, bitsize += 3 /* 3 bits per octal digit */) { |
|
277 /* consistency check: make sure we only have octal digits! */ |
|
278 /* Assumes ASCII */ |
|
279 if (('0' > *sval) || ('7' < *sval)) |
|
280 ERROR; |
|
281 } |
|
282 |
|
283 /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */ |
|
284 if (0 == bitsize) bitsize = 1; |
|
285 |
|
286 return _encode_int(bitsize); |
|
287 } |
|
288 |
|
289 |
|
290 /* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-') |
|
291 * due to the way the source code is parsed by iec.flex. |
|
292 */ |
|
293 void *get_sizeof_datatype_c::visit(hex_integer_c *symbol) { |
|
294 const char *sval = symbol->value; |
|
295 int bitsize = 0; |
|
296 |
|
297 /* first 3 characters had better be "16#" ! */ |
|
298 if (NULL == sval) ERROR; |
|
299 if ('\0' == *sval) ERROR; |
|
300 if ( '1' != *sval) ERROR; |
|
301 sval++; |
|
302 if ('\0' == *sval) ERROR; |
|
303 if ( '6' != *sval) ERROR; |
|
304 sval++; |
|
305 if ('\0' == *sval) ERROR; |
|
306 if ( '#' != *sval) ERROR; |
|
307 sval++; |
|
308 if ('\0' == *sval) ERROR; |
|
309 |
|
310 /* determine the number of bits used... */ |
|
311 for (bitsize = 0; '\0' != *sval; sval++, bitsize += 4 /* 4 bits per hex digit */) { |
|
312 /* consistency check: make sure we only have hex digits! */ |
|
313 /* Assumes ASCII */ |
|
314 if (!(('0' <= *sval) && ('9' >= *sval)) && |
|
315 !(('A' <= *sval) && ('F' >= *sval)) && |
|
316 !(('a' <= *sval) && ('b' >= *sval))) |
|
317 ERROR; |
|
318 } |
|
319 |
|
320 /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */ |
|
321 if (0 == bitsize) bitsize = 1; |
|
322 |
|
323 return _encode_int(bitsize); |
|
324 } |
|
325 |
|
326 |
|
327 /***********************************/ |
|
328 /* B 1.3.1 - Elementary Data Types */ |
|
329 /***********************************/ |
|
330 // void *get_sizeof_datatype_c::visit(time_type_name_c *symbol) {return _encode_int(0); } |
|
331 void *get_sizeof_datatype_c::visit(bool_type_name_c *symbol) {return _encode_int(1); } |
|
332 void *get_sizeof_datatype_c::visit(sint_type_name_c *symbol) {return _encode_int(8); } |
|
333 void *get_sizeof_datatype_c::visit(int_type_name_c *symbol) {return _encode_int(16);} |
|
334 void *get_sizeof_datatype_c::visit(dint_type_name_c *symbol) {return _encode_int(32);} |
|
335 void *get_sizeof_datatype_c::visit(lint_type_name_c *symbol) {return _encode_int(64);} |
|
336 void *get_sizeof_datatype_c::visit(usint_type_name_c *symbol) {return _encode_int(8); } |
|
337 void *get_sizeof_datatype_c::visit(uint_type_name_c *symbol) {return _encode_int(16);} |
|
338 void *get_sizeof_datatype_c::visit(udint_type_name_c *symbol) {return _encode_int(32);} |
|
339 void *get_sizeof_datatype_c::visit(ulint_type_name_c *symbol) {return _encode_int(64);} |
|
340 void *get_sizeof_datatype_c::visit(real_type_name_c *symbol) {return _encode_int(32);} |
|
341 void *get_sizeof_datatype_c::visit(lreal_type_name_c *symbol) {return _encode_int(64);} |
|
342 // void *get_sizeof_datatype_c::visit(date_type_name_c *symbol) {return _encode_int(0); } |
|
343 // void *get_sizeof_datatype_c::visit(tod_type_name_c *symbol) {return _encode_int(0); } |
|
344 // void *get_sizeof_datatype_c::visit(dt_type_name_c *symbol) {return _encode_int(0); } |
|
345 void *get_sizeof_datatype_c::visit(byte_type_name_c *symbol) {return _encode_int(8); } |
|
346 void *get_sizeof_datatype_c::visit(word_type_name_c *symbol) {return _encode_int(16);} |
|
347 void *get_sizeof_datatype_c::visit(dword_type_name_c *symbol) {return _encode_int(32);} |
|
348 void *get_sizeof_datatype_c::visit(lword_type_name_c *symbol) {return _encode_int(64);} |
|
349 // void *get_sizeof_datatype_c::visit(string_type_name_c *symbol) {return _encode_int(0); } |
|
350 // void *get_sizeof_datatype_c::visit(wstring_type_name_c *symbol) {return _encode_int(0); } |
|
351 /******************************************************/ |
|
352 /* Extensions to the base standard as defined in */ |
|
353 /* "Safety Software Technical Specification, */ |
|
354 /* Part 1: Concepts and Function Blocks, */ |
|
355 /* Version 1.0 – Official Release" */ |
|
356 /* by PLCopen - Technical Committee 5 - 2006-01-31 */ |
|
357 /******************************************************/ |
|
358 void *get_sizeof_datatype_c::visit(safebool_type_name_c *symbol) {return _encode_int(1);} |
|
359 |
|
360 /********************************/ |
|
361 /* B 1.3.3 - Derived data types */ |
|
362 /********************************/ |
|
363 // Not yet supported... |