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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.90 - (show annotations)
Thu Mar 7 01:21:07 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.89: +113 -61 lines
File MIME type: text/plain
(protect, unprotect): New functions to protect values from GC.

1 /* printf, sscanf, fgets, fprintf, fopen, perror */
2 #include <stdio.h>
3 /* exit, EXIT_SUCCESS, malloc, free */
4 #include <stdlib.h>
5 /* NULL */
6 #include <stddef.h>
7 /* dlopen, dlsym, dlerror */
8 #include <dlfcn.h>
9 /* strcmp, strcpy, strlen, strcat, strdup */
10 #include <string.h>
11 /* getopt, STDIN_FILENO, STDOUT_FILENO */
12 #include <unistd.h>
13 /* EX_NOINPUT, EX_USAGE */
14 #include <sysexits.h>
15 /* mtrace, muntrace */
16 #include <mcheck.h>
17
18 #include "stack.h"
19
20 /* Initialize a newly created environment */
21 void init_env(environment *env)
22 {
23 int i;
24
25 env->gc_limit= 20;
26 env->gc_count= 0;
27 env->gc_ref= NULL;
28 env->gc_protect= NULL;
29
30 env->head= NULL;
31 for(i= 0; i<HASHTBLSIZE; i++)
32 env->symbols[i]= NULL;
33 env->err= 0;
34 env->in_string= NULL;
35 env->free_string= NULL;
36 env->inputstream= stdin;
37 env->interactive= 1;
38 }
39
40 void printerr(const char* in_string) {
41 fprintf(stderr, "Err: %s\n", in_string);
42 }
43
44 /* Discard the top element of the stack. */
45 extern void toss(environment *env)
46 {
47 stackitem *temp= env->head;
48
49 if((env->head)==NULL) {
50 printerr("Too Few Arguments");
51 env->err= 1;
52 return;
53 }
54
55 env->head= env->head->next; /* Remove the top stack item */
56 free(temp); /* Free the old top stack item */
57
58 gc_init(env);
59 }
60
61 /* Returns a pointer to a pointer to an element in the hash table. */
62 symbol **hash(hashtbl in_hashtbl, const char *in_string)
63 {
64 int i= 0;
65 unsigned int out_hash= 0;
66 char key= '\0';
67 symbol **position;
68
69 while(1){ /* Hash in_string */
70 key= in_string[i++];
71 if(key=='\0')
72 break;
73 out_hash= out_hash*32+key;
74 }
75
76 out_hash= out_hash%HASHTBLSIZE;
77 position= &(in_hashtbl[out_hash]);
78
79 while(1){
80 if(*position==NULL) /* If empty */
81 return position;
82
83 if(strcmp(in_string, (*position)->id)==0) /* If match */
84 return position;
85
86 position= &((*position)->next); /* Try next */
87 }
88 }
89
90 value* new_val(environment *env) {
91 value *nval= malloc(sizeof(value));
92 stackitem *nitem= malloc(sizeof(stackitem));
93
94 nval->content.ptr= NULL;
95 protect(env, nval);
96
97 gc_init(env);
98
99 nitem->item= nval;
100 nitem->next= env->gc_ref;
101 env->gc_ref= nitem;
102
103 env->gc_count++;
104 unprotect(env);
105
106 return nval;
107 }
108
109 void gc_mark(value *val) {
110 stackitem *iterator;
111
112 if(val==NULL || val->gc_garb==0)
113 return;
114
115 val->gc_garb= 0;
116
117 if(val->type==list) {
118 iterator= val->content.ptr;
119
120 while(iterator!=NULL) {
121 gc_mark(iterator->item);
122 iterator= iterator->next;
123 }
124 }
125 }
126
127 extern void gc_init(environment *env) {
128 stackitem *new_head= NULL, *titem, *iterator= env->gc_ref;
129 symbol *tsymb;
130 int i;
131
132 if(env->gc_count < env->gc_limit)
133 return;
134
135 while(iterator!=NULL) {
136 iterator->item->gc_garb= 1;
137 iterator= iterator->next;
138 }
139
140 /* Mark */
141 iterator= env->gc_protect;
142 while(iterator!=NULL) {
143 gc_mark(iterator->item);
144 iterator= iterator->next;
145 }
146
147 iterator= env->head;
148 while(iterator!=NULL) {
149 gc_mark(iterator->item);
150 iterator= iterator->next;
151 }
152
153 for(i= 0; i<HASHTBLSIZE; i++) {
154 tsymb= env->symbols[i];
155 while(tsymb!=NULL) {
156 gc_mark(tsymb->val);
157 tsymb= tsymb->next;
158 }
159 }
160
161 env->gc_count= 0;
162
163 /* Sweep */
164 while(env->gc_ref!=NULL) {
165
166 if(env->gc_ref->item->gc_garb) {
167 switch(env->gc_ref->item->type) {
168 case string:
169 free(env->gc_ref->item->content.ptr);
170 break;
171 case integer:
172 break;
173 case list:
174 while(env->gc_ref->item->content.ptr!=NULL) {
175 titem= env->gc_ref->item->content.ptr;
176 env->gc_ref->item->content.ptr= titem->next;
177 free(titem);
178 }
179 break;
180 default:
181 break;
182 }
183 free(env->gc_ref->item);
184 titem= env->gc_ref->next;
185 free(env->gc_ref);
186 env->gc_ref= titem;
187 } else {
188 titem= env->gc_ref->next;
189 env->gc_ref->next= new_head;
190 new_head= env->gc_ref;
191 env->gc_ref= titem;
192 env->gc_count++;
193 }
194 }
195
196 env->gc_limit= env->gc_count*2;
197 env->gc_ref= new_head;
198 }
199
200 void protect(environment *env, value *val)
201 {
202 stackitem *new_item= malloc(sizeof(stackitem));
203 new_item->item= val;
204 new_item->next= env->gc_protect;
205 env->gc_protect= new_item;
206 }
207
208 void unprotect(environment *env)
209 {
210 stackitem *temp= env->gc_protect;
211 env->gc_protect= env->gc_protect->next;
212 free(temp);
213 }
214
215 /* Push a value onto the stack */
216 void push_val(environment *env, value *val)
217 {
218 stackitem *new_item= malloc(sizeof(stackitem));
219 new_item->item= val;
220 new_item->next= env->head;
221 env->head= new_item;
222 }
223
224 /* Push an integer onto the stack. */
225 void push_int(environment *env, int in_val)
226 {
227 value *new_value= new_val(env);
228
229 new_value->content.val= in_val;
230 new_value->type= integer;
231
232 push_val(env, new_value);
233 }
234
235 /* Copy a string onto the stack. */
236 void push_cstring(environment *env, const char *in_string)
237 {
238 value *new_value= new_val(env);
239
240 new_value->content.ptr= malloc(strlen(in_string)+1);
241 strcpy(new_value->content.ptr, in_string);
242 new_value->type= string;
243
244 push_val(env, new_value);
245 }
246
247 /* Mangle a symbol name to a valid C identifier name */
248 char *mangle_str(const char *old_string){
249 char validchars[]= "0123456789abcdef";
250 char *new_string, *current;
251
252 new_string= malloc((strlen(old_string)*2)+4);
253 strcpy(new_string, "sx_"); /* Stack eXternal */
254 current= new_string+3;
255 while(old_string[0] != '\0'){
256 current[0]= validchars[(unsigned char)(old_string[0])/16];
257 current[1]= validchars[(unsigned char)(old_string[0])%16];
258 current+= 2;
259 old_string++;
260 }
261 current[0]= '\0';
262
263 return new_string; /* The caller must free() it */
264 }
265
266 extern void mangle(environment *env){
267 char *new_string;
268
269 if((env->head)==NULL) {
270 printerr("Too Few Arguments");
271 env->err= 1;
272 return;
273 }
274
275 if(env->head->item->type!=string) {
276 printerr("Bad Argument Type");
277 env->err= 2;
278 return;
279 }
280
281 new_string= mangle_str((const char *)(env->head->item->content.ptr));
282
283 toss(env);
284 if(env->err) return;
285
286 push_cstring(env, new_string);
287 }
288
289 /* Push a symbol onto the stack. */
290 void push_sym(environment *env, const char *in_string)
291 {
292 value *new_value; /* A new symbol value */
293 /* ...which might point to... */
294 symbol **new_symbol; /* (if needed) A new actual symbol */
295 /* ...which, if possible, will be bound to... */
296 value *new_fvalue; /* (if needed) A new function value */
297 /* ...which will point to... */
298 void *funcptr; /* A function pointer */
299
300 static void *handle= NULL; /* Dynamic linker handle */
301 const char *dlerr; /* Dynamic linker error */
302 char *mangled; /* Mangled function name */
303
304 new_value= new_val(env);
305
306 /* The new value is a symbol */
307 new_value->type= symb;
308
309 /* Look up the symbol name in the hash table */
310 new_symbol= hash(env->symbols, in_string);
311 new_value->content.ptr= *new_symbol;
312
313 if(*new_symbol==NULL) { /* If symbol was undefined */
314
315 /* Create a new symbol */
316 (*new_symbol)= malloc(sizeof(symbol));
317 (*new_symbol)->val= NULL; /* undefined value */
318 (*new_symbol)->next= NULL;
319 (*new_symbol)->id= malloc(strlen(in_string)+1);
320 strcpy((*new_symbol)->id, in_string);
321
322 /* Intern the new symbol in the hash table */
323 new_value->content.ptr= *new_symbol;
324
325 /* Try to load the symbol name as an external function, to see if
326 we should bind the symbol to a new function pointer value */
327 if(handle==NULL) /* If no handle */
328 handle= dlopen(NULL, RTLD_LAZY);
329
330 mangled= mangle_str(in_string); /* mangle the name */
331 funcptr= dlsym(handle, mangled); /* and try to find it */
332 free(mangled);
333 dlerr= dlerror();
334 if(dlerr != NULL) { /* If no function was found */
335 funcptr= dlsym(handle, in_string); /* Get function pointer */
336 dlerr= dlerror();
337 }
338 if(dlerr==NULL) { /* If a function was found */
339 new_fvalue= new_val(env); /* Create a new value */
340 new_fvalue->type= func; /* The new value is a function pointer */
341 new_fvalue->content.ptr= funcptr; /* Store function pointer */
342 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
343 function value */
344 }
345 }
346 push_val(env, new_value);
347 }
348
349 /* Print newline. */
350 extern void nl()
351 {
352 printf("\n");
353 }
354
355 /* Gets the type of a value */
356 extern void type(environment *env){
357 int typenum;
358
359 if((env->head)==NULL) {
360 printerr("Too Few Arguments");
361 env->err=1;
362 return;
363 }
364 typenum=env->head->item->type;
365 toss(env);
366 switch(typenum){
367 case integer:
368 push_sym(env, "integer");
369 break;
370 case string:
371 push_sym(env, "string");
372 break;
373 case symb:
374 push_sym(env, "symbol");
375 break;
376 case func:
377 push_sym(env, "function");
378 break;
379 case list:
380 push_sym(env, "list");
381 break;
382 }
383 }
384
385 /* Prints the top element of the stack. */
386 void print_h(stackitem *stack_head, int noquote)
387 {
388 switch(stack_head->item->type) {
389 case integer:
390 printf("%d", stack_head->item->content.val);
391 break;
392 case string:
393 if(noquote)
394 printf("%s", (char*)stack_head->item->content.ptr);
395 else
396 printf("\"%s\"", (char*)stack_head->item->content.ptr);
397 break;
398 case symb:
399 printf("%s", ((symbol *)(stack_head->item->content.ptr))->id);
400 break;
401 case func:
402 printf("#<function %p>", (funcp)(stack_head->item->content.ptr));
403 break;
404 case list:
405 /* A list is just a stack, so make stack_head point to it */
406 stack_head=(stackitem *)(stack_head->item->content.ptr);
407 printf("[ ");
408 while(stack_head != NULL) {
409 print_h(stack_head, noquote);
410 printf(" ");
411 stack_head=stack_head->next;
412 }
413 printf("]");
414 break;
415 }
416 }
417
418 extern void print_(environment *env) {
419 if(env->head==NULL) {
420 printerr("Too Few Arguments");
421 env->err=1;
422 return;
423 }
424 print_h(env->head, 0);
425 nl();
426 }
427
428 /* Prints the top element of the stack and then discards it. */
429 extern void print(environment *env)
430 {
431 print_(env);
432 if(env->err) return;
433 toss(env);
434 }
435
436 extern void princ_(environment *env) {
437 if(env->head==NULL) {
438 printerr("Too Few Arguments");
439 env->err=1;
440 return;
441 }
442 print_h(env->head, 1);
443 }
444
445 /* Prints the top element of the stack and then discards it. */
446 extern void princ(environment *env)
447 {
448 princ_(env);
449 if(env->err) return;
450 toss(env);
451 }
452
453 /* Only to be called by function printstack. */
454 void print_st(stackitem *stack_head, long counter)
455 {
456 if(stack_head->next != NULL)
457 print_st(stack_head->next, counter+1);
458 printf("%ld: ", counter);
459 print_h(stack_head, 0);
460 nl();
461 }
462
463 /* Prints the stack. */
464 extern void printstack(environment *env)
465 {
466 if(env->head == NULL) {
467 printf("Stack Empty\n");
468 return;
469 }
470 print_st(env->head, 1);
471 }
472
473 /* Swap the two top elements on the stack. */
474 extern void swap(environment *env)
475 {
476 stackitem *temp= env->head;
477
478 if(env->head==NULL || env->head->next==NULL) {
479 printerr("Too Few Arguments");
480 env->err=1;
481 return;
482 }
483
484 env->head= env->head->next;
485 temp->next= env->head->next;
486 env->head->next= temp;
487 }
488
489 /* Rotate the first three elements on the stack. */
490 extern void rot(environment *env)
491 {
492 stackitem *temp= env->head;
493
494 if(env->head==NULL || env->head->next==NULL
495 || env->head->next->next==NULL) {
496 printerr("Too Few Arguments");
497 env->err=1;
498 return;
499 }
500
501 env->head= env->head->next->next;
502 temp->next->next= env->head->next;
503 env->head->next= temp;
504 }
505
506 /* Recall a value from a symbol, if bound */
507 extern void rcl(environment *env)
508 {
509 value *val;
510
511 if(env->head == NULL) {
512 printerr("Too Few Arguments");
513 env->err=1;
514 return;
515 }
516
517 if(env->head->item->type!=symb) {
518 printerr("Bad Argument Type");
519 env->err=2;
520 return;
521 }
522
523 val=((symbol *)(env->head->item->content.ptr))->val;
524 if(val == NULL){
525 printerr("Unbound Variable");
526 env->err=3;
527 return;
528 }
529 protect(env, val);
530 toss(env); /* toss the symbol */
531 if(env->err) return;
532 push_val(env, val); /* Return its bound value */
533 unprotect(env);
534 }
535
536 /* If the top element is a symbol, determine if it's bound to a
537 function value, and if it is, toss the symbol and execute the
538 function. */
539 extern void eval(environment *env)
540 {
541 funcp in_func;
542 value* temp_val;
543 stackitem* iterator;
544
545 eval_start:
546
547 if(env->head==NULL) {
548 printerr("Too Few Arguments");
549 env->err=1;
550 return;
551 }
552
553 switch(env->head->item->type) {
554 /* if it's a symbol */
555 case symb:
556 rcl(env); /* get its contents */
557 if(env->err) return;
558 if(env->head->item->type!=symb){ /* don't recurse symbols */
559 goto eval_start;
560 }
561 return;
562
563 /* If it's a lone function value, run it */
564 case func:
565 in_func= (funcp)(env->head->item->content.ptr);
566 toss(env);
567 if(env->err) return;
568 return in_func(env);
569
570 /* If it's a list */
571 case list:
572 temp_val= env->head->item;
573 protect(env, temp_val);
574 toss(env);
575 if(env->err) return;
576 iterator= (stackitem*)temp_val->content.ptr;
577 unprotect(env);
578
579 while(iterator!=NULL) {
580 push_val(env, iterator->item);
581
582 if(env->head->item->type==symb
583 && strcmp(";", ((symbol*)(env->head->item->content.ptr))->id)==0) {
584 toss(env);
585 if(env->err) return;
586
587 if(iterator->next == NULL){
588 goto eval_start;
589 }
590 eval(env);
591 if(env->err) return;
592 }
593 iterator= iterator->next;
594 }
595 return;
596
597 default:
598 return;
599 }
600 }
601
602 /* Reverse (flip) a list */
603 extern void rev(environment *env){
604 stackitem *old_head, *new_head, *item;
605
606 if((env->head)==NULL) {
607 printerr("Too Few Arguments");
608 env->err= 1;
609 return;
610 }
611
612 if(env->head->item->type!=list) {
613 printerr("Bad Argument Type");
614 env->err= 2;
615 return;
616 }
617
618 old_head= (stackitem *)(env->head->item->content.ptr);
619 new_head= NULL;
620 while(old_head != NULL){
621 item= old_head;
622 old_head= old_head->next;
623 item->next= new_head;
624 new_head= item;
625 }
626 env->head->item->content.ptr= new_head;
627 }
628
629 /* Make a list. */
630 extern void pack(environment *env)
631 {
632 stackitem *iterator, *temp;
633 value *pack;
634
635 iterator= env->head;
636
637 if(iterator==NULL
638 || (iterator->item->type==symb
639 && ((symbol*)(iterator->item->content.ptr))->id[0]=='[')) {
640 temp= NULL;
641 toss(env);
642 } else {
643 /* Search for first delimiter */
644 while(iterator->next!=NULL
645 && (iterator->next->item->type!=symb
646 || ((symbol*)(iterator->next->item->content.ptr))->id[0]!='['))
647 iterator= iterator->next;
648
649 /* Extract list */
650 temp= env->head;
651 env->head= iterator->next;
652 iterator->next= NULL;
653
654 if(env->head!=NULL)
655 toss(env);
656 }
657
658 /* Push list */
659 pack= new_val(env);
660 pack->type= list;
661 pack->content.ptr= temp;
662
663 push_val(env, pack);
664 rev(env);
665 }
666
667 /* Relocate elements of the list on the stack. */
668 extern void expand(environment *env)
669 {
670 stackitem *temp, *new_head;
671
672 /* Is top element a list? */
673 if(env->head==NULL) {
674 printerr("Too Few Arguments");
675 env->err= 1;
676 return;
677 }
678 if(env->head->item->type!=list) {
679 printerr("Bad Argument Type");
680 env->err= 2;
681 return;
682 }
683
684 rev(env);
685
686 if(env->err)
687 return;
688
689 /* The first list element is the new stack head */
690 new_head= temp= env->head->item->content.ptr;
691
692 toss(env);
693
694 /* Find the end of the list */
695 while(temp->next!=NULL)
696 temp= temp->next;
697
698 /* Connect the tail of the list with the old stack head */
699 temp->next= env->head;
700 env->head= new_head; /* ...and voila! */
701
702 }
703
704 /* Compares two elements by reference. */
705 extern void eq(environment *env)
706 {
707 void *left, *right;
708 int result;
709
710 if((env->head)==NULL || env->head->next==NULL) {
711 printerr("Too Few Arguments");
712 env->err= 1;
713 return;
714 }
715
716 left= env->head->item->content.ptr;
717 swap(env);
718 right= env->head->item->content.ptr;
719 result= (left==right);
720
721 toss(env); toss(env);
722 push_int(env, result);
723 }
724
725 /* Negates the top element on the stack. */
726 extern void not(environment *env)
727 {
728 int val;
729
730 if((env->head)==NULL) {
731 printerr("Too Few Arguments");
732 env->err= 1;
733 return;
734 }
735
736 if(env->head->item->type!=integer) {
737 printerr("Bad Argument Type");
738 env->err= 2;
739 return;
740 }
741
742 val= env->head->item->content.val;
743 toss(env);
744 push_int(env, !val);
745 }
746
747 /* Compares the two top elements on the stack and return 0 if they're the
748 same. */
749 extern void neq(environment *env)
750 {
751 eq(env);
752 not(env);
753 }
754
755 /* Give a symbol some content. */
756 extern void def(environment *env)
757 {
758 symbol *sym;
759
760 /* Needs two values on the stack, the top one must be a symbol */
761 if(env->head==NULL || env->head->next==NULL) {
762 printerr("Too Few Arguments");
763 env->err= 1;
764 return;
765 }
766
767 if(env->head->item->type!=symb) {
768 printerr("Bad Argument Type");
769 env->err= 2;
770 return;
771 }
772
773 /* long names are a pain */
774 sym= env->head->item->content.ptr;
775
776 /* Bind the symbol to the value */
777 sym->val= env->head->next->item;
778
779 toss(env); toss(env);
780 }
781
782 /* Quit stack. */
783 extern void quit(environment *env)
784 {
785 long i;
786
787 clear(env);
788
789 if (env->err) return;
790 for(i= 0; i<HASHTBLSIZE; i++) {
791 while(env->symbols[i]!= NULL) {
792 forget_sym(&(env->symbols[i]));
793 }
794 env->symbols[i]= NULL;
795 }
796
797 env->gc_limit= 0;
798 gc_init(env);
799
800 if(env->free_string!=NULL)
801 free(env->free_string);
802
803 muntrace();
804
805 exit(EXIT_SUCCESS);
806 }
807
808 /* Clear stack */
809 extern void clear(environment *env)
810 {
811 while(env->head!=NULL)
812 toss(env);
813 }
814
815 /* List all defined words */
816 extern void words(environment *env)
817 {
818 symbol *temp;
819 int i;
820
821 for(i= 0; i<HASHTBLSIZE; i++) {
822 temp= env->symbols[i];
823 while(temp!=NULL) {
824 printf("%s\n", temp->id);
825 temp= temp->next;
826 }
827 }
828 }
829
830 /* Internal forget function */
831 void forget_sym(symbol **hash_entry) {
832 symbol *temp;
833
834 temp= *hash_entry;
835 *hash_entry= (*hash_entry)->next;
836
837 free(temp->id);
838 free(temp);
839 }
840
841 /* Forgets a symbol (remove it from the hash table) */
842 extern void forget(environment *env)
843 {
844 char* sym_id;
845 stackitem *stack_head= env->head;
846
847 if(stack_head==NULL) {
848 printerr("Too Few Arguments");
849 env->err=1;
850 return;
851 }
852
853 if(stack_head->item->type!=symb) {
854 printerr("Bad Argument Type");
855 env->err=2;
856 return;
857 }
858
859 sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
860 toss(env);
861
862 return forget_sym(hash(env->symbols, sym_id));
863 }
864
865 /* Returns the current error number to the stack */
866 extern void errn(environment *env){
867 push_int(env, env->err);
868 }
869
870 int main(int argc, char **argv)
871 {
872 environment myenv;
873
874 int c; /* getopt option character */
875
876 mtrace();
877
878 init_env(&myenv);
879
880 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
881
882 while ((c = getopt (argc, argv, "i")) != -1)
883 switch (c)
884 {
885 case 'i':
886 myenv.interactive = 1;
887 break;
888 case '?':
889 fprintf (stderr,
890 "Unknown option character `\\x%x'.\n",
891 optopt);
892 return EX_USAGE;
893 default:
894 abort ();
895 }
896
897 if (optind < argc) {
898 myenv.interactive = 0;
899 myenv.inputstream= fopen(argv[optind], "r");
900 if(myenv.inputstream== NULL) {
901 perror(argv[0]);
902 exit (EX_NOINPUT);
903 }
904 }
905
906 while(1) {
907 if(myenv.in_string==NULL) {
908 if (myenv.interactive) {
909 if(myenv.err) {
910 printf("(error %d)\n", myenv.err);
911 }
912 nl();
913 printstack(&myenv);
914 printf("> ");
915 }
916 myenv.err=0;
917 }
918 sx_72656164(&myenv);
919 if (myenv.err==4) {
920 return EX_NOINPUT;
921 } else if(myenv.head!=NULL
922 && myenv.head->item->type==symb
923 && ((symbol*)(myenv.head->item->content.ptr))->id[0]==';') {
924 toss(&myenv); /* No error check in main */
925 eval(&myenv);
926 }
927 gc_init(&myenv);
928 }
929 quit(&myenv);
930 return EXIT_FAILURE;
931 }
932
933 /* "+" */
934 extern void sx_2b(environment *env) {
935 int a, b;
936 size_t len;
937 char* new_string;
938 value *a_val, *b_val;
939
940 if((env->head)==NULL || env->head->next==NULL) {
941 printerr("Too Few Arguments");
942 env->err= 1;
943 return;
944 }
945
946 if(env->head->item->type==string
947 && env->head->next->item->type==string) {
948 a_val= env->head->item;
949 b_val= env->head->next->item;
950 protect(env, a_val); protect(env, b_val);
951 toss(env); if(env->err) return;
952 toss(env); if(env->err) return;
953 len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
954 new_string= malloc(len);
955 strcpy(new_string, b_val->content.ptr);
956 strcat(new_string, a_val->content.ptr);
957 push_cstring(env, new_string);
958 unprotect(env); unprotect(env);
959 free(new_string);
960 return;
961 }
962
963 if(env->head->item->type!=integer
964 || env->head->next->item->type!=integer) {
965 printerr("Bad Argument Type");
966 env->err=2;
967 return;
968 }
969 a= env->head->item->content.val;
970 toss(env); if(env->err) return;
971
972 b= env->head->item->content.val;
973 toss(env); if(env->err) return;
974 push_int(env, a+b);
975 }
976
977 /* "-" */
978 extern void sx_2d(environment *env) {
979 int a, b;
980
981 if((env->head)==NULL || env->head->next==NULL) {
982 printerr("Too Few Arguments");
983 env->err=1;
984 return;
985 }
986
987 if(env->head->item->type!=integer
988 || env->head->next->item->type!=integer) {
989 printerr("Bad Argument Type");
990 env->err=2;
991 return;
992 }
993
994 a=env->head->item->content.val;
995 toss(env); if(env->err) return;
996 b=env->head->item->content.val;
997 toss(env); if(env->err) return;
998 push_int(env, b-a);
999 }
1000
1001 /* ">" */
1002 extern void sx_3e(environment *env) {
1003 int a, b;
1004
1005 if((env->head)==NULL || env->head->next==NULL) {
1006 printerr("Too Few Arguments");
1007 env->err=1;
1008 return;
1009 }
1010
1011 if(env->head->item->type!=integer
1012 || env->head->next->item->type!=integer) {
1013 printerr("Bad Argument Type");
1014 env->err=2;
1015 return;
1016 }
1017
1018 a=env->head->item->content.val;
1019 toss(env); if(env->err) return;
1020 b=env->head->item->content.val;
1021 toss(env); if(env->err) return;
1022 push_int(env, b>a);
1023 }
1024
1025 /* Return copy of a value */
1026 value *copy_val(environment *env, value *old_value){
1027 stackitem *old_item, *new_item, *prev_item;
1028
1029 value *new_value= new_val(env);
1030
1031 protect(env, old_value);
1032 new_value->type= old_value->type;
1033
1034 switch(old_value->type){
1035 case integer:
1036 new_value->content.val= old_value->content.val;
1037 break;
1038 case string:
1039 (char *)(new_value->content.ptr)=
1040 strdup((char *)(old_value->content.ptr));
1041 break;
1042 case func:
1043 case symb:
1044 new_value->content.ptr= old_value->content.ptr;
1045 break;
1046 case list:
1047 new_value->content.ptr= NULL;
1048
1049 prev_item= NULL;
1050 old_item= (stackitem*)(old_value->content.ptr);
1051
1052 while(old_item != NULL) { /* While list is not empty */
1053 new_item= malloc(sizeof(stackitem));
1054 new_item->item= copy_val(env, old_item->item); /* recurse */
1055 new_item->next= NULL;
1056 if(prev_item != NULL) /* If this wasn't the first item */
1057 prev_item->next= new_item; /* point the previous item to the
1058 new item */
1059 else
1060 new_value->content.ptr= new_item;
1061 old_item= old_item->next;
1062 prev_item= new_item;
1063 }
1064 break;
1065 }
1066
1067 unprotect(env);
1068
1069 return new_value;
1070 }
1071
1072 /* "dup"; duplicates an item on the stack */
1073 extern void sx_647570(environment *env) {
1074 if((env->head)==NULL) {
1075 printerr("Too Few Arguments");
1076 env->err= 1;
1077 return;
1078 }
1079 push_val(env, copy_val(env, env->head->item));
1080 }
1081
1082 /* "if", If-Then */
1083 extern void sx_6966(environment *env) {
1084
1085 int truth;
1086
1087 if((env->head)==NULL || env->head->next==NULL) {
1088 printerr("Too Few Arguments");
1089 env->err= 1;
1090 return;
1091 }
1092
1093 if(env->head->next->item->type != integer) {
1094 printerr("Bad Argument Type");
1095 env->err=2;
1096 return;
1097 }
1098
1099 swap(env);
1100 if(env->err) return;
1101
1102 truth=env->head->item->content.val;
1103
1104 toss(env);
1105 if(env->err) return;
1106
1107 if(truth)
1108 eval(env);
1109 else
1110 toss(env);
1111 }
1112
1113 /* If-Then-Else */
1114 extern void ifelse(environment *env) {
1115
1116 int truth;
1117
1118 if((env->head)==NULL || env->head->next==NULL
1119 || env->head->next->next==NULL) {
1120 printerr("Too Few Arguments");
1121 env->err=1;
1122 return;
1123 }
1124
1125 if(env->head->next->next->item->type != integer) {
1126 printerr("Bad Argument Type");
1127 env->err=2;
1128 return;
1129 }
1130
1131 rot(env);
1132 if(env->err) return;
1133
1134 truth=env->head->item->content.val;
1135
1136 toss(env);
1137 if(env->err) return;
1138
1139 if(!truth)
1140 swap(env);
1141 if(env->err) return;
1142
1143 toss(env);
1144 if(env->err) return;
1145
1146 eval(env);
1147 }
1148
1149 /* "while" */
1150 extern void sx_7768696c65(environment *env) {
1151
1152 int truth;
1153 value *loop, *test;
1154
1155 if((env->head)==NULL || env->head->next==NULL) {
1156 printerr("Too Few Arguments");
1157 env->err=1;
1158 return;
1159 }
1160
1161 loop= env->head->item;
1162 protect(env, loop);
1163 toss(env); if(env->err) return;
1164
1165 test= env->head->item;
1166 protect(env, test);
1167 toss(env); if(env->err) return;
1168
1169 do {
1170 push_val(env, test);
1171 eval(env);
1172
1173 if(env->head->item->type != integer) {
1174 printerr("Bad Argument Type");
1175 env->err= 2;
1176 return;
1177 }
1178
1179 truth= env->head->item->content.val;
1180 toss(env); if(env->err) return;
1181
1182 if(truth) {
1183 push_val(env, loop);
1184 eval(env);
1185 } else {
1186 toss(env);
1187 }
1188
1189 } while(truth);
1190
1191 unprotect(env); unprotect(env);
1192 }
1193
1194
1195 /* "for"; for-loop */
1196 extern void sx_666f72(environment *env) {
1197 value *loop;
1198 int foo1, foo2;
1199
1200 if(env->head==NULL || env->head->next==NULL
1201 || env->head->next->next==NULL) {
1202 printerr("Too Few Arguments");
1203 env->err= 1;
1204 return;
1205 }
1206
1207 if(env->head->next->item->type!=integer
1208 || env->head->next->next->item->type!=integer) {
1209 printerr("Bad Argument Type");
1210 env->err= 2;
1211 return;
1212 }
1213
1214 loop= env->head->item;
1215 protect(env, loop);
1216 toss(env); if(env->err) return;
1217
1218 foo2= env->head->item->content.val;
1219 toss(env); if(env->err) return;
1220
1221 foo1= env->head->item->content.val;
1222 toss(env); if(env->err) return;
1223
1224 if(foo1<=foo2) {
1225 while(foo1<=foo2) {
1226 push_int(env, foo1);
1227 push_val(env, loop);
1228 eval(env); if(env->err) return;
1229 foo1++;
1230 }
1231 } else {
1232 while(foo1>=foo2) {
1233 push_int(env, foo1);
1234 push_val(env, loop);
1235 eval(env); if(env->err) return;
1236 foo1--;
1237 }
1238 }
1239 unprotect(env);
1240 }
1241
1242 /* Variant of for-loop */
1243 extern void foreach(environment *env) {
1244
1245 value *loop, *foo;
1246 stackitem *iterator;
1247
1248 if((env->head)==NULL || env->head->next==NULL) {
1249 printerr("Too Few Arguments");
1250 env->err= 1;
1251 return;
1252 }
1253
1254 if(env->head->next->item->type != list) {
1255 printerr("Bad Argument Type");
1256 env->err= 2;
1257 return;
1258 }
1259
1260 loop= env->head->item;
1261 protect(env, loop);
1262 toss(env); if(env->err) return;
1263
1264 foo= env->head->item;
1265 protect(env, foo);
1266 toss(env); if(env->err) return;
1267
1268 iterator= foo->content.ptr;
1269
1270 while(iterator!=NULL) {
1271 push_val(env, iterator->item);
1272 push_val(env, loop);
1273 eval(env); if(env->err) return;
1274 iterator= iterator->next;
1275 }
1276 unprotect(env); unprotect(env);
1277 }
1278
1279 /* "to" */
1280 extern void to(environment *env) {
1281 int i, start, ending;
1282 stackitem *temp_head;
1283 value *temp_val;
1284
1285 if((env->head)==NULL || env->head->next==NULL) {
1286 printerr("Too Few Arguments");
1287 env->err=1;
1288 return;
1289 }
1290
1291 if(env->head->item->type!=integer
1292 || env->head->next->item->type!=integer) {
1293 printerr("Bad Argument Type");
1294 env->err=2;
1295 return;
1296 }
1297
1298 ending= env->head->item->content.val;
1299 toss(env); if(env->err) return;
1300 start= env->head->item->content.val;
1301 toss(env); if(env->err) return;
1302
1303 temp_head= env->head;
1304 env->head= NULL;
1305
1306 if(ending>=start) {
1307 for(i= ending; i>=start; i--)
1308 push_int(env, i);
1309 } else {
1310 for(i= ending; i<=start; i++)
1311 push_int(env, i);
1312 }
1313
1314 temp_val= new_val(env);
1315 temp_val->content.ptr= env->head;
1316 temp_val->type= list;
1317 env->head= temp_head;
1318 push_val(env, temp_val);
1319 }
1320
1321 /* Read a string */
1322 extern void readline(environment *env) {
1323 char in_string[101];
1324
1325 if(fgets(in_string, 100, env->inputstream)==NULL)
1326 push_cstring(env, "");
1327 else
1328 push_cstring(env, in_string);
1329 }
1330
1331 /* "read"; Read a value and place on stack */
1332 extern void sx_72656164(environment *env) {
1333 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1334 const char strform[]= "\"%[^\"]\"%n";
1335 const char intform[]= "%i%n";
1336 const char blankform[]= "%*[ \t]%n";
1337 const char ebrackform[]= "]%n";
1338 const char semicform[]= ";%n";
1339 const char bbrackform[]= "[%n";
1340
1341 int itemp, readlength= -1;
1342 static int depth= 0;
1343 char *match;
1344 size_t inlength;
1345
1346 if(env->in_string==NULL) {
1347 if(depth > 0 && env->interactive) {
1348 printf("]> ");
1349 }
1350 readline(env); if(env->err) return;
1351
1352 if(((char *)(env->head->item->content.ptr))[0]=='\0'){
1353 env->err= 4; /* "" means EOF */
1354 return;
1355 }
1356
1357 env->in_string= malloc(strlen(env->head->item->content.ptr)+1);
1358 env->free_string= env->in_string; /* Save the original pointer */
1359 strcpy(env->in_string, env->head->item->content.ptr);
1360 toss(env); if(env->err) return;
1361 }
1362
1363 inlength= strlen(env->in_string)+1;
1364 match= malloc(inlength);
1365
1366 if(sscanf(env->in_string, blankform, &readlength)!=EOF
1367 && readlength != -1) {
1368 ;
1369 } else if(sscanf(env->in_string, intform, &itemp, &readlength) != EOF
1370 && readlength != -1) {
1371 push_int(env, itemp);
1372 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1373 && readlength != -1) {
1374 push_cstring(env, match);
1375 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1376 && readlength != -1) {
1377 push_sym(env, match);
1378 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1379 && readlength != -1) {
1380 pack(env); if(env->err) return;
1381 if(depth != 0) depth--;
1382 } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1383 && readlength != -1) {
1384 push_sym(env, ";");
1385 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1386 && readlength != -1) {
1387 push_sym(env, "[");
1388 depth++;
1389 } else {
1390 free(env->free_string);
1391 env->in_string = env->free_string = NULL;
1392 }
1393 if ( env->in_string != NULL) {
1394 env->in_string += readlength;
1395 }
1396
1397 free(match);
1398
1399 if(depth)
1400 return sx_72656164(env);
1401 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26