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