aboutsummaryrefslogtreecommitdiff
path: root/sys/qpoe/qpexmodfil.x
blob: 7df4b926a10b9d6defc9043841c1d49164bf1049 (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
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include <mach.h>
include "qpoe.h"
include "qpex.h"

# QPEX_MODFILTER -- Compile an event attribute expression to be used for event
# attribute filtering, modifying the the current EAF as directed by the expr.
# An event attribute expression consists of a sequence of independent terms
# of the form "attribute = expr", e.g.,
#
#       pha=%104B, e=100:, t=(:9,11:29,33,42:65,67:99,!(82,87),103), ...
#
# 
# Variants on "attr = expr" are "attr := expr" and "attr += expr".  In the
# case of :=, any expression terms already entered for the named attribute
# will be REPLACED by the new expression.  In the case of +=, the given
# expression denotes an additional condition which the attribute must satisfy
# to pass the filter, i.e., a new term is added to the existing filter.  The
# case = is the same as +=, i.e., the default action is to modify rather than
# replace any existing filter.
# 
#
# Our function is to extract each attribute=expr term and compile it into a
# series of instructions to be repeatedly executed (interpreted) at runtime
# to evaluate the expression for a particular event structure.  Terms are
# compiled and evaluated in the order in which they appear in the expression
# list (except for replacement terms), allowing the user to manually optimize
# the filter by giving terms which are most likely to fail first.
#
# The expression list may contain references to predefined global or local
# (datafile) macros, external macro files, or back-quoted CL commands for
# which the output is to be substituted as for a macro.  In all cases, macro
# substitution is handled at a lower level in the gettok routine.  In
# particular, the logical names of the fields of the event structure are
# implemented as predefined datafile-local macros, hence we are concerned only
# with physical field names here.  The form of a physical field name is
# a datatype code [SIRD] followed by the decimal zero-indexed byte offset
# of the field in the event structure, e.g., S0, S2, R4, etc. (short integer
# field at offset 0, same at offset 2, Real*4 field at offset 4, etc.).
#
# The function value is OK if the expression list compiles without any errors,
# or ERR if some compilation error occurs.  Compilation errors cause an error
# message to be output to STDERR and the affected terms to be skipped, but are
# otherwise ignored.

int procedure qpex_modfilter (ex, exprlist)

pointer ex                      #I qpex descriptor
char    exprlist[ARB]           #I list of attribute=expr expressions

bool	replace
int	boffset, offset, max_offset, dtype
int	status, sz_expr, token, parenlevel, nchars, buflen
pointer	sp, atname, assignop, tokbuf, expr, qp, ip, op, in, et_tail

pointer	qp_opentext()
int	qpex_codegeni(), qpex_codegenr(), qpex_codegend()
int	qp_gettok(), strlen(), gstrcpy(), ctoi(), sizeof()
errchk	malloc, qp_opentext, qp_gettok, realloc, qpex_delete

string	qpexwarn "QPEX Warning"
define	eatup_ 91
define	badatt_ 92

begin
	call smark (sp)
	call salloc (atname, SZ_TOKBUF, TY_CHAR)
	call salloc (assignop, SZ_TOKBUF, TY_CHAR)
	call salloc (tokbuf, SZ_TOKBUF, TY_CHAR)

	status = OK
	sz_expr = DEF_SZEXPRBUF
	et_tail = EX_ETTAIL(ex)
	qp = EX_QP(ex)

	# Allocate a variable size expression buffer.
	call malloc (expr, sz_expr, TY_CHAR)

	# Open the expression list for token input with macro expansion.
	in = qp_opentext (qp, exprlist)

	# Accumulate and compile successive attribute=expr terms of the
	# expression list.

	repeat {
	    # Get attribute name.
	    switch (qp_gettok (in, Memc[atname], SZ_TOKBUF)) {
	    case EOF:
		break			# input exhausted
	    case ',', ';':
		next			# null statement
	    case TOK_IDENTIFIER:
		;			# got one
	    default:
		call eprintf ("%s: unexpected token `%s'\n")
		    call pargstr (qpexwarn)
		    call pargstr (Memc[atname])
		goto eatup_
	    }

	    # Get operator.
	    switch (qp_gettok (in, Memc[assignop], SZ_TOKBUF)) {
	    case TOK_PLUSEQUALS, '=':
		replace = false
	    case TOK_COLONEQUALS:
		replace = true

	    default:
		call eprintf ("%s: missing assignment token (`%s')\n")
		    call pargstr (qpexwarn)
		    call pargstr (Memc[atname])
eatup_
		# A half-hearted attempt to ignore the offending statement...
		while (qp_gettok (in, Memc[expr], sz_expr) != EOF)
		    if (Memc[expr] == ',')
			break

		# The default is to add to any existing filter.
		replace = false
	    }

	    parenlevel = 0
	    token = NULL

	    # Accumulate expression.
	    for (op=expr;  token != EOF;  ) {
		# Get next token from input stream.
		token = qp_gettok (in, Memc[tokbuf], SZ_TOKBUF)

		# Process any special tokens.
		switch (token) {
		case EOF:
		    break
		case '(':
		    parenlevel = parenlevel + 1
		case ')':
		    parenlevel = parenlevel - 1
		    if (parenlevel < 0) {
			call eprintf ("%s: missing left parenthesis\n")
			    call pargstr (qpexwarn)
			parenlevel = 0
			status = ERR
			next
		    }
		case ',', ';':
		    # An unparenthesized comma terminates the expression.
		    if (parenlevel <= 0)
			break
		}

		# Allocate more storage if expr buf fills.
		nchars = strlen (Memc[tokbuf])
		buflen = op - expr
		if (buflen + nchars > sz_expr) {
		    sz_expr = sz_expr + INC_SZEXPRBUF
		    call realloc (expr, sz_expr, TY_CHAR)
		    op = expr + buflen
		}

		# Concatenate token string to expr.
		op = op + gstrcpy (Memc[tokbuf], Memc[op], SZ_TOKBUF)
	    }

	    Memc[op] = EOS
	    if (parenlevel > 0) {
		call eprintf ("%s: missing right parenthesis in expression\n")
		    call pargstr (qpexwarn)
		status = ERR
	    }

	    # Parse the attribute name to determine the datatype and offset.

	    # Get byte offset of field.
	    ip = atname + 1
	    if (ctoi (Memc, ip, boffset) <= 0)
		goto badatt_

	    # Get datatype and scaled offset; check field alignment.
	    switch (Memc[atname]) {
	    case 'S', 's':
		dtype = TY_SHORT
		offset = boffset / (SZ_SHORT * SZB_CHAR)
		if (offset * SZ_SHORT * SZB_CHAR != boffset)
		    goto badatt_
	    case 'I', 'i':
		dtype = TY_INT
		offset = boffset / (SZ_INT * SZB_CHAR)
		if (offset * SZ_INT * SZB_CHAR != boffset)
		    goto badatt_
	    case 'R', 'r':
		dtype = TY_REAL
		offset = boffset / (SZ_REAL * SZB_CHAR)
		if (offset * SZ_REAL * SZB_CHAR != boffset)
		    goto badatt_
	    case 'D', 'd':
		dtype = TY_DOUBLE
		offset = boffset / (SZ_DOUBLE * SZB_CHAR)
		if (offset * SZ_DOUBLE * SZB_CHAR != boffset)
		    goto badatt_
	    default:
		goto badatt_
	    }
	    
	    # Verify that the field is in range in the event struct.
	    # (Actually, we don't know the event struct at compile time...)

	    max_offset = (boffset / SZB_CHAR) + sizeof(dtype) - 1
	    if (boffset < 0 || max_offset > ARB) {
badatt_		call eprintf ("%s: bad attribute name `%s'\n")
		    call pargstr (qpexwarn)
		    call pargstr (Memc[atname])
		status = ERR
		next
	    }

	    # Clobber any old expression for the given attribute if replace
	    # mode is in effect.  Only previous expression terms are affected,
	    # hence in single expressions like "pha=x,pha=y", the second entry
	    # does not clobber the first.

	    if (replace)
		call qpex_delete (ex, et_tail, offset, dtype)

	    # Compile the expression.
	    switch (dtype) {
	    case TY_SHORT, TY_INT:
		if (qpex_codegeni (ex, Memc[atname], Memc[assignop],
		    Memc[expr], offset, dtype) == ERR)
		    status = ERR
	    case TY_REAL:
		if (qpex_codegenr (ex, Memc[atname], Memc[assignop],
		    Memc[expr], offset, dtype) == ERR)
		    status = ERR
	    case TY_DOUBLE:
		if (qpex_codegend (ex, Memc[atname], Memc[assignop],
		    Memc[expr], offset, dtype) == ERR)
		    status = ERR
	    }
	}

	call qp_closetext (in)
	call mfree (expr, TY_CHAR)
	call sfree (sp)

	return (status)
end