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