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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.106 - (show annotations)
Tue Mar 12 15:13:48 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.105: +21 -1 lines
File MIME type: text/plain
stack.c:
(sx_656c7365): New function "else".

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26