aboutsummaryrefslogtreecommitdiff
path: root/pkg/tbtables/selector/trseval.x
blob: eae7db8e310753ec35a00b47e3e43c88957d160d (plain) (blame)
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