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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.113 - (show annotations)
Sun Mar 17 00:55:58 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.112: +91 -22 lines
File MIME type: text/plain
stack.c (CAR, CDR): Extra parentheses around macros is probably a good idea.
(type): "list" renamed to "pair".
(print_h): Renamed to "print_val", and it now takes a value, not a
	   stack.  All callers changed.  Also, bugfix: print improper
	   lists correctly.
(setcar, setcdr, car, cdr): New functions.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26