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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.105 - (show annotations)
Tue Mar 12 14:53:19 2002 UTC (22 years, 2 months ago) by masse
Branch: MAIN
Changes since 1.104: +12 -13 lines
File MIME type: text/plain
stack.h:
(value->content.sym): New entry in content union. All callers changed.

stack.c:
(foreach): Bugfix.

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.104 $\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 /* "while" */
1366 extern void sx_7768696c65(environment *env)
1367 {
1368 int truth;
1369 value *loop, *test;
1370
1371 if(env->head==NULL || CDR(env->head)==NULL) {
1372 printerr("Too Few Arguments");
1373 env->err= 1;
1374 return;
1375 }
1376
1377 loop= CAR(env->head);
1378 protect(loop);
1379 toss(env); if(env->err) return;
1380
1381 test= CAR(env->head);
1382 protect(test);
1383 toss(env); if(env->err) return;
1384
1385 do {
1386 push_val(env, test);
1387 eval(env);
1388
1389 if(CAR(env->head)->type != integer) {
1390 printerr("Bad Argument Type");
1391 env->err= 2;
1392 return;
1393 }
1394
1395 truth= CAR(env->head)->content.i;
1396 toss(env); if(env->err) return;
1397
1398 if(truth) {
1399 push_val(env, loop);
1400 eval(env);
1401 } else {
1402 toss(env);
1403 }
1404
1405 } while(truth);
1406
1407 unprotect(loop); unprotect(test);
1408 }
1409
1410
1411 /* "for"; for-loop */
1412 extern void sx_666f72(environment *env)
1413 {
1414 value *loop;
1415 int foo1, foo2;
1416
1417 if(env->head==NULL || CDR(env->head)==NULL
1418 || CDR(CDR(env->head))==NULL) {
1419 printerr("Too Few Arguments");
1420 env->err= 1;
1421 return;
1422 }
1423
1424 if(CAR(CDR(env->head))->type!=integer
1425 || CAR(CDR(CDR(env->head)))->type!=integer) {
1426 printerr("Bad Argument Type");
1427 env->err= 2;
1428 return;
1429 }
1430
1431 loop= CAR(env->head);
1432 protect(loop);
1433 toss(env); if(env->err) return;
1434
1435 foo2= CAR(env->head)->content.i;
1436 toss(env); if(env->err) return;
1437
1438 foo1= CAR(env->head)->content.i;
1439 toss(env); if(env->err) return;
1440
1441 if(foo1<=foo2) {
1442 while(foo1<=foo2) {
1443 push_int(env, foo1);
1444 push_val(env, loop);
1445 eval(env); if(env->err) return;
1446 foo1++;
1447 }
1448 } else {
1449 while(foo1>=foo2) {
1450 push_int(env, foo1);
1451 push_val(env, loop);
1452 eval(env); if(env->err) return;
1453 foo1--;
1454 }
1455 }
1456 unprotect(loop);
1457 }
1458
1459 /* Variant of for-loop */
1460 extern void foreach(environment *env)
1461 {
1462 value *loop, *foo;
1463 value *iterator;
1464
1465 if(env->head==NULL || CDR(env->head)==NULL) {
1466 printerr("Too Few Arguments");
1467 env->err= 1;
1468 return;
1469 }
1470
1471 if(CAR(CDR(env->head))->type!=tcons) {
1472 printerr("Bad Argument Type");
1473 env->err= 2;
1474 return;
1475 }
1476
1477 loop= CAR(env->head);
1478 protect(loop);
1479 toss(env); if(env->err) return;
1480
1481 foo= CAR(env->head);
1482 protect(foo);
1483 toss(env); if(env->err) return;
1484
1485 iterator= foo;
1486
1487 while(iterator!=NULL) {
1488 push_val(env, CAR(iterator));
1489 push_val(env, loop);
1490 eval(env); if(env->err) return;
1491 if (iterator->type == tcons){
1492 iterator= CDR(iterator);
1493 } else {
1494 printerr("Bad Argument Type"); /* Improper list */
1495 env->err= 2;
1496 break;
1497 }
1498 }
1499 unprotect(loop); unprotect(foo);
1500 }
1501
1502 /* "to" */
1503 extern void to(environment *env)
1504 {
1505 int ending, start, i;
1506 value *iterator, *temp;
1507
1508 if(env->head==NULL || CDR(env->head)==NULL) {
1509 printerr("Too Few Arguments");
1510 env->err= 1;
1511 return;
1512 }
1513
1514 if(CAR(env->head)->type!=integer
1515 || CAR(CDR(env->head))->type!=integer) {
1516 printerr("Bad Argument Type");
1517 env->err= 2;
1518 return;
1519 }
1520
1521 ending= CAR(env->head)->content.i;
1522 toss(env); if(env->err) return;
1523 start= CAR(env->head)->content.i;
1524 toss(env); if(env->err) return;
1525
1526 push_sym(env, "[");
1527
1528 if(ending>=start) {
1529 for(i= ending; i>=start; i--)
1530 push_int(env, i);
1531 } else {
1532 for(i= ending; i<=start; i++)
1533 push_int(env, i);
1534 }
1535
1536 iterator= env->head;
1537
1538 if(iterator==NULL
1539 || (CAR(iterator)->type==symb
1540 && CAR(iterator)->content.sym->id[0]=='[')) {
1541 temp= NULL;
1542 toss(env);
1543 } else {
1544 /* Search for first delimiter */
1545 while(CDR(iterator)!=NULL
1546 && (CAR(CDR(iterator))->type!=symb
1547 || CAR(CDR(iterator))->content.sym->id[0]!='['))
1548 iterator= CDR(iterator);
1549
1550 /* Extract list */
1551 temp= env->head;
1552 env->head= CDR(iterator);
1553 CDR(iterator)= NULL;
1554
1555 if(env->head!=NULL)
1556 toss(env);
1557 }
1558
1559 /* Push list */
1560 push_val(env, temp);
1561 }
1562
1563 /* Read a string */
1564 extern void readline(environment *env)
1565 {
1566 char in_string[101];
1567
1568 if(fgets(in_string, 100, env->inputstream)==NULL)
1569 push_cstring(env, "");
1570 else
1571 push_cstring(env, in_string);
1572 }
1573
1574 /* "read"; Read a value and place on stack */
1575 extern void sx_72656164(environment *env)
1576 {
1577 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1578 const char strform[]= "\"%[^\"]\"%n";
1579 const char intform[]= "%i%n";
1580 const char fltform[]= "%f%n";
1581 const char blankform[]= "%*[ \t]%n";
1582 const char ebrackform[]= "]%n";
1583 const char semicform[]= ";%n";
1584 const char bbrackform[]= "[%n";
1585
1586 int itemp, readlength= -1;
1587 int count= -1;
1588 float ftemp;
1589 static int depth= 0;
1590 char *match, *ctemp;
1591 size_t inlength;
1592
1593 if(env->in_string==NULL) {
1594 if(depth > 0 && env->interactive) {
1595 printf("]> ");
1596 }
1597 readline(env); if(env->err) return;
1598
1599 if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1600 env->err= 4; /* "" means EOF */
1601 return;
1602 }
1603
1604 env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1605 env->free_string= env->in_string; /* Save the original pointer */
1606 strcpy(env->in_string, CAR(env->head)->content.ptr);
1607 toss(env); if(env->err) return;
1608 }
1609
1610 inlength= strlen(env->in_string)+1;
1611 match= malloc(inlength);
1612
1613 if(sscanf(env->in_string, blankform, &readlength) != EOF
1614 && readlength != -1) {
1615 ;
1616 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
1617 && readlength != -1) {
1618 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
1619 && count==readlength) {
1620 push_int(env, itemp);
1621 } else {
1622 push_float(env, ftemp);
1623 }
1624 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1625 && readlength != -1) {
1626 push_cstring(env, match);
1627 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1628 && readlength != -1) {
1629 push_sym(env, match);
1630 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1631 && readlength != -1) {
1632 pack(env); if(env->err) return;
1633 if(depth != 0) depth--;
1634 } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1635 && readlength != -1) {
1636 push_sym(env, ";");
1637 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1638 && readlength != -1) {
1639 push_sym(env, "[");
1640 depth++;
1641 } else {
1642 free(env->free_string);
1643 env->in_string = env->free_string = NULL;
1644 }
1645 if (env->in_string != NULL) {
1646 env->in_string += readlength;
1647 }
1648
1649 free(match);
1650
1651 if(depth)
1652 return sx_72656164(env);
1653 }
1654
1655 extern void beep(environment *env)
1656 {
1657 int freq, dur, period, ticks;
1658
1659 if(env->head==NULL || CDR(env->head)==NULL) {
1660 printerr("Too Few Arguments");
1661 env->err= 1;
1662 return;
1663 }
1664
1665 if(CAR(env->head)->type!=integer
1666 || CAR(CDR(env->head))->type!=integer) {
1667 printerr("Bad Argument Type");
1668 env->err= 2;
1669 return;
1670 }
1671
1672 dur= CAR(env->head)->content.i;
1673 toss(env);
1674 freq= CAR(env->head)->content.i;
1675 toss(env);
1676
1677 period= 1193180/freq; /* convert freq from Hz to period
1678 length */
1679 ticks= dur*.001193180; /* convert duration from µseconds to
1680 timer ticks */
1681
1682 /* ticks=dur/1000; */
1683
1684 /* if (ioctl(STDOUT_FILENO, KDMKTONE, (125<<16) + 0x637)==0) */
1685 switch (ioctl(STDOUT_FILENO, KDMKTONE, (ticks<<16) | period)){
1686 case 0:
1687 usleep(dur);
1688 return;
1689 case -1:
1690 perror("beep");
1691 env->err= 5;
1692 return;
1693 default:
1694 abort();
1695 }
1696 }
1697
1698 /* "wait" */
1699 extern void sx_77616974(environment *env)
1700 {
1701 int dur;
1702
1703 if(env->head==NULL) {
1704 printerr("Too Few Arguments");
1705 env->err= 1;
1706 return;
1707 }
1708
1709 if(CAR(env->head)->type!=integer) {
1710 printerr("Bad Argument Type");
1711 env->err= 2;
1712 return;
1713 }
1714
1715 dur= CAR(env->head)->content.i;
1716 toss(env);
1717
1718 usleep(dur);
1719 }
1720
1721 extern void copying(environment *env)
1722 {
1723 printf("GNU GENERAL PUBLIC LICENSE\n\
1724 Version 2, June 1991\n\
1725 \n\
1726 Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
1727 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
1728 Everyone is permitted to copy and distribute verbatim copies\n\
1729 of this license document, but changing it is not allowed.\n\
1730 \n\
1731 Preamble\n\
1732 \n\
1733 The licenses for most software are designed to take away your\n\
1734 freedom to share and change it. By contrast, the GNU General Public\n\
1735 License is intended to guarantee your freedom to share and change free\n\
1736 software--to make sure the software is free for all its users. This\n\
1737 General Public License applies to most of the Free Software\n\
1738 Foundation's software and to any other program whose authors commit to\n\
1739 using it. (Some other Free Software Foundation software is covered by\n\
1740 the GNU Library General Public License instead.) You can apply it to\n\
1741 your programs, too.\n\
1742 \n\
1743 When we speak of free software, we are referring to freedom, not\n\
1744 price. Our General Public Licenses are designed to make sure that you\n\
1745 have the freedom to distribute copies of free software (and charge for\n\
1746 this service if you wish), that you receive source code or can get it\n\
1747 if you want it, that you can change the software or use pieces of it\n\
1748 in new free programs; and that you know you can do these things.\n\
1749 \n\
1750 To protect your rights, we need to make restrictions that forbid\n\
1751 anyone to deny you these rights or to ask you to surrender the rights.\n\
1752 These restrictions translate to certain responsibilities for you if you\n\
1753 distribute copies of the software, or if you modify it.\n\
1754 \n\
1755 For example, if you distribute copies of such a program, whether\n\
1756 gratis or for a fee, you must give the recipients all the rights that\n\
1757 you have. You must make sure that they, too, receive or can get the\n\
1758 source code. And you must show them these terms so they know their\n\
1759 rights.\n\
1760 \n\
1761 We protect your rights with two steps: (1) copyright the software, and\n\
1762 (2) offer you this license which gives you legal permission to copy,\n\
1763 distribute and/or modify the software.\n\
1764 \n\
1765 Also, for each author's protection and ours, we want to make certain\n\
1766 that everyone understands that there is no warranty for this free\n\
1767 software. If the software is modified by someone else and passed on, we\n\
1768 want its recipients to know that what they have is not the original, so\n\
1769 that any problems introduced by others will not reflect on the original\n\
1770 authors' reputations.\n\
1771 \n\
1772 Finally, any free program is threatened constantly by software\n\
1773 patents. We wish to avoid the danger that redistributors of a free\n\
1774 program will individually obtain patent licenses, in effect making the\n\
1775 program proprietary. To prevent this, we have made it clear that any\n\
1776 patent must be licensed for everyone's free use or not licensed at all.\n\
1777 \n\
1778 The precise terms and conditions for copying, distribution and\n\
1779 modification follow.\n\
1780 \n\
1781 GNU GENERAL PUBLIC LICENSE\n\
1782 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
1783 \n\
1784 0. This License applies to any program or other work which contains\n\
1785 a notice placed by the copyright holder saying it may be distributed\n\
1786 under the terms of this General Public License. The \"Program\", below,\n\
1787 refers to any such program or work, and a \"work based on the Program\"\n\
1788 means either the Program or any derivative work under copyright law:\n\
1789 that is to say, a work containing the Program or a portion of it,\n\
1790 either verbatim or with modifications and/or translated into another\n\
1791 language. (Hereinafter, translation is included without limitation in\n\
1792 the term \"modification\".) Each licensee is addressed as \"you\".\n\
1793 \n\
1794 Activities other than copying, distribution and modification are not\n\
1795 covered by this License; they are outside its scope. The act of\n\
1796 running the Program is not restricted, and the output from the Program\n\
1797 is covered only if its contents constitute a work based on the\n\
1798 Program (independent of having been made by running the Program).\n\
1799 Whether that is true depends on what the Program does.\n\
1800 \n\
1801 1. You may copy and distribute verbatim copies of the Program's\n\
1802 source code as you receive it, in any medium, provided that you\n\
1803 conspicuously and appropriately publish on each copy an appropriate\n\
1804 copyright notice and disclaimer of warranty; keep intact all the\n\
1805 notices that refer to this License and to the absence of any warranty;\n\
1806 and give any other recipients of the Program a copy of this License\n\
1807 along with the Program.\n\
1808 \n\
1809 You may charge a fee for the physical act of transferring a copy, and\n\
1810 you may at your option offer warranty protection in exchange for a fee.\n\
1811 \n\
1812 2. You may modify your copy or copies of the Program or any portion\n\
1813 of it, thus forming a work based on the Program, and copy and\n\
1814 distribute such modifications or work under the terms of Section 1\n\
1815 above, provided that you also meet all of these conditions:\n\
1816 \n\
1817 a) You must cause the modified files to carry prominent notices\n\
1818 stating that you changed the files and the date of any change.\n\
1819 \n\
1820 b) You must cause any work that you distribute or publish, that in\n\
1821 whole or in part contains or is derived from the Program or any\n\
1822 part thereof, to be licensed as a whole at no charge to all third\n\
1823 parties under the terms of this License.\n\
1824 \n\
1825 c) If the modified program normally reads commands interactively\n\
1826 when run, you must cause it, when started running for such\n\
1827 interactive use in the most ordinary way, to print or display an\n\
1828 announcement including an appropriate copyright notice and a\n\
1829 notice that there is no warranty (or else, saying that you provide\n\
1830 a warranty) and that users may redistribute the program under\n\
1831 these conditions, and telling the user how to view a copy of this\n\
1832 License. (Exception: if the Program itself is interactive but\n\
1833 does not normally print such an announcement, your work based on\n\
1834 the Program is not required to print an announcement.)\n\
1835 \n\
1836 These requirements apply to the modified work as a whole. If\n\
1837 identifiable sections of that work are not derived from the Program,\n\
1838 and can be reasonably considered independent and separate works in\n\
1839 themselves, then this License, and its terms, do not apply to those\n\
1840 sections when you distribute them as separate works. But when you\n\
1841 distribute the same sections as part of a whole which is a work based\n\
1842 on the Program, the distribution of the whole must be on the terms of\n\
1843 this License, whose permissions for other licensees extend to the\n\
1844 entire whole, and thus to each and every part regardless of who wrote it.\n\
1845 \n\
1846 Thus, it is not the intent of this section to claim rights or contest\n\
1847 your rights to work written entirely by you; rather, the intent is to\n\
1848 exercise the right to control the distribution of derivative or\n\
1849 collective works based on the Program.\n\
1850 \n\
1851 In addition, mere aggregation of another work not based on the Program\n\
1852 with the Program (or with a work based on the Program) on a volume of\n\
1853 a storage or distribution medium does not bring the other work under\n\
1854 the scope of this License.\n\
1855 \n\
1856 3. You may copy and distribute the Program (or a work based on it,\n\
1857 under Section 2) in object code or executable form under the terms of\n\
1858 Sections 1 and 2 above provided that you also do one of the following:\n\
1859 \n\
1860 a) Accompany it with the complete corresponding machine-readable\n\
1861 source code, which must be distributed under the terms of Sections\n\
1862 1 and 2 above on a medium customarily used for software interchange; or,\n\
1863 \n\
1864 b) Accompany it with a written offer, valid for at least three\n\
1865 years, to give any third party, for a charge no more than your\n\
1866 cost of physically performing source distribution, a complete\n\
1867 machine-readable copy of the corresponding source code, to be\n\
1868 distributed under the terms of Sections 1 and 2 above on a medium\n\
1869 customarily used for software interchange; or,\n\
1870 \n\
1871 c) Accompany it with the information you received as to the offer\n\
1872 to distribute corresponding source code. (This alternative is\n\
1873 allowed only for noncommercial distribution and only if you\n\
1874 received the program in object code or executable form with such\n\
1875 an offer, in accord with Subsection b above.)\n\
1876 \n\
1877 The source code for a work means the preferred form of the work for\n\
1878 making modifications to it. For an executable work, complete source\n\
1879 code means all the source code for all modules it contains, plus any\n\
1880 associated interface definition files, plus the scripts used to\n\
1881 control compilation and installation of the executable. However, as a\n\
1882 special exception, the source code distributed need not include\n\
1883 anything that is normally distributed (in either source or binary\n\
1884 form) with the major components (compiler, kernel, and so on) of the\n\
1885 operating system on which the executable runs, unless that component\n\
1886 itself accompanies the executable.\n\
1887 \n\
1888 If distribution of executable or object code is made by offering\n\
1889 access to copy from a designated place, then offering equivalent\n\
1890 access to copy the source code from the same place counts as\n\
1891 distribution of the source code, even though third parties are not\n\
1892 compelled to copy the source along with the object code.\n\
1893 \n\
1894 4. You may not copy, modify, sublicense, or distribute the Program\n\
1895 except as expressly provided under this License. Any attempt\n\
1896 otherwise to copy, modify, sublicense or distribute the Program is\n\
1897 void, and will automatically terminate your rights under this License.\n\
1898 However, parties who have received copies, or rights, from you under\n\
1899 this License will not have their licenses terminated so long as such\n\
1900 parties remain in full compliance.\n\
1901 \n\
1902 5. You are not required to accept this License, since you have not\n\
1903 signed it. However, nothing else grants you permission to modify or\n\
1904 distribute the Program or its derivative works. These actions are\n\
1905 prohibited by law if you do not accept this License. Therefore, by\n\
1906 modifying or distributing the Program (or any work based on the\n\
1907 Program), you indicate your acceptance of this License to do so, and\n\
1908 all its terms and conditions for copying, distributing or modifying\n\
1909 the Program or works based on it.\n\
1910 \n\
1911 6. Each time you redistribute the Program (or any work based on the\n\
1912 Program), the recipient automatically receives a license from the\n\
1913 original licensor to copy, distribute or modify the Program subject to\n\
1914 these terms and conditions. You may not impose any further\n\
1915 restrictions on the recipients' exercise of the rights granted herein.\n\
1916 You are not responsible for enforcing compliance by third parties to\n\
1917 this License.\n\
1918 \n\
1919 7. If, as a consequence of a court judgment or allegation of patent\n\
1920 infringement or for any other reason (not limited to patent issues),\n\
1921 conditions are imposed on you (whether by court order, agreement or\n\
1922 otherwise) that contradict the conditions of this License, they do not\n\
1923 excuse you from the conditions of this License. If you cannot\n\
1924 distribute so as to satisfy simultaneously your obligations under this\n\
1925 License and any other pertinent obligations, then as a consequence you\n\
1926 may not distribute the Program at all. For example, if a patent\n\
1927 license would not permit royalty-free redistribution of the Program by\n\
1928 all those who receive copies directly or indirectly through you, then\n\
1929 the only way you could satisfy both it and this License would be to\n\
1930 refrain entirely from distribution of the Program.\n\
1931 \n\
1932 If any portion of this section is held invalid or unenforceable under\n\
1933 any particular circumstance, the balance of the section is intended to\n\
1934 apply and the section as a whole is intended to apply in other\n\
1935 circumstances.\n\
1936 \n\
1937 It is not the purpose of this section to induce you to infringe any\n\
1938 patents or other property right claims or to contest validity of any\n\
1939 such claims; this section has the sole purpose of protecting the\n\
1940 integrity of the free software distribution system, which is\n\
1941 implemented by public license practices. Many people have made\n\
1942 generous contributions to the wide range of software distributed\n\
1943 through that system in reliance on consistent application of that\n\
1944 system; it is up to the author/donor to decide if he or she is willing\n\
1945 to distribute software through any other system and a licensee cannot\n\
1946 impose that choice.\n\
1947 \n\
1948 This section is intended to make thoroughly clear what is believed to\n\
1949 be a consequence of the rest of this License.\n\
1950 \n\
1951 8. If the distribution and/or use of the Program is restricted in\n\
1952 certain countries either by patents or by copyrighted interfaces, the\n\
1953 original copyright holder who places the Program under this License\n\
1954 may add an explicit geographical distribution limitation excluding\n\
1955 those countries, so that distribution is permitted only in or among\n\
1956 countries not thus excluded. In such case, this License incorporates\n\
1957 the limitation as if written in the body of this License.\n\
1958 \n\
1959 9. The Free Software Foundation may publish revised and/or new versions\n\
1960 of the General Public License from time to time. Such new versions will\n\
1961 be similar in spirit to the present version, but may differ in detail to\n\
1962 address new problems or concerns.\n\
1963 \n\
1964 Each version is given a distinguishing version number. If the Program\n\
1965 specifies a version number of this License which applies to it and \"any\n\
1966 later version\", you have the option of following the terms and conditions\n\
1967 either of that version or of any later version published by the Free\n\
1968 Software Foundation. If the Program does not specify a version number of\n\
1969 this License, you may choose any version ever published by the Free Software\n\
1970 Foundation.\n\
1971 \n\
1972 10. If you wish to incorporate parts of the Program into other free\n\
1973 programs whose distribution conditions are different, write to the author\n\
1974 to ask for permission. For software which is copyrighted by the Free\n\
1975 Software Foundation, write to the Free Software Foundation; we sometimes\n\
1976 make exceptions for this. Our decision will be guided by the two goals\n\
1977 of preserving the free status of all derivatives of our free software and\n\
1978 of promoting the sharing and reuse of software generally.\n");
1979 }
1980
1981 extern void warranty(environment *env)
1982 {
1983 printf(" NO WARRANTY\n\
1984 \n\
1985 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
1986 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
1987 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
1988 PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
1989 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
1990 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
1991 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
1992 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
1993 REPAIR OR CORRECTION.\n\
1994 \n\
1995 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
1996 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
1997 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
1998 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
1999 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
2000 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
2001 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
2002 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
2003 POSSIBILITY OF SUCH DAMAGES.\n");
2004 }
2005
2006 /* "*" */
2007 extern void sx_2a(environment *env)
2008 {
2009 int a, b;
2010 float fa, fb;
2011
2012 if(env->head==NULL || CDR(env->head)==NULL) {
2013 printerr("Too Few Arguments");
2014 env->err= 1;
2015 return;
2016 }
2017
2018 if(CAR(env->head)->type==integer
2019 && CAR(CDR(env->head))->type==integer) {
2020 a= CAR(env->head)->content.i;
2021 toss(env); if(env->err) return;
2022 b= CAR(env->head)->content.i;
2023 toss(env); if(env->err) return;
2024 push_int(env, b*a);
2025
2026 return;
2027 }
2028
2029 if(CAR(env->head)->type==tfloat
2030 && CAR(CDR(env->head))->type==tfloat) {
2031 fa= CAR(env->head)->content.f;
2032 toss(env); if(env->err) return;
2033 fb= CAR(env->head)->content.f;
2034 toss(env); if(env->err) return;
2035 push_float(env, fb*fa);
2036
2037 return;
2038 }
2039
2040 if(CAR(env->head)->type==tfloat
2041 && CAR(CDR(env->head))->type==integer) {
2042 fa= CAR(env->head)->content.f;
2043 toss(env); if(env->err) return;
2044 b= CAR(env->head)->content.i;
2045 toss(env); if(env->err) return;
2046 push_float(env, b*fa);
2047
2048 return;
2049 }
2050
2051 if(CAR(env->head)->type==integer
2052 && CAR(CDR(env->head))->type==tfloat) {
2053 a= CAR(env->head)->content.i;
2054 toss(env); if(env->err) return;
2055 fb= CAR(env->head)->content.f;
2056 toss(env); if(env->err) return;
2057 push_float(env, fb*a);
2058
2059 return;
2060 }
2061
2062 printerr("Bad Argument Type");
2063 env->err= 2;
2064 }
2065
2066 /* "/" */
2067 extern void sx_2f(environment *env)
2068 {
2069 int a, b;
2070 float fa, fb;
2071
2072 if(env->head==NULL || CDR(env->head)==NULL) {
2073 printerr("Too Few Arguments");
2074 env->err= 1;
2075 return;
2076 }
2077
2078 if(CAR(env->head)->type==integer
2079 && CAR(CDR(env->head))->type==integer) {
2080 a= CAR(env->head)->content.i;
2081 toss(env); if(env->err) return;
2082 b= CAR(env->head)->content.i;
2083 toss(env); if(env->err) return;
2084 push_float(env, b/a);
2085
2086 return;
2087 }
2088
2089 if(CAR(env->head)->type==tfloat
2090 && CAR(CDR(env->head))->type==tfloat) {
2091 fa= CAR(env->head)->content.f;
2092 toss(env); if(env->err) return;
2093 fb= CAR(env->head)->content.f;
2094 toss(env); if(env->err) return;
2095 push_float(env, fb/fa);
2096
2097 return;
2098 }
2099
2100 if(CAR(env->head)->type==tfloat
2101 && CAR(CDR(env->head))->type==integer) {
2102 fa= CAR(env->head)->content.f;
2103 toss(env); if(env->err) return;
2104 b= CAR(env->head)->content.i;
2105 toss(env); if(env->err) return;
2106 push_float(env, b/fa);
2107
2108 return;
2109 }
2110
2111 if(CAR(env->head)->type==integer
2112 && CAR(CDR(env->head))->type==tfloat) {
2113 a= CAR(env->head)->content.i;
2114 toss(env); if(env->err) return;
2115 fb= CAR(env->head)->content.f;
2116 toss(env); if(env->err) return;
2117 push_float(env, fb/a);
2118
2119 return;
2120 }
2121
2122 printerr("Bad Argument Type");
2123 env->err= 2;
2124 }
2125
2126 /* "mod" */
2127 extern void mod(environment *env)
2128 {
2129 int a, b;
2130
2131 if(env->head==NULL || CDR(env->head)==NULL) {
2132 printerr("Too Few Arguments");
2133 env->err= 1;
2134 return;
2135 }
2136
2137 if(CAR(env->head)->type==integer
2138 && CAR(CDR(env->head))->type==integer) {
2139 a= CAR(env->head)->content.i;
2140 toss(env); if(env->err) return;
2141 b= CAR(env->head)->content.i;
2142 toss(env); if(env->err) return;
2143 push_int(env, b%a);
2144
2145 return;
2146 }
2147
2148 printerr("Bad Argument Type");
2149 env->err= 2;
2150 }
2151
2152 /* "div" */
2153 extern void sx_646976(environment *env)
2154 {
2155 int a, b;
2156
2157 if(env->head==NULL || CDR(env->head)==NULL) {
2158 printerr("Too Few Arguments");
2159 env->err= 1;
2160 return;
2161 }
2162
2163 if(CAR(env->head)->type==integer
2164 && CAR(CDR(env->head))->type==integer) {
2165 a= CAR(env->head)->content.i;
2166 toss(env); if(env->err) return;
2167 b= CAR(env->head)->content.i;
2168 toss(env); if(env->err) return;
2169 push_int(env, (int)b/a);
2170
2171 return;
2172 }
2173
2174 printerr("Bad Argument Type");
2175 env->err= 2;
2176 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26