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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.127 - (hide annotations)
Mon Aug 4 11:57:33 2003 UTC (20 years, 8 months ago) by masse
Branch: MAIN
Changes since 1.126: +3 -3 lines
File MIME type: text/plain
(gc_init) Making use of macros "CAR" and "CDR".

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.88 #include "stack.h"
25 masse 1.1
26 teddy 1.28 /* Initialize a newly created environment */
27     void init_env(environment *env)
28 masse 1.1 {
29 masse 1.46 int i;
30 masse 1.1
31 teddy 1.100 env->gc_limit= 400000;
32 masse 1.87 env->gc_count= 0;
33 masse 1.90 env->gc_ref= NULL;
34 masse 1.87
35 teddy 1.111 env->head= new_val(env);
36 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
37 teddy 1.28 env->symbols[i]= NULL;
38 teddy 1.84 env->err= 0;
39     env->in_string= NULL;
40     env->free_string= NULL;
41     env->inputstream= stdin;
42     env->interactive= 1;
43 masse 1.1 }
44    
45 masse 1.95 void printerr(const char* in_string)
46     {
47 teddy 1.48 fprintf(stderr, "Err: %s\n", in_string);
48     }
49    
50 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
51 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
52 masse 1.1 {
53 masse 1.46 int i= 0;
54     unsigned int out_hash= 0;
55 teddy 1.18 char key= '\0';
56 teddy 1.28 symbol **position;
57 masse 1.1
58 masse 1.16 while(1){ /* Hash in_string */
59 masse 1.1 key= in_string[i++];
60     if(key=='\0')
61     break;
62     out_hash= out_hash*32+key;
63     }
64    
65     out_hash= out_hash%HASHTBLSIZE;
66     position= &(in_hashtbl[out_hash]);
67    
68 masse 1.25 while(1){
69 teddy 1.18 if(*position==NULL) /* If empty */
70 masse 1.1 return position;
71    
72 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
73 masse 1.1 return position;
74    
75 masse 1.16 position= &((*position)->next); /* Try next */
76 masse 1.1 }
77     }
78    
79 masse 1.95 /* Create new value */
80     value* new_val(environment *env)
81     {
82 masse 1.87 value *nval= malloc(sizeof(value));
83     stackitem *nitem= malloc(sizeof(stackitem));
84    
85 teddy 1.118 assert(nval != NULL);
86     assert(nitem != NULL);
87    
88 masse 1.87 nval->content.ptr= NULL;
89 teddy 1.117 nval->type= empty;
90 masse 1.87
91     nitem->item= nval;
92     nitem->next= env->gc_ref;
93 masse 1.102
94 masse 1.87 env->gc_ref= nitem;
95    
96 teddy 1.101 env->gc_count += sizeof(value);
97 teddy 1.99 nval->gc.flag.mark= 0;
98     nval->gc.flag.protect= 0;
99 masse 1.93
100 masse 1.87 return nval;
101     }
102    
103 masse 1.126
104 masse 1.95 /* Mark values recursively.
105     Marked values are not collected by the GC. */
106 teddy 1.96 inline void gc_mark(value *val)
107 masse 1.95 {
108 masse 1.102 if(val==NULL || val->gc.flag.mark)
109 masse 1.87 return;
110    
111 teddy 1.99 val->gc.flag.mark= 1;
112 masse 1.87
113 masse 1.104 if(val->type==tcons) {
114     gc_mark(CAR(val));
115     gc_mark(CDR(val));
116 masse 1.87 }
117     }
118    
119 teddy 1.96
120 masse 1.95 /* Start GC */
121     extern void gc_init(environment *env)
122     {
123 masse 1.102 stackitem *new_head= NULL, *titem;
124 masse 1.87 symbol *tsymb;
125     int i;
126    
127 masse 1.102 if(env->interactive)
128 teddy 1.101 printf("Garbage collecting.");
129 teddy 1.100
130 masse 1.95 /* Mark values on stack */
131 masse 1.104 gc_mark(env->head);
132 masse 1.87
133 masse 1.102 if(env->interactive)
134 teddy 1.100 printf(".");
135 masse 1.102
136 teddy 1.100
137 masse 1.93 /* Mark values in hashtable */
138 masse 1.102 for(i= 0; i<HASHTBLSIZE; i++)
139     for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next)
140 masse 1.97 if (tsymb->val != NULL)
141     gc_mark(tsymb->val);
142 masse 1.87
143 masse 1.102
144     if(env->interactive)
145 teddy 1.100 printf(".");
146 masse 1.102
147 masse 1.87 env->gc_count= 0;
148    
149 masse 1.95 while(env->gc_ref!=NULL) { /* Sweep unused values */
150 masse 1.90
151 teddy 1.99 if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */
152 masse 1.93
153 teddy 1.116 /* Remove content */
154     switch(env->gc_ref->item->type){
155     case string:
156 masse 1.87 free(env->gc_ref->item->content.ptr);
157 teddy 1.116 break;
158     case tcons:
159     free(env->gc_ref->item->content.c);
160     break;
161 teddy 1.124 case port:
162 teddy 1.116 case empty:
163     case integer:
164     case tfloat:
165     case func:
166     case symb:
167     /* Symbol strings are freed when walking the hash table */
168 masse 1.126 break;
169 teddy 1.116 }
170 masse 1.102
171 masse 1.93 free(env->gc_ref->item); /* Remove from gc_ref */
172 masse 1.87 titem= env->gc_ref->next;
173 masse 1.93 free(env->gc_ref); /* Remove value */
174 masse 1.87 env->gc_ref= titem;
175 masse 1.97 continue;
176 teddy 1.110 }
177     #ifdef DEBUG
178     printf("Kept value (%p)", env->gc_ref->item);
179     if(env->gc_ref->item->gc.flag.mark)
180     printf(" (marked)");
181     if(env->gc_ref->item->gc.flag.protect)
182     printf(" (protected)");
183     switch(env->gc_ref->item->type){
184     case integer:
185     printf(" integer: %d", env->gc_ref->item->content.i);
186     break;
187     case func:
188     printf(" func: %p", env->gc_ref->item->content.ptr);
189     break;
190     case symb:
191     printf(" symb: %s", env->gc_ref->item->content.sym->id);
192     break;
193     case tcons:
194 masse 1.127 printf(" tcons: %p\t%p", CAR(env->gc_ref->item),
195     CDR(env->gc_ref->item));
196 teddy 1.110 break;
197     default:
198     printf(" <unknown %d>", (env->gc_ref->item->type));
199     }
200     printf("\n");
201     #endif /* DEBUG */
202 masse 1.102
203     /* Keep values */
204     env->gc_count += sizeof(value);
205     if(env->gc_ref->item->type==string)
206 teddy 1.114 env->gc_count += strlen(env->gc_ref->item->content.ptr)+1;
207 masse 1.97
208     titem= env->gc_ref->next;
209     env->gc_ref->next= new_head;
210     new_head= env->gc_ref;
211 teddy 1.99 new_head->item->gc.flag.mark= 0;
212 masse 1.97 env->gc_ref= titem;
213 masse 1.87 }
214    
215 teddy 1.100 if (env->gc_limit < env->gc_count*2)
216     env->gc_limit= env->gc_count*2;
217 teddy 1.101
218 masse 1.87 env->gc_ref= new_head;
219 teddy 1.100
220 masse 1.102 if(env->interactive)
221 teddy 1.110 printf("done (%d bytes still allocated)\n", env->gc_count);
222 teddy 1.100
223 masse 1.87 }
224    
225 masse 1.126 inline void gc_maybe(environment *env)
226     {
227     if(env->gc_count < env->gc_limit)
228     return;
229     else
230     return gc_init(env);
231     }
232    
233 masse 1.95 /* Protect values from GC */
234 masse 1.98 void protect(value *val)
235 masse 1.90 {
236 masse 1.102 if(val==NULL || val->gc.flag.protect)
237 masse 1.98 return;
238    
239 teddy 1.99 val->gc.flag.protect= 1;
240 masse 1.98
241 masse 1.104 if(val->type==tcons) {
242     protect(CAR(val));
243     protect(CDR(val));
244 masse 1.98 }
245 masse 1.90 }
246    
247 masse 1.95 /* Unprotect values from GC */
248 masse 1.98 void unprotect(value *val)
249 masse 1.90 {
250 masse 1.102 if(val==NULL || !(val->gc.flag.protect))
251 masse 1.98 return;
252    
253 teddy 1.99 val->gc.flag.protect= 0;
254 masse 1.98
255 masse 1.104 if(val->type==tcons) {
256     unprotect(CAR(val));
257     unprotect(CDR(val));
258 masse 1.98 }
259 masse 1.90 }
260    
261 teddy 1.29 /* Push a value onto the stack */
262 masse 1.72 void push_val(environment *env, value *val)
263 teddy 1.29 {
264 masse 1.104 value *new_value= new_val(env);
265 masse 1.102
266 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
267 masse 1.108 assert(new_value->content.c!=NULL);
268 teddy 1.116 env->gc_count += sizeof(pair);
269 masse 1.104 new_value->type= tcons;
270     CAR(new_value)= val;
271     CDR(new_value)= env->head;
272     env->head= new_value;
273 teddy 1.29 }
274    
275 masse 1.95 /* Push an integer onto the stack */
276 masse 1.72 void push_int(environment *env, int in_val)
277 masse 1.1 {
278 masse 1.87 value *new_value= new_val(env);
279 teddy 1.28
280 masse 1.93 new_value->content.i= in_val;
281 teddy 1.28 new_value->type= integer;
282 masse 1.1
283 masse 1.75 push_val(env, new_value);
284 masse 1.1 }
285    
286 masse 1.95 /* Push a floating point number onto the stack */
287 masse 1.93 void push_float(environment *env, float in_val)
288     {
289     value *new_value= new_val(env);
290    
291     new_value->content.f= in_val;
292     new_value->type= tfloat;
293    
294     push_val(env, new_value);
295     }
296    
297 masse 1.14 /* Copy a string onto the stack. */
298 masse 1.72 void push_cstring(environment *env, const char *in_string)
299 masse 1.1 {
300 masse 1.87 value *new_value= new_val(env);
301 teddy 1.101 int length= strlen(in_string)+1;
302 teddy 1.28
303 teddy 1.101 new_value->content.ptr= malloc(length);
304 teddy 1.118 assert(new_value != NULL);
305 teddy 1.101 env->gc_count += length;
306 teddy 1.28 strcpy(new_value->content.ptr, in_string);
307     new_value->type= string;
308 masse 1.1
309 masse 1.75 push_val(env, new_value);
310 masse 1.1 }
311    
312 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
313 masse 1.95 char *mangle_str(const char *old_string)
314     {
315 masse 1.90 char validchars[]= "0123456789abcdef";
316 teddy 1.48 char *new_string, *current;
317    
318 masse 1.90 new_string= malloc((strlen(old_string)*2)+4);
319 teddy 1.118 assert(new_string != NULL);
320 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
321 masse 1.90 current= new_string+3;
322 teddy 1.48 while(old_string[0] != '\0'){
323 masse 1.90 current[0]= validchars[(unsigned char)(old_string[0])/16];
324     current[1]= validchars[(unsigned char)(old_string[0])%16];
325     current+= 2;
326 teddy 1.48 old_string++;
327     }
328 masse 1.90 current[0]= '\0';
329 teddy 1.48
330     return new_string; /* The caller must free() it */
331     }
332    
333 masse 1.95 extern void mangle(environment *env)
334     {
335 teddy 1.48 char *new_string;
336    
337 teddy 1.111 if(env->head->type==empty) {
338 teddy 1.48 printerr("Too Few Arguments");
339 masse 1.90 env->err= 1;
340 teddy 1.48 return;
341     }
342    
343 masse 1.104 if(CAR(env->head)->type!=string) {
344 teddy 1.48 printerr("Bad Argument Type");
345 masse 1.90 env->err= 2;
346 teddy 1.48 return;
347     }
348    
349 masse 1.104 new_string=
350     mangle_str((const char *)(CAR(env->head)->content.ptr));
351 teddy 1.48
352     toss(env);
353     if(env->err) return;
354    
355 masse 1.81 push_cstring(env, new_string);
356 teddy 1.48 }
357    
358 teddy 1.28 /* Push a symbol onto the stack. */
359 teddy 1.35 void push_sym(environment *env, const char *in_string)
360 masse 1.1 {
361 teddy 1.28 value *new_value; /* A new symbol value */
362     /* ...which might point to... */
363 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
364 teddy 1.28 /* ...which, if possible, will be bound to... */
365     value *new_fvalue; /* (if needed) A new function value */
366     /* ...which will point to... */
367     void *funcptr; /* A function pointer */
368    
369     static void *handle= NULL; /* Dynamic linker handle */
370 teddy 1.48 const char *dlerr; /* Dynamic linker error */
371     char *mangled; /* Mangled function name */
372 teddy 1.28
373 masse 1.87 new_value= new_val(env);
374 masse 1.98 protect(new_value);
375 masse 1.93 new_fvalue= new_val(env);
376 masse 1.98 protect(new_fvalue);
377 teddy 1.28
378     /* The new value is a symbol */
379     new_value->type= symb;
380    
381     /* Look up the symbol name in the hash table */
382 teddy 1.29 new_symbol= hash(env->symbols, in_string);
383     new_value->content.ptr= *new_symbol;
384 teddy 1.28
385 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
386 teddy 1.28
387     /* Create a new symbol */
388 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
389 teddy 1.118 assert((*new_symbol) != NULL);
390 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
391     (*new_symbol)->next= NULL;
392     (*new_symbol)->id= malloc(strlen(in_string)+1);
393 teddy 1.118 assert((*new_symbol)->id != NULL);
394 teddy 1.29 strcpy((*new_symbol)->id, in_string);
395 masse 1.1
396 teddy 1.28 /* Intern the new symbol in the hash table */
397 teddy 1.29 new_value->content.ptr= *new_symbol;
398 masse 1.1
399 teddy 1.28 /* Try to load the symbol name as an external function, to see if
400     we should bind the symbol to a new function pointer value */
401 masse 1.16 if(handle==NULL) /* If no handle */
402 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
403 masse 1.6
404 masse 1.90 mangled= mangle_str(in_string); /* mangle the name */
405 teddy 1.86 funcptr= dlsym(handle, mangled); /* and try to find it */
406 masse 1.95
407 masse 1.90 dlerr= dlerror();
408 teddy 1.48 if(dlerr != NULL) { /* If no function was found */
409 teddy 1.86 funcptr= dlsym(handle, in_string); /* Get function pointer */
410 masse 1.90 dlerr= dlerror();
411 teddy 1.48 }
412 masse 1.95
413 teddy 1.48 if(dlerr==NULL) { /* If a function was found */
414 masse 1.90 new_fvalue->type= func; /* The new value is a function pointer */
415     new_fvalue->content.ptr= funcptr; /* Store function pointer */
416 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
417     function value */
418 teddy 1.28 }
419 masse 1.95
420     free(mangled);
421 masse 1.1 }
422 masse 1.95
423 masse 1.75 push_val(env, new_value);
424 masse 1.98 unprotect(new_value); unprotect(new_fvalue);
425 masse 1.1 }
426    
427 teddy 1.114 /* Print a value */
428 teddy 1.124 void print_val(environment *env, value *val, int noquote, stackitem *stack, FILE *stream)
429 masse 1.8 {
430 teddy 1.117 stackitem *titem, *tstack;
431     int depth;
432    
433 teddy 1.113 switch(val->type) {
434 teddy 1.112 case empty:
435 teddy 1.124 if(fprintf(stream, "[]") < 0){
436     perror("print_val");
437     env->err= 5;
438     return;
439     }
440 teddy 1.112 break;
441 teddy 1.28 case integer:
442 teddy 1.124 if(fprintf(stream, "%d", val->content.i) < 0){
443     perror("print_val");
444     env->err= 5;
445     return;
446     }
447 masse 1.93 break;
448     case tfloat:
449 teddy 1.124 if(fprintf(stream, "%f", val->content.f) < 0){
450     perror("print_val");
451     env->err= 5;
452     return;
453     }
454 teddy 1.2 break;
455     case string:
456 teddy 1.124 if(noquote){
457     if(fprintf(stream, "%s", (char*)(val->content.ptr)) < 0){
458     perror("print_val");
459     env->err= 5;
460     return;
461     }
462     } else { /* quote */
463     if(fprintf(stream, "\"%s\"", (char*)(val->content.ptr)) < 0){
464     perror("print_val");
465     env->err= 5;
466     return;
467     }
468     }
469 teddy 1.2 break;
470 teddy 1.28 case symb:
471 teddy 1.124 if(fprintf(stream, "%s", val->content.sym->id) < 0){
472     perror("print_val");
473     env->err= 5;
474     return;
475     }
476 masse 1.6 break;
477 teddy 1.35 case func:
478 teddy 1.124 if(fprintf(stream, "#<function %p>", (funcp)(val->content.ptr)) < 0){
479     perror("print_val");
480     env->err= 5;
481     return;
482     }
483     break;
484     case port:
485     if(fprintf(stream, "#<port %p>", (funcp)(val->content.p)) < 0){
486     perror("print_val");
487     env->err= 5;
488     return;
489     }
490 teddy 1.35 break;
491 masse 1.102 case tcons:
492 teddy 1.124 if(fprintf(stream, "[ ") < 0){
493     perror("print_val");
494     env->err= 5;
495     return;
496     }
497 teddy 1.117 tstack= stack;
498 teddy 1.113 do {
499 teddy 1.117 titem=malloc(sizeof(stackitem));
500 teddy 1.118 assert(titem != NULL);
501 teddy 1.117 titem->item=val;
502     titem->next=tstack;
503     tstack=titem; /* Put it on the stack */
504     /* Search a stack of values being printed to see if we are already
505     printing this value */
506     titem=tstack;
507     depth=0;
508     while(titem != NULL && titem->item != CAR(val)){
509     titem=titem->next;
510     depth++;
511     }
512     if(titem != NULL){ /* If we found it on the stack, */
513 teddy 1.124 if(fprintf(stream, "#%d#", depth) < 0){ /* print a depth reference */
514     perror("print_val");
515     env->err= 5;
516     free(titem);
517     return;
518     }
519 teddy 1.117 } else {
520 teddy 1.124 print_val(env, CAR(val), noquote, tstack, stream);
521 teddy 1.117 }
522 teddy 1.114 val= CDR(val);
523     switch(val->type){
524 teddy 1.112 case empty:
525     break;
526     case tcons:
527 teddy 1.117 /* Search a stack of values being printed to see if we are already
528     printing this value */
529     titem=tstack;
530     depth=0;
531     while(titem != NULL && titem->item != val){
532     titem=titem->next;
533     depth++;
534     }
535     if(titem != NULL){ /* If we found it on the stack, */
536 teddy 1.124 if(fprintf(stream, " . #%d#", depth) < 0){ /* print a depth reference */
537     perror("print_val");
538     env->err= 5;
539     goto printval_end;
540     }
541 teddy 1.117 } else {
542 teddy 1.124 if(fprintf(stream, " ") < 0){
543     perror("print_val");
544     env->err= 5;
545     goto printval_end;
546     }
547 teddy 1.117 }
548 teddy 1.112 break;
549     default:
550 teddy 1.124 if(fprintf(stream, " . ") < 0){ /* Improper list */
551     perror("print_val");
552     env->err= 5;
553     goto printval_end;
554     }
555     print_val(env, val, noquote, tstack, stream);
556 teddy 1.112 }
557 teddy 1.117 } while(val->type == tcons && titem == NULL);
558 teddy 1.124
559     printval_end:
560    
561 teddy 1.117 titem=tstack;
562     while(titem != stack){
563     tstack=titem->next;
564     free(titem);
565     titem=tstack;
566     }
567 teddy 1.124
568     if(! (env->err)){
569     if(fprintf(stream, " ]") < 0){
570     perror("print_val");
571     env->err= 5;
572     }
573     }
574 teddy 1.35 break;
575 teddy 1.2 }
576 masse 1.1 }
577    
578 masse 1.26 /* Swap the two top elements on the stack. */
579 teddy 1.28 extern void swap(environment *env)
580 masse 1.26 {
581 masse 1.104 value *temp= env->head;
582 masse 1.26
583 teddy 1.111 if(env->head->type == empty || CDR(env->head)->type == empty) {
584 teddy 1.36 printerr("Too Few Arguments");
585 teddy 1.35 env->err=1;
586 masse 1.26 return;
587 teddy 1.28 }
588 masse 1.26
589 masse 1.104 env->head= CDR(env->head);
590     CDR(temp)= CDR(env->head);
591     CDR(env->head)= temp;
592 masse 1.26 }
593    
594 teddy 1.33 /* Recall a value from a symbol, if bound */
595 teddy 1.31 extern void rcl(environment *env)
596     {
597     value *val;
598    
599 teddy 1.111 if(env->head->type==empty) {
600 teddy 1.36 printerr("Too Few Arguments");
601 masse 1.102 env->err= 1;
602 teddy 1.31 return;
603     }
604    
605 masse 1.104 if(CAR(env->head)->type!=symb) {
606 teddy 1.36 printerr("Bad Argument Type");
607 masse 1.102 env->err= 2;
608 teddy 1.31 return;
609     }
610 teddy 1.35
611 masse 1.105 val= CAR(env->head)->content.sym->val;
612 teddy 1.33 if(val == NULL){
613 teddy 1.36 printerr("Unbound Variable");
614 masse 1.102 env->err= 3;
615 teddy 1.33 return;
616     }
617 teddy 1.110 push_val(env, val); /* Return the symbol's bound value */
618     swap(env);
619     if(env->err) return;
620     toss(env); /* toss the symbol */
621 teddy 1.35 if(env->err) return;
622 teddy 1.31 }
623 masse 1.26
624 masse 1.126
625 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
626     function value, and if it is, toss the symbol and execute the
627     function. */
628 teddy 1.28 extern void eval(environment *env)
629 masse 1.1 {
630     funcp in_func;
631 masse 1.44 value* temp_val;
632 masse 1.104 value* iterator;
633 masse 1.44
634 teddy 1.80 eval_start:
635    
636 teddy 1.96 gc_maybe(env);
637    
638 teddy 1.111 if(env->head->type==empty) {
639 teddy 1.36 printerr("Too Few Arguments");
640 masse 1.102 env->err= 1;
641 masse 1.1 return;
642 masse 1.17 }
643 masse 1.1
644 masse 1.104 switch(CAR(env->head)->type) {
645 masse 1.46 /* if it's a symbol */
646     case symb:
647 teddy 1.35 rcl(env); /* get its contents */
648     if(env->err) return;
649 masse 1.104 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
650 teddy 1.64 goto eval_start;
651 teddy 1.29 }
652 teddy 1.59 return;
653 masse 1.22
654 masse 1.46 /* If it's a lone function value, run it */
655     case func:
656 masse 1.104 in_func= (funcp)(CAR(env->head)->content.ptr);
657 teddy 1.28 toss(env);
658 teddy 1.35 if(env->err) return;
659 masse 1.89 return in_func(env);
660 masse 1.44
661 masse 1.46 /* If it's a list */
662 masse 1.102 case tcons:
663 masse 1.104 temp_val= CAR(env->head);
664 masse 1.98 protect(temp_val);
665 masse 1.93
666     toss(env); if(env->err) return;
667 masse 1.104 iterator= temp_val;
668 masse 1.90
669 teddy 1.111 while(iterator->type != empty) {
670 masse 1.104 push_val(env, CAR(iterator));
671 masse 1.90
672 masse 1.104 if(CAR(env->head)->type==symb
673 masse 1.105 && CAR(env->head)->content.sym->id[0]==';') {
674 masse 1.44 toss(env);
675     if(env->err) return;
676 masse 1.90
677 teddy 1.111 if(CDR(iterator)->type == empty){
678 teddy 1.64 goto eval_start;
679 teddy 1.59 }
680 masse 1.44 eval(env);
681 masse 1.46 if(env->err) return;
682 masse 1.44 }
683 teddy 1.111 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
684 masse 1.104 iterator= CDR(iterator);
685 teddy 1.103 else {
686     printerr("Bad Argument Type"); /* Improper list */
687     env->err= 2;
688     return;
689     }
690 masse 1.44 }
691 masse 1.98 unprotect(temp_val);
692 teddy 1.59 return;
693 masse 1.46
694 teddy 1.116 case empty:
695 teddy 1.124 toss(env);
696 teddy 1.116 case integer:
697     case tfloat:
698     case string:
699 teddy 1.124 case port:
700 teddy 1.59 return;
701 masse 1.26 }
702 masse 1.1 }
703    
704 masse 1.126 /* List all defined words */
705     extern void words(environment *env)
706     {
707     symbol *temp;
708     int i;
709    
710     for(i= 0; i<HASHTBLSIZE; i++) {
711     temp= env->symbols[i];
712     while(temp!=NULL) {
713     #ifdef DEBUG
714     if (temp->val != NULL && temp->val->gc.flag.protect)
715     printf("(protected) ");
716     #endif /* DEBUG */
717     printf("%s ", temp->id);
718     temp= temp->next;
719     }
720     }
721     }
722    
723     /* Quit stack. */
724     extern void quit(environment *env)
725 masse 1.95 {
726 masse 1.126 int i;
727    
728     while(env->head->type != empty)
729     toss(env);
730 teddy 1.40
731 masse 1.126 if (env->err) return;
732     for(i= 0; i<HASHTBLSIZE; i++) {
733     while(env->symbols[i]!= NULL) {
734     forget_sym(&(env->symbols[i]));
735     }
736     env->symbols[i]= NULL;
737 teddy 1.40 }
738    
739 masse 1.126 env->gc_limit= 0;
740     gc_maybe(env);
741    
742     words(env);
743 teddy 1.111
744 masse 1.126 if(env->free_string!=NULL)
745     free(env->free_string);
746    
747     #ifdef __linux__
748     muntrace();
749     #endif
750 teddy 1.40
751 masse 1.126 exit(EXIT_SUCCESS);
752 teddy 1.40 }
753    
754 masse 1.126 /* Internal forget function */
755     void forget_sym(symbol **hash_entry)
756 masse 1.19 {
757 masse 1.126 symbol *temp;
758 teddy 1.111
759 masse 1.126 temp= *hash_entry;
760     *hash_entry= (*hash_entry)->next;
761    
762     free(temp->id);
763     free(temp);
764     }
765 masse 1.93
766 masse 1.126 /* Only to be called by itself function printstack. */
767     void print_st(environment *env, value *stack_head, long counter)
768     {
769     if(CDR(stack_head)->type != empty)
770     print_st(env, CDR(stack_head), counter+1);
771     printf("%ld: ", counter);
772     print_val(env, CAR(stack_head), 0, NULL, stdout);
773     printf("\n");
774 masse 1.1 }
775 teddy 1.55
776 masse 1.126 /* Prints the stack. */
777     extern void printstack(environment *env)
778 masse 1.95 {
779 masse 1.126 if(env->head->type == empty) {
780     printf("Stack Empty\n");
781 masse 1.58 return;
782     }
783    
784 masse 1.126 print_st(env, env->head, 1);
785 teddy 1.56 }
786 masse 1.65
787 masse 1.126 int main(int argc, char **argv)
788 masse 1.95 {
789 masse 1.126 environment myenv;
790 masse 1.89
791 masse 1.126 int c; /* getopt option character */
792 masse 1.89
793 masse 1.126 #ifdef __linux__
794     mtrace();
795     #endif
796 masse 1.89
797 masse 1.126 init_env(&myenv);
798 masse 1.89
799 masse 1.126 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
800 masse 1.89
801 masse 1.126 while ((c = getopt (argc, argv, "i")) != -1)
802     switch (c)
803     {
804     case 'i':
805     myenv.interactive = 1;
806     break;
807     case '?':
808     fprintf (stderr,
809     "Unknown option character '\\x%x'.\n",
810     optopt);
811     return EX_USAGE;
812     default:
813     abort ();
814     }
815    
816     if (optind < argc) {
817     myenv.interactive = 0;
818     myenv.inputstream= fopen(argv[optind], "r");
819     if(myenv.inputstream== NULL) {
820     perror(argv[0]);
821     exit (EX_NOINPUT);
822 masse 1.89 }
823     }
824    
825 masse 1.126 if(myenv.interactive) {
826 masse 1.127 printf("Stack version $Revision: 1.126 $\n\
827 masse 1.126 Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn\n\
828     Stack comes with ABSOLUTELY NO WARRANTY; for details type 'warranty;'.\n\
829     This is free software, and you are welcome to redistribute it\n\
830     under certain conditions; type 'copying;' for details.\n");
831 masse 1.65 }
832    
833 masse 1.126 while(1) {
834     if(myenv.in_string==NULL) {
835     if (myenv.interactive) {
836     if(myenv.err) {
837     printf("(error %d)\n", myenv.err);
838     myenv.err= 0;
839     }
840     printf("\n");
841     printstack(&myenv);
842     printf("> ");
843     }
844     myenv.err=0;
845     }
846     readstream(&myenv, myenv.inputstream);
847     if (myenv.err) { /* EOF or other error */
848     myenv.err=0;
849     quit(&myenv);
850     } else if(myenv.head->type!=empty
851     && CAR(myenv.head)->type==symb
852     && CAR(myenv.head)->content.sym->id[0] == ';') {
853     toss(&myenv); if(myenv.err) continue;
854     eval(&myenv);
855 teddy 1.103 } else {
856 masse 1.126 gc_maybe(&myenv);
857 teddy 1.103 }
858 masse 1.65 }
859 masse 1.126 quit(&myenv);
860     return EXIT_FAILURE;
861 masse 1.65 }
862 masse 1.66
863 masse 1.126 /* Return copy of a value */
864     value *copy_val(environment *env, value *old_value)
865 masse 1.95 {
866 masse 1.126 value *new_value;
867 masse 1.121
868 masse 1.126 if(old_value==NULL)
869     return NULL;
870 masse 1.95
871 masse 1.126 new_value= new_val(env);
872     new_value->type= old_value->type;
873 masse 1.66
874 masse 1.126 switch(old_value->type){
875     case tfloat:
876     case integer:
877     case func:
878     case symb:
879     case empty:
880     case port:
881     new_value->content= old_value->content;
882     break;
883     case string:
884     (char *)(new_value->content.ptr)=
885     strdup((char *)(old_value->content.ptr));
886     break;
887     case tcons:
888 masse 1.66
889 masse 1.126 new_value->content.c= malloc(sizeof(pair));
890     assert(new_value->content.c!=NULL);
891     env->gc_count += sizeof(pair);
892 masse 1.66
893 masse 1.126 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
894     CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
895     break;
896 masse 1.67 }
897 masse 1.66
898 masse 1.126 return new_value;
899 teddy 1.124 }
900    
901     /* read a line from a stream; used by readline */
902     void readlinestream(environment *env, FILE *stream)
903     {
904 masse 1.68 char in_string[101];
905    
906 teddy 1.124 if(fgets(in_string, 100, stream)==NULL) {
907 teddy 1.84 push_cstring(env, "");
908 teddy 1.124 if (! feof(stream)){
909     perror("readline");
910     env->err= 5;
911     }
912     } else {
913 teddy 1.84 push_cstring(env, in_string);
914 teddy 1.124 }
915 masse 1.68 }
916    
917 masse 1.126 /* Reverse (flip) a list */
918     extern void rev(environment *env)
919 masse 1.95 {
920 masse 1.126 value *old_head, *new_head, *item;
921 teddy 1.124
922     if(env->head->type==empty) {
923     printerr("Too Few Arguments");
924     env->err= 1;
925     return;
926     }
927    
928 masse 1.126 if(CAR(env->head)->type==empty)
929     return; /* Don't reverse an empty list */
930    
931     if(CAR(env->head)->type!=tcons) {
932 teddy 1.124 printerr("Bad Argument Type");
933     env->err= 2;
934     return;
935     }
936    
937 masse 1.126 old_head= CAR(env->head);
938     new_head= new_val(env);
939     while(old_head->type != empty) {
940     item= old_head;
941     old_head= CDR(old_head);
942     CDR(item)= new_head;
943     new_head= item;
944     }
945     CAR(env->head)= new_head;
946     }
947    
948     /* Make a list. */
949     extern void pack(environment *env)
950     {
951     value *iterator, *temp, *ending;
952    
953     ending=new_val(env);
954    
955     iterator= env->head;
956     if(iterator->type == empty
957     || (CAR(iterator)->type==symb
958     && CAR(iterator)->content.sym->id[0]=='[')) {
959     temp= ending;
960     toss(env);
961     } else {
962     /* Search for first delimiter */
963     while(CDR(iterator)->type != empty
964     && (CAR(CDR(iterator))->type!=symb
965     || CAR(CDR(iterator))->content.sym->id[0]!='['))
966     iterator= CDR(iterator);
967    
968     /* Extract list */
969     temp= env->head;
970     env->head= CDR(iterator);
971     CDR(iterator)= ending;
972    
973     if(env->head->type != empty)
974     toss(env);
975     }
976    
977     /* Push list */
978 teddy 1.124
979 masse 1.126 push_val(env, temp);
980     rev(env);
981 teddy 1.124 }
982    
983     /* read from a stream; used by "read" and "readport" */
984     void readstream(environment *env, FILE *stream)
985     {
986 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
987     const char strform[]= "\"%[^\"]\"%n";
988     const char intform[]= "%i%n";
989 masse 1.93 const char fltform[]= "%f%n";
990 teddy 1.78 const char blankform[]= "%*[ \t]%n";
991 masse 1.90 const char ebrackform[]= "]%n";
992     const char semicform[]= ";%n";
993     const char bbrackform[]= "[%n";
994 masse 1.68
995 teddy 1.78 int itemp, readlength= -1;
996 masse 1.93 int count= -1;
997     float ftemp;
998 masse 1.68 static int depth= 0;
999 teddy 1.116 char *match;
1000 masse 1.68 size_t inlength;
1001    
1002 masse 1.70 if(env->in_string==NULL) {
1003 teddy 1.84 if(depth > 0 && env->interactive) {
1004 teddy 1.80 printf("]> ");
1005     }
1006 masse 1.126 readlinestream(env, env->inputstream);
1007     if(env->err) return;
1008 teddy 1.84
1009 masse 1.104 if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1010 teddy 1.85 env->err= 4; /* "" means EOF */
1011 teddy 1.84 return;
1012     }
1013 masse 1.68
1014 masse 1.104 env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1015 teddy 1.118 assert(env->in_string != NULL);
1016 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
1017 masse 1.104 strcpy(env->in_string, CAR(env->head)->content.ptr);
1018 masse 1.68 toss(env); if(env->err) return;
1019     }
1020    
1021 masse 1.70 inlength= strlen(env->in_string)+1;
1022 masse 1.68 match= malloc(inlength);
1023 teddy 1.118 assert(match != NULL);
1024 masse 1.68
1025 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
1026 teddy 1.78 && readlength != -1) {
1027 masse 1.71 ;
1028 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
1029 teddy 1.78 && readlength != -1) {
1030 masse 1.93 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
1031     && count==readlength) {
1032     push_int(env, itemp);
1033     } else {
1034     push_float(env, ftemp);
1035     }
1036 teddy 1.114 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
1037     && readlength != -1) {
1038     push_cstring(env, "");
1039 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1040     && readlength != -1) {
1041 masse 1.72 push_cstring(env, match);
1042 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1043     && readlength != -1) {
1044 masse 1.68 push_sym(env, match);
1045 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1046     && readlength != -1) {
1047 masse 1.68 pack(env); if(env->err) return;
1048 teddy 1.78 if(depth != 0) depth--;
1049     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1050     && readlength != -1) {
1051 masse 1.68 push_sym(env, ";");
1052 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1053     && readlength != -1) {
1054 masse 1.68 push_sym(env, "[");
1055     depth++;
1056     } else {
1057 teddy 1.78 free(env->free_string);
1058     env->in_string = env->free_string = NULL;
1059     }
1060 masse 1.126 if (env->in_string != NULL) {
1061     env->in_string += readlength;
1062 teddy 1.91 }
1063    
1064 masse 1.126 free(match);
1065 teddy 1.91
1066 masse 1.126 if(depth)
1067     return readstream(env, env->inputstream);
1068 masse 1.95 }
1069 teddy 1.91
1070 masse 1.95 extern void copying(environment *env)
1071     {
1072 teddy 1.111 printf(" GNU GENERAL PUBLIC LICENSE\n\
1073 teddy 1.91 Version 2, June 1991\n\
1074     \n\
1075     Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
1076     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
1077     Everyone is permitted to copy and distribute verbatim copies\n\
1078     of this license document, but changing it is not allowed.\n\
1079     \n\
1080     Preamble\n\
1081     \n\
1082     The licenses for most software are designed to take away your\n\
1083     freedom to share and change it. By contrast, the GNU General Public\n\
1084     License is intended to guarantee your freedom to share and change free\n\
1085     software--to make sure the software is free for all its users. This\n\
1086     General Public License applies to most of the Free Software\n\
1087     Foundation's software and to any other program whose authors commit to\n\
1088     using it. (Some other Free Software Foundation software is covered by\n\
1089     the GNU Library General Public License instead.) You can apply it to\n\
1090     your programs, too.\n\
1091     \n\
1092     When we speak of free software, we are referring to freedom, not\n\
1093     price. Our General Public Licenses are designed to make sure that you\n\
1094     have the freedom to distribute copies of free software (and charge for\n\
1095     this service if you wish), that you receive source code or can get it\n\
1096     if you want it, that you can change the software or use pieces of it\n\
1097     in new free programs; and that you know you can do these things.\n\
1098     \n\
1099     To protect your rights, we need to make restrictions that forbid\n\
1100     anyone to deny you these rights or to ask you to surrender the rights.\n\
1101     These restrictions translate to certain responsibilities for you if you\n\
1102     distribute copies of the software, or if you modify it.\n\
1103     \n\
1104     For example, if you distribute copies of such a program, whether\n\
1105     gratis or for a fee, you must give the recipients all the rights that\n\
1106     you have. You must make sure that they, too, receive or can get the\n\
1107     source code. And you must show them these terms so they know their\n\
1108     rights.\n\
1109     \n\
1110     We protect your rights with two steps: (1) copyright the software, and\n\
1111     (2) offer you this license which gives you legal permission to copy,\n\
1112     distribute and/or modify the software.\n\
1113     \n\
1114     Also, for each author's protection and ours, we want to make certain\n\
1115     that everyone understands that there is no warranty for this free\n\
1116     software. If the software is modified by someone else and passed on, we\n\
1117     want its recipients to know that what they have is not the original, so\n\
1118     that any problems introduced by others will not reflect on the original\n\
1119     authors' reputations.\n\
1120     \n\
1121     Finally, any free program is threatened constantly by software\n\
1122     patents. We wish to avoid the danger that redistributors of a free\n\
1123     program will individually obtain patent licenses, in effect making the\n\
1124     program proprietary. To prevent this, we have made it clear that any\n\
1125     patent must be licensed for everyone's free use or not licensed at all.\n\
1126     \n\
1127     The precise terms and conditions for copying, distribution and\n\
1128     modification follow.\n\
1129     \n\
1130     GNU GENERAL PUBLIC LICENSE\n\
1131     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
1132     \n\
1133     0. This License applies to any program or other work which contains\n\
1134     a notice placed by the copyright holder saying it may be distributed\n\
1135     under the terms of this General Public License. The \"Program\", below,\n\
1136     refers to any such program or work, and a \"work based on the Program\"\n\
1137     means either the Program or any derivative work under copyright law:\n\
1138     that is to say, a work containing the Program or a portion of it,\n\
1139     either verbatim or with modifications and/or translated into another\n\
1140     language. (Hereinafter, translation is included without limitation in\n\
1141     the term \"modification\".) Each licensee is addressed as \"you\".\n\
1142     \n\
1143     Activities other than copying, distribution and modification are not\n\
1144     covered by this License; they are outside its scope. The act of\n\
1145     running the Program is not restricted, and the output from the Program\n\
1146     is covered only if its contents constitute a work based on the\n\
1147     Program (independent of having been made by running the Program).\n\
1148     Whether that is true depends on what the Program does.\n\
1149     \n\
1150     1. You may copy and distribute verbatim copies of the Program's\n\
1151     source code as you receive it, in any medium, provided that you\n\
1152     conspicuously and appropriately publish on each copy an appropriate\n\
1153     copyright notice and disclaimer of warranty; keep intact all the\n\
1154     notices that refer to this License and to the absence of any warranty;\n\
1155     and give any other recipients of the Program a copy of this License\n\
1156     along with the Program.\n\
1157     \n\
1158     You may charge a fee for the physical act of transferring a copy, and\n\
1159     you may at your option offer warranty protection in exchange for a fee.\n\
1160     \n\
1161     2. You may modify your copy or copies of the Program or any portion\n\
1162     of it, thus forming a work based on the Program, and copy and\n\
1163     distribute such modifications or work under the terms of Section 1\n\
1164     above, provided that you also meet all of these conditions:\n\
1165     \n\
1166     a) You must cause the modified files to carry prominent notices\n\
1167     stating that you changed the files and the date of any change.\n\
1168     \n\
1169     b) You must cause any work that you distribute or publish, that in\n\
1170     whole or in part contains or is derived from the Program or any\n\
1171     part thereof, to be licensed as a whole at no charge to all third\n\
1172     parties under the terms of this License.\n\
1173     \n\
1174     c) If the modified program normally reads commands interactively\n\
1175     when run, you must cause it, when started running for such\n\
1176     interactive use in the most ordinary way, to print or display an\n\
1177     announcement including an appropriate copyright notice and a\n\
1178     notice that there is no warranty (or else, saying that you provide\n\
1179     a warranty) and that users may redistribute the program under\n\
1180     these conditions, and telling the user how to view a copy of this\n\
1181     License. (Exception: if the Program itself is interactive but\n\
1182     does not normally print such an announcement, your work based on\n\
1183     the Program is not required to print an announcement.)\n\
1184     \n\
1185     These requirements apply to the modified work as a whole. If\n\
1186     identifiable sections of that work are not derived from the Program,\n\
1187     and can be reasonably considered independent and separate works in\n\
1188     themselves, then this License, and its terms, do not apply to those\n\
1189     sections when you distribute them as separate works. But when you\n\
1190     distribute the same sections as part of a whole which is a work based\n\
1191     on the Program, the distribution of the whole must be on the terms of\n\
1192     this License, whose permissions for other licensees extend to the\n\
1193     entire whole, and thus to each and every part regardless of who wrote it.\n\
1194     \n\
1195     Thus, it is not the intent of this section to claim rights or contest\n\
1196     your rights to work written entirely by you; rather, the intent is to\n\
1197     exercise the right to control the distribution of derivative or\n\
1198     collective works based on the Program.\n\
1199     \n\
1200     In addition, mere aggregation of another work not based on the Program\n\
1201     with the Program (or with a work based on the Program) on a volume of\n\
1202     a storage or distribution medium does not bring the other work under\n\
1203     the scope of this License.\n\
1204     \n\
1205     3. You may copy and distribute the Program (or a work based on it,\n\
1206     under Section 2) in object code or executable form under the terms of\n\
1207     Sections 1 and 2 above provided that you also do one of the following:\n\
1208     \n\
1209     a) Accompany it with the complete corresponding machine-readable\n\
1210     source code, which must be distributed under the terms of Sections\n\
1211     1 and 2 above on a medium customarily used for software interchange; or,\n\
1212     \n\
1213     b) Accompany it with a written offer, valid for at least three\n\
1214     years, to give any third party, for a charge no more than your\n\
1215     cost of physically performing source distribution, a complete\n\
1216     machine-readable copy of the corresponding source code, to be\n\
1217     distributed under the terms of Sections 1 and 2 above on a medium\n\
1218     customarily used for software interchange; or,\n\
1219     \n\
1220     c) Accompany it with the information you received as to the offer\n\
1221     to distribute corresponding source code. (This alternative is\n\
1222     allowed only for noncommercial distribution and only if you\n\
1223     received the program in object code or executable form with such\n\
1224     an offer, in accord with Subsection b above.)\n\
1225     \n\
1226     The source code for a work means the preferred form of the work for\n\
1227     making modifications to it. For an executable work, complete source\n\
1228     code means all the source code for all modules it contains, plus any\n\
1229     associated interface definition files, plus the scripts used to\n\
1230     control compilation and installation of the executable. However, as a\n\
1231     special exception, the source code distributed need not include\n\
1232     anything that is normally distributed (in either source or binary\n\
1233     form) with the major components (compiler, kernel, and so on) of the\n\
1234     operating system on which the executable runs, unless that component\n\
1235     itself accompanies the executable.\n\
1236     \n\
1237     If distribution of executable or object code is made by offering\n\
1238     access to copy from a designated place, then offering equivalent\n\
1239     access to copy the source code from the same place counts as\n\
1240     distribution of the source code, even though third parties are not\n\
1241     compelled to copy the source along with the object code.\n\
1242     \n\
1243     4. You may not copy, modify, sublicense, or distribute the Program\n\
1244     except as expressly provided under this License. Any attempt\n\
1245     otherwise to copy, modify, sublicense or distribute the Program is\n\
1246     void, and will automatically terminate your rights under this License.\n\
1247     However, parties who have received copies, or rights, from you under\n\
1248     this License will not have their licenses terminated so long as such\n\
1249     parties remain in full compliance.\n\
1250     \n\
1251     5. You are not required to accept this License, since you have not\n\
1252     signed it. However, nothing else grants you permission to modify or\n\
1253     distribute the Program or its derivative works. These actions are\n\
1254     prohibited by law if you do not accept this License. Therefore, by\n\
1255     modifying or distributing the Program (or any work based on the\n\
1256     Program), you indicate your acceptance of this License to do so, and\n\
1257     all its terms and conditions for copying, distributing or modifying\n\
1258     the Program or works based on it.\n\
1259     \n\
1260     6. Each time you redistribute the Program (or any work based on the\n\
1261     Program), the recipient automatically receives a license from the\n\
1262     original licensor to copy, distribute or modify the Program subject to\n\
1263     these terms and conditions. You may not impose any further\n\
1264     restrictions on the recipients' exercise of the rights granted herein.\n\
1265     You are not responsible for enforcing compliance by third parties to\n\
1266     this License.\n\
1267     \n\
1268     7. If, as a consequence of a court judgment or allegation of patent\n\
1269     infringement or for any other reason (not limited to patent issues),\n\
1270     conditions are imposed on you (whether by court order, agreement or\n\
1271     otherwise) that contradict the conditions of this License, they do not\n\
1272     excuse you from the conditions of this License. If you cannot\n\
1273     distribute so as to satisfy simultaneously your obligations under this\n\
1274     License and any other pertinent obligations, then as a consequence you\n\
1275     may not distribute the Program at all. For example, if a patent\n\
1276     license would not permit royalty-free redistribution of the Program by\n\
1277     all those who receive copies directly or indirectly through you, then\n\
1278     the only way you could satisfy both it and this License would be to\n\
1279     refrain entirely from distribution of the Program.\n\
1280     \n\
1281     If any portion of this section is held invalid or unenforceable under\n\
1282     any particular circumstance, the balance of the section is intended to\n\
1283     apply and the section as a whole is intended to apply in other\n\
1284     circumstances.\n\
1285     \n\
1286     It is not the purpose of this section to induce you to infringe any\n\
1287     patents or other property right claims or to contest validity of any\n\
1288     such claims; this section has the sole purpose of protecting the\n\
1289     integrity of the free software distribution system, which is\n\
1290     implemented by public license practices. Many people have made\n\
1291     generous contributions to the wide range of software distributed\n\
1292     through that system in reliance on consistent application of that\n\
1293     system; it is up to the author/donor to decide if he or she is willing\n\
1294     to distribute software through any other system and a licensee cannot\n\
1295     impose that choice.\n\
1296     \n\
1297     This section is intended to make thoroughly clear what is believed to\n\
1298     be a consequence of the rest of this License.\n\
1299     \n\
1300     8. If the distribution and/or use of the Program is restricted in\n\
1301     certain countries either by patents or by copyrighted interfaces, the\n\
1302     original copyright holder who places the Program under this License\n\
1303     may add an explicit geographical distribution limitation excluding\n\
1304     those countries, so that distribution is permitted only in or among\n\
1305     countries not thus excluded. In such case, this License incorporates\n\
1306     the limitation as if written in the body of this License.\n\
1307     \n\
1308     9. The Free Software Foundation may publish revised and/or new versions\n\
1309     of the General Public License from time to time. Such new versions will\n\
1310     be similar in spirit to the present version, but may differ in detail to\n\
1311     address new problems or concerns.\n\
1312     \n\
1313     Each version is given a distinguishing version number. If the Program\n\
1314     specifies a version number of this License which applies to it and \"any\n\
1315     later version\", you have the option of following the terms and conditions\n\
1316     either of that version or of any later version published by the Free\n\
1317     Software Foundation. If the Program does not specify a version number of\n\
1318     this License, you may choose any version ever published by the Free Software\n\
1319     Foundation.\n\
1320     \n\
1321     10. If you wish to incorporate parts of the Program into other free\n\
1322     programs whose distribution conditions are different, write to the author\n\
1323     to ask for permission. For software which is copyrighted by the Free\n\
1324     Software Foundation, write to the Free Software Foundation; we sometimes\n\
1325     make exceptions for this. Our decision will be guided by the two goals\n\
1326     of preserving the free status of all derivatives of our free software and\n\
1327     of promoting the sharing and reuse of software generally.\n");
1328     }
1329    
1330 masse 1.95 extern void warranty(environment *env)
1331     {
1332 teddy 1.91 printf(" NO WARRANTY\n\
1333     \n\
1334     11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
1335     FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
1336     OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
1337     PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
1338     OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
1339     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
1340     TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
1341     PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
1342     REPAIR OR CORRECTION.\n\
1343     \n\
1344     12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
1345     WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
1346     REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
1347     INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
1348     OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
1349     TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
1350     YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
1351     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
1352     POSSIBILITY OF SUCH DAMAGES.\n");
1353 masse 1.92 }
1354    
1355 teddy 1.120 /* General assoc function */
1356     void assocgen(environment *env, funcp eqfunc)
1357     {
1358 teddy 1.119 value *key, *item;
1359    
1360     /* Needs two values on the stack, the top one must be an association
1361     list */
1362     if(env->head->type==empty || CDR(env->head)->type==empty) {
1363     printerr("Too Few Arguments");
1364     env->err= 1;
1365     return;
1366     }
1367    
1368     if(CAR(env->head)->type!=tcons) {
1369     printerr("Bad Argument Type");
1370     env->err= 2;
1371     return;
1372     }
1373    
1374     key=CAR(CDR(env->head));
1375     item=CAR(env->head);
1376    
1377     while(item->type == tcons){
1378     if(CAR(item)->type != tcons){
1379     printerr("Bad Argument Type");
1380     env->err= 2;
1381     return;
1382     }
1383     push_val(env, key);
1384     push_val(env, CAR(CAR(item)));
1385 teddy 1.120 eqfunc(env); if(env->err) return;
1386    
1387     /* Check the result of 'eqfunc' */
1388     if(env->head->type==empty) {
1389     printerr("Too Few Arguments");
1390     env->err= 1;
1391     return;
1392     }
1393     if(CAR(env->head)->type!=integer) {
1394     printerr("Bad Argument Type");
1395     env->err= 2;
1396     return;
1397     }
1398    
1399 teddy 1.119 if(CAR(env->head)->content.i){
1400 teddy 1.120 toss(env); if(env->err) return;
1401 teddy 1.119 break;
1402     }
1403 teddy 1.120 toss(env); if(env->err) return;
1404    
1405     if(item->type!=tcons) {
1406     printerr("Bad Argument Type");
1407     env->err= 2;
1408     return;
1409     }
1410    
1411 teddy 1.119 item=CDR(item);
1412     }
1413    
1414     if(item->type == tcons){ /* A match was found */
1415     push_val(env, CAR(item));
1416     } else {
1417     push_int(env, 0);
1418     }
1419     swap(env); if(env->err) return;
1420     toss(env); if(env->err) return;
1421     swap(env); if(env->err) return;
1422     toss(env);
1423 masse 1.123 }
1424    
1425 masse 1.126 /* Discard the top element of the stack. */
1426     extern void toss(environment *env)
1427 masse 1.123 {
1428 masse 1.126 if(env->head->type==empty) {
1429 teddy 1.124 printerr("Too Few Arguments");
1430 masse 1.126 env->err= 1;
1431 teddy 1.124 return;
1432     }
1433 masse 1.126
1434     env->head= CDR(env->head); /* Remove the top stack item */
1435 teddy 1.124 }
1436    

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26