Commit | Line | Data |
---|---|---|
b329a001 ML |
1 | /* Copyright (c) 1982 Regents of the University of California */ |
2 | ||
0022c355 ML |
3 | static char sccsid[] = "@(#)check.c 1.7 (Berkeley) %G%"; |
4 | ||
5 | static char rcsid[] = "$Header: check.c,v 1.5 84/12/26 10:38:35 linton Exp $"; | |
b329a001 ML |
6 | |
7 | /* | |
8 | * Check a tree for semantic correctness. | |
9 | */ | |
10 | ||
11 | #include "defs.h" | |
12 | #include "tree.h" | |
13 | #include "operators.h" | |
14 | #include "events.h" | |
15 | #include "symbols.h" | |
16 | #include "scanner.h" | |
17 | #include "source.h" | |
18 | #include "object.h" | |
19 | #include "mappings.h" | |
20 | #include "process.h" | |
0022c355 | 21 | #include <signal.h> |
b329a001 ML |
22 | |
23 | #ifndef public | |
24 | #endif | |
25 | ||
26 | /* | |
27 | * Check that the nodes in a tree have the correct arguments | |
28 | * in order to be evaluated. Basically the error checking here | |
29 | * frees the evaluation routines from worrying about anything | |
30 | * except dynamic errors, e.g. subscript out of range. | |
31 | */ | |
32 | ||
33 | public check(p) | |
34 | register Node p; | |
35 | { | |
0022c355 | 36 | Node p1, p2; |
b329a001 ML |
37 | Address addr; |
38 | Symbol f; | |
39 | ||
40 | checkref(p); | |
41 | switch (p->op) { | |
0022c355 ML |
42 | case O_ASSIGN: |
43 | p1 = p->value.arg[0]; | |
44 | p2 = p->value.arg[1]; | |
45 | if (not compatible(p1->nodetype, p2->nodetype)) { | |
46 | error("incompatible types"); | |
47 | } | |
48 | break; | |
49 | ||
50 | case O_CATCH: | |
51 | case O_IGNORE: | |
52 | if (p->value.lcon < 0 or p->value.lcon > NSIG) { | |
53 | error("invalid signal number"); | |
54 | } | |
55 | break; | |
56 | ||
57 | case O_CONT: | |
58 | if (p->value.lcon != DEFSIG and ( | |
59 | p->value.lcon < 0 or p->value.lcon > NSIG) | |
60 | ) { | |
61 | error("invalid signal number"); | |
62 | } | |
63 | break; | |
64 | ||
65 | case O_DUMP: | |
66 | if (p->value.arg[0] != nil) { | |
67 | if (p->value.arg[0]->op == O_SYM) { | |
68 | f = p->value.arg[0]->value.sym; | |
69 | if (not isblock(f)) { | |
70 | error("\"%s\" is not a block", symname(f)); | |
71 | } | |
72 | } else { | |
73 | beginerrmsg(); | |
74 | fprintf(stderr, "expected a symbol, found \""); | |
75 | prtree(stderr, p->value.arg[0]); | |
76 | fprintf(stderr, "\""); | |
77 | enderrmsg(); | |
78 | } | |
79 | } | |
80 | break; | |
81 | ||
b329a001 ML |
82 | case O_LIST: |
83 | if (p->value.arg[0]->op == O_SYM) { | |
84 | f = p->value.arg[0]->value.sym; | |
85 | if (not isblock(f) or ismodule(f)) { | |
86 | error("\"%s\" is not a procedure or function", symname(f)); | |
87 | } | |
88 | addr = firstline(f); | |
89 | if (addr == NOADDR) { | |
90 | error("\"%s\" is empty", symname(f)); | |
91 | } | |
92 | } | |
93 | break; | |
94 | ||
95 | case O_TRACE: | |
96 | case O_TRACEI: | |
97 | chktrace(p); | |
98 | break; | |
99 | ||
100 | case O_STOP: | |
101 | case O_STOPI: | |
102 | chkstop(p); | |
103 | break; | |
104 | ||
0022c355 | 105 | case O_CALLPROC: |
2fd0f574 SL |
106 | case O_CALL: |
107 | if (not isroutine(p->value.arg[0]->nodetype)) { | |
108 | beginerrmsg(); | |
109 | fprintf(stderr, "\""); | |
110 | prtree(stderr, p->value.arg[0]); | |
111 | fprintf(stderr, "\" not call-able"); | |
112 | enderrmsg(); | |
113 | } | |
114 | break; | |
115 | ||
0022c355 ML |
116 | case O_WHEREIS: |
117 | if (p->value.arg[0]->op == O_SYM and | |
118 | p->value.arg[0]->value.sym == nil) { | |
119 | error("symbol not defined"); | |
120 | } | |
121 | break; | |
122 | ||
b329a001 ML |
123 | default: |
124 | break; | |
125 | } | |
126 | } | |
127 | ||
128 | /* | |
129 | * Check arguments to a trace command. | |
130 | */ | |
131 | ||
132 | private chktrace(p) | |
133 | Node p; | |
134 | { | |
135 | Node exp, place, cond; | |
136 | ||
137 | exp = p->value.arg[0]; | |
138 | place = p->value.arg[1]; | |
139 | cond = p->value.arg[2]; | |
140 | if (exp == nil) { | |
141 | chkblock(place); | |
142 | } else if (exp->op == O_LCON or exp->op == O_QLINE) { | |
143 | if (place != nil) { | |
144 | error("unexpected \"at\" or \"in\""); | |
145 | } | |
146 | if (p->op == O_TRACE) { | |
147 | chkline(exp); | |
148 | } else { | |
149 | chkaddr(exp); | |
150 | } | |
151 | } else if (place != nil and (place->op == O_QLINE or place->op == O_LCON)) { | |
152 | if (p->op == O_TRACE) { | |
153 | chkline(place); | |
154 | } else { | |
155 | chkaddr(place); | |
156 | } | |
157 | } else { | |
7bf092d9 | 158 | if (exp->op != O_RVAL and exp->op != O_SYM and exp->op != O_CALL) { |
b329a001 ML |
159 | error("can't trace expressions"); |
160 | } | |
161 | chkblock(place); | |
162 | } | |
163 | } | |
164 | ||
165 | /* | |
166 | * Check arguments to a stop command. | |
167 | */ | |
168 | ||
169 | private chkstop(p) | |
170 | Node p; | |
171 | { | |
172 | Node exp, place, cond; | |
173 | ||
174 | exp = p->value.arg[0]; | |
175 | place = p->value.arg[1]; | |
176 | cond = p->value.arg[2]; | |
177 | if (exp != nil) { | |
7cc22d81 | 178 | if (exp->op != O_RVAL and exp->op != O_SYM and exp->op != O_LCON) { |
b329a001 ML |
179 | beginerrmsg(); |
180 | fprintf(stderr, "expected variable, found "); | |
181 | prtree(stderr, exp); | |
182 | enderrmsg(); | |
183 | } | |
184 | chkblock(place); | |
2fd0f574 SL |
185 | } else if (place != nil) { |
186 | if (place->op == O_SYM) { | |
187 | chkblock(place); | |
b329a001 | 188 | } else { |
2fd0f574 SL |
189 | if (p->op == O_STOP) { |
190 | chkline(place); | |
191 | } else { | |
192 | chkaddr(place); | |
193 | } | |
b329a001 ML |
194 | } |
195 | } | |
196 | } | |
197 | ||
198 | /* | |
199 | * Check to see that the given node specifies some subprogram. | |
200 | * Nil is ok since that means the entire program. | |
201 | */ | |
202 | ||
203 | private chkblock(b) | |
204 | Node b; | |
205 | { | |
2fd0f574 SL |
206 | Symbol p, outer; |
207 | ||
b329a001 ML |
208 | if (b != nil) { |
209 | if (b->op != O_SYM) { | |
210 | beginerrmsg(); | |
211 | fprintf(stderr, "expected subprogram, found "); | |
212 | prtree(stderr, b); | |
213 | enderrmsg(); | |
2fd0f574 SL |
214 | } else if (ismodule(b->value.sym)) { |
215 | outer = b->value.sym; | |
216 | while (outer != nil) { | |
217 | find(p, outer->name) where p->block == outer endfind(p); | |
218 | if (p == nil) { | |
219 | outer = nil; | |
220 | error("\"%s\" is not a subprogram", symname(b->value.sym)); | |
221 | } else if (ismodule(p)) { | |
222 | outer = p; | |
223 | } else { | |
224 | outer = nil; | |
225 | b->value.sym = p; | |
226 | } | |
227 | } | |
0022c355 ML |
228 | } else if ( |
229 | b->value.sym->class == VAR and | |
230 | b->value.sym->name == b->value.sym->block->name and | |
231 | b->value.sym->block->class == FUNC | |
232 | ) { | |
233 | b->value.sym = b->value.sym->block; | |
2fd0f574 | 234 | } else if (not isblock(b->value.sym)) { |
b329a001 ML |
235 | error("\"%s\" is not a subprogram", symname(b->value.sym)); |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | /* | |
241 | * Check to make sure a node corresponds to a source line. | |
242 | */ | |
243 | ||
244 | private chkline(p) | |
245 | Node p; | |
246 | { | |
247 | if (p == nil) { | |
248 | error("missing line"); | |
249 | } else if (p->op != O_QLINE and p->op != O_LCON) { | |
250 | error("expected source line number, found \"%t\"", p); | |
251 | } | |
252 | } | |
253 | ||
254 | /* | |
255 | * Check to make sure a node corresponds to an address. | |
256 | */ | |
257 | ||
258 | private chkaddr(p) | |
259 | Node p; | |
260 | { | |
261 | if (p == nil) { | |
262 | error("missing address"); | |
263 | } else if (p->op != O_LCON and p->op != O_QLINE) { | |
264 | beginerrmsg(); | |
265 | fprintf(stderr, "expected address, found \""); | |
266 | prtree(stderr, p); | |
267 | fprintf(stderr, "\""); | |
268 | enderrmsg(); | |
269 | } | |
270 | } |