/[cvs]/stack/stack.c
ViewVC logotype

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.121 - (hide annotations)
Wed Mar 27 14:45:17 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.120: +8 -6 lines
File MIME type: text/plain
stack.c: (to): Bugfix.

1 teddy 1.116 /* -*- coding: utf-8; -*- */
2 teddy 1.91 /*
3     stack - an interactive interpreter for a stack-based language
4     Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn
5    
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10    
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     GNU General Public License for more details.
15    
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19    
20     Authors: Mats Alritzson <masse@fukt.bth.se>
21     Teddy Hogeborn <teddy@fukt.bth.se>
22     */
23    
24 teddy 1.117 #define CAR(X) ((X)->content.c->car)
25     #define CDR(X) ((X)->content.c->cdr)
26 masse 1.104
27 teddy 1.84 /* printf, sscanf, fgets, fprintf, fopen, perror */
28 masse 1.1 #include <stdio.h>
29 teddy 1.52 /* exit, EXIT_SUCCESS, malloc, free */
30 masse 1.1 #include <stdlib.h>
31     /* NULL */
32     #include <stddef.h>
33 teddy 1.3 /* dlopen, dlsym, dlerror */
34 masse 1.1 #include <dlfcn.h>
35 teddy 1.52 /* strcmp, strcpy, strlen, strcat, strdup */
36 masse 1.47 #include <string.h>
37 teddy 1.91 /* getopt, STDIN_FILENO, STDOUT_FILENO, usleep */
38 teddy 1.84 #include <unistd.h>
39     /* EX_NOINPUT, EX_USAGE */
40     #include <sysexits.h>
41 masse 1.108 /* assert */
42     #include <assert.h>
43 masse 1.107
44     #ifdef __linux__
45 masse 1.83 /* mtrace, muntrace */
46     #include <mcheck.h>
47 teddy 1.91 /* ioctl */
48     #include <sys/ioctl.h>
49     /* KDMKTONE */
50     #include <linux/kd.h>
51 masse 1.107 #endif /* __linux__ */
52 masse 1.1
53 teddy 1.88 #include "stack.h"
54 masse 1.1
55 teddy 1.28 /* Initialize a newly created environment */
56     void init_env(environment *env)
57 masse 1.1 {
58 masse 1.46 int i;
59 masse 1.1
60 teddy 1.100 env->gc_limit= 400000;
61 masse 1.87 env->gc_count= 0;
62 masse 1.90 env->gc_ref= NULL;
63 masse 1.87
64 teddy 1.111 env->head= new_val(env);
65 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
66 teddy 1.28 env->symbols[i]= NULL;
67 teddy 1.84 env->err= 0;
68     env->in_string= NULL;
69     env->free_string= NULL;
70     env->inputstream= stdin;
71     env->interactive= 1;
72 masse 1.1 }
73    
74 masse 1.95 void printerr(const char* in_string)
75     {
76 teddy 1.48 fprintf(stderr, "Err: %s\n", in_string);
77     }
78    
79     /* Discard the top element of the stack. */
80     extern void toss(environment *env)
81     {
82 teddy 1.111 if(env->head->type==empty) {
83 teddy 1.48 printerr("Too Few Arguments");
84 masse 1.90 env->err= 1;
85 teddy 1.48 return;
86     }
87    
88 masse 1.104 env->head= CDR(env->head); /* Remove the top stack item */
89 teddy 1.48 }
90    
91 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
92 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
93 masse 1.1 {
94 masse 1.46 int i= 0;
95     unsigned int out_hash= 0;
96 teddy 1.18 char key= '\0';
97 teddy 1.28 symbol **position;
98 masse 1.1
99 masse 1.16 while(1){ /* Hash in_string */
100 masse 1.1 key= in_string[i++];
101     if(key=='\0')
102     break;
103     out_hash= out_hash*32+key;
104     }
105    
106     out_hash= out_hash%HASHTBLSIZE;
107     position= &(in_hashtbl[out_hash]);
108    
109 masse 1.25 while(1){
110 teddy 1.18 if(*position==NULL) /* If empty */
111 masse 1.1 return position;
112    
113 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
114 masse 1.1 return position;
115    
116 masse 1.16 position= &((*position)->next); /* Try next */
117 masse 1.1 }
118     }
119    
120 masse 1.95 /* Create new value */
121     value* new_val(environment *env)
122     {
123 masse 1.87 value *nval= malloc(sizeof(value));
124     stackitem *nitem= malloc(sizeof(stackitem));
125    
126 teddy 1.118 assert(nval != NULL);
127     assert(nitem != NULL);
128    
129 masse 1.87 nval->content.ptr= NULL;
130 teddy 1.117 nval->type= empty;
131 masse 1.87
132     nitem->item= nval;
133     nitem->next= env->gc_ref;
134 masse 1.102
135 masse 1.87 env->gc_ref= nitem;
136    
137 teddy 1.101 env->gc_count += sizeof(value);
138 teddy 1.99 nval->gc.flag.mark= 0;
139     nval->gc.flag.protect= 0;
140 masse 1.93
141 masse 1.87 return nval;
142     }
143    
144 masse 1.95 /* Mark values recursively.
145     Marked values are not collected by the GC. */
146 teddy 1.96 inline void gc_mark(value *val)
147 masse 1.95 {
148 masse 1.102 if(val==NULL || val->gc.flag.mark)
149 masse 1.87 return;
150    
151 teddy 1.99 val->gc.flag.mark= 1;
152 masse 1.87
153 masse 1.104 if(val->type==tcons) {
154     gc_mark(CAR(val));
155     gc_mark(CDR(val));
156 masse 1.87 }
157     }
158    
159 teddy 1.96 inline void gc_maybe(environment *env)
160     {
161     if(env->gc_count < env->gc_limit)
162     return;
163     else
164     return gc_init(env);
165     }
166    
167 masse 1.95 /* Start GC */
168     extern void gc_init(environment *env)
169     {
170 masse 1.102 stackitem *new_head= NULL, *titem;
171 masse 1.87 symbol *tsymb;
172     int i;
173    
174 masse 1.102 if(env->interactive)
175 teddy 1.101 printf("Garbage collecting.");
176 teddy 1.100
177 masse 1.95 /* Mark values on stack */
178 masse 1.104 gc_mark(env->head);
179 masse 1.87
180 masse 1.102 if(env->interactive)
181 teddy 1.100 printf(".");
182 masse 1.102
183 teddy 1.100
184 masse 1.93 /* Mark values in hashtable */
185 masse 1.102 for(i= 0; i<HASHTBLSIZE; i++)
186     for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next)
187 masse 1.97 if (tsymb->val != NULL)
188     gc_mark(tsymb->val);
189 masse 1.87
190 masse 1.102
191     if(env->interactive)
192 teddy 1.100 printf(".");
193 masse 1.102
194 masse 1.87 env->gc_count= 0;
195    
196 masse 1.95 while(env->gc_ref!=NULL) { /* Sweep unused values */
197 masse 1.90
198 teddy 1.99 if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */
199 masse 1.93
200 teddy 1.116 /* Remove content */
201     switch(env->gc_ref->item->type){
202     case string:
203 masse 1.87 free(env->gc_ref->item->content.ptr);
204 teddy 1.116 break;
205     case tcons:
206     free(env->gc_ref->item->content.c);
207     break;
208     case empty:
209     case integer:
210     case tfloat:
211     case func:
212     case symb:
213     /* Symbol strings are freed when walking the hash table */
214     }
215 masse 1.102
216 masse 1.93 free(env->gc_ref->item); /* Remove from gc_ref */
217 masse 1.87 titem= env->gc_ref->next;
218 masse 1.93 free(env->gc_ref); /* Remove value */
219 masse 1.87 env->gc_ref= titem;
220 masse 1.97 continue;
221 teddy 1.110 }
222     #ifdef DEBUG
223     printf("Kept value (%p)", env->gc_ref->item);
224     if(env->gc_ref->item->gc.flag.mark)
225     printf(" (marked)");
226     if(env->gc_ref->item->gc.flag.protect)
227     printf(" (protected)");
228     switch(env->gc_ref->item->type){
229     case integer:
230     printf(" integer: %d", env->gc_ref->item->content.i);
231     break;
232     case func:
233     printf(" func: %p", env->gc_ref->item->content.ptr);
234     break;
235     case symb:
236     printf(" symb: %s", env->gc_ref->item->content.sym->id);
237     break;
238     case tcons:
239     printf(" tcons: %p\t%p", env->gc_ref->item->content.c->car,
240     env->gc_ref->item->content.c->cdr);
241     break;
242     default:
243     printf(" <unknown %d>", (env->gc_ref->item->type));
244     }
245     printf("\n");
246     #endif /* DEBUG */
247 masse 1.102
248     /* Keep values */
249     env->gc_count += sizeof(value);
250     if(env->gc_ref->item->type==string)
251 teddy 1.114 env->gc_count += strlen(env->gc_ref->item->content.ptr)+1;
252 masse 1.97
253     titem= env->gc_ref->next;
254     env->gc_ref->next= new_head;
255     new_head= env->gc_ref;
256 teddy 1.99 new_head->item->gc.flag.mark= 0;
257 masse 1.97 env->gc_ref= titem;
258 masse 1.87 }
259    
260 teddy 1.100 if (env->gc_limit < env->gc_count*2)
261     env->gc_limit= env->gc_count*2;
262 teddy 1.101
263 masse 1.87 env->gc_ref= new_head;
264 teddy 1.100
265 masse 1.102 if(env->interactive)
266 teddy 1.110 printf("done (%d bytes still allocated)\n", env->gc_count);
267 teddy 1.100
268 masse 1.87 }
269    
270 masse 1.95 /* Protect values from GC */
271 masse 1.98 void protect(value *val)
272 masse 1.90 {
273 masse 1.102 if(val==NULL || val->gc.flag.protect)
274 masse 1.98 return;
275    
276 teddy 1.99 val->gc.flag.protect= 1;
277 masse 1.98
278 masse 1.104 if(val->type==tcons) {
279     protect(CAR(val));
280     protect(CDR(val));
281 masse 1.98 }
282 masse 1.90 }
283    
284 masse 1.95 /* Unprotect values from GC */
285 masse 1.98 void unprotect(value *val)
286 masse 1.90 {
287 masse 1.102 if(val==NULL || !(val->gc.flag.protect))
288 masse 1.98 return;
289    
290 teddy 1.99 val->gc.flag.protect= 0;
291 masse 1.98
292 masse 1.104 if(val->type==tcons) {
293     unprotect(CAR(val));
294     unprotect(CDR(val));
295 masse 1.98 }
296 masse 1.90 }
297    
298 teddy 1.29 /* Push a value onto the stack */
299 masse 1.72 void push_val(environment *env, value *val)
300 teddy 1.29 {
301 masse 1.104 value *new_value= new_val(env);
302 masse 1.102
303 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
304 masse 1.108 assert(new_value->content.c!=NULL);
305 teddy 1.116 env->gc_count += sizeof(pair);
306 masse 1.104 new_value->type= tcons;
307     CAR(new_value)= val;
308     CDR(new_value)= env->head;
309     env->head= new_value;
310 teddy 1.29 }
311    
312 masse 1.95 /* Push an integer onto the stack */
313 masse 1.72 void push_int(environment *env, int in_val)
314 masse 1.1 {
315 masse 1.87 value *new_value= new_val(env);
316 teddy 1.28
317 masse 1.93 new_value->content.i= in_val;
318 teddy 1.28 new_value->type= integer;
319 masse 1.1
320 masse 1.75 push_val(env, new_value);
321 masse 1.1 }
322    
323 masse 1.95 /* Push a floating point number onto the stack */
324 masse 1.93 void push_float(environment *env, float in_val)
325     {
326     value *new_value= new_val(env);
327    
328     new_value->content.f= in_val;
329     new_value->type= tfloat;
330    
331     push_val(env, new_value);
332     }
333    
334 masse 1.14 /* Copy a string onto the stack. */
335 masse 1.72 void push_cstring(environment *env, const char *in_string)
336 masse 1.1 {
337 masse 1.87 value *new_value= new_val(env);
338 teddy 1.101 int length= strlen(in_string)+1;
339 teddy 1.28
340 teddy 1.101 new_value->content.ptr= malloc(length);
341 teddy 1.118 assert(new_value != NULL);
342 teddy 1.101 env->gc_count += length;
343 teddy 1.28 strcpy(new_value->content.ptr, in_string);
344     new_value->type= string;
345 masse 1.1
346 masse 1.75 push_val(env, new_value);
347 masse 1.1 }
348    
349 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
350 masse 1.95 char *mangle_str(const char *old_string)
351     {
352 masse 1.90 char validchars[]= "0123456789abcdef";
353 teddy 1.48 char *new_string, *current;
354    
355 masse 1.90 new_string= malloc((strlen(old_string)*2)+4);
356 teddy 1.118 assert(new_string != NULL);
357 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
358 masse 1.90 current= new_string+3;
359 teddy 1.48 while(old_string[0] != '\0'){
360 masse 1.90 current[0]= validchars[(unsigned char)(old_string[0])/16];
361     current[1]= validchars[(unsigned char)(old_string[0])%16];
362     current+= 2;
363 teddy 1.48 old_string++;
364     }
365 masse 1.90 current[0]= '\0';
366 teddy 1.48
367     return new_string; /* The caller must free() it */
368     }
369    
370 masse 1.95 extern void mangle(environment *env)
371     {
372 teddy 1.48 char *new_string;
373    
374 teddy 1.111 if(env->head->type==empty) {
375 teddy 1.48 printerr("Too Few Arguments");
376 masse 1.90 env->err= 1;
377 teddy 1.48 return;
378     }
379    
380 masse 1.104 if(CAR(env->head)->type!=string) {
381 teddy 1.48 printerr("Bad Argument Type");
382 masse 1.90 env->err= 2;
383 teddy 1.48 return;
384     }
385    
386 masse 1.104 new_string=
387     mangle_str((const char *)(CAR(env->head)->content.ptr));
388 teddy 1.48
389     toss(env);
390     if(env->err) return;
391    
392 masse 1.81 push_cstring(env, new_string);
393 teddy 1.48 }
394    
395 teddy 1.28 /* Push a symbol onto the stack. */
396 teddy 1.35 void push_sym(environment *env, const char *in_string)
397 masse 1.1 {
398 teddy 1.28 value *new_value; /* A new symbol value */
399     /* ...which might point to... */
400 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
401 teddy 1.28 /* ...which, if possible, will be bound to... */
402     value *new_fvalue; /* (if needed) A new function value */
403     /* ...which will point to... */
404     void *funcptr; /* A function pointer */
405    
406     static void *handle= NULL; /* Dynamic linker handle */
407 teddy 1.48 const char *dlerr; /* Dynamic linker error */
408     char *mangled; /* Mangled function name */
409 teddy 1.28
410 masse 1.87 new_value= new_val(env);
411 masse 1.98 protect(new_value);
412 masse 1.93 new_fvalue= new_val(env);
413 masse 1.98 protect(new_fvalue);
414 teddy 1.28
415     /* The new value is a symbol */
416     new_value->type= symb;
417    
418     /* Look up the symbol name in the hash table */
419 teddy 1.29 new_symbol= hash(env->symbols, in_string);
420     new_value->content.ptr= *new_symbol;
421 teddy 1.28
422 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
423 teddy 1.28
424     /* Create a new symbol */
425 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
426 teddy 1.118 assert((*new_symbol) != NULL);
427 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
428     (*new_symbol)->next= NULL;
429     (*new_symbol)->id= malloc(strlen(in_string)+1);
430 teddy 1.118 assert((*new_symbol)->id != NULL);
431 teddy 1.29 strcpy((*new_symbol)->id, in_string);
432 masse 1.1
433 teddy 1.28 /* Intern the new symbol in the hash table */
434 teddy 1.29 new_value->content.ptr= *new_symbol;
435 masse 1.1
436 teddy 1.28 /* Try to load the symbol name as an external function, to see if
437     we should bind the symbol to a new function pointer value */
438 masse 1.16 if(handle==NULL) /* If no handle */
439 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
440 masse 1.6
441 masse 1.90 mangled= mangle_str(in_string); /* mangle the name */
442 teddy 1.86 funcptr= dlsym(handle, mangled); /* and try to find it */
443 masse 1.95
444 masse 1.90 dlerr= dlerror();
445 teddy 1.48 if(dlerr != NULL) { /* If no function was found */
446 teddy 1.86 funcptr= dlsym(handle, in_string); /* Get function pointer */
447 masse 1.90 dlerr= dlerror();
448 teddy 1.48 }
449 masse 1.95
450 teddy 1.48 if(dlerr==NULL) { /* If a function was found */
451 masse 1.90 new_fvalue->type= func; /* The new value is a function pointer */
452     new_fvalue->content.ptr= funcptr; /* Store function pointer */
453 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
454     function value */
455 teddy 1.28 }
456 masse 1.95
457     free(mangled);
458 masse 1.1 }
459 masse 1.95
460 masse 1.75 push_val(env, new_value);
461 masse 1.98 unprotect(new_value); unprotect(new_fvalue);
462 masse 1.1 }
463    
464 masse 1.14 /* Print newline. */
465 masse 1.34 extern void nl()
466 masse 1.8 {
467     printf("\n");
468     }
469 masse 1.1
470 teddy 1.37 /* Gets the type of a value */
471 masse 1.95 extern void type(environment *env)
472     {
473 teddy 1.111 if(env->head->type==empty) {
474 teddy 1.37 printerr("Too Few Arguments");
475 masse 1.104 env->err= 1;
476 teddy 1.37 return;
477     }
478 masse 1.104
479 teddy 1.112 switch(CAR(env->head)->type){
480     case empty:
481     push_sym(env, "empty");
482     break;
483 teddy 1.37 case integer:
484     push_sym(env, "integer");
485     break;
486 masse 1.93 case tfloat:
487     push_sym(env, "float");
488     break;
489 teddy 1.37 case string:
490     push_sym(env, "string");
491     break;
492     case symb:
493     push_sym(env, "symbol");
494     break;
495     case func:
496     push_sym(env, "function");
497     break;
498 masse 1.102 case tcons:
499 teddy 1.113 push_sym(env, "pair");
500 teddy 1.37 break;
501     }
502 teddy 1.112 swap(env);
503     if (env->err) return;
504     toss(env);
505 teddy 1.37 }
506    
507 teddy 1.114 /* Print a value */
508 teddy 1.117 void print_val(value *val, int noquote, stackitem *stack)
509 masse 1.8 {
510 teddy 1.117 stackitem *titem, *tstack;
511     int depth;
512    
513 teddy 1.113 switch(val->type) {
514 teddy 1.112 case empty:
515     printf("[]");
516     break;
517 teddy 1.28 case integer:
518 teddy 1.113 printf("%d", val->content.i);
519 masse 1.93 break;
520     case tfloat:
521 teddy 1.113 printf("%f", val->content.f);
522 teddy 1.2 break;
523     case string:
524 teddy 1.80 if(noquote)
525 teddy 1.113 printf("%s", (char*)(val->content.ptr));
526 teddy 1.80 else
527 teddy 1.113 printf("\"%s\"", (char*)(val->content.ptr));
528 teddy 1.2 break;
529 teddy 1.28 case symb:
530 teddy 1.113 printf("%s", val->content.sym->id);
531 masse 1.6 break;
532 teddy 1.35 case func:
533 teddy 1.113 printf("#<function %p>", (funcp)(val->content.ptr));
534 teddy 1.35 break;
535 masse 1.102 case tcons:
536 teddy 1.38 printf("[ ");
537 teddy 1.117 tstack= stack;
538 teddy 1.113 do {
539 teddy 1.117 titem=malloc(sizeof(stackitem));
540 teddy 1.118 assert(titem != NULL);
541 teddy 1.117 titem->item=val;
542     titem->next=tstack;
543     tstack=titem; /* Put it on the stack */
544     /* Search a stack of values being printed to see if we are already
545     printing this value */
546     titem=tstack;
547     depth=0;
548     while(titem != NULL && titem->item != CAR(val)){
549     titem=titem->next;
550     depth++;
551     }
552     if(titem != NULL){ /* If we found it on the stack, */
553     printf("#%d#", depth); /* print a depth reference */
554     } else {
555     print_val(CAR(val), noquote, tstack);
556     }
557 teddy 1.114 val= CDR(val);
558     switch(val->type){
559 teddy 1.112 case empty:
560     break;
561     case tcons:
562 teddy 1.117 /* Search a stack of values being printed to see if we are already
563     printing this value */
564     titem=tstack;
565     depth=0;
566     while(titem != NULL && titem->item != val){
567     titem=titem->next;
568     depth++;
569     }
570     if(titem != NULL){ /* If we found it on the stack, */
571     printf(" . #%d#", depth); /* print a depth reference */
572     } else {
573     printf(" ");
574     }
575 teddy 1.112 break;
576     default:
577 teddy 1.111 printf(" . "); /* Improper list */
578 teddy 1.117 print_val(val, noquote, tstack);
579 teddy 1.112 }
580 teddy 1.117 } while(val->type == tcons && titem == NULL);
581     titem=tstack;
582     while(titem != stack){
583     tstack=titem->next;
584     free(titem);
585     titem=tstack;
586     }
587 teddy 1.111 printf(" ]");
588 teddy 1.35 break;
589 teddy 1.2 }
590 masse 1.1 }
591    
592 masse 1.95 extern void print_(environment *env)
593     {
594 teddy 1.111 if(env->head->type==empty) {
595 teddy 1.36 printerr("Too Few Arguments");
596 masse 1.104 env->err= 1;
597 teddy 1.35 return;
598     }
599 teddy 1.117 print_val(CAR(env->head), 0, NULL);
600 teddy 1.80 nl();
601 teddy 1.28 }
602    
603 masse 1.14 /* Prints the top element of the stack and then discards it. */
604 teddy 1.28 extern void print(environment *env)
605 masse 1.8 {
606 teddy 1.28 print_(env);
607 teddy 1.35 if(env->err) return;
608 teddy 1.28 toss(env);
609 masse 1.8 }
610    
611 masse 1.95 extern void princ_(environment *env)
612     {
613 teddy 1.111 if(env->head->type==empty) {
614 teddy 1.80 printerr("Too Few Arguments");
615 masse 1.104 env->err= 1;
616 teddy 1.80 return;
617     }
618 teddy 1.117 print_val(CAR(env->head), 1, NULL);
619 teddy 1.80 }
620    
621     /* Prints the top element of the stack and then discards it. */
622     extern void princ(environment *env)
623     {
624     princ_(env);
625     if(env->err) return;
626     toss(env);
627     }
628    
629 masse 1.14 /* Only to be called by function printstack. */
630 masse 1.104 void print_st(value *stack_head, long counter)
631 masse 1.8 {
632 teddy 1.111 if(CDR(stack_head)->type != empty)
633 masse 1.104 print_st(CDR(stack_head), counter+1);
634 masse 1.8 printf("%ld: ", counter);
635 teddy 1.117 print_val(CAR(stack_head), 0, NULL);
636 masse 1.8 nl();
637     }
638    
639 masse 1.14 /* Prints the stack. */
640 teddy 1.28 extern void printstack(environment *env)
641 masse 1.1 {
642 teddy 1.111 if(env->head->type == empty) {
643 teddy 1.80 printf("Stack Empty\n");
644 teddy 1.35 return;
645 masse 1.1 }
646 masse 1.95
647 teddy 1.35 print_st(env->head, 1);
648 masse 1.1 }
649    
650 masse 1.26 /* Swap the two top elements on the stack. */
651 teddy 1.28 extern void swap(environment *env)
652 masse 1.26 {
653 masse 1.104 value *temp= env->head;
654 masse 1.26
655 teddy 1.111 if(env->head->type == empty || CDR(env->head)->type == empty) {
656 teddy 1.36 printerr("Too Few Arguments");
657 teddy 1.35 env->err=1;
658 masse 1.26 return;
659 teddy 1.28 }
660 masse 1.26
661 masse 1.104 env->head= CDR(env->head);
662     CDR(temp)= CDR(env->head);
663     CDR(env->head)= temp;
664 masse 1.26 }
665    
666 teddy 1.56 /* Rotate the first three elements on the stack. */
667     extern void rot(environment *env)
668     {
669 masse 1.104 value *temp= env->head;
670 teddy 1.56
671 teddy 1.111 if(env->head->type == empty || CDR(env->head)->type == empty
672     || CDR(CDR(env->head))->type == empty) {
673 teddy 1.56 printerr("Too Few Arguments");
674 masse 1.104 env->err= 1;
675 teddy 1.56 return;
676     }
677 masse 1.104
678     env->head= CDR(CDR(env->head));
679     CDR(CDR(temp))= CDR(env->head);
680     CDR(env->head)= temp;
681 teddy 1.56 }
682    
683 teddy 1.33 /* Recall a value from a symbol, if bound */
684 teddy 1.31 extern void rcl(environment *env)
685     {
686     value *val;
687    
688 teddy 1.111 if(env->head->type==empty) {
689 teddy 1.36 printerr("Too Few Arguments");
690 masse 1.102 env->err= 1;
691 teddy 1.31 return;
692     }
693    
694 masse 1.104 if(CAR(env->head)->type!=symb) {
695 teddy 1.36 printerr("Bad Argument Type");
696 masse 1.102 env->err= 2;
697 teddy 1.31 return;
698     }
699 teddy 1.35
700 masse 1.105 val= CAR(env->head)->content.sym->val;
701 teddy 1.33 if(val == NULL){
702 teddy 1.36 printerr("Unbound Variable");
703 masse 1.102 env->err= 3;
704 teddy 1.33 return;
705     }
706 teddy 1.110 push_val(env, val); /* Return the symbol's bound value */
707     swap(env);
708     if(env->err) return;
709     toss(env); /* toss the symbol */
710 teddy 1.35 if(env->err) return;
711 teddy 1.31 }
712 masse 1.26
713 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
714     function value, and if it is, toss the symbol and execute the
715     function. */
716 teddy 1.28 extern void eval(environment *env)
717 masse 1.1 {
718     funcp in_func;
719 masse 1.44 value* temp_val;
720 masse 1.104 value* iterator;
721 masse 1.44
722 teddy 1.80 eval_start:
723    
724 teddy 1.96 gc_maybe(env);
725    
726 teddy 1.111 if(env->head->type==empty) {
727 teddy 1.36 printerr("Too Few Arguments");
728 masse 1.102 env->err= 1;
729 masse 1.1 return;
730 masse 1.17 }
731 masse 1.1
732 masse 1.104 switch(CAR(env->head)->type) {
733 masse 1.46 /* if it's a symbol */
734     case symb:
735 teddy 1.35 rcl(env); /* get its contents */
736     if(env->err) return;
737 masse 1.104 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
738 teddy 1.64 goto eval_start;
739 teddy 1.29 }
740 teddy 1.59 return;
741 masse 1.22
742 masse 1.46 /* If it's a lone function value, run it */
743     case func:
744 masse 1.104 in_func= (funcp)(CAR(env->head)->content.ptr);
745 teddy 1.28 toss(env);
746 teddy 1.35 if(env->err) return;
747 masse 1.89 return in_func(env);
748 masse 1.44
749 masse 1.46 /* If it's a list */
750 masse 1.102 case tcons:
751 masse 1.104 temp_val= CAR(env->head);
752 masse 1.98 protect(temp_val);
753 masse 1.93
754     toss(env); if(env->err) return;
755 masse 1.104 iterator= temp_val;
756 masse 1.90
757 teddy 1.111 while(iterator->type != empty) {
758 masse 1.104 push_val(env, CAR(iterator));
759 masse 1.90
760 masse 1.104 if(CAR(env->head)->type==symb
761 masse 1.105 && CAR(env->head)->content.sym->id[0]==';') {
762 masse 1.44 toss(env);
763     if(env->err) return;
764 masse 1.90
765 teddy 1.111 if(CDR(iterator)->type == empty){
766 teddy 1.64 goto eval_start;
767 teddy 1.59 }
768 masse 1.44 eval(env);
769 masse 1.46 if(env->err) return;
770 masse 1.44 }
771 teddy 1.111 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
772 masse 1.104 iterator= CDR(iterator);
773 teddy 1.103 else {
774     printerr("Bad Argument Type"); /* Improper list */
775     env->err= 2;
776     return;
777     }
778 masse 1.44 }
779 masse 1.98 unprotect(temp_val);
780 teddy 1.59 return;
781 masse 1.46
782 teddy 1.116 case empty:
783     case integer:
784     case tfloat:
785     case string:
786 teddy 1.59 return;
787 masse 1.26 }
788 masse 1.1 }
789    
790 masse 1.44 /* Reverse (flip) a list */
791 masse 1.95 extern void rev(environment *env)
792     {
793 masse 1.104 value *old_head, *new_head, *item;
794 teddy 1.40
795 teddy 1.111 if(env->head->type==empty) {
796 teddy 1.40 printerr("Too Few Arguments");
797 masse 1.90 env->err= 1;
798 teddy 1.40 return;
799     }
800    
801 teddy 1.111 if(CAR(env->head)->type==empty)
802     return; /* Don't reverse an empty list */
803    
804 masse 1.104 if(CAR(env->head)->type!=tcons) {
805 teddy 1.40 printerr("Bad Argument Type");
806 masse 1.90 env->err= 2;
807 teddy 1.40 return;
808     }
809    
810 masse 1.104 old_head= CAR(env->head);
811 teddy 1.111 new_head= new_val(env);
812     while(old_head->type != empty) {
813 masse 1.90 item= old_head;
814 masse 1.104 old_head= CDR(old_head);
815     CDR(item)= new_head;
816 masse 1.90 new_head= item;
817 teddy 1.40 }
818 masse 1.104 CAR(env->head)= new_head;
819 teddy 1.40 }
820    
821 masse 1.19 /* Make a list. */
822 teddy 1.28 extern void pack(environment *env)
823 masse 1.19 {
824 teddy 1.111 value *iterator, *temp, *ending;
825    
826     ending=new_val(env);
827 masse 1.19
828 teddy 1.28 iterator= env->head;
829 teddy 1.111 if(iterator->type == empty
830 masse 1.104 || (CAR(iterator)->type==symb
831 masse 1.105 && CAR(iterator)->content.sym->id[0]=='[')) {
832 teddy 1.111 temp= ending;
833 teddy 1.28 toss(env);
834 masse 1.24 } else {
835     /* Search for first delimiter */
836 teddy 1.111 while(CDR(iterator)->type != empty
837 masse 1.104 && (CAR(CDR(iterator))->type!=symb
838 masse 1.105 || CAR(CDR(iterator))->content.sym->id[0]!='['))
839 masse 1.104 iterator= CDR(iterator);
840 masse 1.24
841     /* Extract list */
842 teddy 1.28 temp= env->head;
843 masse 1.104 env->head= CDR(iterator);
844 teddy 1.111 CDR(iterator)= ending;
845 masse 1.93
846 teddy 1.111 if(env->head->type != empty)
847 teddy 1.28 toss(env);
848 masse 1.24 }
849 masse 1.19
850     /* Push list */
851 teddy 1.28
852 masse 1.104 push_val(env, temp);
853 teddy 1.40 rev(env);
854 masse 1.19 }
855    
856 masse 1.16 /* Relocate elements of the list on the stack. */
857 teddy 1.28 extern void expand(environment *env)
858 masse 1.1 {
859 masse 1.104 value *temp, *new_head;
860 masse 1.8
861 masse 1.16 /* Is top element a list? */
862 teddy 1.111 if(env->head->type==empty) {
863 teddy 1.36 printerr("Too Few Arguments");
864 masse 1.90 env->err= 1;
865 masse 1.8 return;
866 masse 1.17 }
867 masse 1.104
868     if(CAR(env->head)->type!=tcons) {
869 teddy 1.36 printerr("Bad Argument Type");
870 masse 1.90 env->err= 2;
871 teddy 1.36 return;
872     }
873 masse 1.43
874     rev(env);
875    
876     if(env->err)
877     return;
878 masse 1.8
879 masse 1.16 /* The first list element is the new stack head */
880 masse 1.104 new_head= temp= CAR(env->head);
881 masse 1.8
882 teddy 1.28 toss(env);
883 masse 1.24
884 teddy 1.28 /* Find the end of the list */
885 teddy 1.111 while(CDR(temp)->type != empty) {
886 masse 1.104 if (CDR(temp)->type == tcons)
887     temp= CDR(temp);
888 teddy 1.103 else {
889     printerr("Bad Argument Type"); /* Improper list */
890     env->err= 2;
891     return;
892     }
893     }
894 masse 1.8
895 teddy 1.28 /* Connect the tail of the list with the old stack head */
896 masse 1.104 CDR(temp)= env->head;
897 teddy 1.28 env->head= new_head; /* ...and voila! */
898    
899 teddy 1.5 }
900 masse 1.11
901 masse 1.14 /* Compares two elements by reference. */
902 teddy 1.28 extern void eq(environment *env)
903 masse 1.11 {
904     void *left, *right;
905    
906 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
907 teddy 1.36 printerr("Too Few Arguments");
908 masse 1.90 env->err= 1;
909 masse 1.11 return;
910 masse 1.17 }
911 masse 1.11
912 masse 1.104 left= CAR(env->head)->content.ptr;
913     right= CAR(CDR(env->head))->content.ptr;
914 teddy 1.28 toss(env); toss(env);
915 masse 1.102
916     push_int(env, left==right);
917 masse 1.11 }
918    
919 masse 1.14 /* Negates the top element on the stack. */
920 teddy 1.28 extern void not(environment *env)
921 masse 1.11 {
922 teddy 1.28 int val;
923 masse 1.11
924 teddy 1.111 if(env->head->type==empty) {
925 teddy 1.36 printerr("Too Few Arguments");
926 masse 1.90 env->err= 1;
927 masse 1.11 return;
928 masse 1.17 }
929 masse 1.11
930 masse 1.104 if(CAR(env->head)->type!=integer) {
931 teddy 1.36 printerr("Bad Argument Type");
932 masse 1.90 env->err= 2;
933 teddy 1.36 return;
934     }
935    
936 masse 1.104 val= CAR(env->head)->content.i;
937 teddy 1.28 toss(env);
938 masse 1.72 push_int(env, !val);
939 masse 1.11 }
940    
941 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
942     same. */
943 teddy 1.28 extern void neq(environment *env)
944 masse 1.11 {
945 teddy 1.28 eq(env);
946     not(env);
947 masse 1.11 }
948 masse 1.12
949 masse 1.14 /* Give a symbol some content. */
950 teddy 1.28 extern void def(environment *env)
951 masse 1.12 {
952 teddy 1.28 symbol *sym;
953 masse 1.12
954 teddy 1.28 /* Needs two values on the stack, the top one must be a symbol */
955 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
956 teddy 1.36 printerr("Too Few Arguments");
957 masse 1.90 env->err= 1;
958 masse 1.12 return;
959 masse 1.17 }
960 masse 1.12
961 masse 1.104 if(CAR(env->head)->type!=symb) {
962 teddy 1.36 printerr("Bad Argument Type");
963 masse 1.90 env->err= 2;
964 teddy 1.36 return;
965     }
966    
967 teddy 1.28 /* long names are a pain */
968 masse 1.104 sym= CAR(env->head)->content.ptr;
969 teddy 1.28
970     /* Bind the symbol to the value */
971 masse 1.104 sym->val= CAR(CDR(env->head));
972 masse 1.12
973 teddy 1.28 toss(env); toss(env);
974 masse 1.12 }
975 masse 1.10
976 masse 1.14 /* Quit stack. */
977 teddy 1.28 extern void quit(environment *env)
978 teddy 1.5 {
979 masse 1.95 int i;
980 teddy 1.77
981     clear(env);
982 masse 1.83
983 teddy 1.77 if (env->err) return;
984     for(i= 0; i<HASHTBLSIZE; i++) {
985 masse 1.79 while(env->symbols[i]!= NULL) {
986 teddy 1.77 forget_sym(&(env->symbols[i]));
987     }
988 teddy 1.80 env->symbols[i]= NULL;
989 teddy 1.77 }
990 masse 1.83
991 masse 1.90 env->gc_limit= 0;
992 teddy 1.96 gc_maybe(env);
993 masse 1.87
994 teddy 1.110 words(env);
995    
996 masse 1.83 if(env->free_string!=NULL)
997     free(env->free_string);
998    
999 masse 1.107 #ifdef __linux__
1000 masse 1.83 muntrace();
1001 masse 1.107 #endif
1002 masse 1.83
1003 teddy 1.5 exit(EXIT_SUCCESS);
1004 masse 1.24 }
1005    
1006     /* Clear stack */
1007 teddy 1.28 extern void clear(environment *env)
1008 masse 1.24 {
1009 teddy 1.111 while(env->head->type != empty)
1010 teddy 1.28 toss(env);
1011 masse 1.1 }
1012    
1013 teddy 1.33 /* List all defined words */
1014 masse 1.32 extern void words(environment *env)
1015     {
1016     symbol *temp;
1017     int i;
1018    
1019     for(i= 0; i<HASHTBLSIZE; i++) {
1020     temp= env->symbols[i];
1021     while(temp!=NULL) {
1022 teddy 1.110 #ifdef DEBUG
1023     if (temp->val != NULL && temp->val->gc.flag.protect)
1024     printf("(protected) ");
1025     #endif /* DEBUG */
1026 masse 1.32 printf("%s\n", temp->id);
1027     temp= temp->next;
1028     }
1029     }
1030     }
1031 masse 1.34
1032 teddy 1.77 /* Internal forget function */
1033 masse 1.95 void forget_sym(symbol **hash_entry)
1034     {
1035 teddy 1.77 symbol *temp;
1036    
1037     temp= *hash_entry;
1038     *hash_entry= (*hash_entry)->next;
1039    
1040     free(temp->id);
1041     free(temp);
1042     }
1043    
1044 masse 1.34 /* Forgets a symbol (remove it from the hash table) */
1045     extern void forget(environment *env)
1046     {
1047     char* sym_id;
1048    
1049 teddy 1.111 if(env->head->type==empty) {
1050 teddy 1.36 printerr("Too Few Arguments");
1051 masse 1.102 env->err= 1;
1052 teddy 1.36 return;
1053     }
1054    
1055 teddy 1.111 if(CAR(env->head)->type!=symb) {
1056 teddy 1.36 printerr("Bad Argument Type");
1057 masse 1.102 env->err= 2;
1058 masse 1.34 return;
1059     }
1060    
1061 teddy 1.111 sym_id= CAR(env->head)->content.sym->id;
1062 masse 1.34 toss(env);
1063    
1064 teddy 1.77 return forget_sym(hash(env->symbols, sym_id));
1065 teddy 1.36 }
1066    
1067     /* Returns the current error number to the stack */
1068 masse 1.95 extern void errn(environment *env)
1069     {
1070 masse 1.72 push_int(env, env->err);
1071 teddy 1.36 }
1072 masse 1.69
1073 teddy 1.84 int main(int argc, char **argv)
1074 masse 1.1 {
1075 teddy 1.28 environment myenv;
1076 masse 1.1
1077 teddy 1.84 int c; /* getopt option character */
1078    
1079 masse 1.107 #ifdef __linux__
1080 masse 1.83 mtrace();
1081 masse 1.107 #endif
1082 masse 1.83
1083 teddy 1.28 init_env(&myenv);
1084 masse 1.1
1085 teddy 1.84 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
1086    
1087     while ((c = getopt (argc, argv, "i")) != -1)
1088     switch (c)
1089     {
1090     case 'i':
1091     myenv.interactive = 1;
1092     break;
1093     case '?':
1094     fprintf (stderr,
1095 teddy 1.110 "Unknown option character '\\x%x'.\n",
1096 teddy 1.84 optopt);
1097     return EX_USAGE;
1098     default:
1099     abort ();
1100     }
1101    
1102     if (optind < argc) {
1103     myenv.interactive = 0;
1104     myenv.inputstream= fopen(argv[optind], "r");
1105     if(myenv.inputstream== NULL) {
1106     perror(argv[0]);
1107     exit (EX_NOINPUT);
1108     }
1109     }
1110    
1111 teddy 1.91 if(myenv.interactive) {
1112 masse 1.121 printf("Stack version $Revision: 1.120 $\n\
1113 teddy 1.91 Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn\n\
1114 teddy 1.110 Stack comes with ABSOLUTELY NO WARRANTY; for details type 'warranty;'.\n\
1115 teddy 1.91 This is free software, and you are welcome to redistribute it\n\
1116 teddy 1.110 under certain conditions; type 'copying;' for details.\n");
1117 teddy 1.91 }
1118    
1119 masse 1.69 while(1) {
1120 teddy 1.85 if(myenv.in_string==NULL) {
1121     if (myenv.interactive) {
1122     if(myenv.err) {
1123     printf("(error %d)\n", myenv.err);
1124     }
1125     nl();
1126     printstack(&myenv);
1127     printf("> ");
1128     }
1129     myenv.err=0;
1130 teddy 1.80 }
1131 teddy 1.110 sx_72656164(&myenv); /* "read" */
1132     if (myenv.err==4) { /* EOF */
1133     myenv.err=0;
1134     quit(&myenv);
1135 teddy 1.111 } else if(myenv.head->type!=empty
1136 masse 1.104 && CAR(myenv.head)->type==symb
1137 masse 1.105 && CAR(myenv.head)->content.sym->id[0]
1138 masse 1.104 ==';') {
1139 masse 1.69 toss(&myenv); /* No error check in main */
1140     eval(&myenv);
1141 teddy 1.35 }
1142 teddy 1.96 gc_maybe(&myenv);
1143 masse 1.1 }
1144 teddy 1.41 quit(&myenv);
1145 teddy 1.42 return EXIT_FAILURE;
1146 teddy 1.48 }
1147    
1148 teddy 1.85 /* "+" */
1149 masse 1.95 extern void sx_2b(environment *env)
1150     {
1151 teddy 1.48 int a, b;
1152 masse 1.93 float fa, fb;
1153 masse 1.49 size_t len;
1154     char* new_string;
1155     value *a_val, *b_val;
1156 teddy 1.48
1157 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1158 teddy 1.48 printerr("Too Few Arguments");
1159 masse 1.90 env->err= 1;
1160 masse 1.49 return;
1161     }
1162    
1163 masse 1.104 if(CAR(env->head)->type==string
1164     && CAR(CDR(env->head))->type==string) {
1165     a_val= CAR(env->head);
1166     b_val= CAR(CDR(env->head));
1167 masse 1.98 protect(a_val); protect(b_val);
1168 masse 1.49 toss(env); if(env->err) return;
1169     toss(env); if(env->err) return;
1170     len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
1171     new_string= malloc(len);
1172 teddy 1.118 assert(new_string != NULL);
1173 masse 1.49 strcpy(new_string, b_val->content.ptr);
1174     strcat(new_string, a_val->content.ptr);
1175 masse 1.72 push_cstring(env, new_string);
1176 masse 1.98 unprotect(a_val); unprotect(b_val);
1177 masse 1.49 free(new_string);
1178 masse 1.93
1179 teddy 1.48 return;
1180     }
1181    
1182 masse 1.104 if(CAR(env->head)->type==integer
1183     && CAR(CDR(env->head))->type==integer) {
1184     a= CAR(env->head)->content.i;
1185 masse 1.93 toss(env); if(env->err) return;
1186 masse 1.104 b= CAR(env->head)->content.i;
1187 masse 1.93 toss(env); if(env->err) return;
1188     push_int(env, b+a);
1189    
1190     return;
1191     }
1192    
1193 masse 1.104 if(CAR(env->head)->type==tfloat
1194     && CAR(CDR(env->head))->type==tfloat) {
1195     fa= CAR(env->head)->content.f;
1196 masse 1.93 toss(env); if(env->err) return;
1197 masse 1.104 fb= CAR(env->head)->content.f;
1198 masse 1.93 toss(env); if(env->err) return;
1199     push_float(env, fb+fa);
1200    
1201     return;
1202     }
1203    
1204 masse 1.104 if(CAR(env->head)->type==tfloat
1205     && CAR(CDR(env->head))->type==integer) {
1206     fa= CAR(env->head)->content.f;
1207 masse 1.93 toss(env); if(env->err) return;
1208 masse 1.104 b= CAR(env->head)->content.i;
1209 masse 1.93 toss(env); if(env->err) return;
1210     push_float(env, b+fa);
1211    
1212     return;
1213     }
1214    
1215 masse 1.104 if(CAR(env->head)->type==integer
1216     && CAR(CDR(env->head))->type==tfloat) {
1217     a= CAR(env->head)->content.i;
1218 masse 1.93 toss(env); if(env->err) return;
1219 masse 1.104 fb= CAR(env->head)->content.f;
1220 masse 1.93 toss(env); if(env->err) return;
1221     push_float(env, fb+a);
1222    
1223 teddy 1.48 return;
1224     }
1225 masse 1.93
1226     printerr("Bad Argument Type");
1227     env->err=2;
1228 masse 1.1 }
1229 teddy 1.55
1230 teddy 1.85 /* "-" */
1231 masse 1.95 extern void sx_2d(environment *env)
1232     {
1233 teddy 1.62 int a, b;
1234 masse 1.93 float fa, fb;
1235 teddy 1.60
1236 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1237 teddy 1.60 printerr("Too Few Arguments");
1238     env->err=1;
1239     return;
1240     }
1241    
1242 masse 1.104 if(CAR(env->head)->type==integer
1243     && CAR(CDR(env->head))->type==integer) {
1244     a= CAR(env->head)->content.i;
1245 masse 1.93 toss(env); if(env->err) return;
1246 masse 1.104 b= CAR(env->head)->content.i;
1247 masse 1.93 toss(env); if(env->err) return;
1248     push_int(env, b-a);
1249    
1250     return;
1251     }
1252    
1253 masse 1.104 if(CAR(env->head)->type==tfloat
1254     && CAR(CDR(env->head))->type==tfloat) {
1255     fa= CAR(env->head)->content.f;
1256 masse 1.93 toss(env); if(env->err) return;
1257 masse 1.104 fb= CAR(env->head)->content.f;
1258 masse 1.93 toss(env); if(env->err) return;
1259     push_float(env, fb-fa);
1260    
1261     return;
1262     }
1263    
1264 masse 1.104 if(CAR(env->head)->type==tfloat
1265     && CAR(CDR(env->head))->type==integer) {
1266     fa= CAR(env->head)->content.f;
1267 masse 1.93 toss(env); if(env->err) return;
1268 masse 1.104 b= CAR(env->head)->content.i;
1269 masse 1.93 toss(env); if(env->err) return;
1270     push_float(env, b-fa);
1271    
1272     return;
1273     }
1274    
1275 masse 1.104 if(CAR(env->head)->type==integer
1276     && CAR(CDR(env->head))->type==tfloat) {
1277     a= CAR(env->head)->content.i;
1278 masse 1.93 toss(env); if(env->err) return;
1279 masse 1.104 fb= CAR(env->head)->content.f;
1280 masse 1.93 toss(env); if(env->err) return;
1281     push_float(env, fb-a);
1282    
1283 teddy 1.60 return;
1284     }
1285 masse 1.90
1286 masse 1.93 printerr("Bad Argument Type");
1287     env->err=2;
1288 teddy 1.60 }
1289    
1290 teddy 1.85 /* ">" */
1291 masse 1.95 extern void sx_3e(environment *env)
1292     {
1293 teddy 1.62 int a, b;
1294 masse 1.93 float fa, fb;
1295 teddy 1.61
1296 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1297 teddy 1.61 printerr("Too Few Arguments");
1298 masse 1.102 env->err= 1;
1299 teddy 1.61 return;
1300     }
1301    
1302 masse 1.104 if(CAR(env->head)->type==integer
1303     && CAR(CDR(env->head))->type==integer) {
1304     a= CAR(env->head)->content.i;
1305 masse 1.93 toss(env); if(env->err) return;
1306 masse 1.104 b= CAR(env->head)->content.i;
1307 masse 1.93 toss(env); if(env->err) return;
1308     push_int(env, b>a);
1309    
1310     return;
1311     }
1312    
1313 masse 1.104 if(CAR(env->head)->type==tfloat
1314     && CAR(CDR(env->head))->type==tfloat) {
1315     fa= CAR(env->head)->content.f;
1316 masse 1.93 toss(env); if(env->err) return;
1317 masse 1.104 fb= CAR(env->head)->content.f;
1318 masse 1.93 toss(env); if(env->err) return;
1319     push_int(env, fb>fa);
1320    
1321     return;
1322     }
1323    
1324 masse 1.104 if(CAR(env->head)->type==tfloat
1325     && CAR(CDR(env->head))->type==integer) {
1326     fa= CAR(env->head)->content.f;
1327 masse 1.93 toss(env); if(env->err) return;
1328 masse 1.104 b= CAR(env->head)->content.i;
1329 masse 1.93 toss(env); if(env->err) return;
1330     push_int(env, b>fa);
1331    
1332     return;
1333     }
1334    
1335 masse 1.104 if(CAR(env->head)->type==integer
1336     && CAR(CDR(env->head))->type==tfloat) {
1337     a= CAR(env->head)->content.i;
1338 masse 1.93 toss(env); if(env->err) return;
1339 masse 1.104 fb= CAR(env->head)->content.f;
1340 masse 1.93 toss(env); if(env->err) return;
1341     push_int(env, fb>a);
1342    
1343 teddy 1.61 return;
1344     }
1345 masse 1.90
1346 masse 1.93 printerr("Bad Argument Type");
1347 masse 1.104 env->err= 2;
1348 masse 1.93 }
1349    
1350     /* "<" */
1351 masse 1.95 extern void sx_3c(environment *env)
1352     {
1353 masse 1.93 swap(env); if(env->err) return;
1354     sx_3e(env);
1355     }
1356    
1357     /* "<=" */
1358 masse 1.95 extern void sx_3c3d(environment *env)
1359     {
1360 masse 1.93 sx_3e(env); if(env->err) return;
1361     not(env);
1362     }
1363    
1364     /* ">=" */
1365 masse 1.95 extern void sx_3e3d(environment *env)
1366     {
1367 masse 1.93 sx_3c(env); if(env->err) return;
1368     not(env);
1369 teddy 1.61 }
1370    
1371 teddy 1.55 /* Return copy of a value */
1372 masse 1.95 value *copy_val(environment *env, value *old_value)
1373     {
1374 masse 1.93 value *new_value;
1375 teddy 1.55
1376 masse 1.104 if(old_value==NULL)
1377     return NULL;
1378    
1379 masse 1.98 protect(old_value);
1380 masse 1.93 new_value= new_val(env);
1381 masse 1.90 new_value->type= old_value->type;
1382 masse 1.87
1383 teddy 1.55 switch(old_value->type){
1384 masse 1.93 case tfloat:
1385 teddy 1.55 case integer:
1386 masse 1.93 case func:
1387     case symb:
1388 teddy 1.116 case empty:
1389 masse 1.93 new_value->content= old_value->content;
1390 teddy 1.55 break;
1391     case string:
1392 masse 1.90 (char *)(new_value->content.ptr)=
1393     strdup((char *)(old_value->content.ptr));
1394 teddy 1.55 break;
1395 masse 1.102 case tcons:
1396 teddy 1.55
1397 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
1398 masse 1.108 assert(new_value->content.c!=NULL);
1399 teddy 1.116 env->gc_count += sizeof(pair);
1400 masse 1.108
1401 masse 1.104 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
1402     CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
1403 teddy 1.55 break;
1404     }
1405 masse 1.90
1406 masse 1.108 unprotect(old_value);
1407 masse 1.90
1408 teddy 1.55 return new_value;
1409     }
1410    
1411 teddy 1.84 /* "dup"; duplicates an item on the stack */
1412 masse 1.95 extern void sx_647570(environment *env)
1413     {
1414 teddy 1.111 if(env->head->type==empty) {
1415 teddy 1.55 printerr("Too Few Arguments");
1416 masse 1.90 env->err= 1;
1417 teddy 1.55 return;
1418     }
1419 masse 1.104 push_val(env, copy_val(env, CAR(env->head)));
1420 teddy 1.55 }
1421 teddy 1.56
1422 teddy 1.59 /* "if", If-Then */
1423 masse 1.95 extern void sx_6966(environment *env)
1424     {
1425 teddy 1.56 int truth;
1426    
1427 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1428 teddy 1.56 printerr("Too Few Arguments");
1429 masse 1.90 env->err= 1;
1430 teddy 1.56 return;
1431     }
1432    
1433 masse 1.104 if(CAR(CDR(env->head))->type != integer) {
1434 teddy 1.56 printerr("Bad Argument Type");
1435 masse 1.102 env->err= 2;
1436 teddy 1.56 return;
1437     }
1438    
1439     swap(env);
1440     if(env->err) return;
1441    
1442 masse 1.104 truth= CAR(env->head)->content.i;
1443 teddy 1.56
1444     toss(env);
1445     if(env->err) return;
1446    
1447     if(truth)
1448     eval(env);
1449     else
1450     toss(env);
1451     }
1452    
1453     /* If-Then-Else */
1454 masse 1.95 extern void ifelse(environment *env)
1455     {
1456 teddy 1.56 int truth;
1457    
1458 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1459     || CDR(CDR(env->head))->type==empty) {
1460 teddy 1.56 printerr("Too Few Arguments");
1461 masse 1.102 env->err= 1;
1462 teddy 1.56 return;
1463     }
1464    
1465 masse 1.104 if(CAR(CDR(CDR(env->head)))->type!=integer) {
1466 teddy 1.56 printerr("Bad Argument Type");
1467 masse 1.102 env->err= 2;
1468 teddy 1.56 return;
1469     }
1470    
1471     rot(env);
1472     if(env->err) return;
1473    
1474 masse 1.104 truth= CAR(env->head)->content.i;
1475 teddy 1.56
1476     toss(env);
1477     if(env->err) return;
1478    
1479     if(!truth)
1480     swap(env);
1481     if(env->err) return;
1482    
1483     toss(env);
1484     if(env->err) return;
1485    
1486     eval(env);
1487 masse 1.106 }
1488    
1489     extern void sx_656c7365(environment *env)
1490     {
1491 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1492     || CDR(CDR(env->head))->type==empty || CDR(CDR(CDR(env->head)))->type==empty
1493     || CDR(CDR(CDR(CDR(env->head))))->type==empty) {
1494 masse 1.109 printerr("Too Few Arguments");
1495     env->err= 1;
1496     return;
1497     }
1498    
1499     if(CAR(CDR(env->head))->type!=symb
1500     || strcmp(CAR(CDR(env->head))->content.sym->id, "then")!=0
1501     || CAR(CDR(CDR(CDR(env->head))))->type!=symb
1502     || strcmp(CAR(CDR(CDR(CDR(env->head))))->content.sym->id, "if")!=0) {
1503     printerr("Bad Argument Type");
1504     env->err= 2;
1505     return;
1506     }
1507    
1508     swap(env); toss(env); rot(env); toss(env);
1509     ifelse(env);
1510     }
1511    
1512     extern void then(environment *env)
1513     {
1514 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1515     || CDR(CDR(env->head))->type==empty) {
1516 masse 1.106 printerr("Too Few Arguments");
1517     env->err= 1;
1518     return;
1519     }
1520    
1521     if(CAR(CDR(env->head))->type!=symb
1522     || strcmp(CAR(CDR(env->head))->content.sym->id, "if")!=0) {
1523     printerr("Bad Argument Type");
1524     env->err= 2;
1525     return;
1526     }
1527    
1528     swap(env); toss(env);
1529 masse 1.109 sx_6966(env);
1530 masse 1.58 }
1531    
1532 teddy 1.85 /* "while" */
1533 masse 1.95 extern void sx_7768696c65(environment *env)
1534     {
1535 masse 1.58 int truth;
1536 masse 1.63 value *loop, *test;
1537 masse 1.58
1538 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1539 masse 1.58 printerr("Too Few Arguments");
1540 masse 1.102 env->err= 1;
1541 masse 1.58 return;
1542     }
1543    
1544 masse 1.104 loop= CAR(env->head);
1545 masse 1.98 protect(loop);
1546 masse 1.63 toss(env); if(env->err) return;
1547    
1548 masse 1.104 test= CAR(env->head);
1549 masse 1.98 protect(test);
1550 masse 1.63 toss(env); if(env->err) return;
1551    
1552 masse 1.58 do {
1553 masse 1.72 push_val(env, test);
1554 masse 1.63 eval(env);
1555 masse 1.58
1556 masse 1.104 if(CAR(env->head)->type != integer) {
1557 masse 1.58 printerr("Bad Argument Type");
1558 masse 1.90 env->err= 2;
1559 masse 1.58 return;
1560     }
1561    
1562 masse 1.104 truth= CAR(env->head)->content.i;
1563 masse 1.58 toss(env); if(env->err) return;
1564    
1565     if(truth) {
1566 masse 1.72 push_val(env, loop);
1567 masse 1.58 eval(env);
1568     } else {
1569     toss(env);
1570     }
1571    
1572     } while(truth);
1573 masse 1.90
1574 masse 1.98 unprotect(loop); unprotect(test);
1575 teddy 1.56 }
1576 masse 1.65
1577 masse 1.89
1578     /* "for"; for-loop */
1579 masse 1.95 extern void sx_666f72(environment *env)
1580     {
1581 masse 1.89 value *loop;
1582     int foo1, foo2;
1583    
1584 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1585     || CDR(CDR(env->head))->type==empty) {
1586 masse 1.89 printerr("Too Few Arguments");
1587     env->err= 1;
1588     return;
1589     }
1590    
1591 masse 1.104 if(CAR(CDR(env->head))->type!=integer
1592     || CAR(CDR(CDR(env->head)))->type!=integer) {
1593 masse 1.89 printerr("Bad Argument Type");
1594     env->err= 2;
1595     return;
1596     }
1597    
1598 masse 1.104 loop= CAR(env->head);
1599 masse 1.98 protect(loop);
1600 masse 1.89 toss(env); if(env->err) return;
1601    
1602 masse 1.104 foo2= CAR(env->head)->content.i;
1603 masse 1.89 toss(env); if(env->err) return;
1604    
1605 masse 1.104 foo1= CAR(env->head)->content.i;
1606 masse 1.89 toss(env); if(env->err) return;
1607    
1608     if(foo1<=foo2) {
1609     while(foo1<=foo2) {
1610     push_int(env, foo1);
1611     push_val(env, loop);
1612     eval(env); if(env->err) return;
1613     foo1++;
1614     }
1615     } else {
1616     while(foo1>=foo2) {
1617     push_int(env, foo1);
1618     push_val(env, loop);
1619     eval(env); if(env->err) return;
1620     foo1--;
1621     }
1622     }
1623 masse 1.98 unprotect(loop);
1624 masse 1.89 }
1625    
1626     /* Variant of for-loop */
1627 masse 1.95 extern void foreach(environment *env)
1628     {
1629 masse 1.65 value *loop, *foo;
1630 masse 1.104 value *iterator;
1631 masse 1.65
1632 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1633 masse 1.65 printerr("Too Few Arguments");
1634 masse 1.90 env->err= 1;
1635 masse 1.65 return;
1636     }
1637    
1638 masse 1.104 if(CAR(CDR(env->head))->type!=tcons) {
1639 masse 1.65 printerr("Bad Argument Type");
1640 masse 1.90 env->err= 2;
1641 masse 1.65 return;
1642     }
1643    
1644 masse 1.104 loop= CAR(env->head);
1645 masse 1.98 protect(loop);
1646 masse 1.65 toss(env); if(env->err) return;
1647    
1648 masse 1.104 foo= CAR(env->head);
1649 masse 1.98 protect(foo);
1650 masse 1.65 toss(env); if(env->err) return;
1651    
1652 masse 1.104 iterator= foo;
1653 masse 1.65
1654     while(iterator!=NULL) {
1655 masse 1.104 push_val(env, CAR(iterator));
1656 masse 1.72 push_val(env, loop);
1657 masse 1.65 eval(env); if(env->err) return;
1658 masse 1.105 if (iterator->type == tcons){
1659 masse 1.104 iterator= CDR(iterator);
1660 teddy 1.103 } else {
1661     printerr("Bad Argument Type"); /* Improper list */
1662     env->err= 2;
1663     break;
1664     }
1665 masse 1.65 }
1666 masse 1.98 unprotect(loop); unprotect(foo);
1667 masse 1.65 }
1668 masse 1.66
1669 teddy 1.85 /* "to" */
1670 masse 1.95 extern void to(environment *env)
1671     {
1672     int ending, start, i;
1673 masse 1.121 value *iterator, *temp, *end;
1674    
1675     end= new_val(env);
1676 masse 1.95
1677 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1678 masse 1.66 printerr("Too Few Arguments");
1679 masse 1.102 env->err= 1;
1680 masse 1.66 return;
1681     }
1682    
1683 masse 1.104 if(CAR(env->head)->type!=integer
1684     || CAR(CDR(env->head))->type!=integer) {
1685 masse 1.66 printerr("Bad Argument Type");
1686 masse 1.102 env->err= 2;
1687 masse 1.66 return;
1688     }
1689    
1690 masse 1.104 ending= CAR(env->head)->content.i;
1691 masse 1.66 toss(env); if(env->err) return;
1692 masse 1.104 start= CAR(env->head)->content.i;
1693 masse 1.66 toss(env); if(env->err) return;
1694    
1695 masse 1.95 push_sym(env, "[");
1696 masse 1.66
1697 masse 1.67 if(ending>=start) {
1698 masse 1.74 for(i= ending; i>=start; i--)
1699 masse 1.72 push_int(env, i);
1700 masse 1.67 } else {
1701 masse 1.74 for(i= ending; i<=start; i++)
1702 masse 1.72 push_int(env, i);
1703 masse 1.67 }
1704 masse 1.66
1705 masse 1.95 iterator= env->head;
1706 masse 1.93
1707 teddy 1.111 if(iterator->type==empty
1708 masse 1.104 || (CAR(iterator)->type==symb
1709 masse 1.105 && CAR(iterator)->content.sym->id[0]=='[')) {
1710 masse 1.121 temp= end;
1711 masse 1.95 toss(env);
1712     } else {
1713     /* Search for first delimiter */
1714 masse 1.121 while(CDR(iterator)->type!=empty
1715 masse 1.104 && (CAR(CDR(iterator))->type!=symb
1716 masse 1.105 || CAR(CDR(iterator))->content.sym->id[0]!='['))
1717 masse 1.104 iterator= CDR(iterator);
1718 masse 1.95
1719     /* Extract list */
1720     temp= env->head;
1721 masse 1.104 env->head= CDR(iterator);
1722 masse 1.121 CDR(iterator)= end;
1723 masse 1.95
1724 masse 1.121 if(env->head->type!=empty)
1725 masse 1.95 toss(env);
1726     }
1727    
1728     /* Push list */
1729 masse 1.104 push_val(env, temp);
1730 masse 1.66 }
1731 masse 1.68
1732     /* Read a string */
1733 masse 1.95 extern void readline(environment *env)
1734     {
1735 masse 1.68 char in_string[101];
1736    
1737 teddy 1.84 if(fgets(in_string, 100, env->inputstream)==NULL)
1738     push_cstring(env, "");
1739     else
1740     push_cstring(env, in_string);
1741 masse 1.68 }
1742    
1743 teddy 1.84 /* "read"; Read a value and place on stack */
1744 masse 1.95 extern void sx_72656164(environment *env)
1745     {
1746 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1747     const char strform[]= "\"%[^\"]\"%n";
1748     const char intform[]= "%i%n";
1749 masse 1.93 const char fltform[]= "%f%n";
1750 teddy 1.78 const char blankform[]= "%*[ \t]%n";
1751 masse 1.90 const char ebrackform[]= "]%n";
1752     const char semicform[]= ";%n";
1753     const char bbrackform[]= "[%n";
1754 masse 1.68
1755 teddy 1.78 int itemp, readlength= -1;
1756 masse 1.93 int count= -1;
1757     float ftemp;
1758 masse 1.68 static int depth= 0;
1759 teddy 1.116 char *match;
1760 masse 1.68 size_t inlength;
1761    
1762 masse 1.70 if(env->in_string==NULL) {
1763 teddy 1.84 if(depth > 0 && env->interactive) {
1764 teddy 1.80 printf("]> ");
1765     }
1766 masse 1.68 readline(env); if(env->err) return;
1767 teddy 1.84
1768 masse 1.104 if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1769 teddy 1.85 env->err= 4; /* "" means EOF */
1770 teddy 1.84 return;
1771     }
1772 masse 1.68
1773 masse 1.104 env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1774 teddy 1.118 assert(env->in_string != NULL);
1775 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
1776 masse 1.104 strcpy(env->in_string, CAR(env->head)->content.ptr);
1777 masse 1.68 toss(env); if(env->err) return;
1778     }
1779    
1780 masse 1.70 inlength= strlen(env->in_string)+1;
1781 masse 1.68 match= malloc(inlength);
1782 teddy 1.118 assert(match != NULL);
1783 masse 1.68
1784 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
1785 teddy 1.78 && readlength != -1) {
1786 masse 1.71 ;
1787 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
1788 teddy 1.78 && readlength != -1) {
1789 masse 1.93 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
1790     && count==readlength) {
1791     push_int(env, itemp);
1792     } else {
1793     push_float(env, ftemp);
1794     }
1795 teddy 1.114 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
1796     && readlength != -1) {
1797     push_cstring(env, "");
1798 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1799     && readlength != -1) {
1800 masse 1.72 push_cstring(env, match);
1801 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1802     && readlength != -1) {
1803 masse 1.68 push_sym(env, match);
1804 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1805     && readlength != -1) {
1806 masse 1.68 pack(env); if(env->err) return;
1807 teddy 1.78 if(depth != 0) depth--;
1808     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1809     && readlength != -1) {
1810 masse 1.68 push_sym(env, ";");
1811 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1812     && readlength != -1) {
1813 masse 1.68 push_sym(env, "[");
1814     depth++;
1815     } else {
1816 teddy 1.78 free(env->free_string);
1817     env->in_string = env->free_string = NULL;
1818     }
1819 masse 1.93 if (env->in_string != NULL) {
1820 teddy 1.78 env->in_string += readlength;
1821 masse 1.68 }
1822 masse 1.83
1823     free(match);
1824 masse 1.68
1825 masse 1.71 if(depth)
1826 teddy 1.84 return sx_72656164(env);
1827 teddy 1.91 }
1828    
1829 masse 1.107 #ifdef __linux__
1830 masse 1.95 extern void beep(environment *env)
1831     {
1832 teddy 1.91 int freq, dur, period, ticks;
1833    
1834 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1835 teddy 1.91 printerr("Too Few Arguments");
1836 masse 1.102 env->err= 1;
1837 teddy 1.91 return;
1838     }
1839    
1840 masse 1.104 if(CAR(env->head)->type!=integer
1841     || CAR(CDR(env->head))->type!=integer) {
1842 teddy 1.91 printerr("Bad Argument Type");
1843 masse 1.102 env->err= 2;
1844 teddy 1.91 return;
1845     }
1846    
1847 masse 1.104 dur= CAR(env->head)->content.i;
1848 teddy 1.91 toss(env);
1849 masse 1.104 freq= CAR(env->head)->content.i;
1850 teddy 1.91 toss(env);
1851    
1852 masse 1.102 period= 1193180/freq; /* convert freq from Hz to period
1853 teddy 1.91 length */
1854 masse 1.102 ticks= dur*.001193180; /* convert duration from µseconds to
1855 teddy 1.91 timer ticks */
1856    
1857     /* ticks=dur/1000; */
1858    
1859 masse 1.102 /* if (ioctl(STDOUT_FILENO, KDMKTONE, (125<<16) + 0x637)==0) */
1860 teddy 1.91 switch (ioctl(STDOUT_FILENO, KDMKTONE, (ticks<<16) | period)){
1861     case 0:
1862     usleep(dur);
1863     return;
1864     case -1:
1865     perror("beep");
1866 masse 1.102 env->err= 5;
1867 teddy 1.91 return;
1868     default:
1869     abort();
1870     }
1871 masse 1.95 }
1872 masse 1.107 #endif /* __linux__ */
1873 teddy 1.91
1874     /* "wait" */
1875 masse 1.95 extern void sx_77616974(environment *env)
1876     {
1877 teddy 1.91 int dur;
1878    
1879 teddy 1.111 if(env->head->type==empty) {
1880 teddy 1.91 printerr("Too Few Arguments");
1881 masse 1.102 env->err= 1;
1882 teddy 1.91 return;
1883     }
1884    
1885 masse 1.104 if(CAR(env->head)->type!=integer) {
1886 teddy 1.91 printerr("Bad Argument Type");
1887 masse 1.102 env->err= 2;
1888 teddy 1.91 return;
1889     }
1890    
1891 masse 1.104 dur= CAR(env->head)->content.i;
1892 teddy 1.91 toss(env);
1893    
1894     usleep(dur);
1895 masse 1.95 }
1896 teddy 1.91
1897 masse 1.95 extern void copying(environment *env)
1898     {
1899 teddy 1.111 printf(" GNU GENERAL PUBLIC LICENSE\n\
1900 teddy 1.91 Version 2, June 1991\n\
1901     \n\
1902     Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
1903     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
1904     Everyone is permitted to copy and distribute verbatim copies\n\
1905     of this license document, but changing it is not allowed.\n\
1906     \n\
1907     Preamble\n\
1908     \n\
1909     The licenses for most software are designed to take away your\n\
1910     freedom to share and change it. By contrast, the GNU General Public\n\
1911     License is intended to guarantee your freedom to share and change free\n\
1912     software--to make sure the software is free for all its users. This\n\
1913     General Public License applies to most of the Free Software\n\
1914     Foundation's software and to any other program whose authors commit to\n\
1915     using it. (Some other Free Software Foundation software is covered by\n\
1916     the GNU Library General Public License instead.) You can apply it to\n\
1917     your programs, too.\n\
1918     \n\
1919     When we speak of free software, we are referring to freedom, not\n\
1920     price. Our General Public Licenses are designed to make sure that you\n\
1921     have the freedom to distribute copies of free software (and charge for\n\
1922     this service if you wish), that you receive source code or can get it\n\
1923     if you want it, that you can change the software or use pieces of it\n\
1924     in new free programs; and that you know you can do these things.\n\
1925     \n\
1926     To protect your rights, we need to make restrictions that forbid\n\
1927     anyone to deny you these rights or to ask you to surrender the rights.\n\
1928     These restrictions translate to certain responsibilities for you if you\n\
1929     distribute copies of the software, or if you modify it.\n\
1930     \n\
1931     For example, if you distribute copies of such a program, whether\n\
1932     gratis or for a fee, you must give the recipients all the rights that\n\
1933     you have. You must make sure that they, too, receive or can get the\n\
1934     source code. And you must show them these terms so they know their\n\
1935     rights.\n\
1936     \n\
1937     We protect your rights with two steps: (1) copyright the software, and\n\
1938     (2) offer you this license which gives you legal permission to copy,\n\
1939     distribute and/or modify the software.\n\
1940     \n\
1941     Also, for each author's protection and ours, we want to make certain\n\
1942     that everyone understands that there is no warranty for this free\n\
1943     software. If the software is modified by someone else and passed on, we\n\
1944     want its recipients to know that what they have is not the original, so\n\
1945     that any problems introduced by others will not reflect on the original\n\
1946     authors' reputations.\n\
1947     \n\
1948     Finally, any free program is threatened constantly by software\n\
1949     patents. We wish to avoid the danger that redistributors of a free\n\
1950     program will individually obtain patent licenses, in effect making the\n\
1951     program proprietary. To prevent this, we have made it clear that any\n\
1952     patent must be licensed for everyone's free use or not licensed at all.\n\
1953     \n\
1954     The precise terms and conditions for copying, distribution and\n\
1955     modification follow.\n\
1956     \n\
1957     GNU GENERAL PUBLIC LICENSE\n\
1958     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
1959     \n\
1960     0. This License applies to any program or other work which contains\n\
1961     a notice placed by the copyright holder saying it may be distributed\n\
1962     under the terms of this General Public License. The \"Program\", below,\n\
1963     refers to any such program or work, and a \"work based on the Program\"\n\
1964     means either the Program or any derivative work under copyright law:\n\
1965     that is to say, a work containing the Program or a portion of it,\n\
1966     either verbatim or with modifications and/or translated into another\n\
1967     language. (Hereinafter, translation is included without limitation in\n\
1968     the term \"modification\".) Each licensee is addressed as \"you\".\n\
1969     \n\
1970     Activities other than copying, distribution and modification are not\n\
1971     covered by this License; they are outside its scope. The act of\n\
1972     running the Program is not restricted, and the output from the Program\n\
1973     is covered only if its contents constitute a work based on the\n\
1974     Program (independent of having been made by running the Program).\n\
1975     Whether that is true depends on what the Program does.\n\
1976     \n\
1977     1. You may copy and distribute verbatim copies of the Program's\n\
1978     source code as you receive it, in any medium, provided that you\n\
1979     conspicuously and appropriately publish on each copy an appropriate\n\
1980     copyright notice and disclaimer of warranty; keep intact all the\n\
1981     notices that refer to this License and to the absence of any warranty;\n\
1982     and give any other recipients of the Program a copy of this License\n\
1983     along with the Program.\n\
1984     \n\
1985     You may charge a fee for the physical act of transferring a copy, and\n\
1986     you may at your option offer warranty protection in exchange for a fee.\n\
1987     \n\
1988     2. You may modify your copy or copies of the Program or any portion\n\
1989     of it, thus forming a work based on the Program, and copy and\n\
1990     distribute such modifications or work under the terms of Section 1\n\
1991     above, provided that you also meet all of these conditions:\n\
1992     \n\
1993     a) You must cause the modified files to carry prominent notices\n\
1994     stating that you changed the files and the date of any change.\n\
1995     \n\
1996     b) You must cause any work that you distribute or publish, that in\n\
1997     whole or in part contains or is derived from the Program or any\n\
1998     part thereof, to be licensed as a whole at no charge to all third\n\
1999     parties under the terms of this License.\n\
2000     \n\
2001     c) If the modified program normally reads commands interactively\n\
2002     when run, you must cause it, when started running for such\n\
2003     interactive use in the most ordinary way, to print or display an\n\
2004     announcement including an appropriate copyright notice and a\n\
2005     notice that there is no warranty (or else, saying that you provide\n\
2006     a warranty) and that users may redistribute the program under\n\
2007     these conditions, and telling the user how to view a copy of this\n\
2008     License. (Exception: if the Program itself is interactive but\n\
2009     does not normally print such an announcement, your work based on\n\
2010     the Program is not required to print an announcement.)\n\
2011     \n\
2012     These requirements apply to the modified work as a whole. If\n\
2013     identifiable sections of that work are not derived from the Program,\n\
2014     and can be reasonably considered independent and separate works in\n\
2015     themselves, then this License, and its terms, do not apply to those\n\
2016     sections when you distribute them as separate works. But when you\n\
2017     distribute the same sections as part of a whole which is a work based\n\
2018     on the Program, the distribution of the whole must be on the terms of\n\
2019     this License, whose permissions for other licensees extend to the\n\
2020     entire whole, and thus to each and every part regardless of who wrote it.\n\
2021     \n\
2022     Thus, it is not the intent of this section to claim rights or contest\n\
2023     your rights to work written entirely by you; rather, the intent is to\n\
2024     exercise the right to control the distribution of derivative or\n\
2025     collective works based on the Program.\n\
2026     \n\
2027     In addition, mere aggregation of another work not based on the Program\n\
2028     with the Program (or with a work based on the Program) on a volume of\n\
2029     a storage or distribution medium does not bring the other work under\n\
2030     the scope of this License.\n\
2031     \n\
2032     3. You may copy and distribute the Program (or a work based on it,\n\
2033     under Section 2) in object code or executable form under the terms of\n\
2034     Sections 1 and 2 above provided that you also do one of the following:\n\
2035     \n\
2036     a) Accompany it with the complete corresponding machine-readable\n\
2037     source code, which must be distributed under the terms of Sections\n\
2038     1 and 2 above on a medium customarily used for software interchange; or,\n\
2039     \n\
2040     b) Accompany it with a written offer, valid for at least three\n\
2041     years, to give any third party, for a charge no more than your\n\
2042     cost of physically performing source distribution, a complete\n\
2043     machine-readable copy of the corresponding source code, to be\n\
2044     distributed under the terms of Sections 1 and 2 above on a medium\n\
2045     customarily used for software interchange; or,\n\
2046     \n\
2047     c) Accompany it with the information you received as to the offer\n\
2048     to distribute corresponding source code. (This alternative is\n\
2049     allowed only for noncommercial distribution and only if you\n\
2050     received the program in object code or executable form with such\n\
2051     an offer, in accord with Subsection b above.)\n\
2052     \n\
2053     The source code for a work means the preferred form of the work for\n\
2054     making modifications to it. For an executable work, complete source\n\
2055     code means all the source code for all modules it contains, plus any\n\
2056     associated interface definition files, plus the scripts used to\n\
2057     control compilation and installation of the executable. However, as a\n\
2058     special exception, the source code distributed need not include\n\
2059     anything that is normally distributed (in either source or binary\n\
2060     form) with the major components (compiler, kernel, and so on) of the\n\
2061     operating system on which the executable runs, unless that component\n\
2062     itself accompanies the executable.\n\
2063     \n\
2064     If distribution of executable or object code is made by offering\n\
2065     access to copy from a designated place, then offering equivalent\n\
2066     access to copy the source code from the same place counts as\n\
2067     distribution of the source code, even though third parties are not\n\
2068     compelled to copy the source along with the object code.\n\
2069     \n\
2070     4. You may not copy, modify, sublicense, or distribute the Program\n\
2071     except as expressly provided under this License. Any attempt\n\
2072     otherwise to copy, modify, sublicense or distribute the Program is\n\
2073     void, and will automatically terminate your rights under this License.\n\
2074     However, parties who have received copies, or rights, from you under\n\
2075     this License will not have their licenses terminated so long as such\n\
2076     parties remain in full compliance.\n\
2077     \n\
2078     5. You are not required to accept this License, since you have not\n\
2079     signed it. However, nothing else grants you permission to modify or\n\
2080     distribute the Program or its derivative works. These actions are\n\
2081     prohibited by law if you do not accept this License. Therefore, by\n\
2082     modifying or distributing the Program (or any work based on the\n\
2083     Program), you indicate your acceptance of this License to do so, and\n\
2084     all its terms and conditions for copying, distributing or modifying\n\
2085     the Program or works based on it.\n\
2086     \n\
2087     6. Each time you redistribute the Program (or any work based on the\n\
2088     Program), the recipient automatically receives a license from the\n\
2089     original licensor to copy, distribute or modify the Program subject to\n\
2090     these terms and conditions. You may not impose any further\n\
2091     restrictions on the recipients' exercise of the rights granted herein.\n\
2092     You are not responsible for enforcing compliance by third parties to\n\
2093     this License.\n\
2094     \n\
2095     7. If, as a consequence of a court judgment or allegation of patent\n\
2096     infringement or for any other reason (not limited to patent issues),\n\
2097     conditions are imposed on you (whether by court order, agreement or\n\
2098     otherwise) that contradict the conditions of this License, they do not\n\
2099     excuse you from the conditions of this License. If you cannot\n\
2100     distribute so as to satisfy simultaneously your obligations under this\n\
2101     License and any other pertinent obligations, then as a consequence you\n\
2102     may not distribute the Program at all. For example, if a patent\n\
2103     license would not permit royalty-free redistribution of the Program by\n\
2104     all those who receive copies directly or indirectly through you, then\n\
2105     the only way you could satisfy both it and this License would be to\n\
2106     refrain entirely from distribution of the Program.\n\
2107     \n\
2108     If any portion of this section is held invalid or unenforceable under\n\
2109     any particular circumstance, the balance of the section is intended to\n\
2110     apply and the section as a whole is intended to apply in other\n\
2111     circumstances.\n\
2112     \n\
2113     It is not the purpose of this section to induce you to infringe any\n\
2114     patents or other property right claims or to contest validity of any\n\
2115     such claims; this section has the sole purpose of protecting the\n\
2116     integrity of the free software distribution system, which is\n\
2117     implemented by public license practices. Many people have made\n\
2118     generous contributions to the wide range of software distributed\n\
2119     through that system in reliance on consistent application of that\n\
2120     system; it is up to the author/donor to decide if he or she is willing\n\
2121     to distribute software through any other system and a licensee cannot\n\
2122     impose that choice.\n\
2123     \n\
2124     This section is intended to make thoroughly clear what is believed to\n\
2125     be a consequence of the rest of this License.\n\
2126     \n\
2127     8. If the distribution and/or use of the Program is restricted in\n\
2128     certain countries either by patents or by copyrighted interfaces, the\n\
2129     original copyright holder who places the Program under this License\n\
2130     may add an explicit geographical distribution limitation excluding\n\
2131     those countries, so that distribution is permitted only in or among\n\
2132     countries not thus excluded. In such case, this License incorporates\n\
2133     the limitation as if written in the body of this License.\n\
2134     \n\
2135     9. The Free Software Foundation may publish revised and/or new versions\n\
2136     of the General Public License from time to time. Such new versions will\n\
2137     be similar in spirit to the present version, but may differ in detail to\n\
2138     address new problems or concerns.\n\
2139     \n\
2140     Each version is given a distinguishing version number. If the Program\n\
2141     specifies a version number of this License which applies to it and \"any\n\
2142     later version\", you have the option of following the terms and conditions\n\
2143     either of that version or of any later version published by the Free\n\
2144     Software Foundation. If the Program does not specify a version number of\n\
2145     this License, you may choose any version ever published by the Free Software\n\
2146     Foundation.\n\
2147     \n\
2148     10. If you wish to incorporate parts of the Program into other free\n\
2149     programs whose distribution conditions are different, write to the author\n\
2150     to ask for permission. For software which is copyrighted by the Free\n\
2151     Software Foundation, write to the Free Software Foundation; we sometimes\n\
2152     make exceptions for this. Our decision will be guided by the two goals\n\
2153     of preserving the free status of all derivatives of our free software and\n\
2154     of promoting the sharing and reuse of software generally.\n");
2155     }
2156    
2157 masse 1.95 extern void warranty(environment *env)
2158     {
2159 teddy 1.91 printf(" NO WARRANTY\n\
2160     \n\
2161     11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
2162     FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
2163     OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
2164     PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
2165     OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
2166     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
2167     TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
2168     PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
2169     REPAIR OR CORRECTION.\n\
2170     \n\
2171     12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
2172     WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
2173     REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
2174     INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
2175     OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
2176     TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
2177     YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
2178     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
2179     POSSIBILITY OF SUCH DAMAGES.\n");
2180 masse 1.92 }
2181    
2182     /* "*" */
2183     extern void sx_2a(environment *env)
2184     {
2185     int a, b;
2186 masse 1.93 float fa, fb;
2187 masse 1.92
2188 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2189 masse 1.92 printerr("Too Few Arguments");
2190 masse 1.102 env->err= 1;
2191 masse 1.92 return;
2192     }
2193    
2194 masse 1.104 if(CAR(env->head)->type==integer
2195     && CAR(CDR(env->head))->type==integer) {
2196     a= CAR(env->head)->content.i;
2197 masse 1.93 toss(env); if(env->err) return;
2198 masse 1.104 b= CAR(env->head)->content.i;
2199 masse 1.93 toss(env); if(env->err) return;
2200     push_int(env, b*a);
2201    
2202     return;
2203     }
2204    
2205 masse 1.104 if(CAR(env->head)->type==tfloat
2206     && CAR(CDR(env->head))->type==tfloat) {
2207     fa= CAR(env->head)->content.f;
2208 masse 1.93 toss(env); if(env->err) return;
2209 masse 1.104 fb= CAR(env->head)->content.f;
2210 masse 1.93 toss(env); if(env->err) return;
2211     push_float(env, fb*fa);
2212    
2213     return;
2214     }
2215    
2216 masse 1.104 if(CAR(env->head)->type==tfloat
2217     && CAR(CDR(env->head))->type==integer) {
2218     fa= CAR(env->head)->content.f;
2219 masse 1.93 toss(env); if(env->err) return;
2220 masse 1.104 b= CAR(env->head)->content.i;
2221 masse 1.93 toss(env); if(env->err) return;
2222     push_float(env, b*fa);
2223    
2224     return;
2225     }
2226    
2227 masse 1.104 if(CAR(env->head)->type==integer
2228     && CAR(CDR(env->head))->type==tfloat) {
2229     a= CAR(env->head)->content.i;
2230 masse 1.93 toss(env); if(env->err) return;
2231 masse 1.104 fb= CAR(env->head)->content.f;
2232 masse 1.93 toss(env); if(env->err) return;
2233     push_float(env, fb*a);
2234    
2235 masse 1.92 return;
2236     }
2237    
2238 masse 1.93 printerr("Bad Argument Type");
2239 masse 1.102 env->err= 2;
2240 masse 1.92 }
2241    
2242     /* "/" */
2243     extern void sx_2f(environment *env)
2244     {
2245     int a, b;
2246 masse 1.93 float fa, fb;
2247 masse 1.92
2248 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2249 masse 1.92 printerr("Too Few Arguments");
2250 masse 1.102 env->err= 1;
2251 masse 1.92 return;
2252     }
2253    
2254 masse 1.104 if(CAR(env->head)->type==integer
2255     && CAR(CDR(env->head))->type==integer) {
2256     a= CAR(env->head)->content.i;
2257 masse 1.93 toss(env); if(env->err) return;
2258 masse 1.104 b= CAR(env->head)->content.i;
2259 masse 1.93 toss(env); if(env->err) return;
2260     push_float(env, b/a);
2261    
2262     return;
2263     }
2264    
2265 masse 1.104 if(CAR(env->head)->type==tfloat
2266     && CAR(CDR(env->head))->type==tfloat) {
2267     fa= CAR(env->head)->content.f;
2268 masse 1.93 toss(env); if(env->err) return;
2269 masse 1.104 fb= CAR(env->head)->content.f;
2270 masse 1.93 toss(env); if(env->err) return;
2271     push_float(env, fb/fa);
2272    
2273     return;
2274     }
2275    
2276 masse 1.104 if(CAR(env->head)->type==tfloat
2277     && CAR(CDR(env->head))->type==integer) {
2278     fa= CAR(env->head)->content.f;
2279 masse 1.93 toss(env); if(env->err) return;
2280 masse 1.104 b= CAR(env->head)->content.i;
2281 masse 1.93 toss(env); if(env->err) return;
2282     push_float(env, b/fa);
2283    
2284     return;
2285     }
2286    
2287 masse 1.104 if(CAR(env->head)->type==integer
2288     && CAR(CDR(env->head))->type==tfloat) {
2289     a= CAR(env->head)->content.i;
2290 masse 1.93 toss(env); if(env->err) return;
2291 masse 1.104 fb= CAR(env->head)->content.f;
2292 masse 1.93 toss(env); if(env->err) return;
2293     push_float(env, fb/a);
2294    
2295 masse 1.92 return;
2296     }
2297    
2298 masse 1.93 printerr("Bad Argument Type");
2299 masse 1.102 env->err= 2;
2300 masse 1.92 }
2301    
2302     /* "mod" */
2303     extern void mod(environment *env)
2304     {
2305     int a, b;
2306    
2307 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2308 masse 1.92 printerr("Too Few Arguments");
2309 masse 1.94 env->err= 1;
2310 masse 1.92 return;
2311     }
2312    
2313 masse 1.104 if(CAR(env->head)->type==integer
2314     && CAR(CDR(env->head))->type==integer) {
2315     a= CAR(env->head)->content.i;
2316 masse 1.93 toss(env); if(env->err) return;
2317 masse 1.104 b= CAR(env->head)->content.i;
2318 masse 1.93 toss(env); if(env->err) return;
2319     push_int(env, b%a);
2320    
2321 masse 1.92 return;
2322     }
2323    
2324 masse 1.93 printerr("Bad Argument Type");
2325 masse 1.102 env->err= 2;
2326 masse 1.94 }
2327    
2328     /* "div" */
2329     extern void sx_646976(environment *env)
2330     {
2331     int a, b;
2332    
2333 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2334 masse 1.94 printerr("Too Few Arguments");
2335     env->err= 1;
2336     return;
2337     }
2338    
2339 masse 1.104 if(CAR(env->head)->type==integer
2340     && CAR(CDR(env->head))->type==integer) {
2341     a= CAR(env->head)->content.i;
2342 masse 1.94 toss(env); if(env->err) return;
2343 masse 1.104 b= CAR(env->head)->content.i;
2344 masse 1.94 toss(env); if(env->err) return;
2345     push_int(env, (int)b/a);
2346    
2347     return;
2348     }
2349    
2350     printerr("Bad Argument Type");
2351     env->err= 2;
2352 teddy 1.113 }
2353    
2354     extern void setcar(environment *env)
2355     {
2356     if(env->head->type==empty || CDR(env->head)->type==empty) {
2357     printerr("Too Few Arguments");
2358     env->err= 1;
2359     return;
2360     }
2361    
2362     if(CDR(env->head)->type!=tcons) {
2363     printerr("Bad Argument Type");
2364     env->err= 2;
2365     return;
2366     }
2367    
2368     CAR(CAR(CDR(env->head)))=CAR(env->head);
2369     toss(env);
2370     }
2371    
2372     extern void setcdr(environment *env)
2373     {
2374     if(env->head->type==empty || CDR(env->head)->type==empty) {
2375     printerr("Too Few Arguments");
2376     env->err= 1;
2377     return;
2378     }
2379    
2380     if(CDR(env->head)->type!=tcons) {
2381     printerr("Bad Argument Type");
2382     env->err= 2;
2383     return;
2384     }
2385    
2386     CDR(CAR(CDR(env->head)))=CAR(env->head);
2387     toss(env);
2388     }
2389    
2390     extern void car(environment *env)
2391     {
2392     if(env->head->type==empty) {
2393     printerr("Too Few Arguments");
2394     env->err= 1;
2395     return;
2396     }
2397    
2398     if(CAR(env->head)->type!=tcons) {
2399     printerr("Bad Argument Type");
2400     env->err= 2;
2401     return;
2402     }
2403    
2404     CAR(env->head)=CAR(CAR(env->head));
2405     }
2406    
2407     extern void cdr(environment *env)
2408     {
2409     if(env->head->type==empty) {
2410     printerr("Too Few Arguments");
2411     env->err= 1;
2412     return;
2413     }
2414    
2415     if(CAR(env->head)->type!=tcons) {
2416     printerr("Bad Argument Type");
2417     env->err= 2;
2418     return;
2419     }
2420    
2421     CAR(env->head)=CDR(CAR(env->head));
2422 teddy 1.115 }
2423    
2424     extern void cons(environment *env)
2425     {
2426     value *val;
2427    
2428     if(env->head->type==empty || CDR(env->head)->type==empty) {
2429     printerr("Too Few Arguments");
2430     env->err= 1;
2431     return;
2432     }
2433    
2434     val=new_val(env);
2435     val->content.c= malloc(sizeof(pair));
2436     assert(val->content.c!=NULL);
2437 teddy 1.116
2438     env->gc_count += sizeof(pair);
2439 teddy 1.115 val->type=tcons;
2440    
2441     CAR(val)= CAR(CDR(env->head));
2442     CDR(val)= CAR(env->head);
2443    
2444     push_val(env, val);
2445    
2446     swap(env); if(env->err) return;
2447     toss(env); if(env->err) return;
2448     swap(env); if(env->err) return;
2449     toss(env); if(env->err) return;
2450 teddy 1.119 }
2451    
2452     /* 2: 3 => */
2453     /* 1: [ [ 1 . 2 ] [ 3 . 4 ] ] => 1: [ 3 . 4 ] */
2454     extern void assq(environment *env)
2455     {
2456 teddy 1.120 assocgen(env, eq);
2457     }
2458    
2459    
2460     /* General assoc function */
2461     void assocgen(environment *env, funcp eqfunc)
2462     {
2463 teddy 1.119 value *key, *item;
2464    
2465     /* Needs two values on the stack, the top one must be an association
2466     list */
2467     if(env->head->type==empty || CDR(env->head)->type==empty) {
2468     printerr("Too Few Arguments");
2469     env->err= 1;
2470     return;
2471     }
2472    
2473     if(CAR(env->head)->type!=tcons) {
2474     printerr("Bad Argument Type");
2475     env->err= 2;
2476     return;
2477     }
2478    
2479     key=CAR(CDR(env->head));
2480     item=CAR(env->head);
2481    
2482     while(item->type == tcons){
2483     if(CAR(item)->type != tcons){
2484     printerr("Bad Argument Type");
2485     env->err= 2;
2486     return;
2487     }
2488     push_val(env, key);
2489     push_val(env, CAR(CAR(item)));
2490 teddy 1.120 eqfunc(env); if(env->err) return;
2491    
2492     /* Check the result of 'eqfunc' */
2493     if(env->head->type==empty) {
2494     printerr("Too Few Arguments");
2495     env->err= 1;
2496     return;
2497     }
2498     if(CAR(env->head)->type!=integer) {
2499     printerr("Bad Argument Type");
2500     env->err= 2;
2501     return;
2502     }
2503    
2504 teddy 1.119 if(CAR(env->head)->content.i){
2505 teddy 1.120 toss(env); if(env->err) return;
2506 teddy 1.119 break;
2507     }
2508 teddy 1.120 toss(env); if(env->err) return;
2509    
2510     if(item->type!=tcons) {
2511     printerr("Bad Argument Type");
2512     env->err= 2;
2513     return;
2514     }
2515    
2516 teddy 1.119 item=CDR(item);
2517     }
2518    
2519     if(item->type == tcons){ /* A match was found */
2520     push_val(env, CAR(item));
2521     } else {
2522     push_int(env, 0);
2523     }
2524     swap(env); if(env->err) return;
2525     toss(env); if(env->err) return;
2526     swap(env); if(env->err) return;
2527     toss(env);
2528 masse 1.68 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26