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
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <syserr.h>
include <mach.h>
include "qpex.h"
.help qpexdata
.nf --------------------------------------------------------------------------
QPEXDATA -- Data management package for QPEX. The QPEX data structures
consist of the QPEX descriptor and two main data buffers, the program buffer
(pb), containing the instructions to be executed (interpreted) to evaluate
an expression, and the data buffer (db), containing assorted data structures,
e.g., the linked list of expression term descriptors, the lookup table
descriptors, storage for DOUBLE data appearing in the compiled expression,
and so on. The program and data buffers are dynamically allocated but are
not relocatable, so to absolute pointers may be used to reference the objects
therein (hence, runtime overflow is possible).
During expression compilation the following routines are used to add data
objects to the program and data buffers:
qpex_mark (ex, pb_save, db_save)
qpex_free (ex, pb_save, db_save)
ip = qpex_pbpos (ex)
qpex_pbpin (ex, opcode, arg1, arg2, arg3)
ptr = qpex_dbpstr (ex, strval)
intval = qpex_refd (ex, dval)
ptr = qpex_dballoc (ex, nelem, dtype)
QPEX_MARK and QPEX_FREE are used to mark the current tops of the two buffers
and subspequently free storage back to that point, e.g., for error recovery
following detection of a compilation error. QPEX_PBPOS returns a pointer to
the location in the program buffer where next instruction will be placed.
QPEX_PBPIN compiles an instruction at that location.
The main storage allocator for the data buffer is QPEX_DBALLOC, which allocates
a properly aligned buffer of the indicated type in the data buffer, and returns
a pointer of the same type as the function value. QPEX_DBPSTR stores a string
constant in the data buffer and returns a pointer to the stored string.
QPEX_REFD stores the given type double constant in the data buffer and returns
(as an integer) a pointer to the stored value (this is necessary to permit
only SZ_INT argument fields in instructions).
.endhelp ---------------------------------------------------------------------
# QPEX_MARK -- Mark the top of the program and data buffers.
procedure qpex_mark (ex, pb_save, db_save)
pointer ex #I QPEX descriptor
pointer pb_save, db_save #O saved pointers
begin
pb_save = EX_PBOP(ex)
db_save = EX_DBOP(ex)
end
# QPEX_FREE -- Free storage back to the marked points.
procedure qpex_free (ex, pb_save, db_save)
pointer ex #I QPEX descriptor
pointer pb_save, db_save #I saved pointers
pointer top, prev, lt, et
pointer coerce()
begin
# Free space in program buffer.
call aclri (Memi[pb_save], EX_PBTOP(ex) - pb_save)
EX_PBOP(ex) = pb_save
# Free space in the data buffer. Prune the LUT and ETERM lists
# and then reset the data buffer pointer.
# The LT list is backward linked from the most recent entry.
top = coerce (db_save, TY_CHAR, TY_STRUCT)
for (lt=EX_LTHEAD(ex); lt != NULL; lt=LT_NEXT(lt))
if (lt >= top) {
call mfree (LT_LUTP(lt), TY_SHORT)
EX_LTHEAD(ex) = LT_NEXT(lt)
}
# The ET list is forward linked from the first entry.
prev = NULL
for (et=EX_ETHEAD(ex); et != NULL; et=ET_NEXT(et))
if (et >= top) {
if (prev != NULL)
ET_NEXT(prev) = NULL
EX_ETTAIL(ex) = prev
break
}
EX_DBOP(ex) = db_save
end
# QPEX_PBPOS -- Return a pointer to the program buffer location where the
# next instruction to be compiled will be located.
pointer procedure qpex_pbpos (ex)
pointer ex #I QPEX descriptor
begin
return (EX_PBOP(ex))
end
# QPEX_PBPIN -- Add an insruction at the end of the program buffer.
procedure qpex_pbpin (ex, opcode, arg1, arg2, arg3)
pointer ex #I QPEX descriptor
int opcode #I instruction opcode
int arg1,arg2,arg3 #I instruction data fields (typeless)
pointer op
errchk syserr
begin
op = EX_PBOP(ex)
if (op >= EX_PBTOP(ex))
call syserr (SYS_QPEXPBOVFL)
OPCODE(op) = opcode
IARG1(op) = arg1
IARG2(op) = arg2
IARG3(op) = arg3
EX_PBOP(ex) = op + LEN_INSTRUCTION
end
# QPEX_DBPSTR -- Store a string constant in the data buffer, returning a
# pointer to the stored string as the function value.
pointer procedure qpex_dbpstr (ex, strval)
pointer ex #I QPEX descriptor
char strval[ARB] #I string to be stored
pointer op
int nchars
int strlen()
errchk syserr
begin
op = EX_DBOP(ex)
nchars = strlen (strval) + 1
if (op + nchars >= EX_DBTOP(ex))
call syserr (SYS_QPEXDBOVFL)
call strcpy (strval, Memc[op], nchars)
EX_DBOP(ex) = op + nchars
return (op)
end
# QPEX_REFD -- Reference a type DOUBLE datum, returning (as an integer) a
# pointer to the double value, which is stored in the data buffer.
int procedure qpex_refd (ex, value)
pointer ex #I QPEX descriptor
double value #I double value
pointer dp
pointer qpex_dballoc()
errchk qpex_dballoc
begin
dp = qpex_dballoc (ex, 1, TY_DOUBLE)
Memd[dp] = value
return (dp)
end
# QPEX_DBALLOC -- Allocate storage of the indicated type in the data
# buffer, returning a typed pointer to the buffer. The buffer is fully
# aligned.
pointer procedure qpex_dballoc (ex, nelem, dtype)
pointer ex #I QPEX descriptor
int nelem #I amount of storage desired
int dtype #I datatype of the storage element
pointer op, top
pointer coerce()
int sizeof()
errchk syserr
begin
op = EX_DBOP(ex)
while (mod (op-1, SZ_DOUBLE) != 0)
op = op + 1
top = op + nelem * sizeof(dtype)
if (top >= EX_DBTOP(ex))
call syserr (SYS_QPEXDBOVFL)
EX_DBOP(ex) = top
return (coerce (op, TY_CHAR, dtype))
end
|