Commit | Line | Data |
---|---|---|
0758c694 BJ |
1 | /* Copyright (c) 1979 Regents of the University of California */ |
2 | # | |
3 | /* | |
4 | * pi - Pascal interpreter code translator | |
5 | * | |
6 | * Charles Haley, Bill Joy UCB | |
7 | * Version 1.2 January 1979 | |
8 | */ | |
9 | ||
10 | #include "0.h" | |
11 | #include "tree.h" | |
12 | ||
13 | /* | |
14 | * Funchdr inserts | |
15 | * declaration of a the | |
16 | * prog/proc/func into the | |
17 | * namelist. It also handles | |
18 | * the arguments and puts out | |
19 | * a transfer which defines | |
20 | * the entry point of a procedure. | |
21 | */ | |
22 | ||
23 | funchdr(r) | |
24 | int *r; | |
25 | { | |
26 | register struct nl *p; | |
27 | register *il, **rl; | |
28 | int *rll, o; | |
29 | struct nl *cp, *dp, *sp; | |
30 | int *pp; | |
31 | ||
32 | send(REVFHDR, r); | |
33 | if (inpflist(r[2])) { | |
34 | opush('l'); | |
35 | yyretrieve(); /* kludge */ | |
36 | } | |
37 | line = r[1]; | |
38 | if (r[3] == NIL && (p=lookup1(r[2])) != NIL && bn == cbn) { | |
39 | /* | |
40 | * Symbol already defined | |
41 | * in this block. it is either | |
42 | * a redeclared symbol (error) | |
43 | * or a forward declaration. | |
44 | */ | |
45 | if ((p->class == FUNC || p->class == PROC) && (p->nl_flags & NFORWD) != 0) { | |
46 | /* | |
47 | * Grammar doesnt forbid | |
48 | * types on a resolution | |
49 | * of a forward function | |
50 | * declaration. | |
51 | */ | |
52 | if (p->class == FUNC && r[4]) | |
53 | error("Function type should be given only in forward declaration"); | |
54 | return (p); | |
55 | } | |
56 | } | |
57 | /* | |
58 | * Declare the prog/proc/func | |
59 | */ | |
60 | switch (r[0]) { | |
61 | case T_PROG: | |
62 | program = p = defnl(r[2], PROG, 0, 0); | |
63 | break; | |
64 | case T_PDEC: | |
65 | if (r[4] != NIL) | |
66 | error("Procedures do not have types, only functions do"); | |
67 | p = enter(defnl(r[2], PROC, 0, 0)); | |
68 | break; | |
69 | case T_FDEC: | |
70 | il = r[4]; | |
71 | if (il == NIL) | |
72 | error("Function type must be specified"); | |
73 | else if (il[0] != T_TYID) { | |
74 | il = NIL; | |
75 | error("Function type can be specified only by using a type identifier"); | |
76 | } else | |
77 | il = gtype(il); | |
78 | p = enter(defnl(r[2], FUNC, il, NIL)); | |
79 | /* | |
80 | * An arbitrary restriction | |
81 | */ | |
82 | switch (o = classify(p->type)) { | |
83 | case TFILE: | |
84 | case TARY: | |
85 | case TREC: | |
86 | case TSET: | |
87 | case TSTR: | |
88 | warning(); | |
89 | if (opt('s')) | |
90 | standard(); | |
91 | error("Functions should not return %ss", clnames[o]); | |
92 | } | |
93 | break; | |
94 | default: | |
95 | panic("funchdr"); | |
96 | } | |
97 | if (r[0] != T_PROG) { | |
98 | /* | |
99 | * Mark this proc/func as | |
100 | * begin forward declared | |
101 | */ | |
102 | p->nl_flags =| NFORWD; | |
103 | /* | |
104 | * Enter the parameters | |
105 | * in the next block for | |
106 | * the time being | |
107 | */ | |
108 | if (++cbn >= DSPLYSZ) { | |
109 | error("Procedure/function nesting too deep"); | |
110 | pexit(ERRS); | |
111 | } | |
112 | /* | |
113 | * For functions, the function variable | |
114 | */ | |
115 | if (p->class == FUNC) { | |
116 | cp = defnl(r[2], FVAR, p->type, 0); | |
117 | cp->chain = p; | |
118 | p->value[NL_FVAR] = cp; | |
119 | } | |
120 | /* | |
121 | * Enter the parameters | |
122 | */ | |
123 | cp = sp = p; | |
124 | for (rl = r[3]; rl != NIL; rl = rl[2]) { | |
125 | p = NIL; | |
126 | if (rl[1] == NIL) | |
127 | continue; | |
128 | /* | |
129 | * Parametric procedures | |
130 | * don't have types | |
131 | */ | |
132 | if (rl[1][0] != T_PPROC) { | |
133 | rll = rl[1][2]; | |
134 | if (rll[0] != T_TYID) { | |
135 | error("Types for arguments can be specified only by using type identifiers"); | |
136 | p = NIL; | |
137 | } else | |
138 | p = gtype(rll); | |
139 | } | |
140 | for (il = rl[1][1]; il != NIL; il = il[2]) { | |
141 | switch (rl[1][0]) { | |
142 | default: | |
143 | panic("funchdr2"); | |
144 | case T_PVAL: | |
145 | if (p != NIL) { | |
146 | if (p->class == FILE) | |
147 | error("Files cannot be passed by value"); | |
148 | else if (p->nl_flags & NFILES) | |
149 | error("Files cannot be a component of %ss passed by value", | |
150 | nameof(p)); | |
151 | } | |
152 | dp = defnl(il[1], VAR, p, 0); | |
153 | break; | |
154 | case T_PVAR: | |
155 | dp = defnl(il[1], REF, p, 0); | |
156 | break; | |
157 | case T_PFUNC: | |
158 | case T_PPROC: | |
159 | error("Procedure/function parameters not implemented"); | |
160 | continue; | |
161 | } | |
162 | if (dp != NIL) { | |
163 | cp->chain = dp; | |
164 | cp = dp; | |
165 | } | |
166 | } | |
167 | } | |
168 | cbn--; | |
169 | p = sp; | |
170 | } else { | |
171 | cp = p; | |
172 | for (rl = r[3]; rl; rl = rl[2]) { | |
173 | if (rl[1] == NIL) | |
174 | continue; | |
175 | dp = defnl(rl[1], VAR, 0, 0); | |
176 | cp->chain = dp; | |
177 | cp = dp; | |
178 | } | |
179 | } | |
180 | return (p); | |
181 | } | |
182 | ||
183 | /* | |
184 | * Funcbody is called | |
185 | * when the actual (resolved) | |
186 | * declaration of a procedure is | |
187 | * encountered. It puts the names | |
188 | * of the (function) and parameters | |
189 | * into the symbol table. | |
190 | */ | |
191 | funcbody(fp) | |
192 | struct nl *fp; | |
193 | { | |
194 | register struct nl *q, *p; | |
195 | ||
196 | cbn++; | |
197 | if (cbn >= DSPLYSZ) { | |
198 | error("Too many levels of function/procedure nesting"); | |
199 | pexit(ERRS); | |
200 | } | |
201 | send(REVFBDY); | |
202 | errcnt[cbn] = syneflg; | |
203 | parts = NIL; | |
204 | if (fp == NIL) | |
205 | return (NIL); | |
206 | /* | |
207 | * Save the virtual name | |
208 | * list stack pointer so | |
209 | * the space can be freed | |
210 | * later (funcend). | |
211 | */ | |
212 | fp->value[2] = nlp; | |
213 | if (fp->class != PROG) | |
214 | for (q = fp->chain; q != NIL; q = q->chain) | |
215 | enter(q); | |
216 | if (fp->class == FUNC) { | |
217 | /* | |
218 | * For functions, enter the fvar | |
219 | */ | |
220 | enter(fp->value[NL_FVAR]); | |
221 | } | |
222 | return (fp); | |
223 | } | |
224 | ||
225 | int pnumcnt; | |
226 | struct nl *Fp; | |
227 | /* | |
228 | * Funcend is called to | |
229 | * finish a block by generating | |
230 | * the code for the statements. | |
231 | * It then looks for unresolved declarations | |
232 | * of labels, procedures and functions, | |
233 | * and cleans up the name list. | |
234 | * For the program, it checks the | |
235 | * semantics of the program | |
236 | * statement (yuchh). | |
237 | */ | |
238 | funcend(fp, bundle, endline) | |
239 | struct nl *fp; | |
240 | int *bundle; | |
241 | int endline; | |
242 | { | |
243 | register struct nl *p; | |
244 | register int i, b; | |
245 | int *blk; | |
246 | char *cp; | |
247 | ||
248 | blk = bundle[2]; | |
249 | if (fp == NIL) { | |
250 | cbn--; | |
251 | return; | |
252 | } | |
253 | send(REVFEND, bundle, endline, syneflg == errcnt[cbn]); | |
254 | if (Fp != NIL) | |
255 | Fp = fp; | |
256 | /* | |
257 | * Clean up the symbol table displays and check for unresolves | |
258 | */ | |
259 | line = endline; | |
260 | b = cbn; | |
261 | for (i = 0; i <= 077; i++) { | |
262 | for (p = disptab[i]; p != NIL && (p->nl_block & 037) == b; p = p->nl_next) | |
263 | if (p->class == BADUSE) { | |
264 | cp = "s"; | |
265 | if (p->chain->ud_next == NIL) | |
266 | cp++; | |
267 | eholdnl(); | |
268 | if (p->value[NL_KINDS] & ISUNDEF) | |
269 | nerror("%s undefined on line%s", p->symbol, cp); | |
270 | else | |
271 | nerror("%s improperly used on line%s", p->symbol, cp); | |
272 | pnumcnt = 10; | |
273 | pnums(p->chain); | |
274 | putchar('\n'); | |
275 | } | |
276 | /* | |
277 | * Pop this symbol | |
278 | * table slot | |
279 | */ | |
280 | disptab[i] = p; | |
281 | } | |
282 | ||
283 | #ifdef DEBUG | |
284 | dumpnl(fp->value[2], fp->symbol); | |
285 | #endif | |
286 | /* | |
287 | * Restore the | |
288 | * (virtual) name list | |
289 | * position | |
290 | */ | |
291 | nlfree(fp->value[2]); | |
292 | /* | |
293 | * Proc/func has been | |
294 | * resolved | |
295 | */ | |
296 | fp->nl_flags =& ~NFORWD; | |
297 | elineon(); | |
298 | cbn--; | |
299 | if (inpflist(fp->symbol)) { | |
300 | opop('l'); | |
301 | } | |
302 | } | |
303 | ||
304 | pnums(p) | |
305 | struct udinfo *p; | |
306 | { | |
307 | ||
308 | if (p->ud_next != NIL) | |
309 | pnums(p->ud_next); | |
310 | if (pnumcnt == 0) { | |
311 | printf("\n\t"); | |
312 | pnumcnt = 20; | |
313 | } | |
314 | pnumcnt--; | |
315 | printf(" %d", p->ud_line); | |
316 | } | |
317 | ||
318 | nerror(a1, a2, a3) | |
319 | { | |
320 | ||
321 | if (Fp != NIL) { | |
322 | yySsync(); | |
323 | printf("In %s %s:\n", classes[Fp->class], Fp->symbol); | |
324 | Fp = NIL; | |
325 | } | |
326 | elineoff(); | |
327 | error(a1, a2, a3); | |
328 | } |