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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +11 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +10 -0
- data/README.md +29 -0
- data/Rakefile +12 -0
- data/ext/c5.0/Makefile +86 -0
- data/ext/c5.0/attwinnow.c +394 -0
- data/ext/c5.0/c50.c +330 -0
- data/ext/c5.0/classify.c +700 -0
- data/ext/c5.0/confmat.c +195 -0
- data/ext/c5.0/construct.c +853 -0
- data/ext/c5.0/contin.c +613 -0
- data/ext/c5.0/defns.i +788 -0
- data/ext/c5.0/discr.c +307 -0
- data/ext/c5.0/extern.i +170 -0
- data/ext/c5.0/formrules.c +720 -0
- data/ext/c5.0/formtree.c +1158 -0
- data/ext/c5.0/getdata.c +521 -0
- data/ext/c5.0/getnames.c +733 -0
- data/ext/c5.0/global.c +211 -0
- data/ext/c5.0/gpl.txt +674 -0
- data/ext/c5.0/implicitatt.c +1112 -0
- data/ext/c5.0/info.c +146 -0
- data/ext/c5.0/mcost.c +138 -0
- data/ext/c5.0/modelfiles.c +952 -0
- data/ext/c5.0/p-thresh.c +313 -0
- data/ext/c5.0/prune.c +1069 -0
- data/ext/c5.0/report.c +345 -0
- data/ext/c5.0/rules.c +579 -0
- data/ext/c5.0/ruletree.c +398 -0
- data/ext/c5.0/siftrules.c +1285 -0
- data/ext/c5.0/sort.c +156 -0
- data/ext/c5.0/subset.c +599 -0
- data/ext/c5.0/text.i +223 -0
- data/ext/c5.0/trees.c +740 -0
- data/ext/c5.0/update.c +129 -0
- data/ext/c5.0/utility.c +1146 -0
- data/ext/c5.0/xval +150 -0
- data/ext/c5.0/xval.c +402 -0
- data/ext/gritbot/Makefile +98 -0
- data/ext/gritbot/check.c +1110 -0
- data/ext/gritbot/cluster.c +342 -0
- data/ext/gritbot/common.c +1269 -0
- data/ext/gritbot/continatt.c +412 -0
- data/ext/gritbot/defns.i +623 -0
- data/ext/gritbot/discratt.c +459 -0
- data/ext/gritbot/extern.i +101 -0
- data/ext/gritbot/getdata.c +329 -0
- data/ext/gritbot/getnames.c +573 -0
- data/ext/gritbot/global.c +104 -0
- data/ext/gritbot/gpl.txt +674 -0
- data/ext/gritbot/gritbot.c +295 -0
- data/ext/gritbot/implicitatt.c +1108 -0
- data/ext/gritbot/inspect.c +794 -0
- data/ext/gritbot/modelfiles.c +687 -0
- data/ext/gritbot/outlier.c +415 -0
- data/ext/gritbot/sort.c +130 -0
- data/ext/gritbot/text.i +159 -0
- data/ext/gritbot/update.c +126 -0
- data/ext/gritbot/utility.c +1029 -0
- data/ext/see5-installer/extconf.rb +25 -0
- data/lib/see5/installer.rb +10 -0
- data/lib/see5/installer/version.rb +7 -0
- data/see5-installer.gemspec +30 -0
- 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
|
+
}
|