mageec  0.1.0
MAchine Guided Energy Efficient Compilation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
implicitatt.c
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Copyright 2010 Rulequest Research Pty Ltd. */
4 /* */
5 /* This file is part of C5.0 GPL Edition, a single-threaded version */
6 /* of C5.0 release 2.07. */
7 /* */
8 /* C5.0 GPL Edition is free software: you can redistribute it and/or */
9 /* modify it under the terms of the GNU General Public License as */
10 /* published by the Free Software Foundation, either version 3 of the */
11 /* License, or (at your option) any later version. */
12 /* */
13 /* C5.0 GPL Edition is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
16 /* General Public License for more details. */
17 /* */
18 /* You should have received a copy of the GNU General Public License */
19 /* (gpl.txt) along with C5.0 GPL Edition. If not, see */
20 /* */
21 /* <http://www.gnu.org/licenses/>. */
22 /* */
23 /*************************************************************************/
24 
25 
26 
27 /*************************************************************************/
28 /* */
29 /* Routines to handle implicitly-defined attributes */
30 /* ------------------------------------------------ */
31 /* */
32 /*************************************************************************/
33 
34 
35 #include "defns.i"
36 #include "extern.i"
37 #include <ctype.h>
38 
39 
40 char *Buff; /* buffer for input characters */
41 int BuffSize, BN; /* size and index of next character */
42 
43 EltRec *TStack; /* expression stack model */
44 int TStackSize, TSN; /* size of stack and index of next entry */
45 
46 int DefSize, DN; /* size of definition and next element */
47 
48 Boolean PreviousError; /* to avoid parasitic errors */
49 
50 AttValue _UNK, /* quasi-constant for unknown value */
51  _NA; /* ditto for not applicable */
52 
53 
54 #define FailSyn(Msg) {DefSyntaxError(Msg); return false;}
55 #define FailSem(Msg) {DefSemanticsError(Fi, Msg, OpCode); return false;}
56 
57 typedef union _xstack_elt
58  {
62  }
63  XStackElt;
64 
65 #define cval _cont_val
66 #define sval _string_val
67 #define dval _discr_val
68 
69 
70 
71 /*************************************************************************/
72 /* */
73 /* A definition is handled in two stages: */
74 /* - The definition is read (up to a line ending with a period) */
75 /* replacing multiple whitespace characters with one space */
76 /* - The definition is then read (using a recursive descent */
77 /* parser), building up a reverse polish expression */
78 /* Syntax and semantics errors are flagged */
79 /* */
80 /*************************************************************************/
81 
82 
83 void ImplicitAtt(FILE *Nf)
84 /* ----------- */
85 {
86 #ifdef CUBIST
87  _UNK.cval = UNKNOWN;
88 #else
89  _UNK.dval = UNKNOWN;
90 #endif
91  _NA.dval = NA;
92 
93  /* Get definition as a string in Buff */
94 
95  ReadDefinition(Nf);
96 
97  PreviousError = false;
98  BN = 0;
99 
100  /* Allocate initial stack and attribute definition */
101 
102  TStack = Alloc(TStackSize=50, EltRec);
103  TSN = 0;
104 
105  AttDef[MaxAtt] = Alloc(DefSize = 100, DefElt);
106  DN = 0;
107 
108  /* Parse Buff as an expression terminated by a period */
109 
110  Expression();
111  if ( ! Find(".") ) DefSyntaxError("'.' ending definition");
112 
113  /* Final check -- defined attribute must not be of type String */
114 
115  if ( ! PreviousError )
116  {
117  if ( DN == 1 && DefOp(AttDef[MaxAtt][0]) == OP_ATT &&
118  strcmp(AttName[MaxAtt], "case weight") )
119  {
120  Error(SAMEATT, AttName[ (long) DefSVal(AttDef[MaxAtt][0]) ], Nil);
121  }
122 
123  if ( TStack[0].Type == 'B' )
124  {
125  /* Defined attributes should never have a value N/A */
126 
127  MaxAttVal[MaxAtt] = 3;
129  AttValName[MaxAtt][1] = strdup("??");
130  AttValName[MaxAtt][2] = strdup("t");
131  AttValName[MaxAtt][3] = strdup("f");
132  }
133  else
134  {
135  MaxAttVal[MaxAtt] = 0;
136  }
137  }
138 
139  if ( PreviousError )
140  {
141  DN = 0;
143  }
144 
145  /* Write a terminating marker */
146 
147  DefOp(AttDef[MaxAtt][DN]) = OP_END;
148 
149  Free(Buff);
150  Free(TStack);
151 }
152 
153 
154 
155 /*************************************************************************/
156 /* */
157 /* Read the text of a definition. Skip comments, collapse */
158 /* multiple whitespace characters. */
159 /* */
160 /*************************************************************************/
161 
162 
163 void ReadDefinition(FILE *f)
164 /* -------------- */
165 {
166  Boolean LastWasPeriod=false;
167  char c;
168 
169  Buff = Alloc(BuffSize=50, char);
170  BN = 0;
171 
172  while ( true )
173  {
174  c = InChar(f);
175 
176  if ( c == '|' ) SkipComment;
177 
178  if ( c == EOF || c == '\n' && LastWasPeriod )
179  {
180  /* The definition is complete. Add a period if it's
181  not there already and terminate the string */
182 
183  if ( ! LastWasPeriod ) Append('.');
184  Append(0);
185 
186  return;
187  }
188 
189  if ( Space(c) )
190  {
191  Append(' ');
192  }
193  else
194  if ( c == '\\' )
195  {
196  /* Escaped character -- bypass any special meaning */
197 
198  Append(InChar(f));
199  }
200  else
201  {
202  LastWasPeriod = ( c == '.' );
203  Append(c);
204  }
205  }
206 }
207 
208 
209 
210 /*************************************************************************/
211 /* */
212 /* Append a character to Buff, resizing it if necessary */
213 /* */
214 /*************************************************************************/
215 
216 
217 void Append(char c)
218 /* ------ */
219 {
220  if ( c == ' ' && (! BN || Buff[BN-1] == ' ' ) ) return;
221 
222  if ( BN >= BuffSize )
223  {
224  Realloc(Buff, BuffSize += 50, char);
225  }
226 
227  Buff[BN++] = c;
228 }
229 
230 
231 
232 /*************************************************************************/
233 /* */
234 /* Recursive descent parser with syntax error checking. */
235 /* The reverse polish is built up by calls to Dump() and DumpOp(), */
236 /* which also check for semantic validity. */
237 /* */
238 /* For possible error messages, each routine also keeps track of */
239 /* the beginning of the construct that it recognises (in Fi). */
240 /* */
241 /*************************************************************************/
242 
243 
245 /* ---------- */
246 {
247  int Fi=BN;
248 
249  if ( Buff[BN] == ' ' ) BN++;
250 
251  if ( ! Conjunct() ) FailSyn("expression");
252 
253  while ( Find("or") )
254  {
255  BN += 2;
256 
257  if ( ! Conjunct() ) FailSyn("expression");
258 
259  DumpOp(OP_OR, Fi);
260  }
261 
262  return true;
263 }
264 
265 
266 
268 /* -------- */
269 {
270  int Fi=BN;
271 
272  if ( ! SExpression() ) FailSyn("expression");
273 
274  while ( Find("and") )
275  {
276  BN += 3;
277 
278  if ( ! SExpression() ) FailSyn("expression");
279 
280  DumpOp(OP_AND, Fi);
281  }
282 
283  return true;
284 }
285 
286 
287 
288 String RelOps[] = {">=", "<=", "!=", "<>", ">", "<", "=", (String) 0};
289 
291 /* ----------- */
292 {
293  int o, Fi=BN;
294 
295  if ( ! AExpression() ) FailSyn("expression");
296 
297  if ( (o = FindOne(RelOps)) >= 0 )
298  {
299  BN += strlen(RelOps[o]);
300 
301  if ( ! AExpression() ) FailSyn("expression");
302 
303  DumpOp(( o == 0 ? OP_GE :
304  o == 1 ? OP_LE :
305  o == 4 ? OP_GT :
306  o == 5 ? OP_LT :
307  o == 2 || o == 3 ?
308  ( TStack[TSN-1].Type == 'S' ? OP_SNE : OP_NE ) :
309  ( TStack[TSN-1].Type == 'S' ? OP_SEQ : OP_EQ ) ), Fi);
310  }
311 
312  return true;
313 }
314 
315 
316 
317 String AddOps[] = {"+", "-", (String) 0};
318 
320 /* ----------- */
321 {
322  int o, Fi=BN;
323 
324  if ( Buff[BN] == ' ' ) BN++;
325 
326  if ( (o = FindOne(AddOps)) >= 0 )
327  {
328  BN += 1;
329  }
330 
331  if ( ! Term() ) FailSyn("expression");
332 
333  if ( o == 1 ) DumpOp(OP_UMINUS, Fi);
334 
335  while ( (o = FindOne(AddOps)) >= 0 )
336  {
337  BN += 1;
338 
339  if ( ! Term() ) FailSyn("arithmetic expression");
340 
341  DumpOp((char)(OP_PLUS + o), Fi);
342  }
343 
344  return true;
345 }
346 
347 
348 
349 String MultOps[] = {"*", "/", "%", (String) 0};
350 
352 /* ---- */
353 {
354  int o, Fi=BN;
355 
356  if ( ! Factor() ) FailSyn("expression");
357 
358  while ( (o = FindOne(MultOps)) >= 0 )
359  {
360  BN += 1;
361 
362  if ( ! Factor() ) FailSyn("arithmetic expression");
363 
364  DumpOp((char)(OP_MULT + o), Fi);
365  }
366 
367  return true;
368 }
369 
370 
371 
373 /* ---- */
374 {
375  int Fi=BN;
376 
377  if ( ! Primary() ) FailSyn("value");
378 
379  while ( Find("^") )
380  {
381  BN += 1;
382 
383  if ( ! Primary() ) FailSyn("exponent");
384 
385  DumpOp(OP_POW, Fi);
386  }
387 
388  return true;
389 }
390 
391 
392 
394 /* ------- */
395 {
396  if ( Atom() )
397  {
398  return true;
399  }
400  else
401  if ( Find("(") )
402  {
403  BN++;
404  if ( ! Expression() ) FailSyn("expression in parentheses");
405  if ( ! Find(")") ) FailSyn("')'");
406  BN++;
407  return true;
408  }
409  else
410  {
411  FailSyn("attribute, value, or '('");
412  }
413 }
414 
415 
416 
417 String Funcs[] = {"sin", "cos", "tan", "log", "exp", "int", (String) 0};
418 
420 /* ---- */
421 {
422  char *EndPtr, *Str, Date[11], Time[9];
423  int o, FirstBN, Fi=BN;
424  ContValue F;
425  Attribute Att;
426 
427  if ( Buff[BN] == ' ' ) BN++;
428 
429  if ( Buff[BN] == '"' )
430  {
431  FirstBN = ++BN;
432  while ( Buff[BN] != '"' )
433  {
434  if ( ! Buff[BN] ) FailSyn("closing '\"'");
435  BN++;
436  }
437 
438  /* Make a copy of the string without double quotes */
439 
440  Buff[BN] = '\00';
441  Str = strdup(Buff + FirstBN);
442 
443  Buff[BN++] = '"';
444  Dump(OP_STR, 0, Str, Fi);
445  }
446  else
447  if ( (Att = FindAttName()) )
448  {
449  BN += strlen(AttName[Att]);
450 
451  Dump(OP_ATT, 0, (String) (long) Att, Fi);
452  }
453  else
454  if ( isdigit(Buff[BN]) )
455  {
456  /* Check for date or time first */
457 
458  if ( ( Buff[BN+4] == '/' && Buff[BN+7] == '/' ||
459  Buff[BN+4] == '-' && Buff[BN+7] == '-' )&&
460  isdigit(Buff[BN+1]) && isdigit(Buff[BN+2]) &&
461  isdigit(Buff[BN+3]) &&
462  isdigit(Buff[BN+5]) && isdigit(Buff[BN+6]) &&
463  isdigit(Buff[BN+8]) && isdigit(Buff[BN+9]) )
464  {
465  memcpy(Date, Buff+BN, 10);
466  Date[10] = '\00';
467  if ( (F = DateToDay(Date)) == 0 )
468  {
469  Error(BADDEF1, Date, "date");
470  }
471 
472  BN += 10;
473  }
474  else
475  if ( Buff[BN+2] == ':' && Buff[BN+5] == ':' &&
476  isdigit(Buff[BN+1]) &&
477  isdigit(Buff[BN+3]) && isdigit(Buff[BN+4]) &&
478  isdigit(Buff[BN+6]) && isdigit(Buff[BN+7]) )
479  {
480  memcpy(Time, Buff+BN, 8);
481  Time[8] = '\00';
482  if ( (F = TimeToSecs(Time)) == 0 )
483  {
484  Error(BADDEF1, Time, "time");
485  }
486 
487  BN += 8;
488  }
489  else
490  {
491  F = strtod(Buff+BN, &EndPtr);
492 
493  /* Check for period after integer */
494 
495  if ( EndPtr > Buff+BN+1 && *(EndPtr-1) == '.' )
496  {
497  EndPtr--;
498  }
499 
500  BN = EndPtr - Buff;
501  }
502 
503  Dump(OP_NUM, F, Nil, Fi);
504  }
505  else
506  if ( (o = FindOne(Funcs)) >= 0 )
507  {
508  BN += 3;
509 
510  if ( ! Find("(") ) FailSyn("'(' after function name");
511  BN++;
512 
513  if ( ! Expression() ) FailSyn("expression");
514 
515  if ( ! Find(")") ) FailSyn("')' after function argument");
516  BN++;
517 
518  DumpOp((char)(OP_SIN + o), Fi);
519  }
520  else
521  if ( Buff[BN] == '?' )
522  {
523  BN++;
524  if ( TStack[TSN-1].Type == 'N' )
525  {
526  Dump(OP_NUM, _UNK.cval, Nil, Fi);
527  }
528  else
529  {
530  Dump(OP_STR, 0, Nil, Fi);
531  }
532  }
533  else
534  if ( ! memcmp(Buff+BN, "N/A", 3) )
535  {
536  BN += 3;
537  if ( TStack[TSN-1].Type == 'N' )
538  {
539  Dump(OP_NUM, _NA.cval, Nil, Fi);
540  }
541  else
542  {
543  Dump(OP_STR, 0, strdup("N/A"), Fi);
544  }
545  }
546  else
547  {
548  return false;
549  }
550 
551  return true;
552 }
553 
554 
555 
556 /*************************************************************************/
557 /* */
558 /* Skip spaces and check for specific string */
559 /* */
560 /*************************************************************************/
561 
562 
564 /* ---- */
565 {
566  if ( Buff[BN] == ' ' ) BN++;
567 
568  return ( ! Buff[BN] ? false : ! memcmp(Buff+BN, S, strlen(S)) );
569 }
570 
571 
572 
573 /*************************************************************************/
574 /* */
575 /* Find one of a zero-terminated list of alternatives */
576 /* */
577 /*************************************************************************/
578 
579 
580 int FindOne(String *Alt)
581 /* ------- */
582 {
583  int a;
584 
585  for ( a = 0 ; Alt[a] ; a++ )
586  {
587  if ( Find(Alt[a]) ) return a;
588  }
589 
590  return -1;
591 }
592 
593 
594 
595 /*************************************************************************/
596 /* */
597 /* Find an attribute name */
598 /* */
599 /*************************************************************************/
600 
601 
603 /* ----------- */
604 {
605  Attribute Att, LongestAtt=0;
606 
607  ForEach(Att, 1, MaxAtt-1)
608  {
609  if ( ! Exclude(Att) && Find(AttName[Att]) )
610  {
611  if ( ! LongestAtt ||
612  strlen(AttName[Att]) > strlen(AttName[LongestAtt]) )
613  {
614  LongestAtt = Att;
615  }
616  }
617  }
618 
619  if ( LongestAtt && ( MaxClass == 1 || ClassThresh ) &&
620  ! strcmp(ClassName[1], AttName[LongestAtt]) )
621  {
622  Error(BADDEF4, Nil, Nil);
623  }
624 
625  return LongestAtt;
626 }
627 
628 
629 
630 /*************************************************************************/
631 /* */
632 /* Error message routines. Syntax errors come from the */
633 /* recursive descent parser, semantics errors from the routines */
634 /* that build up the equivalent polish */
635 /* */
636 /*************************************************************************/
637 
638 
640 /* -------------- */
641 {
642  String RestOfText;
643  int i=10;
644 
645  if ( ! PreviousError )
646  {
647  RestOfText = Buff + BN;
648 
649  /* Abbreviate text if longer than 12 characters */
650 
651  if ( CharWidth(RestOfText) > 12 )
652  {
653 #ifdef UTF8
654  /* Find beginning of UTF-8 character */
655 
656  for ( ; (RestOfText[i] & 0x80) ; i++)
657  ;
658 #endif
659  RestOfText[i] = RestOfText[i+1] = '.';
660  }
661 
662  Error(BADDEF1, RestOfText, Msg);
663  PreviousError = true;
664  }
665 }
666 
667 
668 
669 void DefSemanticsError(int Fi, String Msg, int OpCode)
670 /* ----------------- */
671 {
672  char Exp[1000], XMsg[1000], Op[1000];
673 
674  if ( ! PreviousError )
675  {
676  /* Abbreviate the input if necessary */
677 
678  if ( BN - Fi > 23 )
679  {
680  sprintf(Exp, "%.10s...%.10s", Buff+Fi, Buff+BN-10);
681  }
682  else
683  {
684  sprintf(Exp, "%.*s", BN - Fi, Buff+Fi);
685  }
686 
687  switch ( OpCode )
688  {
689  case OP_AND: sprintf(Op, "%s", "and"); break;
690  case OP_OR: sprintf(Op, "%s", "or"); break;
691  case OP_SEQ:
692  case OP_EQ: sprintf(Op, "%s", "="); break;
693  case OP_SNE:
694  case OP_NE: sprintf(Op, "%s", "<>"); break;
695  case OP_GT: sprintf(Op, "%s", ">"); break;
696  case OP_GE: sprintf(Op, "%s", ">="); break;
697  case OP_LT: sprintf(Op, "%s", "<"); break;
698  case OP_LE: sprintf(Op, "%s", "<="); break;
699  case OP_PLUS: sprintf(Op, "%s", "+"); break;
700  case OP_MINUS: sprintf(Op, "%s", "-"); break;
701  case OP_UMINUS: sprintf(Op, "%s", "unary -"); break;
702  case OP_MULT: sprintf(Op, "%s", "*"); break;
703  case OP_DIV: sprintf(Op, "%s", "/"); break;
704  case OP_MOD: sprintf(Op, "%s", "%"); break;
705  case OP_POW: sprintf(Op, "%s", "^"); break;
706  case OP_SIN: sprintf(Op, "%s", "sin"); break;
707  case OP_COS: sprintf(Op, "%s", "cos"); break;
708  case OP_TAN: sprintf(Op, "%s", "tan"); break;
709  case OP_LOG: sprintf(Op, "%s", "log"); break;
710  case OP_EXP: sprintf(Op, "%s", "exp"); break;
711  case OP_INT: sprintf(Op, "%s", "int");
712  }
713 
714  sprintf(XMsg, "%s with '%s'", Msg, Op);
715  Error(BADDEF2, Exp, XMsg);
716  PreviousError = true;
717  }
718 }
719 
720 
721 
722 /*************************************************************************/
723 /* */
724 /* Reverse polish routines. These use a model of the stack */
725 /* during expression evaluation to detect type conflicts etc */
726 /* */
727 /*************************************************************************/
728 
729 
730 
731 void Dump(char OpCode, ContValue F, String S, int Fi)
732 /* ---- */
733 {
734  if ( Buff[Fi] == ' ' ) Fi++;
735 
736  if ( ! UpdateTStack(OpCode, F, S, Fi) ) return;
737 
738  /* Make sure enough room for this element */
739 
740  if ( DN >= DefSize-1 )
741  {
742  Realloc(AttDef[MaxAtt], DefSize += 100, DefElt);
743  }
744 
745  DefOp(AttDef[MaxAtt][DN]) = OpCode;
746  if ( OpCode == OP_ATT || OpCode == OP_STR )
747  {
748  DefSVal(AttDef[MaxAtt][DN]) = S;
749  }
750  else
751  {
752  DefNVal(AttDef[MaxAtt][DN]) = F;
753  }
754 
755  DN++;
756 }
757 
758 
759 
760 void DumpOp(char OpCode, int Fi)
761 /* ------ */
762 {
763  Dump(OpCode, 0, Nil, Fi);
764 }
765 
766 
767 
768 Boolean UpdateTStack(char OpCode, ContValue F, String S, int Fi)
769 /* ------------ */
770 {
771  if ( TSN >= TStackSize )
772  {
773  Realloc(TStack, TStackSize += 50, EltRec);
774  }
775 
776  switch ( OpCode )
777  {
778  case OP_ATT:
779  TStack[TSN].Type = ( Continuous((long) S) ? 'N' : 'S' );
780  break;
781 
782  case OP_NUM:
783  TStack[TSN].Type = 'N';
784  break;
785 
786  case OP_STR:
787  TStack[TSN].Type = 'S';
788  break;
789 
790  case OP_AND:
791  case OP_OR:
792  if ( TStack[TSN-2].Type != 'B' || TStack[TSN-1].Type != 'B' )
793  {
794  FailSem("non-logical value");
795  }
796  TSN -= 2;
797  break;
798 
799  case OP_EQ:
800  case OP_NE:
801  if ( TStack[TSN-2].Type != TStack[TSN-1].Type )
802  {
803  FailSem("incompatible values");
804  }
805  TSN -= 2;
806  TStack[TSN].Type = 'B';
807  break;
808 
809  case OP_GT:
810  case OP_GE:
811  case OP_LT:
812  case OP_LE:
813  if ( TStack[TSN-2].Type != 'N' || TStack[TSN-1].Type != 'N' )
814  {
815  FailSem("non-arithmetic value");
816  }
817  TSN -= 2;
818  TStack[TSN].Type = 'B';
819  break;
820 
821  case OP_SEQ:
822  case OP_SNE:
823  if ( TStack[TSN-2].Type != 'S' || TStack[TSN-1].Type != 'S' )
824  {
825  FailSem("incompatible values");
826  }
827  TSN -= 2;
828  TStack[TSN].Type = 'B';
829  break;
830 
831  case OP_PLUS:
832  case OP_MINUS:
833  case OP_MULT:
834  case OP_DIV:
835  case OP_MOD:
836  case OP_POW:
837  if ( TStack[TSN-2].Type != 'N' || TStack[TSN-1].Type != 'N' )
838  {
839  FailSem("non-arithmetic value");
840  }
841  TSN -= 2;
842  break;
843 
844  case OP_UMINUS:
845  if ( TStack[TSN-1].Type != 'N' )
846  {
847  FailSem("non-arithmetic value");
848  }
849  TSN--;
850  break;
851 
852  case OP_SIN:
853  case OP_COS:
854  case OP_TAN:
855  case OP_LOG:
856  case OP_EXP:
857  case OP_INT:
858  if ( TStack[TSN-1].Type != 'N' )
859  {
860  FailSem("non-arithmetic argument");
861  }
862  TSN--;
863  }
864 
865  TStack[TSN].Fi = Fi;
866  TStack[TSN].Li = BN-1;
867  TSN++;
868 
869  return true;
870 }
871 
872 
873 
874 /*************************************************************************/
875 /* */
876 /* Evaluate an implicit attribute for a case */
877 /* */
878 /*************************************************************************/
879 
880 #define CUnknownVal(AV) (AV.cval==_UNK.cval)
881 #define DUnknownVal(AV) (AV.dval==_UNK.dval)
882 #define DUNA(a) (DUnknownVal(XStack[a]) || NotApplicVal(XStack[a]))
883 #define CUNA(a) (CUnknownVal(XStack[a]) || NotApplicVal(XStack[a]))
884 #define C1(x) (CUNA(XSN-1) ? _UNK.cval : (x))
885 #define C2(x) (CUNA(XSN-1) || CUNA(XSN-2) ? _UNK.cval : (x))
886 #define CD2(x) (CUNA(XSN-1) || CUNA(XSN-2) ? _UNK.dval : (x))
887 #define D2(x) (DUNA(XSN-1) || DUNA(XSN-2) ? _UNK.dval : (x))
888 
889 
891 /* ----------- */
892 {
893  XStackElt XStack[100]; /* allows 100-level nesting */
894  int XSN=0, DN, bv1, bv2, Mult;
895  double cv1, cv2;
896  String sv1, sv2;
897  Attribute Att;
898  DefElt DElt;
899  AttValue ReturnVal;
900 
901  for ( DN = 0 ; ; DN++)
902  {
903  switch ( DefOp((DElt = D[DN])) )
904  {
905  case OP_ATT:
906  Att = (long) DefSVal(DElt);
907 
908  if ( Continuous(Att) )
909  {
910  XStack[XSN++].cval = CVal(Case, Att);
911  }
912  else
913  {
914  XStack[XSN++].sval =
915  ( Unknown(Case, Att) && ! NotApplic(Case, Att) ? 0 :
916  AttValName[Att][XDVal(Case, Att)] );
917  }
918  break;
919 
920  case OP_NUM:
921  XStack[XSN++].cval = DefNVal(DElt);
922  break;
923 
924  case OP_STR:
925  XStack[XSN++].sval = DefSVal(DElt);
926  break;
927 
928  case OP_AND:
929  bv1 = XStack[XSN-2].dval;
930  bv2 = XStack[XSN-1].dval;
931  XStack[XSN-2].dval = ( bv1 == 3 || bv2 == 3 ? 3 :
932  D2(bv1 == 2 && bv2 == 2 ? 2 : 3) );
933  XSN--;
934  break;
935 
936  case OP_OR:
937  bv1 = XStack[XSN-2].dval;
938  bv2 = XStack[XSN-1].dval;
939  XStack[XSN-2].dval = ( bv1 == 2 || bv2 == 2 ? 2 :
940  D2(bv1 == 2 || bv2 == 2 ? 2 : 3) );
941  XSN--;
942  break;
943 
944  case OP_EQ:
945  cv1 = XStack[XSN-2].cval;
946  cv2 = XStack[XSN-1].cval;
947  XStack[XSN-2].dval = ( cv1 == cv2 ? 2 : 3 );
948  XSN--;
949  break;
950 
951  case OP_NE:
952  cv1 = XStack[XSN-2].cval;
953  cv2 = XStack[XSN-1].cval;
954  XStack[XSN-2].dval = ( cv1 != cv2 ? 2 : 3 );
955  XSN--;
956  break;
957 
958  case OP_GT:
959  cv1 = XStack[XSN-2].cval;
960  cv2 = XStack[XSN-1].cval;
961  XStack[XSN-2].dval = CD2(cv1 > cv2 ? 2 : 3);
962  XSN--;
963  break;
964 
965  case OP_GE:
966  cv1 = XStack[XSN-2].cval;
967  cv2 = XStack[XSN-1].cval;
968  XStack[XSN-2].dval = CD2(cv1 >= cv2 ? 2 : 3);
969  XSN--;
970  break;
971 
972  case OP_LT:
973  cv1 = XStack[XSN-2].cval;
974  cv2 = XStack[XSN-1].cval;
975  XStack[XSN-2].dval = CD2(cv1 < cv2 ? 2 : 3);
976  XSN--;
977  break;
978 
979  case OP_LE:
980  cv1 = XStack[XSN-2].cval;
981  cv2 = XStack[XSN-1].cval;
982  XStack[XSN-2].dval = CD2(cv1 <= cv2 ? 2 : 3);
983  XSN--;
984  break;
985 
986  case OP_SEQ:
987  sv1 = XStack[XSN-2].sval;
988  sv2 = XStack[XSN-1].sval;
989  XStack[XSN-2].dval =
990  ( ! sv1 && ! sv2 ? 2 :
991  ! sv1 || ! sv2 ? 3 :
992  ! strcmp(sv1, sv2) ? 2 : 3 );
993  XSN--;
994  break;
995 
996  case OP_SNE:
997  sv1 = XStack[XSN-2].sval;
998  sv2 = XStack[XSN-1].sval;
999  XStack[XSN-2].dval =
1000  ( ! sv1 && ! sv2 ? 3 :
1001  ! sv1 || ! sv2 ? 2 :
1002  strcmp(sv1, sv2) ? 2 : 3 );
1003  XSN--;
1004  break;
1005 
1006  case OP_PLUS:
1007  cv1 = XStack[XSN-2].cval;
1008  cv2 = XStack[XSN-1].cval;
1009  XStack[XSN-2].cval = C2(cv1 + cv2);
1010  XSN--;
1011  break;
1012 
1013  case OP_MINUS:
1014  cv1 = XStack[XSN-2].cval;
1015  cv2 = XStack[XSN-1].cval;
1016  XStack[XSN-2].cval = C2(cv1 - cv2);
1017  XSN--;
1018  break;
1019 
1020  case OP_MULT:
1021  cv1 = XStack[XSN-2].cval;
1022  cv2 = XStack[XSN-1].cval;
1023  XStack[XSN-2].cval = C2(cv1 * cv2);
1024  XSN--;
1025  break;
1026 
1027  case OP_DIV:
1028  /* Note: have to set precision of result */
1029 
1030  cv1 = XStack[XSN-2].cval;
1031  cv2 = XStack[XSN-1].cval;
1032  if ( ! cv2 ||
1033  CUnknownVal(XStack[XSN-2]) ||
1034  CUnknownVal(XStack[XSN-1]) ||
1035  NotApplicVal(XStack[XSN-2]) ||
1036  NotApplicVal(XStack[XSN-1]) )
1037  {
1038  XStack[XSN-2].cval = _UNK.cval;
1039  }
1040  else
1041  {
1042  Mult = Denominator(cv1);
1043  cv1 = cv1 / cv2;
1044  while ( fabs(cv2) > 1 )
1045  {
1046  Mult *= 10;
1047  cv2 /= 10;
1048  }
1049  XStack[XSN-2].cval = rint(cv1 * Mult) / Mult;
1050  }
1051  XSN--;
1052  break;
1053 
1054  case OP_MOD:
1055  cv1 = XStack[XSN-2].cval;
1056  cv2 = XStack[XSN-1].cval;
1057  XStack[XSN-2].cval = C2(fmod(cv1, cv2));
1058  XSN--;
1059  break;
1060 
1061  case OP_POW:
1062  cv1 = XStack[XSN-2].cval;
1063  cv2 = XStack[XSN-1].cval;
1064  XStack[XSN-2].cval =
1065  ( CUNA(XSN-1) || CUNA(XSN-2) ||
1066  ( cv1 < 0 && ceil(cv2) != cv2 ) ? _UNK.cval :
1067  pow(cv1, cv2) );
1068  XSN--;
1069  break;
1070 
1071  case OP_UMINUS:
1072  cv1 = XStack[XSN-1].cval;
1073  XStack[XSN-1].cval = C1(-cv1);
1074  break;
1075 
1076  case OP_SIN:
1077  cv1 = XStack[XSN-1].cval;
1078  XStack[XSN-1].cval = C1(sin(cv1));
1079  break;
1080 
1081  case OP_COS:
1082  cv1 = XStack[XSN-1].cval;
1083  XStack[XSN-1].cval = C1(cos(cv1));
1084  break;
1085 
1086  case OP_TAN:
1087  cv1 = XStack[XSN-1].cval;
1088  XStack[XSN-1].cval = C1(tan(cv1));
1089  break;
1090 
1091  case OP_LOG:
1092  cv1 = XStack[XSN-1].cval;
1093  XStack[XSN-1].cval =
1094  ( CUNA(XSN-1) || cv1 <= 0 ? _UNK.cval : log(cv1) );
1095  break;
1096 
1097  case OP_EXP:
1098  cv1 = XStack[XSN-1].cval;
1099  XStack[XSN-1].cval = C1(exp(cv1));
1100  break;
1101 
1102  case OP_INT:
1103  cv1 = XStack[XSN-1].cval;
1104  XStack[XSN-1].cval = C1(rint(cv1));
1105  break;
1106 
1107  case OP_END:
1108  ReturnVal.cval = XStack[0].cval; /* cval >= dval bytes */
1109  return ReturnVal;
1110  }
1111  }
1112 }