1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
|
include "trs.h"
#* HISTORY *
#* B.Simon 04-Nov-94 original
#* B.Simon 29-Dec-97 revised to use row set
.help trseval
.nf______________________________________________________________________
This is one of a set of three procedures to select rows of a table
according to a qpoe filter. This procedure evaluates the filter, i.e.,
determines whether it is true or false for a specified row of the
table. The other two procedures are trsopen(), which compiles the
qpoe filter into the pseudocode used by trseval() and trsclose() which
frees the memory held by the pseudocode arrays. Here is an typical
example of the use of these three routines:
tp = tbtopn (table, READ_ONLY, NULL)
numrow = tbpsta (tp, TBL_NROWS)
pcode = trsopen (tp, filter)
do irow = 1, numrow {
if (trseval (tp, irow, pcode)) {
# Do something neat here
}
}
call trsclose (pcode)
call tbtclo (tp)
For sake of an example, suppose we have a star catalog with the
columns Name, Ra, Dec, V, B-V, and U-B. The simplest sort of filter is
the equality test. The name of the column appears on the left of an
equals sign and the column value appears on the right. For example,
[name=eta_uma]. (The brackets in this and the following example are
not actually part of the filter.) Column numbers can be used in place
of the column name. This is especially useful for ascii
tables. Values can be either numbers or strings. It is usually not
necessary to place strings in quotes. However, any string (including
a column name) contains embedded blanks or characters significant to
the qpoe filter, such a equal signs, commas, or colons, it should be
placed in quotes.
Ranges of values can be specified by giving the endpoints of the
ranges separated by a colon. For example, [v=10:15] selects all rows
with visual magnitude between 10 and 15. Ranges include their
endpoints. Ranges can also be used with strings as well as
numbers. Ranges can also be one sided. The filter [dec=80:] selects
all rows with declination greater than or equal to eighty degress and
the filter [dec=:-40] selects all declinations less than or equal to
forty degrees south. A filter can contain a list of single values and
ranges. The values in the list should be enclosed in parentheses. For
example, [name=(eta_uma,alpha_lyr)] or [b-v=(-1:0,0.5:1)].
Individual values or ranges can be negated by placing a ! in front of
them. For example, [name=!eta_uma] selects every row except the star
named eta_uma and [ra=!0:6] selects all rows except those with right
ascension between zero and six hours. An entire list can be negated by
placing a ! in front of the column name or the parentheses enclosing
the list. The filters [!name=(eta_uma,alpha_lyr)] and
[name=!(eta_uma,alpha_lyr)] and [name=(!eta_uma,!alpha_lyr)] are all
equivalent.
Filters can test more than one column in a table. The individual tests
are separated by commas or semicolons. All tests in the filter must
succeed for the filter to be accepted. For example,
[ra=1.3:1.4,dec=40:42] selects a rectangular region in the catalog. A
range of row numbers can also be selected by placing the word row on
the left side of the equals sign. For example, [row=10:20] selects
rows from ten to twenty inclusive and [row=50:] selects all rows from
fifty on. Row selection can be combined with any other test in a
filter. A filter, can also be placed in an include file, for example
[@filter.lis]. Include files can be a part of a larger expression
and include files can contain other files, up to seven levels deep.
.endhelp _________________________________________________________________
# TRSEVAL -- Evaluate a table row selector on a row of a table
bool procedure trseval (tp, irow, pcode)
pointer tp # i: table descriptor
int irow # i: table row number
pointer pcode # i: pseudocode
#--
string notcode "trseval: not pointer to code"
bool rst_inset(), trscalc()
errchk trscalc
begin
# Make sure this is a valid trs descriptor
if (TRS_IDENT(pcode) != TRS_MAGIC)
call error (1, notcode)
# Check to see if the row is in the set first
# if it is, calculate the result of the pseudocode
if (rst_inset (TRS_ROWS(pcode),irow))
if (trscalc (tp,irow, TRS_CODE(pcode)))
return (true)
return (false)
end
# TRSCALC -- Calculate the result of the pseudocode embedded in the descriptor
bool procedure trscalc (tp, irow, codebuf)
pointer tp # i: table descriptor
int irow # i: table row number
pointer codebuf # i: pseudocode
#--
bool jump, stack[MAXSTACK]
double val
int itop, icode,junk, mask1, mask2
pointer sp, str
string ovflow "trscalc: stack overflow"
string badcode "trscalc: bad instruction"
errchk trsgetd, trsgett
bool streq(), strle(), strge()
int trstrim()
begin
call smark (sp)
call salloc (str, SZ_LINE, TY_CHAR)
itop = 0
icode = 0
jump = false
repeat {
if (itop == MAXSTACK)
call error (1, ovflow)
switch (CODE(codebuf+icode)) {
case YDONE: # end instruction
break
case YRANGE: # range instruction, no-op
;
case YAND: # logical and
if (! jump) {
stack[itop-1] = stack[itop-1] && stack[itop]
itop = itop - 1
}
case YOR: # logical or
if (! jump) {
stack[itop-1] = stack[itop-1] || stack[itop]
itop = itop - 1
}
case YNOT: # logical not
stack[itop] = ! stack[itop]
case YEQN: # numeric equality test
call trsgetd (tp, COLUMN(codebuf+icode), irow, val)
itop = itop + 1
stack[itop] = val == Memd[LOVAL(codebuf+icode)]
case YEQS: # string equality check
call trsgett (tp, COLUMN(codebuf+icode), irow,
Memc[str], SZ_LINE)
junk = trstrim (Memc[str])
itop = itop + 1
stack[itop] = streq (Memc[str], Memc[LOVAL(codebuf+icode)])
case YLEN: # numeric less than or equal check
call trsgetd (tp, COLUMN(codebuf+icode), irow, val)
itop = itop + 1
stack[itop] = val <= Memd[LOVAL(codebuf+icode)]
case YLES: # string less than or equal check
call trsgett (tp, COLUMN(codebuf+icode), irow,
Memc[str], SZ_LINE)
junk = trstrim (Memc[str])
itop = itop + 1
stack[itop] = strle (Memc[str], Memc[LOVAL(codebuf+icode)])
case YINN: # numeric inclusion check
call trsgetd (tp, COLUMN(codebuf+icode), irow, val)
itop = itop + 1
stack[itop] = val >= Memd[LOVAL(codebuf+icode)] &&
val <= Memd[HIVAL(codebuf+icode)]
case YINS: # string inclusion check
call trsgett (tp, COLUMN(codebuf+icode), irow,
Memc[str], SZ_LINE)
junk = trstrim (Memc[str])
itop = itop + 1
stack[itop] = strge (Memc[str], Memc[LOVAL(codebuf+icode)]) &&
strle (Memc[str], Memc[HIVAL(codebuf+icode)])
case YGEN: # numeric greater than or equal check
call trsgetd (tp, COLUMN(codebuf+icode), irow, val)
itop = itop + 1
stack[itop] = val >= Memd[LOVAL(codebuf+icode)]
case YGES: # string greater than or equal check
call trsgett (tp, COLUMN(codebuf+icode), irow,
Memc[str], SZ_LINE)
junk = trstrim (Memc[str])
itop = itop + 1
stack[itop] = strge (Memc[str], Memc[LOVAL(codebuf+icode)])
case YMSK: # bit mask
call trsgetd (tp, COLUMN(codebuf+icode), irow, val)
mask1 = val
mask2 = Memd[LOVAL(codebuf+icode)]
itop = itop + 1
stack[itop] = and (mask1, mask2) == mask2
default:
call error (1, badcode)
}
# Set instruction pointer. Peform a jump if the jump field
# corresponding to the result is not NULL. Otherwise,
# increment the pointer.
if (TJUMP(codebuf+icode) != NULL && stack[itop]) {
jump = true
icode = TJUMP(codebuf+icode)
} else if (FJUMP(codebuf+icode) != NULL && ! stack[itop]) {
jump = true
icode = FJUMP(codebuf+icode)
} else {
jump = false
icode = icode + SZ_INSTR
}
}
# This handles the case of an empty program
if (itop == 0)
stack[1] = true
# Return result
call sfree (sp)
return (stack[1])
end
# TRSGETD -- Read double value from table
procedure trsgetd (tp, cp, irow, val)
pointer tp # i: table descriptor
pointer cp # i: column descriptor
int irow # i: column number
double val # o: value read from table
#--
errchk tbegtd
begin
if (cp == NULL) {
val = irow
} else {
call tbegtd (tp, cp, irow, val)
}
end
# TRSGETT -- Read string value from table
procedure trsgett (tp, cp, irow, str, maxch)
pointer tp # i: table descriptor
pointer cp # i: column descriptor
int irow # i: column number
char str[ARB] # o: value read from table
int maxch # i: maximum string length
#--
int junk
errchk itoc, tbgett
int itoc()
begin
if (cp == NULL) {
junk = itoc (irow, str, maxch)
} else {
call tbegtt (tp, cp, irow, str, maxch)
}
end
|