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 DF |
7 | #ifndef lint |
8 | static char sccsid[] = "@(#)check.c 5.1 (Berkeley) %G%"; | |
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]; | |
51 | if (not compatible(p1->nodetype, p2->nodetype)) { | |
52 | error("incompatible types"); | |
53 | } | |
54 | break; | |
55 | ||
56 | case O_CATCH: | |
57 | case O_IGNORE: | |
58 | if (p->value.lcon < 0 or p->value.lcon > NSIG) { | |
59 | error("invalid signal number"); | |
60 | } | |
61 | break; | |
62 | ||
63 | case O_CONT: | |
64 | if (p->value.lcon != DEFSIG and ( | |
65 | p->value.lcon < 0 or p->value.lcon > NSIG) | |
66 | ) { | |
67 | error("invalid signal number"); | |
68 | } | |
69 | break; | |
70 | ||
71 | case O_DUMP: | |
72 | if (p->value.arg[0] != nil) { | |
73 | if (p->value.arg[0]->op == O_SYM) { | |
74 | f = p->value.arg[0]->value.sym; | |
75 | if (not isblock(f)) { | |
76 | error("\"%s\" is not a block", symname(f)); | |
77 | } | |
78 | } else { | |
79 | beginerrmsg(); | |
80 | fprintf(stderr, "expected a symbol, found \""); | |
81 | prtree(stderr, p->value.arg[0]); | |
82 | fprintf(stderr, "\""); | |
83 | enderrmsg(); | |
84 | } | |
85 | } | |
86 | break; | |
87 | ||
b329a001 ML |
88 | case O_LIST: |
89 | if (p->value.arg[0]->op == O_SYM) { | |
90 | f = p->value.arg[0]->value.sym; | |
91 | if (not isblock(f) or ismodule(f)) { | |
92 | error("\"%s\" is not a procedure or function", symname(f)); | |
93 | } | |
94 | addr = firstline(f); | |
95 | if (addr == NOADDR) { | |
96 | error("\"%s\" is empty", symname(f)); | |
97 | } | |
98 | } | |
99 | break; | |
100 | ||
101 | case O_TRACE: | |
102 | case O_TRACEI: | |
103 | chktrace(p); | |
104 | break; | |
105 | ||
106 | case O_STOP: | |
107 | case O_STOPI: | |
108 | chkstop(p); | |
109 | break; | |
110 | ||
0022c355 | 111 | case O_CALLPROC: |
2fd0f574 SL |
112 | case O_CALL: |
113 | if (not isroutine(p->value.arg[0]->nodetype)) { | |
114 | beginerrmsg(); | |
115 | fprintf(stderr, "\""); | |
116 | prtree(stderr, p->value.arg[0]); | |
117 | fprintf(stderr, "\" not call-able"); | |
118 | enderrmsg(); | |
119 | } | |
120 | break; | |
121 | ||
0022c355 ML |
122 | case O_WHEREIS: |
123 | if (p->value.arg[0]->op == O_SYM and | |
124 | p->value.arg[0]->value.sym == nil) { | |
125 | error("symbol not defined"); | |
126 | } | |
127 | break; | |
128 | ||
b329a001 ML |
129 | default: |
130 | break; | |
131 | } | |
132 | } | |
133 | ||
134 | /* | |
135 | * Check arguments to a trace command. | |
136 | */ | |
137 | ||
138 | private chktrace(p) | |
139 | Node p; | |
140 | { | |
141 | Node exp, place, cond; | |
142 | ||
143 | exp = p->value.arg[0]; | |
144 | place = p->value.arg[1]; | |
145 | cond = p->value.arg[2]; | |
146 | if (exp == nil) { | |
147 | chkblock(place); | |
148 | } else if (exp->op == O_LCON or exp->op == O_QLINE) { | |
149 | if (place != nil) { | |
150 | error("unexpected \"at\" or \"in\""); | |
151 | } | |
152 | if (p->op == O_TRACE) { | |
153 | chkline(exp); | |
154 | } else { | |
155 | chkaddr(exp); | |
156 | } | |
157 | } else if (place != nil and (place->op == O_QLINE or place->op == O_LCON)) { | |
158 | if (p->op == O_TRACE) { | |
159 | chkline(place); | |
160 | } else { | |
161 | chkaddr(place); | |
162 | } | |
163 | } else { | |
7bf092d9 | 164 | if (exp->op != O_RVAL and exp->op != O_SYM and exp->op != O_CALL) { |
b329a001 ML |
165 | error("can't trace expressions"); |
166 | } | |
167 | chkblock(place); | |
168 | } | |
169 | } | |
170 | ||
171 | /* | |
172 | * Check arguments to a stop command. | |
173 | */ | |
174 | ||
175 | private chkstop(p) | |
176 | Node p; | |
177 | { | |
178 | Node exp, place, cond; | |
179 | ||
180 | exp = p->value.arg[0]; | |
181 | place = p->value.arg[1]; | |
182 | cond = p->value.arg[2]; | |
183 | if (exp != nil) { | |
7cc22d81 | 184 | if (exp->op != O_RVAL and exp->op != O_SYM and exp->op != O_LCON) { |
b329a001 ML |
185 | beginerrmsg(); |
186 | fprintf(stderr, "expected variable, found "); | |
187 | prtree(stderr, exp); | |
188 | enderrmsg(); | |
189 | } | |
190 | chkblock(place); | |
2fd0f574 SL |
191 | } else if (place != nil) { |
192 | if (place->op == O_SYM) { | |
193 | chkblock(place); | |
b329a001 | 194 | } else { |
2fd0f574 SL |
195 | if (p->op == O_STOP) { |
196 | chkline(place); | |
197 | } else { | |
198 | chkaddr(place); | |
199 | } | |
b329a001 ML |
200 | } |
201 | } | |
202 | } | |
203 | ||
204 | /* | |
205 | * Check to see that the given node specifies some subprogram. | |
206 | * Nil is ok since that means the entire program. | |
207 | */ | |
208 | ||
209 | private chkblock(b) | |
210 | Node b; | |
211 | { | |
2fd0f574 SL |
212 | Symbol p, outer; |
213 | ||
b329a001 ML |
214 | if (b != nil) { |
215 | if (b->op != O_SYM) { | |
216 | beginerrmsg(); | |
217 | fprintf(stderr, "expected subprogram, found "); | |
218 | prtree(stderr, b); | |
219 | enderrmsg(); | |
2fd0f574 SL |
220 | } else if (ismodule(b->value.sym)) { |
221 | outer = b->value.sym; | |
222 | while (outer != nil) { | |
223 | find(p, outer->name) where p->block == outer endfind(p); | |
224 | if (p == nil) { | |
225 | outer = nil; | |
226 | error("\"%s\" is not a subprogram", symname(b->value.sym)); | |
227 | } else if (ismodule(p)) { | |
228 | outer = p; | |
229 | } else { | |
230 | outer = nil; | |
231 | b->value.sym = p; | |
232 | } | |
233 | } | |
0022c355 ML |
234 | } else if ( |
235 | b->value.sym->class == VAR and | |
236 | b->value.sym->name == b->value.sym->block->name and | |
237 | b->value.sym->block->class == FUNC | |
238 | ) { | |
239 | b->value.sym = b->value.sym->block; | |
2fd0f574 | 240 | } else if (not isblock(b->value.sym)) { |
b329a001 ML |
241 | error("\"%s\" is not a subprogram", symname(b->value.sym)); |
242 | } | |
243 | } | |
244 | } | |
245 | ||
246 | /* | |
247 | * Check to make sure a node corresponds to a source line. | |
248 | */ | |
249 | ||
250 | private chkline(p) | |
251 | Node p; | |
252 | { | |
253 | if (p == nil) { | |
254 | error("missing line"); | |
255 | } else if (p->op != O_QLINE and p->op != O_LCON) { | |
256 | error("expected source line number, found \"%t\"", p); | |
257 | } | |
258 | } | |
259 | ||
260 | /* | |
261 | * Check to make sure a node corresponds to an address. | |
262 | */ | |
263 | ||
264 | private chkaddr(p) | |
265 | Node p; | |
266 | { | |
267 | if (p == nil) { | |
268 | error("missing address"); | |
269 | } else if (p->op != O_LCON and p->op != O_QLINE) { | |
270 | beginerrmsg(); | |
271 | fprintf(stderr, "expected address, found \""); | |
272 | prtree(stderr, p); | |
273 | fprintf(stderr, "\""); | |
274 | enderrmsg(); | |
275 | } | |
276 | } |