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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.87 - (hide annotations)
Fri Feb 15 18:27:18 2002 UTC (22 years, 2 months ago) by masse
Branch: MAIN
Changes since 1.86: +134 -109 lines
File MIME type: text/plain
Added GC:
(free_val) Removed (all callers changed).
(new_val, gc_mark, gc_init) New functions.
(copy_val) Added argument with pointer to current environment.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26