1: /*
2: * $Id: operator.c,v 1.11 2025/05/05 23:09:19 snw Exp $
3: * operators pattern-match, divide, multiply, add, power
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
26: * $Log: operator.c,v $
27: * Revision 1.11 2025/05/05 23:09:19 snw
28: * Revert errors in E notation parsing
29: *
30: * Revision 1.10 2025/05/05 23:02:39 snw
31: * More fixes around E notation
32: *
33: * Revision 1.9 2025/05/05 22:52:32 snw
34: * Make E notation error message more appropriate
35: *
36: * Revision 1.8 2025/05/05 19:34:46 snw
37: * Fix E notation code to disallow more than one minus sign after the E
38: *
39: * Revision 1.7 2025/04/10 01:24:38 snw
40: * Remove C++ style comments
41: *
42: * Revision 1.6 2025/04/09 19:52:02 snw
43: * Eliminate as many warnings as possible while building with -Wall
44: *
45: * Revision 1.5 2025/03/09 19:50:47 snw
46: * Second phase of REUSE compliance and header reformat
47: *
48: *
49: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
50: * SPDX-License-Identifier: AGPL-3.0-or-later
51: **/
52:
53: #include "mpsdef.h"
54: #include <stdlib.h>
55: #include <math.h>
56: #include <ctype.h>
57:
58: int unit (char *str);
59: extern void cond_round (char *a, int digits); /* defined in expr.c */
60:
61:
62:
63: #define PLUS '+'
64: #define MINUS '-'
65: #define POINT '.'
66: #define point (POINT-ZERO)
67: #define ZERO '0'
68: #define ONE (ZERO+1)
69: #define TWO (ZERO+2)
70: #define THREE (ZERO+3)
71: #define FIVE (ZERO+(NUMBASE/2))
72: #define NINE (ZERO+NUMBASE-1)
73: #define NUMBASE 10
74:
75: short int
76: pattern (char *a, char *b) /* evaluates a ? b */
77: {
78: short levels; /* depth of stack */
79: register int patx; /* match stack pointer */
80: short notpatclass; /* pattern class negation */
81: char *ptrpcd[PATDEPTH], /* pointers to patcode */
82: *position[PATDEPTH]; /* position of matching substring */
83: short mincnt[PATDEPTH], /* minimum number of matches */
84: maxcnt[PATDEPTH], /* maximum number of matches */
85: actcnt[PATDEPTH]; /* actual count of matches */
86: short Pflag,
87: Pchar; /* status in pattern alternation */
88: short altc; /* alternation counter */
89: short altcnt[PATDEPTH]; /* gr.pat.alternation counters */
90:
91: unsigned char gpmin[PATDEPTH][PATDEPTH][255]; /* grouped pattern minimum lengthes */
92: char *gp_position[PATDEPTH][PATDEPTH]; /* grouped patt.pos.of substr */
93:
94: char *ptrtom; /* pointer to match code */
95: char patcode;
96: int ch;
97: int i;
98:
99: pattrnflag = Pflag = FALSE; /* incomplete match flag */
100: pattrnchar = Pchar = EOL; /* incomplete match supplement */
101: notpatclass = FALSE; /* pattern class negation */
102: patx = 0;
103: while (*b != EOL) { /* get minimum repeat count */
104: mincnt[patx] = 0;
105: maxcnt[patx] = 255;
106: altcnt[patx] = (-1);
107: if (*b != '.') {
108: ch = (*b++) - '0';
109: while (*b >= '0' && *b <= '9') {
110: ch *= 10;
111: ch += (*b++) - '0';
112: }
113: mincnt[patx] = ch;
114: if (*b != '.')
115: maxcnt[patx] = ch;
116: }
117: /* get maximum repeat count */
118: if (*b == '.') {
119: b++;
120: if (*b >= '0' && *b <= '9') {
121: ch = (*b++) - '0';
122: while (*b >= '0' && *b <= '9') {
123: ch *= 10;
124: ch += (*b++) - '0';
125: }
126: maxcnt[patx] = ch;
127: }
128: }
129: if (maxcnt[patx] < mincnt[patx])
130: return '2'; /* just impossible! */
131: ptrpcd[patx] = b;
132: actcnt[patx] = 0;
133: position[patx] = 0;
134: /* scan strlit, ignore it when empty */
135: if (*b == '"' || *b == 'z' || (*b == '\'' && *(b + 1) == '"')) {
136: if (*(++b) == DELIM) {
137: b++;
138: continue;
139: }
140: while (*(++b) != DELIM) ;
141: b++;
142: } else if (*b == '(') {
143: i = 1;
144: b++;
145: while ((ch = *b) != EOL) {
146: b++;
147: if (ch == '"') {
148: while (*(++b) != DELIM) ;
149: }
150: if (ch == '(') {
151: i++;
152: continue;
153: }
154: if (ch == ')') {
155: i--;
156: if (i < 1)
157: break;
158: }
159: }
160: } else
161: while (*(++b) >= 'A') ;
162: if (++patx >= (PATDEPTH - 1))
163: return '3'; /* stack overflow */
164: }
165: levels = patx;
166: if (*(b - 1) == 'e' && mincnt[levels - 1] == 0 && maxcnt[levels - 1] == 255)
167: *(b - 1) = '~'; /* frequent special case: last pattern is '.E' */
168: mincnt[levels] = maxcnt[levels] = 1; /* sentinel, does never match */
169: actcnt[levels] = 0;
170: ptrpcd[levels] = b; /* (*b==EOL) */
171: patx = 0;
172: while (patx <= levels) {
173: while (actcnt[patx] < mincnt[patx]) {
174: actcnt[patx]++;
175: if (*a == EOL) {
176: pattrnflag = TRUE; /* incomplete match flag */
177: if (patx >= levels) {
178: pattrnchar = EOL;
179: return '1';
180: }
181: if (patx > 0) {
182: if (actcnt[patx - 1] != maxcnt[patx - 1])
183: return '0';
184: /* after alternation we are not sure about */
185: /* that supplement character */
186: if (*(ptrpcd[patx - 1]) == '(') {
187: pattrnchar = EOL;
188: return '0';
189: }
190: }
191: if (*(ptrpcd[patx]) == '"')
192: pattrnchar = *(ptrpcd[patx] + 1);
193: return '0';
194: }
195: for (;;)
196: {
197: /***begin section: does that char match current pattern code ***/
198: ptrtom = ptrpcd[patx];
199: ch = (*a);
200: for (;;)
201: {
202: patcode = (*ptrtom++);
203: if ((notpatclass = (patcode == '\'')))
204: patcode = (*ptrtom++);
205: switch (patcode) { /* we live in an ASCII/ISO world !! */
206: case 'c':
207: if (((ch < SP && ch >= NUL)
208: || ch == DEL) != notpatclass)
209: goto match;
210: break;
211: case 'n':
212: if ((ch <= '9' && ch >= '0') != notpatclass)
213: goto match;
214: break;
215: case 'p':
216: if (((ch >= SP && ch <= '/') ||
217: (ch >= ':' && ch <= '@') ||
218: (ch >= '[' && ch <= '`') ||
219: (ch >= '{' && ch <= '~') ||
220: (ch == '\200')) != notpatclass)
221: goto match;
222: break;
223: case 'a':
224: if (((ch >= 'A' && ch <= 'Z') ||
225: (ch >= 'a' && ch <= 'z')) != notpatclass)
226: goto match;
227: break;
228: case 'l':
229: if ((ch >= 'a' && ch <= 'z') != notpatclass)
230: goto match;
231: break;
232: case 'u':
233: if ((ch >= 'A' && ch <= 'Z') != notpatclass)
234: goto match;
235: break;
236: case 'e':
237: if (!notpatclass)
238: goto match;
239: break;
240: case '"':
241: i = 0;
242: while (a[i++] == (*ptrtom++)) ;
243: if ((*--ptrtom) == DELIM) {
244: if (notpatclass)
245: goto nomatch;
246: b = ptrpcd[patx] + 1;
247: while (*b++ != DELIM)
248: a++;
249: goto match0;
250: }
251: if (notpatclass) {
252: i--;
253: while (*ptrtom++ != DELIM) {
254: if (a[i++] == EOL)
255: goto nomatch;
256: }
257: b = ptrpcd[patx] + 2;
258: while (*b++ != DELIM)
259: a++;
260: goto match0;
261: }
262: if (a[i - 1] == EOL) {
263: pattrnflag = TRUE;
264: pattrnchar = *ptrtom;
265: }
266: goto nomatch;
267:
268: case '~':{
269: pattrnchar = EOL; /* '.E' as last pat_atom */
270: pattrnflag = TRUE;
271: return '1';
272: }
273: /* grouped pattern match */
274: case '(':{
275: char aa[256];
276: char bb[256];
277: int i1,
278: min,
279: max;
280: short pflag;
281: short pchar;
282:
283: if (Pflag) {
284: pflag = Pflag;
285: pchar = Pchar;
286: } else {
287: pflag = FALSE;
288: pchar = EOL;
289: }
290: if (altcnt[patx] < 0) {
291: for (altc = 0; altc < PATDEPTH; altc++)
292: gpmin[patx][altc][1] = 0;
293: }
294: altcnt[patx] = 0;
295: alternation:;
296: i = 0;
297: i1 = 1;
298: while (i1) {
299: bb[i] = *ptrtom++;
300: if (bb[i] == '"') {
301: while ((bb[++i] = (*ptrtom++)) != DELIM) ;
302: }
303: if (bb[i] == '(')
304: i1++;
305: if (bb[i] == ')')
306: i1--;
307: if (bb[i] == ',' && i1 == 1)
308: i1--;
309: i++;
310: }
311: bb[--i] = EOL;
312: pminmax (bb, &min, &max);
313:
314: if ((i1 = gpmin[patx][altcnt[patx]][actcnt[patx]]) < min)
315: gpmin[patx][altcnt[patx]][actcnt[patx]] = i1 = min;
316: gpmin[patx][altcnt[patx]][actcnt[patx] + 1] = 0;
317: /* too much charaters to get a match! */
318: if (i1 > max) {
319: if (*(ptrtom - 1) == ',') {
320: altcnt[patx]++;
321: goto alternation;
322: }
323: pattrnflag = pflag;
324: pattrnchar = pchar;
325: goto nomatch;
326: }
327: /* if number of chars too small, try anyway */
328: /* to get info for "incomplete" match */
329: for (i = 0; i < i1; i++)
330: if ((aa[i] = a[i]) == EOL)
331: break;
332: gp_position[patx][actcnt[patx]] = a;
333:
334: for (;;)
335: {
336: aa[i] = EOL;
337: i1 = pattern (aa, bb);
338: if (i1 == '1') {
339: gpmin[patx][altcnt[patx]][actcnt[patx]] = i;
340: a += i;
341: goto match0;
342: }
343: if (i1 != '0')
344: return i1;
345: if (pattrnflag) {
346: if (pflag == FALSE)
347: pchar = pattrnchar;
348: else if (pchar != pattrnchar)
349: pchar = EOL;
350: pflag = TRUE;
351: }
352: if (!pattrnflag) {
353: if (*(ptrtom - 1) == ',') {
354: altcnt[patx]++;
355: goto alternation;
356: }
357: pattrnflag = pflag;
358: pattrnchar = pchar;
359: goto nomatch;
360: }
361: if (a[i] == EOL) {
362: Pflag = pflag;
363: Pchar = pchar;
364: if (*(ptrtom - 1) == ',') {
365: altcnt[patx]++;
366: goto alternation;
367: }
368: pattrnflag = pflag;
369: pattrnchar = pchar;
370: return '0';
371: }
372: aa[i] = a[i];
373: i++;
374: }
375: }
376: /* match one of listed characters ?1Z"string" */
377: case 'z':
378: for (;;)
379: {
380: if ((*++ptrtom) == DELIM) {
381: if (notpatclass)
382: goto match;
383: goto nomatch;
384: }
385: if (ch != *ptrtom) {
386: if (*(ptrtom + 1) == '.' && *(ptrtom + 2) == '.') {
387: if (ch < *ptrtom ||
388: (ch > *(ptrtom + 3) && *(ptrtom + 3) != DELIM)) {
389: ptrtom += 2;
390: continue;
391: }
392: } else
393: continue;
394: }
395: while (*++ptrtom != DELIM) ;
396: if (notpatclass)
397: goto nomatch;
398: goto match;
399: }
400:
401: /* loadable matches */
402: case 'C':
403: i = 0;
404: while (zmc[i] != EOL) {
405: if (zmc[i] == ch && !notpatclass)
406: goto match;
407: i++;
408: }
409: if (notpatclass)
410: goto match;
411: break;
412: case 'N':
413: i = 0;
414: while (zmn[i] != EOL) {
415: if (zmn[i] == ch && !notpatclass)
416: goto match;
417: i++;
418: }
419: if (notpatclass)
420: goto match;
421: break;
422: case 'P':
423: i = 0;
424: while (zmp[i] != EOL) {
425: if (zmp[i] == ch && !notpatclass)
426: goto match;
427: i++;
428: }
429: if (notpatclass)
430: goto match;
431: break;
432: case 'A':
433: i = 0;
434: while (zmu[i] != EOL) {
435: if (zmu[i] == ch && !notpatclass)
436: goto match;
437: i++;
438: }
439: case 'L':
440: i = 0;
441: while (zml[i] != EOL) {
442: if (zml[i] == ch && !notpatclass)
443: goto match;
444: i++;
445: }
446: if (notpatclass)
447: goto match;
448: break;
449: case 'U':
450: i = 0;
451: while (zmu[i] != EOL) {
452: if (zmu[i] == ch && !notpatclass)
453: goto match;
454: i++;
455: }
456: if (notpatclass)
457: goto match;
458: break;
459: default:
460: goto nomatch;
461: } /* end_switch */
462: } /* end repeat */
463: /*** end section: does that char match current pattern atom ***/
464: nomatch:;
465: if (patcode == '(') {
466: for (altc = 0; altc <= altcnt[patx]; altc++)
467: gpmin[patx][altc][actcnt[patx]] = 0;
468: if (--actcnt[patx] > 0) {
469: for (altc = 0; altc <= altcnt[patx]; altc++)
470: gpmin[patx][altc][actcnt[patx]]++;
471: a = gp_position[patx][actcnt[patx]]; /* try previous patterns again */
472: continue;
473: }
474: }
475: do {
476: actcnt[patx] = 0;
477: if (--patx < 0)
478: return '0'; /* stack exhausted */
479: if (*(ptrpcd[patx]) == '(') {
480: if (actcnt[patx] >= maxcnt[patx]) {
481: ++actcnt[patx];
482: patcode = '(';
483: goto nomatch;
484: }
485: }
486: } while (++actcnt[patx] > maxcnt[patx]);
487: a = position[patx]; /* try previous patterns again */
488:
489: } /* end repeat */
490: match:;
491: a++;
492: match0:;
493: }
494: position[patx++] = a; /* pos after last match */
495: }
496: return '0';
497: } /* end of pattern */
498:
499: /******************************************************************************/
500: void pminmax (char *str, int *min, int *max)
501: {
502: int mininc,
503: maxinc,
504: i,
505: ch;
506:
507: *min = 0;
508: *max = 0;
509: mininc = 0;
510: maxinc = 0;
511: i = 0;
512: ch = 0;
513: while (str[i] != EOL) {
514: if (str[i] != '.') { /* scan minimum repeat count */
515: ch = (str[i++]) - '0';
516: while (str[i] >= '0' && str[i] <= '9') {
517: ch *= 10;
518: ch += (str[i++]) - '0';
519: }
520: mininc = ch;
521: maxinc = ch;
522: } else {
523: mininc = 0;
524: maxinc = 255;
525: }
526: if (str[i] == '.') { /* scan maximum repeat count */
527: i++;
528: if (str[i] >= '0' && str[i] <= '9') {
529: ch = (str[i++]) - '0';
530: while (str[i] >= '0' && str[i] <= '9') {
531: ch *= 10;
532: ch += (str[i]++) - '0';
533: }
534: } else
535: ch = 255;
536: maxinc = ch;
537: }
538: /* skip pattern codes */
539: if (str[i] == '"') {
540: int cnt;
541:
542: cnt = 0;
543: while (str[++i] != DELIM)
544: cnt++;
545: mininc = mininc * cnt;
546: maxinc = maxinc * cnt;
547: }
548: if (str[i] == 'z' || str[i] == '"') {
549: while (str[++i] != DELIM) ;
550: i++;
551: } else if (str[i] == '(') {
552: char tmp[256];
553: char *tcur;
554: int tmin,
555: tmax,
556: Tmin,
557: Tmax,
558: i1;
559:
560: tmin = 255;
561: tmax = 0;
562: alternation:;
563: i1 = 1;
564: tcur = tmp;
565: while (i1) {
566: ch = str[++i];
567: *tcur++ = ch;
568: if (ch == '"')
569: while ((*tcur++ = str[++i]) != DELIM) ;
570: if (ch == '(')
571: i1++;
572: if (ch == ')')
573: i1--;
574: if (ch == ',' && i1 == 1)
575: i1--;
576: }
577: *(--tcur) = EOL;
578: pminmax (tmp, &Tmin, &Tmax);
579: if (Tmin < tmin)
580: tmin = Tmin;
581: if (Tmax > tmax)
582: tmax = Tmax;
583: if (str[i] == ',')
584: goto alternation;
585: i++;
586: mininc *= tmin;
587: maxinc *= tmax;
588: } else
589: while (str[++i] >= 'A') ;
590: *min += mininc;
591: *max += maxinc;
592: }
593: if (*max > 255)
594: *max = 255;
595: return;
596: } /* end pminmax() */
597: /******************************************************************************/
598: void add (char *a, char *b) /* string arithmetic a+=b; */
599: {
600:
601: if (b[0] == ZERO)
602: return;
603: if (a[0] == ZERO) {
604: stcpy (a, b);
605: return;
606: } {
607: long dpa, /* decimal point of 'a' */
608: dpb, /* decimal point of 'b' */
609: lena, /* length of 'a' */
610: lenb; /* length of 'b' */
611: char mi; /* minus flag */
612: short sign; /* sign flag if a<0<b sign=-1; */
613:
614: /* if a>0>b sign=1; */
615: /* else sign=0; */
616:
617: register int i;
618: register int ch;
619: register int j;
620: register int carry;
621:
622: #if !defined(_AIX)
623: if (fp_mode) {
624: double fp_a;
625: double fp_b;
626:
627: stcnv_m2c (a);
628: stcnv_m2c (b);
629:
630: fp_a = atof (a);
631: fp_b = atof (b);
632:
633: snprintf (a, STRLEN - 1, fp_conversion, fp_a + fp_b);
634: trim_decimal (a);
635:
636: return;
637: }
638: #endif
639:
640:
641:
642: /* look at the signs */
643: mi = 0;
644: sign = 0;
645: if (a[0] == b[0] && a[0] == MINUS) {
646: mi++;
647: a[0] = b[0] = ZERO;
648: } else if (a[0] == MINUS) {
649: sign--;
650: a[0] = NINE;
651: i = 0;
652: while ((ch = a[++i]) != EOL)
653: if (ch != POINT)
654: a[i] = ZERO + NINE - ch;
655: a[--i]++;
656: } else if (b[0] == MINUS) {
657: sign++;
658: b[0] = NINE;
659: i = 0;
660: while ((ch = b[++i]) != EOL)
661: if (ch != POINT)
662: b[i] = ZERO + NINE - ch;
663: b[--i]++;
664: }
665: /* search decimal points and length */
666: dpa = dpb = (-1);
667: i = 0;
668: while (a[i] != EOL) {
669: if (a[i] == POINT)
670: dpa = i;
671: i++;
672: }
673: lena = i;
674: if (dpa < 0)
675: dpa = i;
676: again:;
677: i = 0;
678: while (b[i] != EOL) {
679: if (b[i] == POINT)
680: dpb = i;
681: i++;
682: }
683: lenb = i;
684: if (dpb < 0)
685: dpb = i;
686: if (i == 1) {
687: if (b[0] == ONE && sign == 0 && dpa > 0) { /* frequent special case: add 1 */
688: i = dpa - 1;
689: while (++a[i] > NINE) {
690: a[i--] = ZERO;
691: if (i < 0) {
692: i = lena;
693: while (i >= 0) {
694: a[i + 1] = a[i];
695: i--;
696: }
697: a[0] = ONE;
698: return;
699: }
700: }
701: return;
702: }
703: }
704: /* copy additional trailing digits from b to a */
705: if (lenb - dpb > lena - dpa) {
706: j = dpa - dpb;
707: if (lenb + j > STRLEN) { /* round off that monster ! */
708: i = STRLEN - j;
709: if (b[i] < FIVE) {
710: b[i] = EOL;
711: lenb--;
712: while (b[--i] == ZERO) {
713: b[i] = EOL;
714: lenb--;
715: }
716: } else {
717: for (;;)
718: {
719: if (i >= dpb) {
720: b[i] = EOL;
721: lenb--;
722: } else
723: b[i] = ZERO;
724: if (--i < 0) {
725: for (i = lenb; i >= 0; i--)
726: b[i + 1] = b[i];
727: b[0] = ONE;
728: dpb = ++lenb;
729: break;
730: }
731: if ((ch = b[i]) == POINT) {
732: dpb = i;
733: continue;
734: }
735: if (ch < NINE && ch >= ZERO) {
736: b[i] = ++ch;
737: break;
738: }
739: }
740: }
741: goto again; /* look what's left from b */
742: }
743: lenb = i = lena - dpa + dpb;
744: j = lena;
745: while ((a[j++] = b[i++]) != EOL) ;
746: lena = (--j);
747: b[lenb] = EOL;
748: }
749: /* $justify a or b */
750: i = dpa - dpb;
751: if (i < 0) {
752: j = lena;
753: if ((i = (lena -= i)) > (STRLEN - 2) /*was 253*/) {
754: merr_raise (M75);
755: return;
756: }
757: ch = (sign >= 0 ? ZERO : NINE);
758: while (j >= 0)
759: a[i--] = a[j--];
760: while (i >= 0)
761: a[i--] = ch;
762: dpa = dpb;
763: } else if (i > 0) {
764: j = lenb;
765: if ((lenb = (i += lenb)) > (STRLEN - 2)/*was 253*/) {
766: merr_raise (M75);
767: return;
768: }
769: ch = (sign <= 0 ? ZERO : NINE);
770: while (j >= 0)
771: b[i--] = b[j--];
772: while (i >= 0)
773: b[i--] = ch;
774: dpb = dpa;
775: }
776: /* now add */
777: carry = 0;
778: for (i = lenb - 1; i >= 0; i--) {
779: if ((ch = a[i]) == POINT)
780: continue;
781: ch += b[i] - ZERO + carry;
782: if ((carry = (ch > NINE)))
783: ch -= NUMBASE;
784: a[i] = ch;
785: }
786: while (a[lena] != EOL)
787: lena++;
788: if (carry) {
789: if ((i = (++lena)) > (STRLEN - 2)/*was 253*/) {
790: merr_raise (M75);
791: return;
792: }
793: while (i > 0) {
794: a[i] = a[i - 1];
795: i--;
796: }
797: a[0] = ONE;
798: }
799: if (sign) {
800: if (a[0] == ONE) {
801: a[0] = ZERO;
802: } else {
803: i = 0;
804: carry = 0;
805: while ((ch = a[++i]) != EOL)
806: if (ch != POINT)
807: a[i] = ZERO + NINE - ch;
808: while (--i > 0) {
809: if (a[i] != POINT) {
810: if (++a[i] <= NINE)
811: break;
812: a[i] = ZERO;
813: }
814: }
815: mi = 1;
816: a[0] = ZERO;
817: }
818: while (a[(int) mi] == ZERO) {
819: stcpy (&a[(int) mi], &a[((int) mi) + 1]);
820: dpa--;
821: }
822: if (dpa < 0)
823: dpa = 0;
824: }
825: /* remove trailing zeroes */
826: i = dpa;
827: while (a[i] != EOL)
828: i++;
829: if (--i > dpa) {
830: while (a[i] == ZERO)
831: a[i--] = EOL;
832: }
833: /* remove trailing point */
834: if (a[i] == POINT)
835: a[i] = EOL;
836: if (mi) {
837: if (a[0] != ZERO) {
838: i = 0;
839: while (a[i++] != EOL) ;
840: while (i > 0) {
841: a[i] = a[i - 1];
842: i--;
843: }
844: }
845: a[0] = MINUS;
846: }
847: if (a[(int) mi] == EOL) {
848: a[0] = ZERO;
849: a[1] = EOL;
850: }
851: return;
852: }
853: }
854: /******************************************************************************/
855: void mul (char *a, char *b) /* string arithmetic a=a*b */
856: {
857: char c[2*(STRLEN+1) /*was 512*/];
858: short alen,
859: blen,
860: clen,
861: mi,
862: tmpx;
863: register int acur;
864: register int bcur;
865: register int ccur;
866: register int carry;
867:
868: #if !defined(_AIX)
869: if (fp_mode) {
870: double fp_a;
871: double fp_b;
872:
873: stcnv_m2c (a);
874: stcnv_m2c (b);
875:
876: fp_a = atof (a);
877: fp_b = atof (b);
878:
879: snprintf (a, STRLEN - 1, fp_conversion, fp_a * fp_b);
880: trim_decimal (a);
881:
882: return;
883: }
884: #endif
885:
886:
887: if (merr () > OK)
888: return; /* avoid nonsense in recursion */
889: /* if zero or one there's not much to do */
890: if (b[1] == EOL) {
891: if (b[0] == ZERO) {
892: a[0] = ZERO;
893: a[1] = EOL;
894: return;
895: }
896: if (b[0] <= ONE)
897: return;
898: if (b[0] == TWO) {
899: multwo:acur = 0;
900: while (a[++acur] != EOL) ;
901: mi = (a[acur - 1] == FIVE);
902: carry = 0;
903: ccur = acur;
904: while (acur >= 0) {
905: if ((bcur = a[--acur]) < ZERO)
906: continue;
907: bcur = bcur * 2 - ZERO + carry;
908: carry = 0;
909: if (bcur > NINE) {
910: carry = 1;
911: bcur -= NUMBASE;
912: }
913: a[acur] = bcur;
914: }
915: if (carry) {
916: acur = ccur;
917: if (acur > (STRLEN - 1)/*was 254*/) {
918: merr_raise (M75);
919: return;
920: }
921: while (acur >= 0) {
922: a[acur + 1] = a[acur];
923: acur--;
924: }
925: a[a[0] == MINUS] = ONE;
926: }
927: if (mi) {
928: if (carry)
929: ccur++;
930: acur = 0;
931: while (acur < ccur)
932: if (a[acur++] == POINT) {
933: a[--ccur] = EOL;
934: if (acur == ccur)
935: a[--ccur] = EOL;
936: return;
937: }
938: }
939: return;
940: }
941: }
942: if (a[1] == EOL) {
943: if (a[0] == ZERO) {
944: return;
945: }
946: if (a[0] <= ONE) {
947: stcpy (a, b);
948: return;
949: }
950: if (a[0] == TWO) {
951: stcpy (a, b);
952: goto multwo;
953: }
954: }
955: /* get length of strings and convert ASCII to decimal */
956: /* have a look at the signs */
957: if ((mi = (a[0] == MINUS))) {
958: a[0] = ZERO;
959: }
960: if (b[0] == MINUS) {
961: b[0] = ZERO;
962: toggle (mi);
963: }
964: carry = 0;
965: alen = 0;
966: while (a[alen] != EOL) {
967: a[alen] -= ZERO;
968: if (a[alen++] == point)
969: carry = alen;
970: }
971: /* append a point on the right side if there was none */
972: if (--carry < 0) {
973: carry = alen;
974: a[alen++] = point;
975: a[alen] = 0;
976: }
977: ccur = 0;
978: blen = 0;
979: while (b[blen] != EOL) {
980: b[blen] -= ZERO;
981: if (b[blen++] == point)
982: ccur = blen;
983: }
984: if (--ccur < 0) {
985: ccur = blen;
986: b[blen++] = point;
987: b[blen] = 0;
988: }
989: carry += ccur;
990: if (carry > (STRLEN - 3) /*was 252*/) {
991: a[0] = EOL;
992: merr_raise (M75);
993: return;
994: }
995: ccur = clen = alen + blen;
996: /* init c to zero */
997: while (ccur >= 0)
998: c[ccur--] = 0;
999: c[carry] = point;
1000:
1001: bcur = blen;
1002: clen = alen + blen - 1;
1003: carry = 0;
1004: while (bcur > 0) {
1005: if (b[--bcur] == point) {
1006: continue;
1007: }
1008: if (c[clen] == point)
1009: clen--;
1010: acur = alen;
1011: ccur = clen--;
1012: while (acur > 0) {
1013: if (a[--acur] == point)
1014: continue;
1015: if (c[--ccur] == point)
1016: --ccur;
1017: tmpx = a[acur] * b[bcur] + c[ccur] + carry;
1018: carry = tmpx / NUMBASE;
1019: c[ccur] = tmpx % NUMBASE;
1020: }
1021: while (carry) {
1022: if (c[--ccur] == point)
1023: ccur--;
1024: if ((c[ccur] += carry) >= NUMBASE) {
1025: c[ccur] -= NUMBASE;
1026: carry = 1;
1027: } else
1028: carry = 0;
1029: }
1030: }
1031: /* copy result to a and convert it */
1032: a[ccur = clen = acur = (alen += blen)] = EOL;
1033: while (--ccur >= 0) {
1034: if (c[ccur] < NUMBASE)
1035: a[ccur] = c[ccur] + ZERO;
1036: else
1037: a[alen = ccur] = POINT;
1038: }
1039: /* oversize string */
1040: if (acur > STRLEN) {
1041: if (a[acur = STRLEN] >= FIVE) {
1042: int l1;
1043:
1044: l1 = STRLEN;
1045: if (a[l1] >= FIVE) {
1046: for (;;)
1047: {
1048: if (a[--l1] == POINT)
1049: l1--;
1050: if (l1 < (a[0] == MINUS)) {
1051: for (l1 = STRLEN; l1 > 0; l1--)
1052: a[l1] = a[l1 - 1];
1053: a[a[0] == MINUS] = ONE;
1054: break;
1055: }
1056: if ((++a[l1]) == (NINE + 1))
1057: a[l1] = ZERO;
1058: else
1059: break;
1060: }
1061: }
1062: }
1063: a[acur] = EOL;
1064: }
1065: /* remove trailing zeroes */
1066: if (acur >= alen) {
1067: while (a[--acur] == ZERO)
1068: a[acur] = EOL;
1069: }
1070: /* remove trailing point */
1071: if (a[acur] == POINT)
1072: a[acur] = EOL;
1073: /* remove leading zeroes */
1074: while (a[mi] == ZERO) {
1075: acur = mi;
1076: while ((a[acur] = a[acur + 1]) != EOL)
1077: acur++;
1078: }
1079: if (a[0] == EOL) {
1080: a[0] = ZERO;
1081: a[1] = EOL;
1082: mi = 0;
1083: }
1084: if (mi) {
1085: if (a[0] != ZERO) {
1086: acur = clen;
1087: while (acur > 0) {
1088: a[acur] = a[acur - 1];
1089: acur--;
1090: }
1091: }
1092: a[0] = MINUS;
1093: }
1094: return;
1095: }
1096: /******************************************************************************
1097: * for a detailed description of the method for the divisions see *
1098: * donald e.knuth 'the art of computer programming' vol.2 p.257 *
1099: ******************************************************************************/
1100: void mdiv (char *uu, char *v, short typ) /* divide string arithmetic */
1101: {
1102: char q[STRLEN + 2 /*was 257*/]; /* quotient */
1103: char u[2*(STRLEN + 1)/*was 512*/];/* intermediate result */
1104: char vv[STRLEN +1 /*was 256*/];
1105: short d,
1106: d1,
1107: k1,
1108: m,
1109: ulen,
1110: vlen,
1111: dpu,
1112: dpv,
1113: guess,
1114: mi,
1115: plus,
1116: v1;
1117: register long int i;
1118: register int j;
1119: register int k;
1120: register int carry = 0;
1121:
1122: #if !defined(_AIX)
1123: if (fp_mode) {
1124: double fp_uu;
1125: double fp_v;
1126:
1127: stcnv_m2c (uu);
1128: stcnv_m2c (v);
1129:
1130: fp_uu = atof (uu);
1131: fp_v = atof (v);
1132:
1133: switch (typ) {
1134:
1135: case '/':
1136: snprintf (uu, STRLEN - 1, fp_conversion, fp_uu / fp_v);
1137: break;
1138:
1139: case '\\':
1140: snprintf (uu, STRLEN - 1, "%ld\201", (long) (fp_uu / fp_v));
1141: break;
1142:
1143: case '#':
1144: snprintf (uu, STRLEN - 1, "%ld\201", (((long) fp_uu) % ((long) fp_v)));
1145: /*snprintf (uu, STRLEN - 1, "%ld\201", ((long) fp_uu < 0 ? (((long) fp_uu % (long) fp_v) + (long) fp_v) % (long) fp_v : (long) fp_uu % (long) fp_v)); */
1146: break;
1147: }
1148:
1149: trim_decimal (uu);
1150:
1151: return;
1152: }
1153: #endif
1154:
1155:
1156: if (merr () > OK)
1157: return; /* avoid nonsense in recursion */
1158: if (uu[0] == ZERO)
1159: return;
1160: #ifdef NEVER
1161: /* should be faster on DIV 2, but causes some error
1162: * in connection with SQRT */
1163: if (v[1] == EOL && typ == '/') {
1164: if (v[0] == ONE)
1165: return;
1166: if (v[0] == TWO) {
1167: carry = 0;
1168: k = (-1);
1169: k1 = (-1);
1170: while ((i = uu[++k]) != EOL) {
1171: if (i < ZERO) {
1172: if (i == POINT) {
1173: k1 = k;
1174: if (k + zprecise < STRLEN)
1175: uu[k + zprecise] = EOL;
1176: }
1177: continue;
1178: }
1179: if (i == EOL)
1180: break;
1181: if (i & 01)
1182: j = NUMBASE;
1183: i = (i + ZERO + carry) / 2;
1184: carry = j;
1185: j = 0;
1186: uu[k] = i;
1187: }
1188: j = (uu[0] == MINUS);
1189: if (uu[j] == ZERO) {
1190: while (j < k) {
1191: uu[j] = uu[j + 1];
1192: j++;
1193: }
1194: k--;
1195: }
1196: if (carry && k < (STRLEN - 2) /*was 253*/) {
1197: if (k1 < 0) {
1198: k1 = k;
1199: uu[k++] = POINT;
1200: }
1201: uu[k++] = FIVE;
1202: uu[k] = EOL;
1203: }
1204: return;
1205: }
1206: }
1207: #endif /* NEVER */
1208: /* look at the signs */
1209: stcpy (u, uu);
1210: mi = 0;
1211: plus = 0;
1212: if (typ != '#') {
1213: if (u[0] == MINUS) {
1214: u[0] = ZERO;
1215: mi = 1;
1216: }
1217: if (v[0] == MINUS) {
1218: v[0] = ZERO;
1219: toggle (mi);
1220: }
1221: } else {
1222: stcpy (vv, v);
1223: if (u[0] == MINUS) {
1224: u[0] = ZERO;
1225: plus = 1;
1226: }
1227: if (v[0] == MINUS) {
1228: v[0] = ZERO;
1229: mi = 1;
1230: toggle (plus);
1231: }
1232: }
1233: /* convert from ASCII to 'number' */
1234: i = 0;
1235: dpv = (-1);
1236: k = 0;
1237: while ((j = v[i]) != EOL) {
1238: j -= ZERO;
1239: if (j == point)
1240: dpv = i;
1241: if (j == 0)
1242: k++;
1243: v[i++] = j;
1244: }
1245:
1246: v[vlen = i] = 0;
1247: v[i + 1] = 0;
1248: v[i + 2] = 0;
1249: if (v[0] != 0) {
1250: while (i >= 0) {
1251: v[i + 1] = v[i];
1252: i--;
1253: }
1254: v[0] = 0;
1255: dpv++;
1256: } else {
1257: vlen--;
1258: }
1259: d1 = 0;
1260:
1261: i = 0;
1262: dpu = (-1);
1263: while (u[i] != EOL) {
1264: u[i] -= ZERO;
1265: if (u[i] == point)
1266: dpu = i;
1267: i++;
1268: }
1269: if (dpu < 0) {
1270: u[dpu = i++] = point;
1271: }
1272: /* u[ulen=i]=0; u[i+1]=0; u[i+2]=0; */
1273: ulen = i;
1274: while (i < 512)
1275: u[i++] = 0;
1276: i = ulen; /* somehow that's necessary - sometimes I check why */
1277: if (u[0] != 0) {
1278: while (i >= 0) {
1279: u[i + 1] = u[i];
1280: i--;
1281: }
1282: u[0] = 0;
1283: dpu++;
1284: } else {
1285: ulen--;
1286: }
1287: if ((vlen + zprecise) > STRLEN && (dpv + zprecise) < vlen)
1288: vlen -= zprecise;
1289:
1290: if (dpv > 0) { /* make v an integer *//* shift v */
1291: d1 = vlen - dpv;
1292: for (i = dpv; i < vlen; i++)
1293: v[i] = v[i + 1];
1294: vlen--;
1295: /* remove leading zeroes */
1296: while (v[1] == 0) {
1297: for (i = 1; i <= vlen; i++)
1298: v[i] = v[i + 1];
1299: vlen--;
1300: }
1301: v[vlen + 1] = 0;
1302: v[vlen + 2] = 0;
1303: /* shift u */
1304: i = dpu;
1305: for (j = 0; j < d1; j++) {
1306: if (i >= ulen) {
1307: u[i + 1] = 0;
1308: ulen++;
1309: }
1310: u[i] = u[i + 1];
1311: i++;
1312: }
1313: u[i] = point;
1314: dpu = i;
1315: }
1316: d = dpu + 1 - ulen;
1317: if (dpv > dpu)
1318: d += dpv - dpu;
1319: if (typ == '/')
1320: d += zprecise;
1321: if ((d + ulen) > STRLEN) {
1322: u[0] = EOL;
1323: merr_raise (M75);
1324: return;
1325: }
1326: while (d > 0) {
1327: u[++ulen] = 0;
1328: d--;
1329: }
1330: /* normalize */
1331: if ((d = NUMBASE / (v[1] + 1)) > 1) {
1332: i = ulen;
1333: carry = 0;
1334: while (i > 0) {
1335: if (u[i] != point) {
1336: carry += u[i] * d;
1337: u[i] = carry % NUMBASE;
1338: carry = carry / NUMBASE;
1339: }
1340: i--;
1341: }
1342: u[0] = carry;
1343: i = vlen;
1344: carry = 0;
1345: while (i > 0) {
1346: carry += v[i] * d;
1347: v[i] = carry % NUMBASE;
1348: carry = carry / NUMBASE;
1349: i--;
1350: }
1351: v[0] = carry;
1352: }
1353: /* initialize */
1354: j = 0;
1355: m = ulen - vlen + 1;
1356: if (m <= dpu)
1357: m = dpu + 1;
1358: for (i = 0; i <= m; q[i++] = ZERO) ;
1359: if (typ == '#') {
1360: m = dpu - vlen;
1361: }
1362: v1 = v[1];
1363:
1364: while (j < m) {
1365: if (u[j] != point) { /* calculate guess */
1366: if ((k = u[j] * NUMBASE + (u[j + 1] == point ? u[j + 2] : u[j + 1])) == 0) {
1367: j++;
1368: continue;
1369: }
1370: k1 = (u[j + 1] == point || u[j + 2] == point ? u[j + 3] : u[j + 2]);
1371: guess = (u[j] == v1 ? (NUMBASE - 1) : k / v1);
1372: if (v[2] * guess > (k - guess * v1) * NUMBASE + k1) {
1373: guess--;
1374: if (v[2] * guess > (k - guess * v1) * NUMBASE + k1)
1375: guess--;
1376: }
1377: /* multiply and subtract */
1378: i = vlen;
1379: carry = 0;
1380: k = j + i;
1381: if (j < dpu && k >= dpu)
1382: k++;
1383: while (k >= 0) {
1384: if (u[k] == point)
1385: k--;
1386: if (i >= 0) {
1387: u[k] -= v[i--] * guess + carry;
1388: } else {
1389: if (carry == 0)
1390: break;
1391: u[k] -= carry;
1392: }
1393: carry = 0;
1394: while (u[k] < 0) {
1395: u[k] += NUMBASE;
1396: carry++;
1397: }
1398: k--;
1399: }
1400: /* test remainder / add back */
1401: if (carry) {
1402: guess--;
1403: i = vlen;
1404: carry = 0;
1405: k = j + i;
1406: if (j < dpu && k >= dpu)
1407: k++;
1408: while (k >= 0) {
1409: if (u[k] == point)
1410: k--;
1411: if (i >= 0) {
1412: u[k] += v[i--] + carry;
1413: } else {
1414: if (carry == 0)
1415: break;
1416: u[k] += carry;
1417: }
1418: carry = u[k] / NUMBASE;
1419: u[k] = u[k] % NUMBASE;
1420: k--;
1421: }
1422: }
1423: q[j++] = guess + ZERO;
1424: u[0] = 0;
1425: } else {
1426: q[j++] = POINT;
1427: }
1428: }
1429: /* unnormalize */
1430: if (typ != '#') {
1431: i = 0;
1432: while (i <= m) {
1433: if ((u[i] = q[i]) == POINT)
1434: dpv = i;
1435: i++;
1436: }
1437: k = vlen;
1438: k1 = dpv;
1439: while (k-- > 0) {
1440: while (k1 <= 0) {
1441: for (i = (++m); i > 0; i--)
1442: u[i] = u[i - 1];
1443: k1++;
1444: u[0] = ZERO;
1445: }
1446: u[k1] = u[k1 - 1];
1447: u[--k1] = POINT;
1448: dpv = k1;
1449: }
1450: u[m] = EOL;
1451: /* rounding */
1452:
1453: if (typ != '/')
1454: u[dpv + 1] = EOL;
1455: else {
1456: k = dpv + zprecise;
1457: k1 = u[k + 1] >= FIVE;
1458: u[k + 1] = EOL;
1459: if (k1) {
1460: do {
1461: if (u[k] != POINT) {
1462: if ((carry = (u[k] == NINE)))
1463: u[k] = ZERO;
1464: else
1465: u[k]++;
1466: }
1467: k--;
1468: } while (carry);
1469: }
1470: }
1471: } else { /* return the remainder */
1472: carry = 0;
1473: if (d > 1) {
1474: for (i = 0; i <= ulen; i++) {
1475: if (u[i] == point) {
1476: u[i] = POINT;
1477: dpu = i;
1478: } else {
1479: u[i] = (j = carry + u[i]) / d + ZERO;
1480: carry = j % d * NUMBASE;
1481: }
1482: }
1483: } else {
1484: for (i = 0; i <= ulen; i++)
1485: if (u[i] == point)
1486: u[dpu = i] = POINT;
1487: else
1488: u[i] += ZERO;
1489: }
1490: u[i] = EOL;
1491: if (d1 > 0) {
1492: u[i + 1] = EOL;
1493: u[i + 2] = EOL;
1494: i = dpu;
1495: for (j = 0; j < d1; j++) {
1496: u[i] = u[i - 1];
1497: i--;
1498: }
1499: u[i] = POINT;
1500: }
1501: }
1502: /* remove trailing zeroes */
1503: i = 0;
1504: k = (-1);
1505: while (u[i] != EOL) {
1506: if (u[i] == POINT)
1507: k = i;
1508: i++;
1509: }
1510: i--;
1511: if (k >= 0) {
1512: while (u[i] == ZERO && i > k)
1513: u[i--] = EOL;
1514: }
1515: /* remove trailing point */
1516: if (u[i] == POINT)
1517: u[i] = EOL;
1518: /* remove leading zeroes */
1519: while (u[0] == ZERO) {
1520: i = 0;
1521: while ((u[i] = u[i + 1]) != EOL)
1522: i++;
1523: }
1524: if (u[0] == EOL) {
1525: u[0] = ZERO;
1526: u[1] = EOL;
1527: mi = 0;
1528: }
1529: if ((mi || plus) && (u[0] != ZERO)) {
1530: if (mi != plus) {
1531: i = stlen (u) + 1;
1532: do {
1533: u[i] = u[i - 1];
1534: i--;
1535: } while (i > 0);
1536: u[0] = MINUS;
1537: }
1538: if (plus)
1539: add (u, vv);
1540: }
1541: stcpy (uu, u);
1542: return;
1543: } /* end div() */
1544: /******************************************************************************/
1545: void power (char *a, char *b) /* raise a to the b-th power */
1546: {
1547: char c[STRLEN + 2/*was 257*/];
1548: char d[4*(STRLEN + 1)/*was 1024*/];/* 257 should be sufficient, but somewhere there */
1549:
1550: /* is a memory leak resulting in wrong results */
1551: /* with fractional powers, e.g. 2**(3/7) */
1552: /* even a value of 513 is too small */
1553: char e[STRLEN + 2/*was 257*/];
1554: register long i;
1555: register long j;
1556:
1557: #if !defined(_AIX)
1558: if (fp_mode) {
1559: double fp_a;
1560: double fp_b;
1561:
1562: stcnv_m2c (a);
1563: stcnv_m2c (b);
1564:
1565: fp_a = atof (a);
1566: fp_b = atof (b);
1567:
1568: snprintf (a, STRLEN - 1, fp_conversion, pow (fp_a, fp_b));
1569:
1570: trim_decimal (a);
1571:
1572: return;
1573: }
1574: #endif
1575:
1576:
1577: if (merr () > OK)
1578: return; /* avoid nonsense in recursion */
1579: /* if zero or one there's not much to do */
1580: if (a[1] == EOL) {
1581: if (a[0] == ZERO) {
1582: if (b[1] == EOL && b[0] == ZERO)
1583: merr_raise (M9);
1584: return;
1585: } /* undef */
1586: if (a[0] == ONE)
1587: return;
1588: }
1589: if (b[0] == MINUS) {
1590: power (a, &b[1]);
1591: if (merr () == M75) {
1592: a[0] = ZERO;
1593: a[1] = EOL;
1594: merr_raise (OK);
1595: return;
1596: }
1597: stcpy (c, a);
1598: a[0] = ONE;
1599: a[1] = EOL;
1600: mdiv (a, c, '/');
1601: return;
1602: }
1603: if (b[1] == EOL) {
1604: switch (b[0]) {
1605: case ZERO:
1606: a[0] = ONE;
1607: a[1] = EOL;
1608: case ONE:
1609: return;
1610: case TWO:
1611: stcpy (c, a);
1612: mul (a, c);
1613: return;
1614: }
1615: }
1616: /* look for decimal point */
1617: e[0] = EOL;
1618: i = 0;
1619: while (b[i] != EOL) {
1620: if (b[i] == POINT) {
1621: if (a[0] == MINUS) {
1622: merr_raise (M9);
1623: return;
1624: } /* undefined case */
1625: if (b[i + 1] == FIVE && b[i + 2] == EOL) { /* half-integer: extra solution */
1626: if (i) {
1627: stcpy (c, b);
1628: add (b, c);
1629: power (a, b);
1630: if (merr () > OK) {
1631: a[0] = ONE;
1632: a[1] = EOL;
1633: return;
1634: }
1635: }
1636: g_sqrt (a);
1637: return;
1638: }
1639: stcpy (e, &b[i]);
1640: b[i] = EOL;
1641: break;
1642: }
1643: i++;
1644: }
1645: stcpy (d, a);
1646: i = intexpr (b);
1647: if (merr () == MXNUM)
1648: return;
1649: /* do it with a small number of multiplications */
1650: /* the number of multiplications is not optimum, but reasonably small */
1651: /* see donald e. knuth "The Art of Computer Programming" Vol.II p.441 */
1652: if (i == 0) {
1653: a[0] = ONE;
1654: a[1] = EOL;
1655: } else {
1656: j = 1;
1657: while (j < i) {
1658: j = j * 2;
1659: if (j < 0) {
1660: merr_raise (MXNUM);
1661: return;
1662: }
1663: }
1664: if (i != j)
1665: j = j / 2;
1666: j = j / 2;
1667: while (j) {
1668: stcpy (c, a);
1669: mul (a, c);
1670: if (i & j) {
1671: stcpy (c, d);
1672: mul (a, c);
1673: }
1674: j = j / 2;
1675: if (merr () == MXNUM)
1676: return;
1677: }
1678: if (e[0] == EOL)
1679: return;
1680: }
1681: /* non integer exponent */
1682: /* state of computation at this point: */
1683: /* d == saved value of a */
1684: /* a == d^^int(b); */
1685: /* e == frac(b); */
1686: {
1687: char Z[STRLEN + 2/*was 257*/];
1688:
1689: /* is fraction the inverse of an integer? */
1690: Z[0] = ONE;
1691: Z[1] = EOL;
1692: stcpy (c, e);
1693: mdiv (Z, c, '/');
1694: i = 0;
1695: for (;;)
1696: {
1697: if ((j = Z[i++]) == EOL) {
1698: j = intexpr (Z);
1699: break;
1700: }
1701: if (j != POINT)
1702: continue;
1703: j = intexpr (Z);
1704: if (Z[i] == NINE)
1705: j++;
1706: break;
1707: }
1708: Z[0] = ONE;
1709: Z[1] = EOL;
1710: lintstr (c, j);
1711: mdiv (Z, c, '/');
1712: /* if integer */
1713:
1714: if (stcmp (Z, e) == 0) {
1715: stcpy (Z, d);
1716: root (Z, j);
1717: if (merr () <= OK) {
1718: mul (a, Z);
1719: return;
1720: } /* on error try other method */
1721: merr_raise (OK);
1722: }
1723: Z[0] = ONE;
1724: Z[1] = EOL;
1725: zprecise += 2;
1726: for (;;)
1727: {
1728: c[0] = TWO;
1729: c[1] = EOL;
1730: mul (e, c);
1731: g_sqrt (d);
1732: if (e[0] == ONE) {
1733: e[0] = ZERO;
1734: numlit (e);
1735: stcpy (c, d);
1736: mul (Z, c);
1737: mround (Z, zprecise);
1738: }
1739: if (e[0] == ZERO)
1740: break;
1741: i = 0;
1742: j = (d[0] == ONE ? ZERO : NINE);
1743: for (;;) {
1744: ++i;
1745: if (d[i] != j && d[i] != '.')
1746: break;
1747: }
1748: if (d[i] == EOL || (i > zprecise))
1749: break;
1750: }
1751: zprecise -= 2;
1752: mul (a, Z);
1753: mround (a, zprecise + 1);
1754: }
1755: return;
1756: } /* end power() */
1757: /******************************************************************************/
1758: void g_sqrt (char *a) /* square root */
1759: {
1760: register int i,
1761: ch;
1762:
1763: if (a[0] == ZERO)
1764: return;
1765: if (a[0] == MINUS) {
1766: merr_raise (M9);
1767: return;
1768: }
1769: if (merr () > OK)
1770: return; /* avoid nonsense in recursion */
1771: {
1772: char tmp1[STRLEN +2 /*was 257*/],
1773: tmp2[STRLEN +2 /*was 257*/],
1774: XX[STRLEN +2 /*was 257*/],
1775: XXX[STRLEN +2 /*was 257*/];
1776:
1777: stcpy (XX, a);
1778: /* look for good initial value */
1779: if (a[0] > ONE || (a[0] == ONE && a[1] != POINT)) {
1780: i = 0;
1781: while ((ch = a[i++]) != EOL) {
1782: if (ch == POINT)
1783: break;
1784: }
1785: if ((i = (i + 1) / 2))
1786: a[i] = EOL;
1787: } else if (a[0] != ONE) {
1788: a[0] = ONE;
1789: a[1] = EOL;
1790: }
1791: /* "Newton's" algorithm with quadratic convergence */
1792: zprecise++;
1793: do {
1794: stcpy (XXX, a);
1795: stcpy (tmp1, XX);
1796: stcpy (tmp2, a);
1797: mdiv (tmp1, tmp2, '/');
1798: if (merr () > OK)
1799: break;
1800: add (a, tmp1);
1801: tmp2[0] = TWO;
1802: tmp2[1] = EOL;
1803: mdiv (a, tmp2, '/');
1804: } while (comp (a, XXX));
1805: zprecise--;
1806: return;
1807: }
1808: } /* end g_sqrt() */
1809: /******************************************************************************/
1810: void root (char *a, long n) /* n.th root */
1811: {
1812: register int i,
1813: ch;
1814:
1815: if (a[0] == ZERO)
1816: return;
1817: if (a[0] == MINUS || n == 0) {
1818: merr_raise (M9);
1819: return;
1820: }
1821: if (merr () > OK)
1822: return; /* avoid nonsense in recursion */
1823: {
1824: char tmp1[STRLEN +2/*was 257*/],
1825: tmp2[STRLEN +2/*was 257*/],
1826: XX[STRLEN +2/*was 257*/],
1827: XXX[STRLEN +2/*was 257*/];
1828: short again;
1829:
1830: stcpy (XX, a);
1831: /* look for good initial value */
1832: if (a[0] > ONE || (a[0] == ONE && a[1] != POINT)) {
1833: i = 0;
1834: while ((ch = a[i++]) != EOL && ch != POINT) ;
1835: if ((i = (i + n - 2) / n) > 0) {
1836: a[0] = THREE;
1837: a[i] = EOL;
1838: }
1839: } else if (a[0] != ONE) {
1840: a[0] = ONE;
1841: a[1] = EOL;
1842: }
1843: /* "Newton's" algorithm with quadratic convergence */
1844:
1845: if (zprecise <= 3)
1846: again = 0; /* speedup div with small zprec. */
1847: else {
1848: again = zprecise;
1849: zprecise = 2;
1850: }
1851: second:;
1852: zprecise++;
1853: for (;;) {
1854: stcpy (XXX, a);
1855: lintstr (tmp1, n - 1);
1856: stcpy (tmp2, a);
1857: power (tmp2, tmp1);
1858: stcpy (tmp1, XX);
1859: mdiv (tmp1, tmp2, '/');
1860: if (merr () > OK)
1861: break;
1862: lintstr (tmp2, n - 1);
1863: mul (a, tmp2);
1864: add (a, tmp1);
1865: lintstr (tmp2, n);
1866: mdiv (a, tmp2, '/');
1867: stcpy (tmp2, a);
1868: mdiv (XXX, tmp2, '/');
1869: tmp2[0] = ONE;
1870: if (zprecise <= 0)
1871: tmp2[1] = EOL;
1872: else {
1873: tmp2[1] = POINT;
1874: for (i = 2; i < zprecise; i++)
1875: tmp2[i] = ZERO;
1876: tmp2[i++] = FIVE;
1877: tmp2[i] = EOL;
1878: }
1879: if (!comp (XXX, tmp2))
1880: continue;
1881: if (zprecise <= 0)
1882: break;
1883: tmp2[0] = POINT;
1884: for (i = 1; i < zprecise; i++)
1885: tmp2[i] = NINE;
1886: tmp2[i - 1] = FIVE;
1887: tmp2[i] = EOL;
1888: if (comp (tmp2, XXX))
1889: break;
1890: }
1891: zprecise--;
1892: if (again) {
1893: zprecise = again;
1894: again = 0;
1895: goto second;
1896: }
1897: return;
1898: }
1899: } /* end root() */
1900: /******************************************************************************/
1901: int numlit (char *str)
1902: {
1903: long j,
1904: mi = 0,
1905: pointx = (-1),
1906: expflg = 0;
1907: long val,
1908: exp = 0L;
1909: int result;
1910: register int i = 0;
1911: register int ch;
1912:
1913: result = 0;
1914: if (str[0] < ONE) {
1915: if (str[0] == EOL) {
1916: str[0] = ZERO;
1917: str[1] = EOL;
1918: return (0);
1919: }
1920: /* compact signs */
1921: while (str[i] == PLUS || str[i] == MINUS)
1922: if (str[i++] == MINUS)
1923: mi++;
1924: if ((j = (mi &= 01)))
1925: str[0] = MINUS;
1926: /* compact leading zeroes */
1927: while (str[i] == ZERO)
1928: i++;
1929: if (i > j)
1930: stcpy (&str[j], &str[i]);
1931: if (str[mi] == EOL) {
1932: str[0] = ZERO;
1933: str[1] = EOL;
1934: return (0);
1935: }
1936: i = mi;
1937: }
1938: while ((ch = str[i]) <= NINE && ch >= ZERO)
1939: i++;
1940: if ((result = unit (&str[i]))) {
1941: if (i == mi) {
1942: str[0] = '0';
1943: i = 1;
1944: }
1945: ch = str[i] = EOL;
1946: }
1947: if (ch == EOL)
1948: return (result);
1949: if (ch == POINT) {
1950: pointx = i++;
1951: while ((ch = str[i]) <= NINE && ch >= ZERO)
1952: i++;
1953: if ((result = unit (&str[i])))
1954: ch = str[i] = EOL;
1955: if (ch == EOL) {
1956: i = pointx;
1957: goto point0;
1958: }
1959: }
1960: /* check for zero mantissa */
1961: j = 0;
1962: while (j < i) {
1963: if (str[j] > ZERO) {
1964: j = (-1);
1965: break;
1966: }
1967: j++;
1968: }
1969: if (j >= 0) {
1970: str[0] = ZERO;
1971: str[1] = EOL;
1972: return (result);
1973: }
1974: /* search for exponent */
1975: for (; ch != EOL; ch = str[++i]) {
1976: if (ch <= NINE && ch >= ZERO) {
1977: if (expflg) {
1978: ch -= ZERO;
1979: val = exp * NUMBASE + ch;
1980: /* check for numeric overflow */
1981: if (((val - ch) / NUMBASE) != exp) {
1982: merr_raise (MXNUM);
1983: return (0);
1984: }
1985: exp = val;
1986: }
1987: continue;
1988: }
1989: if (expflg) {
1990: if (ch == MINUS) {
1991: /* TODO: revisit this; it breaks string coercion
1992: if (str[i + 1] == '-') {
1993: merr_raise (INVEXPR);
1994: return (0);
1995: }
1996: if (!isdigit (str[i + 1])) {
1997: merr_raise (INVEXPR);
1998: return (0);
1999: }
2000: */
2001: expflg = (-expflg);
2002: continue;
2003: }
2004: if (ch == PLUS) {
2005: /* TODO: revisit this; it breaks string coercion
2006: if (str[i + 1] == '+') {
2007: merr_raise (INVEXPR);
2008: return (0);
2009: }
2010: if (!isdigit (str[i + 1])) {
2011: merr_raise (INVEXPR);
2012: return (0);
2013: }
2014: */
2015: continue;
2016: }
2017: }
2018: if ((result = unit (&str[i])))
2019: ch = str[i] = EOL;
2020: str[i] = EOL;
2021: if (ch == 'E' || (lowerflag && ch == 'e')) {
2022: expflg++;
2023: continue;
2024: }
2025: break;
2026: }
2027: /* append a point at the right end */
2028: if (expflg) {
2029: if (pointx < 0) {
2030: i = mi;
2031: while (str[i] != EOL)
2032: i++;
2033: if (i >= (STRLEN - 1)/*was 254*/) {
2034: str[STRLEN] = EOL;
2035: merr_raise (M75);
2036: return (0);
2037: }
2038: str[pointx = i] = POINT;
2039: str[++i] = EOL;
2040: }
2041: /* if exp shift decimal point */
2042: if (expflg > 0) {
2043: while (exp-- > 0) {
2044: if ((str[pointx] = str[pointx + 1]) == EOL) {
2045: if (pointx >= (STRLEN - 1)/*was 254*/)
2046: break;
2047: str[pointx] = ZERO;
2048: str[pointx + 1] = str[pointx + 2] = EOL;
2049: }
2050: pointx++;
2051: }
2052: if (pointx >= (STRLEN - 1)/*was 254*/) {
2053: str[STRLEN] = EOL;
2054: merr_raise (M75);
2055: return (0);
2056: }
2057: str[pointx] = POINT;
2058: } else { /* (expflg<0) */
2059: while (exp-- > 0) {
2060: if (--pointx < 0) {
2061: i = pointx = 0;
2062: while (str[i++] != EOL) ;
2063: if (i >= (STRLEN - 1)/*was 254*/) {
2064: merr_raise (M75);
2065: return (0);
2066: }
2067: while (i-- > 0)
2068: str[i + 1] = str[i];
2069: str[0] = ZERO;
2070: }
2071: str[pointx + 1] = str[pointx];
2072: }
2073: str[pointx] = POINT;
2074: }
2075: }
2076: if ((i = pointx) >= 0) {
2077:
2078: point0:
2079:
2080: while (str[++i] != EOL) ;
2081:
2082: i--;
2083: while (str[i] == ZERO)
2084: str[i--] = EOL; /* remove trailing zeroes */
2085: if (str[i] == POINT)
2086: str[i] = EOL; /* remove trailing point */
2087: }
2088: if (str[mi] == EOL) {
2089: str[0] = ZERO;
2090: str[1] = EOL;
2091: }
2092: return (result);
2093: }
2094: /******************************************************************************/
2095: int unit (char *str)
2096: /**
2097: * str is interpreted as a currency
2098: * symbol
2099: * return value: 1=EUR, 4=DM, ...
2100: * 0=other */
2101:
2102: {
2103: char ch;
2104:
2105: ch = str[0];
2106: if ((ch < 'A') || (ch > 'P'))
2107: return 0;
2108: switch (ch) {
2109: case 'E':
2110: if (str[1] == 'U' && str[2] == 'R')
2111: return 1;
2112: if (str[1] == 'S' && str[2] == 'P')
2113: return 5;
2114: return 0;
2115: case 'D':
2116: if (str[1] == 'M')
2117: return 4;
2118: if (str[1] == 'E' && str[2] == 'M')
2119: return 4;
2120: return 0;
2121: case 'A':
2122: if (str[1] == 'T' && str[2] == 'S')
2123: return 2;
2124: return 0;
2125: case 'B':
2126: if (str[1] == 'F' && str[2] == 'R')
2127: return 3;
2128: return 0;
2129: case 'F':
2130: if (str[1] == 'F')
2131: return 7;
2132: if (str[1] == 'M' && str[2] == 'K')
2133: return 6;
2134: if (str[1] == 'R' && str[2] == 'F')
2135: return 7;
2136: return 0;
2137: case 'I':
2138: if (str[1] == 'E' && str[2] == 'P')
2139: return 8;
2140: if (str[1] == 'T' && str[2] == 'L')
2141: return 9;
2142: return 0;
2143: case 'N':
2144: if (str[1] == 'L' && str[2] == 'G')
2145: return 10;
2146: return 0;
2147: case 'P':
2148: if (str[1] == 'T' && str[2] == 'E')
2149: return 11;
2150: }
2151: return 0;
2152: }
2153: /******************************************************************************/
2154: long intexpr (char *str)
2155: {
2156: {
2157: register int ch;
2158: register int i = 0;
2159: register long value;
2160: register long newval;
2161: short minus = FALSE;
2162:
2163: if ((ch = str[0]) == MINUS) {
2164: ch = str[1];
2165: minus = TRUE;
2166: i = 1;
2167: }
2168: if (ch >= ZERO && ch <= NINE) {
2169: value = ch - ZERO;
2170: while ((ch = str[++i]) >= ZERO && ch <= NINE) {
2171: newval = value * NUMBASE;
2172: if (newval < 0 || ((newval / NUMBASE) != value)) {
2173: merr_raise (MXNUM);
2174: return (minus ? -1 : 1);
2175: };
2176: newval += ((long) ch - ZERO);
2177: if (newval < 0) {
2178: merr_raise (MXNUM);
2179: return (minus ? -1 : 1);
2180: };
2181: value = newval;
2182: }
2183: if (minus)
2184: value = (-value);
2185: if (ch == EOL)
2186: return value;
2187: } else if (ch != ZERO && ch != PLUS && ch != MINUS && ch != POINT)
2188: return 0L;
2189: }
2190: {
2191: register int ch;
2192: register int i = 0;
2193: register long value;
2194: register long newval;
2195: char tmp[STRLEN +2/*was 257*/];
2196:
2197: stcpy (tmp, str);
2198: numlit (tmp);
2199: i = (tmp[0] == MINUS);
2200: if (merr () == MXNUM)
2201: return (i ? -1 : 1);
2202: value = 0L;
2203: while ((ch = tmp[i++]) >= ZERO && ch <= NINE) {
2204: newval = value * NUMBASE;
2205: if (newval < 0 || ((newval / NUMBASE) != value)) {
2206: merr_raise (MXNUM);
2207: value = 1;
2208: break;
2209: }
2210: newval += ((long) ch - ZERO);
2211: if (newval < 0) {
2212: merr_raise (MXNUM);
2213: value = 1;
2214: break;
2215: }
2216: value = newval;
2217: }
2218: if (tmp[0] == MINUS)
2219: value = (-value);
2220: return value;
2221: }
2222: } /* end of intexpr */
2223: /******************************************************************************/
2224: short int tvexpr (char *str) /* str is interpreted as truth valued expression */
2225: {
2226: if (str[0] > ZERO && str[0] <= NINE) {
2227: str[0] = ONE;
2228: str[1] = EOL;
2229: return TRUE;
2230: }
2231: if (str[1] == EOL) {
2232: str[0] = ZERO;
2233: return FALSE;
2234: } {
2235: register int ch;
2236: register int i = 0;
2237: register int pointx = FALSE;
2238: register int sign = FALSE;
2239:
2240: for (;;)
2241: {
2242: if ((ch = str[i]) > ZERO && ch <= NINE) {
2243: str[0] = ONE;
2244: str[1] = EOL;
2245: return TRUE;
2246: }
2247: i++;
2248: if ((ch == PLUS || ch == MINUS) && sign == FALSE)
2249: continue;
2250: sign = TRUE;
2251: if (ch == ZERO)
2252: continue;
2253: if (ch == POINT && pointx == FALSE) {
2254: sign = TRUE;
2255: pointx = TRUE;
2256: continue;
2257: }
2258: str[0] = ZERO;
2259: str[1] = EOL;
2260: return FALSE;
2261: }
2262: }
2263: }
2264:
2265: /******************************************************************************/
2266: void m_op (char *a, char *b, short op)
2267: {
2268: int atyp,
2269: btyp; /* DM/EUR currency types */
2270: char tmp[(STRLEN + 1)/*was 256*/];
2271:
2272: switch (op & 0177) { /* binary operators */
2273: case '_':
2274: if (op & 0200)
2275: break; /* NOT_OPERAND */
2276: if (stcat (a, b) == 0) {
2277: merr_raise (M75);
2278: }
2279: return;
2280: case '=':
2281: if (stcmp (a, b))
2282: *a = ZERO;
2283: else
2284: *a = ONE;
2285: if (op & 0200)
2286: toggle (*a); /* NOT_OPERAND */
2287: a[1] = EOL;
2288: return;
2289: case '[':
2290: if (*b == EOL || find (a, b))
2291: *a = ONE;
2292: else
2293: *a = ZERO;
2294: if (op & 0200)
2295: toggle (*a); /* NOT_OPERAND */
2296: a[1] = EOL;
2297: return;
2298: case ']':
2299: if (*b == EOL) {
2300: if (*a == EOL)
2301: *a = ZERO;
2302: else
2303: *a = ONE;
2304: }
2305: /* frequent special case */
2306: else if (stcmp (a, b) <= 0)
2307: *a = ZERO;
2308: else
2309: *a = ONE;
2310: if (op & 0200)
2311: toggle (*a); /* NOT_OPERAND */
2312: a[1] = EOL;
2313: return;
2314: } /* end switch */
2315: atyp = numlit (a);
2316: if (op == '-') {
2317: stcpy (&tmp[1], b);
2318: tmp[0] = '-';
2319: op = '+';
2320: } else
2321: stcpy (tmp, b);
2322: btyp = numlit (tmp);
2323: switch (op & 0177) { /* binary operators, NOT OMITTED */
2324: case '+':
2325: if (op & 0200) {
2326: merr_raise (ASSIGNER);
2327: return;
2328: } /* NOT_OPERAND */
2329: #ifdef EUR2DEM
2330: if (atyp != btyp) {
2331: char tmp2[256];
2332:
2333: if ((atyp == 0) && (a[0] == '0'))
2334: atyp = btyp; /* zero is any currency */
2335: if ((btyp == 0) && (tmp[0] == '0'))
2336: btyp = atyp; /* zero is any currency */
2337: if (atyp && btyp) {
2338: if (atyp > 1) {
2339: stcpy (tmp2, EUR2WHR[atyp]);
2340: mul (tmp, tmp2);
2341: }
2342: if (btyp > 1) {
2343: zprecise += 4;
2344: stcpy (tmp2, EUR2WHR[btyp]);
2345: mdiv (tmp, tmp2, '/');
2346: zprecise -= 4;
2347: }
2348: } else if (atyp != btyp && typemmflag) {
2349: merr_raise (TYPEMISMATCH);
2350: return;
2351: }
2352: }
2353: #endif /* EUR2DEM */
2354: add (a, tmp);
2355: plus02:
2356: #ifdef EUR2DEM
2357: if (atyp == 0)
2358: break;
2359: if (atyp != btyp)
2360: cond_round (a, zprecise);
2361: if (atyp)
2362: stcat (a, WHR[atyp]);
2363: #endif /* EUR2DEM */
2364: break;
2365:
2366: case '*':
2367: if (op & 0200) {
2368: merr_raise (ASSIGNER);
2369: return;
2370: } /* NOT_OPERAND */
2371: #ifdef EUR2DEM
2372: if (btyp && atyp == 0) {
2373: atyp = btyp;
2374: btyp = 0;
2375: }
2376: if (atyp && btyp) {
2377: if (typemmflag) {
2378: merr_raise (TYPEMISMATCH);
2379: return;
2380: }
2381: atyp = btyp = 0;
2382: }
2383: #endif /* EUR2DEM */
2384: mul (a, tmp);
2385:
2386: #ifdef EUR2DEM
2387: if (atyp) {
2388: cond_round (a, zprecise);
2389: stcat (a, WHR[atyp]);
2390: }
2391: #endif /* EUR2DEM */
2392: break;
2393:
2394: case '/':
2395: case '\\':
2396: case '#':
2397:
2398: if (op & 0200) {
2399: merr_raise (ASSIGNER);
2400: return;
2401: } /* NOT_OPERAND */
2402: #ifdef EUR2DEM
2403: if (atyp != btyp) {
2404: char tmp2[(STRLEN + 1)/*was 256*/];
2405:
2406: if (atyp && btyp) {
2407: if (op == '#') {
2408: if (atyp > 1) {
2409: stcpy (tmp2, EUR2WHR[atyp]);
2410: mul (tmp, tmp2);
2411: }
2412: if (btyp > 1) {
2413: stcpy (tmp2, EUR2WHR[btyp]);
2414: mdiv (tmp, tmp2, '/');
2415: }
2416: } else {
2417: if (atyp > 1) {
2418: stcpy (tmp2, EUR2WHR[atyp]);
2419: mul (tmp, tmp2);
2420: }
2421: if (btyp > 1) {
2422: stcpy (tmp2, EUR2WHR[btyp]);
2423: mul (a, tmp2);
2424: }
2425: atyp = btyp = 0;
2426: }
2427: } else if (btyp && typemmflag && (*a != '0' || op == '#')) {
2428: merr_raise (TYPEMISMATCH);
2429: return;
2430: }
2431: } else if (op != '#')
2432: atyp = 0;
2433: #endif /* EUR2DEM */
2434: if (tmp[0] == ZERO) {
2435: merr_raise (M9);
2436: break;
2437: }
2438: mdiv (a, tmp, op);
2439: goto plus02;
2440:
2441: case ' ':
2442: power (a, tmp);
2443: break; /* ' ' stands for power */
2444:
2445: case '>':
2446:
2447: #ifdef EUR2DEM
2448: if (atyp != btyp) {
2449: char tmp2[(STRLEN + 1)/*was 256*/];
2450:
2451: if ((atyp == 0) && (a[0] == '0'))
2452: atyp = btyp; /* zero is any currency */
2453: if ((btyp == 0) && (tmp[0] == '0'))
2454: btyp = atyp; /* zero is any currency */
2455: if (atyp && btyp) {
2456: if (atyp > 1) {
2457: stcpy (tmp2, EUR2WHR[atyp]);
2458: mul (tmp, tmp2);
2459: }
2460: if (btyp > 1) {
2461: stcpy (tmp2, EUR2WHR[btyp]);
2462: mul (a, tmp2);
2463: }
2464: cond_round (a, zprecise + 2);
2465: cond_round (tmp, zprecise + 2);
2466: } else if (atyp != btyp && typemmflag) {
2467: merr_raise (TYPEMISMATCH);
2468: return;
2469: }
2470: }
2471: #endif /* EUR2DEM */
2472: if (comp (tmp, a))
2473: *a = ONE;
2474: else
2475: *a = ZERO;
2476: if (op & 0200)
2477: toggle (*a); /* NOT_OPERAND */
2478: a[1] = EOL;
2479: break;
2480:
2481: case '<':
2482:
2483: #ifdef EUR2DEM
2484: if (atyp != btyp) {
2485: char tmp2[(STRLEN + 1)/*was 256*/];
2486:
2487: if ((atyp == 0) && (a[0] == '0'))
2488: atyp = btyp; /* zero is any currency */
2489: if ((btyp == 0) && (tmp[0] == '0'))
2490: btyp = atyp; /* zero is any currency */
2491: if (atyp && btyp) {
2492: if (atyp > 1) {
2493: stcpy (tmp2, EUR2WHR[atyp]);
2494: mul (tmp, tmp2);
2495: }
2496: if (btyp > 1) {
2497: stcpy (tmp2, EUR2WHR[btyp]);
2498: mul (a, tmp2);
2499: }
2500: cond_round (a, zprecise + 2);
2501: cond_round (tmp, zprecise + 2);
2502: } else if (atyp != btyp && typemmflag) {
2503: merr_raise (TYPEMISMATCH);
2504: return;
2505: }
2506: }
2507: #endif /* EUR2DEM */
2508: if (comp (a, tmp))
2509: *a = ONE;
2510: else
2511: *a = ZERO;
2512: if (op & 0200)
2513: toggle (*a); /* NOT_OPERAND */
2514: a[1] = EOL;
2515: break;
2516:
2517: case '&':
2518:
2519: if (tvexpr (a)) {
2520: tvexpr (tmp);
2521: *a = *tmp;
2522: }
2523: if (op & 0200)
2524: toggle (*a); /* NOT_OPERAND */
2525: a[1] = EOL;
2526: break;
2527:
2528: case '!':
2529:
2530: if (tvexpr (a) == FALSE && tvexpr (tmp))
2531: *a = ONE;
2532: if (op & 0200)
2533: toggle (*a); /* NOT_OPERAND */
2534: a[1] = EOL;
2535: break;
2536:
2537: default:
2538: merr_raise (ASSIGNER);
2539:
2540: }
2541: return;
2542: } /* end m_op */
2543: /******************************************************************************/
2544: /* rounding */
2545: /* 'a' is assumed to be a 'canonic' numeric string */
2546: /* it is rounded to 'digits' fractional digits */
2547: void mround (char *a, int digits)
2548: {
2549: int ch,
2550: i,
2551: pointpos,
2552: lena;
2553:
2554: pointpos = -1;
2555: i = 0;
2556: i = 0;
2557: while (a[i] != EOL) {
2558: if (a[i] == POINT)
2559: pointpos = i;
2560: i++;
2561: }
2562: lena = i;
2563: if (pointpos < 0)
2564: pointpos = i;
2565: if ((pointpos + digits + 1) >= i)
2566: return; /* nothing to round */
2567: i = pointpos + digits + 1;
2568: if (a[i] < FIVE) {
2569: a[i] = EOL;
2570: while (a[--i] == ZERO)
2571: a[i] = EOL;
2572: if (a[i] == POINT) {
2573: a[i] = EOL;
2574: if (i == 0 || (i == 1 && a[0] == MINUS))
2575: a[0] = ZERO;
2576: }
2577: return;
2578: }
2579: for (;;)
2580: {
2581: if (i >= pointpos)
2582: a[i] = EOL;
2583: else
2584: a[i] = ZERO;
2585: if (--i < (a[0] == MINUS)) {
2586: for (i = lena; i >= 0; i--)
2587: a[i + 1] = a[i];
2588: a[a[0] == '-'] = ONE;
2589: break;
2590: }
2591: if ((ch = a[i]) == POINT)
2592: continue;
2593: if (a[i] < NINE && ch >= ZERO) {
2594: a[i] = ++ch;
2595: break;
2596: }
2597: }
2598: return;
2599: } /* end mround */
2600:
2601: /* End of $Source: /home/cvsroot/freem/src/operator.c,v $ */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>