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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.81 - (show annotations)
Thu Feb 14 19:20:28 2002 UTC (22 years, 2 months ago) by masse
Branch: MAIN
Changes since 1.80: +8 -12 lines
File MIME type: text/plain
(environment) Removed non_eval_flag (all users changed).
(free_val) Always free the value struct and id tag when refcount is 0.
(push_int, push_cstring) Set id tag to NULL.
(mangle) Use push_cstring instead of push_val.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26