see5-installer 0.1.0

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