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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.125 - (show annotations)
Sun Mar 31 02:19:54 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.124: +5 -4 lines
File MIME type: text/plain
stack.c (main): Exit on any error from "read", not just EOF.
		Loop around if the "toss" call fails.
		Don't call 'gc_init' if we already called "eval".

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26