Commit | Line | Data |
---|---|---|
fc2447c0 C |
1 | #ifndef lint |
2 | static char *rcsid = | |
3 | "$Header: frame.c,v 1.3 87/12/14 16:51:52 sklower Exp $"; | |
4 | #endif | |
5 | ||
6 | /* | |
7 | * frame.c $Locker: $ | |
8 | * non local goto handlers | |
9 | * | |
10 | * (c) copyright 1982, Regents of the University of California | |
11 | */ | |
12 | ||
13 | ||
14 | #include "global.h" | |
15 | #include "frame.h" | |
16 | ||
17 | /* | |
18 | * This is a collection of routines for manipulating evaluation frames. | |
19 | * Such frames are generated to mark the state of execution at a certain | |
20 | * spot. They are created upon entry to prog, do, catch, errset and | |
21 | * other misc. functions (such as eval when in *rset mode). | |
22 | * | |
23 | * As described in h/frame.h, each frame is identified by a class, which | |
24 | * says who created the frame. The global variable errp points to the | |
25 | * first (newest) frame on the stack. | |
26 | * The standard way to create a frame is to say | |
27 | * | |
28 | * errp = Pushframe(class,arg1,arg2); /* create and link in new | |
29 | * frame of give class * / | |
30 | * | |
31 | * poping the frame must be done explicity if the routine was not exited by | |
32 | * a non-local goto. This is done by | |
33 | * errp = Popframe(); | |
34 | * | |
35 | * When a frame is created, it marks the current state on the runtime stack. | |
36 | * Execution will continues after the Pushframe call with the value of the | |
37 | * global variable 'retval' set to 0. Some time later control may be thrown | |
38 | * up the stack and it will seem that Pushframe returned again. This time | |
39 | * retval will contain a non-zero value indicating what caused the non-local | |
40 | * jump. retval will have one of the values from C_???? in h/frame.h . | |
41 | * It will not have just of the C_???? values, it will only have a value | |
42 | * which makes sense. For example, coming out of a Pushframe(F_CATCH,tag,nil); | |
43 | * retval will either be 0 (initially) or C_THROW, [and in addition it will | |
44 | * already have been determined that the tag of the catch matches the tag | |
45 | * being thrown, [[ this does not apply to GO's and PROG tags]] ]. | |
46 | * | |
47 | * In doing throws, goto's, returns, or errors up the stack we are always | |
48 | * conscious of the possiblity of unwind-protect sitting between where | |
49 | * control starts and where it wants to get. Thus it may be necessary | |
50 | * to save the state of the non-local jump, give control to the unwind-protect | |
51 | * and have it continue the non-local jump. | |
52 | */ | |
53 | ||
54 | /* | |
55 | * Inonlocalgo(class, arg1, arg2) :: do a general non-local goto. | |
56 | * class - one of the C_???? in h/frame.h | |
57 | * arg1 - tag in C_THROW, C_GO; value in C_RETURN | |
58 | * arg2 - value in C_THROW; | |
59 | * this handles GO's, THROW's, RETURN's but not errors, which have more | |
60 | * state to throw and a lot of different things to do if there is no one | |
61 | * to catch the error. | |
62 | * | |
63 | * This routine never returns. | |
64 | */ | |
65 | ||
66 | Inonlocalgo(class, arg1, arg2) | |
67 | lispval arg1,arg2; | |
68 | { | |
69 | struct frame *uwpframe, *Inlthrow(); | |
70 | lispval handy; | |
71 | ||
72 | /* | |
73 | * scan for something to match 'class', return if nothing found, or | |
74 | * if we must first handle an unwind protect. | |
75 | */ | |
76 | while( uwpframe = Inlthrow(class,arg1,arg2) ) | |
77 | { | |
78 | /* build error frame description to be use to continue this throw */ | |
79 | protect(lispretval = handy = newdot()); | |
80 | handy->d.car = Veruwpt; | |
81 | handy = handy->d.cdr = newdot(); | |
82 | handy->d.car = inewint(class); /* remember type */ | |
83 | handy = handy->d.cdr = newdot(); | |
84 | handy->d.car = arg1; | |
85 | handy = handy->d.cdr = newdot(); | |
86 | handy->d.car = arg2; | |
87 | retval = C_THROW; | |
88 | Iretfromfr(uwpframe); | |
89 | /* NOT REACHED */ | |
90 | } | |
91 | ||
92 | /* | |
93 | * nothing to go to, signal the appropriate error | |
94 | */ | |
95 | ||
96 | switch(class) | |
97 | { | |
98 | case C_GO: errorh1(Vermisc, "No prog to go to with this tag ", | |
99 | nil,FALSE,0,arg1); | |
100 | /* NOT REACHED */ | |
101 | ||
102 | case C_RET: errorh(Vermisc, "No prog to return from", nil, FALSE, 0); | |
103 | /* NOT REACHED */ | |
104 | ||
105 | case C_THROW: errorh1(Vermisc, "No catch for this tag ", nil, FALSE , 0, | |
106 | arg1); | |
107 | /* NOT REACHED */ | |
108 | default: error("Internal Inonlocalgoto error" ,FALSE); | |
109 | /* NOT REACHED */ | |
110 | } | |
111 | } | |
112 | ||
113 | /* | |
114 | * Inlthrow(class,arg1,arg2) :: look up the stack for a form to handle | |
115 | * a value of 'class' being thrown. If found, do the throw. If an | |
116 | * unwind-protect must be done, then return a pointer to that frame | |
117 | * first. If there is nothing to catch this throw, we return 0. | |
118 | */ | |
119 | ||
120 | struct frame * | |
121 | Inlthrow(class, arg1, arg2) | |
122 | lispval arg1, arg2; | |
123 | { | |
124 | struct frame *uwpframe = (struct frame *)0; | |
125 | struct frame *curp; | |
126 | int pass = 1; | |
127 | ||
128 | restart: | |
129 | for(curp = errp; curp != (struct frame *) 0; curp = curp->olderrp) | |
130 | { | |
131 | switch(curp->class) | |
132 | { | |
133 | case F_PROG: if(class == C_RET || class == C_GO) | |
134 | { | |
135 | if(pass == 2) return(uwpframe); | |
136 | else | |
137 | { | |
138 | lispretval = arg1; | |
139 | retval = class; | |
140 | Iretfromfr(curp); | |
141 | /* NOT REACHED */ | |
142 | } | |
143 | } | |
144 | break; | |
145 | ||
146 | case F_CATCH: if((pass == 1) && (curp->larg1 == Veruwpt)) | |
147 | { | |
148 | uwpframe = curp; | |
149 | pass = 2; | |
150 | goto restart; | |
151 | } | |
152 | else if(class == C_THROW | |
153 | && matchtags(arg1,curp->larg1)) | |
154 | { | |
155 | if(pass == 2) return(uwpframe); | |
156 | else | |
157 | { | |
158 | lispretval = arg2; /* value thrown */ | |
159 | retval = class; | |
160 | Iretfromfr(curp); | |
161 | /* NOT REACHED */ | |
162 | } | |
163 | } | |
164 | break; | |
165 | ||
166 | case F_RESET: if(class == C_RESET) | |
167 | { | |
168 | if(pass == 2) return(uwpframe); | |
169 | else | |
170 | { | |
171 | retval = class; | |
172 | Iretfromfr(curp); | |
173 | /* NOT REACHED */ | |
174 | } | |
175 | } | |
176 | break; | |
177 | ||
178 | } | |
179 | } | |
180 | return((struct frame *)0); /* nobody wants it */ | |
181 | } | |
182 | ||
183 | ||
184 | #ifndef tahoe | |
185 | Iretfromfr(fram) | |
186 | register struct frame *fram; | |
187 | { | |
188 | xpopnames(fram->svbnp); | |
189 | qretfromfr(); /* modified in sed script to point to real function */ | |
190 | /* NOT REACHED */ | |
191 | } | |
192 | #endif | |
193 | ||
194 | /* matchtags :: return TRUE if there is any atom in common between the | |
195 | * two tags. Either tag may be an atom or an list of atoms. | |
196 | */ | |
197 | matchtags(tag1,tag2) | |
198 | lispval tag1, tag2; | |
199 | { | |
200 | int repeat1 = FALSE; | |
201 | int repeat2 = FALSE; | |
202 | lispval temp1 = tag1; | |
203 | lispval temp2 = tag2; | |
204 | lispval t1,t2; | |
205 | ||
206 | if(TYPE(tag1) == ATOM) | |
207 | { | |
208 | t1 = tag1; | |
209 | } | |
210 | else { | |
211 | t1 = tag1->d.car; | |
212 | repeat1 = TRUE; | |
213 | } | |
214 | ||
215 | if(TYPE(tag2) == ATOM) | |
216 | { | |
217 | t2 = tag2; | |
218 | } | |
219 | else { | |
220 | t2 = tag2->d.car; | |
221 | repeat2 = TRUE; | |
222 | } | |
223 | ||
224 | loop: | |
225 | if(t1 == t2) return(TRUE); | |
226 | if(repeat2) | |
227 | { | |
228 | if((temp2 = temp2->d.cdr) != nil) | |
229 | { | |
230 | t2 = temp2->d.car; | |
231 | goto loop; | |
232 | } | |
233 | } | |
234 | ||
235 | if(repeat1) | |
236 | { | |
237 | if((temp1 = temp1->d.cdr) != nil) | |
238 | { | |
239 | t1 = temp1->d.car; | |
240 | if(repeat2) | |
241 | { | |
242 | temp2 = tag2; | |
243 | t2 = temp2->d.car; | |
244 | goto loop; | |
245 | } | |
246 | else t2 = tag2; | |
247 | goto loop; | |
248 | } | |
249 | } | |
250 | return(FALSE); | |
251 | } | |
252 | ||
253 | /* | |
254 | * framedump :: debugging routine to print the contents of the error | |
255 | * frame | |
256 | * | |
257 | */ | |
258 | lispval | |
259 | Lframedump() | |
260 | { | |
261 | struct frame *curp; | |
262 | ||
263 | printf("Frame dump\n"); | |
264 | for(curp = errp ; curp != (struct frame *)0 ; curp=curp->olderrp) | |
265 | { | |
266 | printf("at %x is ",curp); | |
267 | ||
268 | switch(curp->class) { | |
269 | case F_PROG: printf(" prog\n"); | |
270 | break; | |
271 | ||
272 | case F_CATCH:printf(" catching "); | |
273 | printr(curp->larg1,stdout); | |
274 | putchar('\n'); | |
275 | break; | |
276 | ||
277 | case F_RESET:printf(" reset \n"); | |
278 | break; | |
279 | ||
280 | case F_EVAL: printf(" eval: "); | |
281 | printr(curp->larg1,stdout); | |
282 | putchar('\n'); | |
283 | break; | |
284 | ||
285 | case F_FUNCALL: printf(" funcall: "); | |
286 | printr(curp->larg1,stdout); | |
287 | putchar('\n'); | |
288 | break; | |
289 | ||
290 | case F_TO_FORT: printf(" calling fortran:\n"); | |
291 | break; | |
292 | ||
293 | case F_TO_LISP: printf(" fortran calling lisp:\n"); | |
294 | break; | |
295 | ||
296 | ||
297 | default: | |
298 | printf(" unknown: %d \n",curp->class); | |
299 | } | |
300 | fflush(stdout); | |
301 | } | |
302 | printf("End of stack\n"); | |
303 | return(nil); | |
304 | } | |
305 |