1 /********************************************************************/
2 /*                                                                  */
3 /*  s7   Seed7 interpreter                                          */
4 /*  Copyright (C) 1990 - 2000  Thomas Mertes                        */
5 /*                                                                  */
6 /*  This program is free software; you can redistribute it and/or   */
7 /*  modify it under the terms of the GNU General Public License as  */
8 /*  published by the Free Software Foundation; either version 2 of  */
9 /*  the License, or (at your option) any later version.             */
10 /*                                                                  */
11 /*  This program is distributed in the hope that it will be useful, */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of  */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   */
14 /*  GNU General Public License for more details.                    */
15 /*                                                                  */
16 /*  You should have received a copy of the GNU General Public       */
17 /*  License along with this program; if not, write to the           */
18 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
19 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
20 /*                                                                  */
21 /*  Module: Analyzer - Scanner                                      */
22 /*  File: seed7/src/numlit.c                                        */
23 /*  Changes: 1990, 1991, 1992, 1993, 1994  Thomas Mertes            */
24 /*  Content: Read the next number from the source file.             */
25 /*                                                                  */
26 /********************************************************************/
27 
28 #define LOG_FUNCTIONS 0
29 #define VERBOSE_EXCEPTIONS 0
30 
31 #include "version.h"
32 
33 #include "stdlib.h"
34 #include "stdio.h"
35 #include "string.h"
36 
37 #include "common.h"
38 #include "data.h"
39 #include "chclsutl.h"
40 #include "identutl.h"
41 #include "error.h"
42 #include "symbol.h"
43 #include "infile.h"
44 #include "stat.h"
45 #include "findid.h"
46 #include "big_drv.h"
47 
48 #undef EXTERN
49 #define EXTERN
50 #include "numlit.h"
51 
52 
53 
readDecimal(register sySizeType position)54 static void readDecimal (register sySizeType position)
55 
56   {
57     register int character;
58 
59   /* readDecimal */
60     logFunction(printf("readDecimal\n"););
61     check_symb_length(position);
62     symbol.name[position++] = (ucharType) in_file.character;
63     while (char_class(character = next_character()) == DIGITCHAR) {
64       check_symb_length(position);
65       symbol.name[position++] = (ucharType) character;
66     } /* while */
67     symbol.name[position] = '\0';
68     in_file.character = character;
69     logFunction(printf("readDecimal -->\n"););
70   } /* readDecimal */
71 
72 
73 
decimalValue(const const_ustriType digits)74 static uintType decimalValue (const const_ustriType digits)
75 
76   {
77     boolType tooBig = FALSE;
78     unsigned int position = 0;
79     uintType digitval;
80     uintType uintValue = 0;
81 
82   /* decimalValue */
83     logFunction(printf("decimalValue(\"%s\")\n", digits););
84     while (digits[position] != '\0') {
85       digitval = ((uintType) digits[position]) - ((uintType) '0');
86       if (unlikely(uintValue > MAX_DIV_10)) {
87         tooBig = TRUE;
88       } else {
89         uintValue = ((uintType) 10) * uintValue + digitval;
90       } /* if */
91       position++;
92     } /* while */
93     if (unlikely(tooBig || uintValue > (uintType) INTTYPE_MAX)) {
94       err_string(CARD_DECIMAL_TOO_BIG, digits);
95       uintValue = 0;
96     } /* if */
97     logFunction(printf("decimalValue --> " FMT_U "\n",
98                        uintValue););
99     return uintValue;
100   } /* decimalValue */
101 
102 
103 
basedValue(const uintType base,const const_ustriType digits)104 static inline intType basedValue (const uintType base, const const_ustriType digits)
105 
106   {
107     boolType illegalDigit = FALSE;
108     boolType tooBig = FALSE;
109     uintType max_div_base;
110     unsigned int position = 0;
111     uintType digitval;
112     uintType uintValue = 0;
113 
114   /* basedValue */
115     logFunction(printf("basedValue(" FMT_U ", \"%s\")\n",
116                        base, digits););
117     max_div_base = (uintType) INTTYPE_MAX / base;
118     while (digits[position] != '\0') {
119       digitval = digit_value[(int) digits[position]];
120       if (unlikely(digitval >= base)) {
121         if (!illegalDigit) {
122           err_num_stri(ILLEGALBASEDDIGIT, (int) digits[position], (int) base, digits);
123           illegalDigit = TRUE;
124         } /* if */
125       } else if (unlikely(uintValue > max_div_base)) {
126         tooBig = TRUE;
127       } else {
128         uintValue = base * uintValue + digitval;
129       } /* if */
130       position++;
131     } /* while */
132     if (unlikely(illegalDigit)) {
133       uintValue = 0;
134     } else if (unlikely(tooBig || uintValue > (uintType) INTTYPE_MAX)) {
135       err_num_stri(CARD_BASED_TOO_BIG, 0, (int) base, digits);
136       uintValue = 0;
137     } /* if */
138     logFunction(printf("basedValue --> " FMT_D "\n",
139                        (intType) uintValue););
140     return (intType) uintValue;
141   } /* basedValue */
142 
143 
144 
readBased(void)145 static inline boolType readBased (void)
146 
147   {
148     register sySizeType position;
149     register int character;
150     boolType okay;
151 
152   /* readBased */
153     position = 0;
154     character = next_character();
155     if (char_class(character) == DIGITCHAR ||
156         char_class(character) == LETTERCHAR) {
157       do {
158         check_symb_length(position);
159         symbol.name[position++] = (ucharType) character;
160         character = next_character();
161       } while (char_class(character) == DIGITCHAR ||
162           char_class(character) == LETTERCHAR);
163       okay = TRUE;
164     } else {
165       err_cchar(EXTDIGITEXPECTED, character);
166       okay = FALSE;
167     } /* if */
168     symbol.name[position] = '\0';
169     in_file.character = character;
170     return okay;
171   } /* readBased */
172 
173 
174 
readBigBased(uintType base)175 static inline bigIntType readBigBased (uintType base)
176 
177   {
178     memSizeType pos;
179     boolType okay = TRUE;
180     uintType digitval;
181     bigIntType result;
182 
183   /* readBigBased */
184     logFunction(printf("readBigBased(" FMT_U ")\n", base););
185     in_file.character = next_character();
186     pos = 0;
187     do {
188       while (pos != symbol.stri_max && symbol.name[pos] != '\0') {
189         digitval = digit_value[(int) symbol.name[pos]];
190         if (unlikely(digitval >= base)) {
191           if (okay) {
192             err_num_stri(ILLEGALBASEDDIGIT,
193                 (int) symbol.name[pos], (int) base, symbol.name);
194             okay = FALSE;
195           } /* if */
196         } /* if */
197         symbol.striValue->mem[pos] = (strElemType) symbol.name[pos];
198         pos++;
199       } /* while */
200       check_stri_length(pos);
201     } while (symbol.name[pos] != '\0');
202     symbol.striValue->size = pos;
203     bigDestr(symbol.bigIntValue);
204     if (okay) {
205       result = bigParseBased(symbol.striValue, (intType) base);
206     } else {
207       result = bigZero();
208     } /* if */
209     logFunction(printf("readBigBased -->\n"););
210     return result;
211   } /* readBigBased */
212 
213 
214 
basedInteger(uintType base)215 static inline void basedInteger (uintType base)
216 
217   { /* basedInteger */
218     if (base < 2 || base > 36) {
219       err_integer(BASE2TO36ALLOWED, (intType) base);
220       base = 36; /* Avoid subsequent errors */
221     } /* if */
222     if (readBased()) {
223       if (in_file.character == '_') {
224         symbol.bigIntValue = readBigBased(base);
225         symbol.sycategory = BIGINTLITERAL;
226       } else {
227         symbol.intValue = basedValue(base, symbol.name);
228         symbol.sycategory = INTLITERAL;
229       } /* if */
230     } else {
231       symbol.intValue = 0;
232       symbol.sycategory = INTLITERAL;
233     } /* if */
234   } /* basedInteger */
235 
236 
237 
intExponent(uintType * ivalue)238 static inline void intExponent (uintType *ivalue)
239 
240   {
241     uintType uintValue;
242     uintType exponent;
243 
244   /* intExponent */
245     uintValue = *ivalue;
246     in_file.character = next_character();
247     if (in_file.character == '+') {
248       in_file.character = next_character();
249     } else {
250       if (in_file.character == '-') {
251         err_warning(NEGATIVEEXPONENT);
252         uintValue = 0;
253         in_file.character = next_character();
254       } /* if */
255     } /* if */
256     if (char_class(in_file.character) == DIGITCHAR) {
257       readDecimal(0);
258       if (uintValue != 0) {
259         exponent = decimalValue(symbol.name);
260         while (exponent > 0) {
261           exponent--;
262           if (uintValue <= MAX_DIV_10) {
263             uintValue *= 10;
264           } else {
265             err_num_stri(CARD_WITH_EXPONENT_TOO_BIG,
266                 0, (int) *ivalue, &symbol.name[0]);
267             exponent = 0;
268             uintValue = 0;
269           } /* if */
270         } /* while */
271       } /* if */
272     } else {
273       err_cchar(DIGITEXPECTED, in_file.character);
274       uintValue = 0;
275     } /* if */
276     *ivalue = uintValue;
277   } /* intExponent */
278 
279 
280 
readBigInteger(void)281 static inline bigIntType readBigInteger (void)
282 
283   {
284     memSizeType pos;
285     bigIntType result;
286 
287   /* readBigInteger */
288     in_file.character = next_character();
289     pos = 0;
290     do {
291       while (pos != symbol.stri_max && symbol.name[pos] != '\0') {
292         symbol.striValue->mem[pos] = (strElemType) symbol.name[pos];
293         pos++;
294       } /* while */
295       check_stri_length(pos);
296     } while (symbol.name[pos] != '\0');
297     symbol.striValue->size = pos;
298     bigDestr(symbol.bigIntValue);
299     result = bigParse(symbol.striValue);
300     return result;
301   } /* readBigInteger */
302 
303 
304 
readFloat(void)305 static inline floatType readFloat (void)
306 
307   {
308     register sySizeType position;
309     floatType result;
310 
311   /* readFloat */
312     logFunction(printf("readFloat\n"););
313     position = strlen((cstriType) symbol.name);
314     check_symb_length(position);
315     symbol.name[position++] = (ucharType) in_file.character;
316     in_file.character = next_character();
317     if (char_class(in_file.character) == DIGITCHAR) {
318       readDecimal(position);
319       if (in_file.character == 'E' || in_file.character == 'e') {
320         position += strlen((cstriType) &symbol.name[position]);
321         check_symb_length(position);
322         symbol.name[position++] = (ucharType) in_file.character;
323         in_file.character = next_character();
324         if (in_file.character == '+' || in_file.character == '-') {
325           check_symb_length(position);
326           symbol.name[position++] = (ucharType) in_file.character;
327           in_file.character = next_character();
328         } /* if */
329         if (char_class(in_file.character) == DIGITCHAR) {
330           readDecimal(position);
331         } else {
332           err_cchar(DIGITEXPECTED, in_file.character);
333         } /* if */
334       } /* if */
335 #if ATOF_ACCEPTS_DENORMAL_NUMBERS
336       result = (floatType) atof((cstriType) symbol.name);
337 #else
338       result = (floatType) strtod((cstriType) symbol.name, NULL);
339 #endif
340       if (in_file.character == '\'') {
341         in_file.character = next_character();
342         if (char_class(in_file.character) == DIGITCHAR) {
343           readDecimal(position);
344         } else {
345           err_cchar(DIGITEXPECTED, in_file.character);
346         } /* if */
347       } /* if */
348     } else {
349 #if ATOF_ACCEPTS_DENORMAL_NUMBERS
350       result = (floatType) atof((cstriType) symbol.name);
351 #else
352       result = (floatType) strtod((cstriType) symbol.name, NULL);
353 #endif
354       if (in_file.character == '\'') {
355         in_file.character = next_character();
356         if (char_class(in_file.character) == DIGITCHAR) {
357           readDecimal(position);
358         } else {
359           err_cchar(DIGITEXPECTED, in_file.character);
360         } /* if */
361       } else {
362         err_cchar(DIGITEXPECTED, in_file.character);
363       } /* if */
364     } /* if */
365     if (in_file.character == '~') {
366       in_file.character = next_character();
367     } /* if */
368     if (in_file.character == 'E' || in_file.character == 'e') {
369       in_file.character = next_character();
370       if (in_file.character == '+' || in_file.character == '-') {
371         in_file.character = next_character();
372       } /* if */
373       if (char_class(in_file.character) == DIGITCHAR) {
374         readDecimal(position);
375       } else {
376         err_cchar(DIGITEXPECTED, in_file.character);
377       } /* if */
378     } /* if */
379     logFunction(printf("readFloat --> " FMT_E "\n", result););
380     return result;
381   } /* readFloat */
382 
383 
384 
385 /**
386  *  Read a numeric literal.
387  *  The function assumes that the next character in in_file
388  *  is the first character of the numeric literal.
389  *  A numeric literal can be:
390  *  - Decimal integer, e.g.: 12345
391  *  - Decimal bigInteger, e.g.: 12345_
392  *  - Based integer, e.g.: 16#fedcba
393  *  - Based bigInteger, e.g.: 16#fedcba_
394  *  - Decimal integer with exponent, e.g.: 123e3
395  *  - Simple float, e.g.: 123.456
396  *  - Float with exponent, e.g.: 12.3e-12
397  */
lit_number(void)398 void lit_number (void)
399 
400   {
401     uintType number;
402 
403   /* lit_number */
404     logFunction(printf("lit_number\n"););
405     readDecimal(0);
406     if (in_file.character == '.') {
407 #if WITH_FLOAT
408       symbol.floatValue = readFloat();
409 #endif
410       symbol.sycategory = FLOATLITERAL;
411     } else if (in_file.character == '_') {
412       symbol.bigIntValue = readBigInteger();
413       symbol.sycategory = BIGINTLITERAL;
414     } else {
415       number = decimalValue(symbol.name);
416       if (in_file.character == '#') {
417         basedInteger(number);
418       } else if (in_file.character == 'E' || in_file.character == 'e') {
419         intExponent(&number);
420         symbol.intValue = (intType) number;
421         symbol.sycategory = INTLITERAL;
422       } else {
423         symbol.intValue = (intType) number;
424         symbol.sycategory = INTLITERAL;
425       } /* if */
426     } /* if */
427     find_literal_ident();
428     symbol.syNumberInLine++;
429 #if WITH_STATISTIC
430     literal_count++;
431 #endif
432     logFunction(printf("lit_number -->\n"););
433   } /* lit_number */
434