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