see5-installer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +11 -0
  4. data/CHANGELOG.md +5 -0
  5. data/Gemfile +10 -0
  6. data/README.md +29 -0
  7. data/Rakefile +12 -0
  8. data/ext/c5.0/Makefile +86 -0
  9. data/ext/c5.0/attwinnow.c +394 -0
  10. data/ext/c5.0/c50.c +330 -0
  11. data/ext/c5.0/classify.c +700 -0
  12. data/ext/c5.0/confmat.c +195 -0
  13. data/ext/c5.0/construct.c +853 -0
  14. data/ext/c5.0/contin.c +613 -0
  15. data/ext/c5.0/defns.i +788 -0
  16. data/ext/c5.0/discr.c +307 -0
  17. data/ext/c5.0/extern.i +170 -0
  18. data/ext/c5.0/formrules.c +720 -0
  19. data/ext/c5.0/formtree.c +1158 -0
  20. data/ext/c5.0/getdata.c +521 -0
  21. data/ext/c5.0/getnames.c +733 -0
  22. data/ext/c5.0/global.c +211 -0
  23. data/ext/c5.0/gpl.txt +674 -0
  24. data/ext/c5.0/implicitatt.c +1112 -0
  25. data/ext/c5.0/info.c +146 -0
  26. data/ext/c5.0/mcost.c +138 -0
  27. data/ext/c5.0/modelfiles.c +952 -0
  28. data/ext/c5.0/p-thresh.c +313 -0
  29. data/ext/c5.0/prune.c +1069 -0
  30. data/ext/c5.0/report.c +345 -0
  31. data/ext/c5.0/rules.c +579 -0
  32. data/ext/c5.0/ruletree.c +398 -0
  33. data/ext/c5.0/siftrules.c +1285 -0
  34. data/ext/c5.0/sort.c +156 -0
  35. data/ext/c5.0/subset.c +599 -0
  36. data/ext/c5.0/text.i +223 -0
  37. data/ext/c5.0/trees.c +740 -0
  38. data/ext/c5.0/update.c +129 -0
  39. data/ext/c5.0/utility.c +1146 -0
  40. data/ext/c5.0/xval +150 -0
  41. data/ext/c5.0/xval.c +402 -0
  42. data/ext/gritbot/Makefile +98 -0
  43. data/ext/gritbot/check.c +1110 -0
  44. data/ext/gritbot/cluster.c +342 -0
  45. data/ext/gritbot/common.c +1269 -0
  46. data/ext/gritbot/continatt.c +412 -0
  47. data/ext/gritbot/defns.i +623 -0
  48. data/ext/gritbot/discratt.c +459 -0
  49. data/ext/gritbot/extern.i +101 -0
  50. data/ext/gritbot/getdata.c +329 -0
  51. data/ext/gritbot/getnames.c +573 -0
  52. data/ext/gritbot/global.c +104 -0
  53. data/ext/gritbot/gpl.txt +674 -0
  54. data/ext/gritbot/gritbot.c +295 -0
  55. data/ext/gritbot/implicitatt.c +1108 -0
  56. data/ext/gritbot/inspect.c +794 -0
  57. data/ext/gritbot/modelfiles.c +687 -0
  58. data/ext/gritbot/outlier.c +415 -0
  59. data/ext/gritbot/sort.c +130 -0
  60. data/ext/gritbot/text.i +159 -0
  61. data/ext/gritbot/update.c +126 -0
  62. data/ext/gritbot/utility.c +1029 -0
  63. data/ext/see5-installer/extconf.rb +25 -0
  64. data/lib/see5/installer.rb +10 -0
  65. data/lib/see5/installer/version.rb +7 -0
  66. data/see5-installer.gemspec +30 -0
  67. metadata +115 -0
@@ -0,0 +1,1112 @@
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
+ {
59
+ DiscrValue _discr_val;
60
+ ContValue _cont_val;
61
+ String _string_val;
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;
128
+ AttValName[MaxAtt] = AllocZero(4, String);
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;
142
+ SpecialStatus[MaxAtt] = EXCLUDE;
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
+
244
+ Boolean Expression()
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
+
267
+ Boolean Conjunct()
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
+
290
+ Boolean SExpression()
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
+
319
+ Boolean AExpression()
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
+
351
+ Boolean Term()
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
+
372
+ Boolean Factor()
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
+
393
+ Boolean Primary()
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
+
419
+ Boolean Atom()
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
+
563
+ Boolean Find(String S)
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
+
602
+ Attribute FindAttName()
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
+
639
+ void DefSyntaxError(String Msg)
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
+
890
+ AttValue EvaluateDef(Definition D, DataRec Case)
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
+ }