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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.84 - (show annotations)
Fri Feb 15 01:21:13 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.83: +63 -20 lines
File MIME type: text/plain
(environment): New members "inputstream" and "interactive".
(init_env): Init all members in the same order as in the struct.
(quit): Bug fix: Don't run "words".
(main): Read options with getopt.  Set the interactive flag.
	Exit on error 4 (EOF) from "read".
(dup): Renamed/mangled to "sx_647570".  All callers changed.
(readline): Push "" if EOF.
(read): Renamed/mangled to "sx_72656164".  All callers changed.
	Don't print prompt unless interactive.
	Abort with error 4 on EOF.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26