Commit | Line | Data |
---|---|---|
73350edc C |
1 | #ifndef lint |
2 | static char *rcsid = | |
3 | "$Header: fex1.c,v 1.5 85/03/24 11:03:51 sklower Exp $"; | |
4 | #endif | |
5 | ||
6 | /* -[Sat Mar 5 19:50:28 1983 by layer]- | |
7 | * fex1.c $Locker: $ | |
8 | * nlambda functions | |
9 | * | |
10 | * (c) copyright 1982, Regents of the University of California | |
11 | */ | |
12 | ||
13 | ||
14 | #include "global.h" | |
15 | #include "frame.h" | |
16 | ||
17 | /* Nprog ****************************************************************/ | |
18 | /* This first sets the local variables to nil while saving their old */ | |
19 | /* values on the name stack. Then, pointers to various things are */ | |
20 | /* saved as this function may be returned to by an "Ngo" or by a */ | |
21 | /* "Lreturn". At the end is the loop that cycles through the contents */ | |
22 | /* of the prog. */ | |
23 | ||
24 | lispval | |
25 | Nprog() { | |
26 | register lispval where, temp; | |
27 | struct nament *savedbnp = bnp; | |
28 | extern struct frame *errp; | |
29 | pbuf pb; | |
30 | extern int retval; | |
31 | extern lispval lispretval; | |
32 | ||
33 | if((np-lbot) < 1) chkarg(1,"prog"); | |
34 | ||
35 | /* shallow bind the local variables to nil */ | |
36 | if(lbot->val->d.car != nil) | |
37 | { | |
38 | for( where = lbot->val->d.car ; where != nil; where = where->d.cdr ) | |
39 | { | |
40 | if(TYPE(where) != DTPR || TYPE(temp=where->d.car) != ATOM) | |
41 | errorh1(Vermisc, | |
42 | "Illegal local variable list in prog ",nil,FALSE, | |
43 | 1,where); | |
44 | PUSHDOWN(temp,nil); | |
45 | } | |
46 | } | |
47 | ||
48 | /* put a frame on the stack which can be 'return'ed to or 'go'ed to */ | |
49 | errp = Pushframe(F_PROG,nil,nil); | |
50 | ||
51 | where = lbot->val->d.cdr; /* first thing in the prog body */ | |
52 | ||
53 | switch (retval) { | |
54 | case C_RET: /* | |
55 | * returning from this prog, value to return | |
56 | * is in lispretval | |
57 | */ | |
58 | errp = Popframe(); | |
59 | popnames(savedbnp); | |
60 | return(lispretval); | |
61 | ||
62 | case C_GO: /* | |
63 | * going to a certain label, label to go to in | |
64 | * in lispretval | |
65 | */ | |
66 | where = (lbot->val)->d.cdr; | |
67 | while ((TYPE(where) == DTPR) | |
68 | && (where->d.car != lispretval)) | |
69 | where = where->d.cdr; | |
70 | if (where->d.car == lispretval) { | |
71 | popnames(errp->svbnp); | |
72 | break; | |
73 | } | |
74 | /* label not found in this prog, must | |
75 | * go up to higher prog | |
76 | */ | |
77 | errp = Popframe(); /* go to next frame */ | |
78 | Inonlocalgo(C_GO,lispretval,nil); | |
79 | ||
80 | /* NOT REACHED */ | |
81 | ||
82 | case C_INITIAL: break; | |
83 | ||
84 | } | |
85 | ||
86 | while (TYPE(where) == DTPR) | |
87 | { | |
88 | temp = where->d.car; | |
89 | if((TYPE(temp))!=ATOM) eval(temp); | |
90 | where = where->d.cdr; | |
91 | } | |
92 | if((where != nil) && (TYPE(where) != DTPR)) | |
93 | errorh1(Vermisc,"Illegal form in prog body ", nil,FALSE,0,where); | |
94 | errp = Popframe(); | |
95 | popnames(savedbnp); /* pop off locals */ | |
96 | return(nil); | |
97 | } | |
98 | ||
99 | lispval globtag; | |
100 | /* | |
101 | Ncatch is now linked to the lisp symbol *catch , which has the form | |
102 | (*catch tag form) | |
103 | tag is evaluated and then the catch entry is set up. | |
104 | then form is evaluated | |
105 | finally the catch entry is removed. | |
106 | ||
107 | *catch is still an nlambda since its arguments should not be evaluated | |
108 | before this routine is called. | |
109 | ||
110 | (catch form [tag]) is translated to (*catch 'tag form) by a macro. | |
111 | */ | |
112 | lispval | |
113 | Ncatch() | |
114 | { | |
115 | register lispval tag; | |
116 | pbuf pb; | |
117 | Savestack(3); /* save stack pointers */ | |
118 | ||
119 | if((TYPE(lbot->val))!=DTPR) return(nil); | |
120 | protect(tag = eval(lbot->val->d.car)); /* protect tag from gc */ | |
121 | ||
122 | errp = Pushframe(F_CATCH,tag,nil); | |
123 | ||
124 | switch(retval) { | |
125 | ||
126 | case C_THROW: /* | |
127 | * value thrown is in lispretval | |
128 | */ | |
129 | break; | |
130 | ||
131 | case C_INITIAL: /* | |
132 | * calculate value of expression | |
133 | */ | |
134 | lispretval = eval(lbot->val->d.cdr->d.car); | |
135 | } | |
136 | ||
137 | ||
138 | errp = Popframe(); | |
139 | Restorestack(); | |
140 | return(lispretval); | |
141 | } | |
142 | /* (errset form [flag]) | |
143 | if present, flag determines if the error message will be printed | |
144 | if an error reaches the errset. | |
145 | if no error occurs, errset returns a list of one element, the | |
146 | value returned from form. | |
147 | if an error occurs, nil is usually returned although it could | |
148 | be non nil if err threw a non nil value | |
149 | */ | |
150 | ||
151 | lispval Nerrset() | |
152 | { | |
153 | lispval temp,flag; | |
154 | pbuf pb; | |
155 | Savestack(0); | |
156 | ||
157 | if(TYPE(lbot->val) != DTPR) return(nil); /* no form */ | |
158 | ||
159 | /* evaluate and save flag first */ | |
160 | flag = lbot->val->d.cdr; | |
161 | if(TYPE(flag) == DTPR) flag = eval(flag->d.car); | |
162 | else flag = tatom; /* if not present , assume t */ | |
163 | protect(flag); | |
164 | ||
165 | errp = Pushframe(F_CATCH,Verall,flag); | |
166 | ||
167 | switch(retval) { | |
168 | ||
169 | case C_THROW: /* | |
170 | * error thrown to this routine, value thrown is | |
171 | * in lispretval | |
172 | */ | |
173 | break; | |
174 | ||
175 | case C_INITIAL: /* | |
176 | * normally just evaluate expression and listify it. | |
177 | */ | |
178 | temp = eval(lbot->val->d.car); | |
179 | protect(temp); | |
180 | (lispretval = newdot())->d.car = temp; | |
181 | break; | |
182 | } | |
183 | ||
184 | errp = Popframe(); | |
185 | Restorestack(); | |
186 | return(lispretval); | |
187 | } | |
188 | ||
189 | /* this was changed from throw to *throw 21nov79 | |
190 | it is now a lambda and really should be called Lthrow | |
191 | */ | |
192 | lispval | |
193 | Nthrow() | |
194 | { | |
195 | switch(np-lbot) { | |
196 | case 0: | |
197 | protect(nil); | |
198 | case 1: | |
199 | protect(nil); | |
200 | case 2: break; | |
201 | default: | |
202 | argerr("throw"); | |
203 | } | |
204 | Inonlocalgo(C_THROW,lbot->val,(lbot+1)->val); | |
205 | /* NOT REACHED */ | |
206 | } | |
207 | ||
208 | ||
209 | ||
210 | /* Ngo ******************************************************************/ | |
211 | /* First argument only is checked - and must be an atom or evaluate */ | |
212 | /* to one. */ | |
213 | lispval | |
214 | Ngo() | |
215 | { | |
216 | register lispval temp; | |
217 | chkarg(1,"go"); | |
218 | ||
219 | temp = (lbot->val)->d.car; | |
220 | if (TYPE(temp) != ATOM) | |
221 | { | |
222 | temp = eval(temp); | |
223 | while(TYPE(temp) != ATOM) | |
224 | temp = errorh1(Vermisc,"Illegal tag to go to",nil,TRUE, 0,lbot->val); | |
225 | } | |
226 | Inonlocalgo(C_GO,temp,nil); | |
227 | /* NOT REACHED */ | |
228 | } | |
229 | ||
230 | ||
231 | /* Nreset ***************************************************************/ | |
232 | /* All arguments are ignored. This just returns-from-break to depth 0. */ | |
233 | lispval | |
234 | Nreset() | |
235 | { | |
236 | Inonlocalgo(C_RESET,inewint(0),nil); | |
237 | } | |
238 | ||
239 | ||
240 | ||
241 | /* Nbreak ***************************************************************/ | |
242 | /* If first argument is not nil, this is evaluated and printed. Then */ | |
243 | /* error is called with the "breaking" message. */ | |
244 | ||
245 | lispval | |
246 | Nbreak() | |
247 | { | |
248 | register lispval hold; register FILE *port; | |
249 | port = okport(Vpoport->a.clb,stdout); | |
250 | fprintf(port,"Breaking:"); | |
251 | ||
252 | if ((hold = lbot->val) != nil && ((hold = hold->d.car) != nil)) | |
253 | { | |
254 | printr(hold,port); | |
255 | } | |
256 | putc('\n',port); | |
257 | dmpport(port); | |
258 | return(errorh(Verbrk,"",nil,TRUE,0)); | |
259 | } | |
260 | ||
261 | ||
262 | /* Nexit ****************************************************************/ | |
263 | /* Just calls lispend with no message. */ | |
264 | Nexit() | |
265 | { | |
266 | lispend(""); | |
267 | } | |
268 | ||
269 | ||
270 | /* Nsys *****************************************************************/ | |
271 | /* Just calls lispend with no message. */ | |
272 | ||
273 | lispval | |
274 | Nsys() | |
275 | { | |
276 | lispend(""); | |
277 | } | |
278 | ||
279 | ||
280 | ||
281 | ||
282 | lispval | |
283 | Ndef() { | |
284 | register lispval arglist, body, name, form; | |
285 | ||
286 | form = lbot->val; | |
287 | name = form->d.car; | |
288 | body = form->d.cdr->d.car; | |
289 | arglist = body->d.cdr->d.car; | |
290 | if((TYPE(arglist))!=DTPR && arglist != nil) | |
291 | error("Warning: defining function with nonlist of args", | |
292 | TRUE); | |
293 | name->a.fnbnd = body; | |
294 | return(name); | |
295 | } | |
296 | ||
297 | ||
298 | lispval | |
299 | Nquote() | |
300 | { | |
301 | return((lbot->val)->d.car); | |
302 | } | |
303 | ||
304 | ||
305 | lispval | |
306 | Nsetq() | |
307 | { register lispval handy, where, value; | |
308 | register int lefttype; | |
309 | ||
310 | value = nil; | |
311 | ||
312 | for(where = lbot->val; where != nil; where = handy->d.cdr) { | |
313 | handy = where->d.cdr; | |
314 | if((TYPE(handy))!=DTPR) | |
315 | error("odd number of args to setq",FALSE); | |
316 | if((lefttype=TYPE(where->d.car))==ATOM) { | |
317 | if(where->d.car==nil) | |
318 | error("Attempt to set nil",FALSE); | |
319 | where->d.car->a.clb = value = eval(handy->d.car); | |
320 | }else if(lefttype==VALUE) | |
321 | where->d.car->l = value = eval(handy->d.car); | |
322 | else errorh1(Vermisc, | |
323 | "Can only setq atoms or values",nil,FALSE,0, | |
324 | where->d.car); | |
325 | } | |
326 | return(value); | |
327 | } | |
328 | ||
329 | ||
330 | lispval | |
331 | Ncond() | |
332 | { | |
333 | register lispval where, last; | |
334 | ||
335 | where = lbot->val; | |
336 | last = nil; | |
337 | for(;;) { | |
338 | if ((TYPE(where))!=DTPR) | |
339 | break; | |
340 | if ((TYPE(where->d.car))!=DTPR) | |
341 | break; | |
342 | if ((last=eval((where->d.car)->d.car)) != nil) | |
343 | break; | |
344 | where = where->d.cdr; | |
345 | } | |
346 | ||
347 | if ((TYPE(where)) != DTPR) | |
348 | return(nil); | |
349 | where = (where->d.car)->d.cdr; | |
350 | while ((TYPE(where))==DTPR) { | |
351 | last = eval(where->d.car); | |
352 | where = where->d.cdr; | |
353 | } | |
354 | return(last); | |
355 | } | |
356 | ||
357 | lispval | |
358 | Nand() | |
359 | { | |
360 | register lispval current, temp; | |
361 | ||
362 | current = lbot->val; | |
363 | temp = tatom; | |
364 | while (current != nil) | |
365 | if ( (temp = current->d.car)!=nil && (temp = eval(temp))!=nil) | |
366 | current = current->d.cdr; | |
367 | else { | |
368 | current = nil; | |
369 | temp = nil; | |
370 | } | |
371 | return(temp); | |
372 | } | |
373 | ||
374 | ||
375 | lispval | |
376 | Nor() | |
377 | { | |
378 | register lispval current, temp; | |
379 | ||
380 | current = lbot->val; | |
381 | temp = nil; | |
382 | while (current != nil) | |
383 | if ( (temp = eval(current->d.car)) == nil) | |
384 | current = current->d.cdr; | |
385 | else | |
386 | break; | |
387 | return(temp); | |
388 | } |