aboutsummaryrefslogtreecommitdiff
path: root/noao/digiphot/photcal/parser/preval.gx
blob: 24eb5e417c32058b1a8ed2fbc2a2fec020e9cc62 (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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
include	"../lib/parser.h"
include	"../lib/preval.h"

# Evaluation stack depth
define	STACK_DEPTH		50


# PR_EVAL - Evaluate an RPN code expression generated by the parser. This
# procedure checks for consistency in the input, although the code generated
# by the parser should be correct, and for stack underflow and overflow.
# The underflow can only happen under wrong generated code, but overflow
# can happen in complex expressions. This is not a syntactic, but related
# with the number of parenthesis used in the original source code expression.
# Illegal operations, such as division by zero, return and undefined value.

real procedure pr_eval (code, vdata, pdata)

pointer	code			# RPN code buffer
real	vdata[ARB]		# variables
real	pdata[ARB]		# parameters

real	pr_evs ()

begin
	return (pr_evs (code, vdata, pdata))
end


# PR_EV[SILRDX] - These procedures are called in chain, one for each indirect
# call to an equation expression (recursion). In this way it is possible to
# have up to six levels of indirection. Altough it works well, this is a patch,
# and should be replaced with a more elegant procedure that keeps a stack of
# indirect calls.

$for (silrdx)
real procedure pr_ev$t (code, vdata, pdata)

pointer	code			# RPN code buffer
real	vdata[ARB]		# variables
real	pdata[ARB]		# parameters

char	str[SZ_LINE]
int	ip			# instruction pointer
int	sp			# stack pointer
int	ins			# current instruction
int	sym			# equation symbol
real	stack[STACK_DEPTH]	# evaluation stack
real	dummy
pointer	caux, paux

$if (datatype == s)
real	pr_evi ()
$endif
$if (datatype == i)
real	pr_evl ()
$endif
$if (datatype == l)
real	pr_evr ()
$endif
$if (datatype == r)
real	pr_evd ()
$endif
$if (datatype == d)
real	pr_evx ()
$endif
pointer	pr_gsym(), pr_gsymp()

begin
	# Set the instruction pointer (offset from the
	# beginning) to the first instruction in the buffer
	ip = 0

	# Get first instruction from the code buffer
	ins = Memi[code + ip]

	# Reset execution stack pointer
	sp = 0

	# Returned value when recursion overflows
	dummy = INDEFR

	# Loop reading instructions from the code buffer
	# until the end-of-code instruction is found
	while (ins != PEV_EOC) {

	    # Branch on the instruction type
	    switch (ins) {

	    case PEV_NUMBER:
		ip = ip + 1
		sp = sp + 1
		stack[sp] = Memr[code + ip]
		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_CATVAR:
		ip = ip + 1
		sp = sp + 1
		stack[sp] = vdata[Memi[code + ip]]
		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_OBSVAR:
		ip = ip + 1
		sp = sp + 1
		stack[sp] = vdata[Memi[code + ip]]
		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_PARAM:
		ip = ip + 1
		sp = sp + 1
		stack[sp] = pdata[Memi[code + ip]]
		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_SETEQ:
		ip = ip + 1
		sp = sp + 1

		sym = pr_gsym (Memi[code + ip], PTY_SETEQ)
		caux = pr_gsymp (sym, PSEQRPNEQ)

		$if (datatype == s)
		stack[sp] = pr_evi (caux, vdata, pdata)
		$endif
		$if (datatype == i)
		stack[sp] = pr_evl (caux, vdata, pdata)
		$endif
		$if (datatype == l)
		stack[sp] = pr_evr (caux, vdata, pdata)
		$endif
		$if (datatype == r)
		stack[sp] = pr_evd (caux, vdata, pdata)
		$endif
		$if (datatype == d)
		stack[sp] = pr_evx (caux, vdata, pdata)
		$endif
		$if (datatype == x)
		stack[sp] = dummy
		$endif

		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_EXTEQ:
		# not yet implemented
		ip = ip + 1
		sp = sp + 1
		stack[sp] = INDEFR
		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_TRNEQ:
		ip = ip + 1
		sp = sp + 1

		sym = pr_gsym (Memi[code + ip], PTY_TRNEQ)
		caux = pr_gsymp (sym, PTEQRPNFIT)
		paux = pr_gsymp (sym, PTEQSPARVAL)

		$if (datatype == s)
		stack[sp] = pr_evi (caux, vdata, Memr[paux])
		$endif
		$if (datatype == i)
		stack[sp] = pr_evl (caux, vdata, Memr[paux])
		$endif
		$if (datatype == l)
		stack[sp] = pr_evr (caux, vdata, Memr[paux])
		$endif
		$if (datatype == r)
		stack[sp] = pr_evd (caux, vdata, Memr[paux])
		$endif
		$if (datatype == d)
		stack[sp] = pr_evx (caux, vdata, Memr[paux])
		$endif
		$if (datatype == x)
		stack[sp] = dummy
		$endif

		if (IS_INDEFR (stack[sp]))
		    break

	    case PEV_UPLUS:
		# do nothing

	    case PEV_UMINUS:
		stack[sp] = - stack[sp]

	    case PEV_PLUS:
		stack[sp - 1] = stack[sp - 1] + stack[sp]
		sp = sp - 1

	    case PEV_MINUS:
		stack[sp - 1] = stack[sp - 1] - stack[sp]
		sp = sp - 1

	    case PEV_STAR:
		stack[sp - 1] = stack[sp - 1] * stack[sp]
		sp = sp - 1

	    case PEV_SLASH:
		if (stack[sp] != 0) {
		    stack[sp - 1] = stack[sp - 1] / stack[sp]
		    sp = sp - 1
		} else {
		    stack[sp - 1] = INDEFR
		    sp = sp - 1
		    break
		}

	    case PEV_EXPON:
		if (stack[sp - 1] != 0)
		    stack[sp - 1] = stack[sp - 1] ** stack[sp]
		else
		    stack[sp - 1] = 0.0
		sp = sp - 1

	    case PEV_ABS:
		stack[sp] = abs (stack[sp])

	    case PEV_ACOS:
		if (abs (stack[sp]) <= 1.0)
		    stack[sp] = acos (stack[sp])
		else {
		    stack[sp] = INDEFR
		    break
		}

	    case PEV_ASIN:
		if (abs (stack[sp]) <= 1.0)
		    stack[sp] = asin (stack[sp])
		else {
		    stack[sp] = INDEFR
		    break
		}

	    case PEV_ATAN:
		stack[sp] = atan (stack[sp])

	    case PEV_COS:
		stack[sp] = cos (stack[sp])

	    case PEV_EXP:
		stack[sp] = exp (stack[sp])

	    case PEV_LOG:
		if (stack[sp] > 0.0)
		    stack[sp] = log (stack[sp])
		else {
		    stack[sp] = INDEFR
		    break
		}

	    case PEV_LOG10:
		if (stack[sp] > 0.0)
		    stack[sp] = log10 (stack[sp])
		else {
		    stack[sp] = INDEFR
		    break
		}

	    case PEV_SIN:
		stack[sp] = sin (stack[sp])

	    case PEV_SQRT:
		if (stack[sp] >= 0.0)
		    stack[sp] = sqrt (stack[sp])
		else {
		    stack[sp] = INDEFR
		    break
		}

	    case PEV_TAN:
		stack[sp] = tan (stack[sp])

	    default:	# (just in case)
		call sprintf (str, SZ_LINE,
		"pr_eval: Evaluation code error (code=%d ip=%d ins=%d sp=%d)")
		    call pargi (code)
		    call pargi (ip)
		    call pargi (ins)
		    call pargi (sp)
		call error (0, str)
	    }

	    # Check for stack overflow. This is the 
	    # only check really needed.
	    if (sp >= STACK_DEPTH) {
		call sprintf (str, SZ_LINE,
		"pr_eval: Evaluation stack overflow (code=%d ip=%d ins=%d sp=%d)")
		    call pargi (code)
		    call pargi (ip)
		    call pargi (ins)
		    call pargi (sp)
		call error (0, str)
	    }

	    # Check for stack underflow (just in case)
	    if (sp < 1) {
		call sprintf (str, SZ_LINE,
		"pr_eval: Evaluation stack underflow (code=%d ip=%d ins=%d sp=%d)")
		    call pargi (code)
		    call pargi (ip)
		    call pargi (ins)
		    call pargi (sp)
		call error (0, str)
	    }

	    # Get next instruction
	    ip = ip + 1
	    ins = Memi[code + ip]
	}

	# Return expression value
	return (stack[sp])
end

$endfor