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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.49 - (hide annotations)
Thu Feb 7 05:24:19 2002 UTC (22 years, 2 months ago) by masse
Branch: MAIN
Changes since 1.48: +22 -1 lines
File MIME type: text/plain
(eval) Bugfix.
(sx_2b) Can now concatenate strings.

1 masse 1.1 /* printf */
2     #include <stdio.h>
3     /* EXIT_SUCCESS */
4     #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.18 /* assert */
10     #include <assert.h>
11 masse 1.47 /* strcat */
12     #include <string.h>
13 masse 1.1
14     #define HASHTBLSIZE 65536
15    
16 teddy 1.28 /* First, define some types. */
17    
18     /* A value of some type */
19     typedef struct {
20 masse 1.16 enum {
21 teddy 1.28 integer,
22 teddy 1.18 string,
23 masse 1.16 func, /* Function pointer */
24 teddy 1.28 symb,
25 masse 1.16 list
26 teddy 1.18 } type; /* Type of stack element */
27    
28 masse 1.1 union {
29 teddy 1.28 void *ptr; /* Pointer to the content */
30 masse 1.16 int val; /* ...or an integer */
31     } content; /* Stores a pointer or an integer */
32 masse 1.1
33 teddy 1.28 int refcount; /* Reference counter */
34    
35     } value;
36    
37     /* A symbol with a name and possible value */
38     /* (These do not need reference counters, they are kept unique by
39     hashing.) */
40     typedef struct symbol_struct {
41     char *id; /* Symbol name */
42     value *val; /* The value (if any) bound to it */
43     struct symbol_struct *next; /* In case of hashing conflicts, a */
44     } symbol; /* symbol is a kind of stack item. */
45    
46     /* A type for a hash table for symbols */
47     typedef symbol *hashtbl[HASHTBLSIZE]; /* Hash table declaration */
48    
49     /* An item (value) on a stack */
50     typedef struct stackitem_struct
51     {
52     value *item; /* The value on the stack */
53     struct stackitem_struct *next; /* Next item */
54 masse 1.1 } stackitem;
55    
56 teddy 1.28 /* An environment; gives access to the stack and a hash table of
57     defined symbols */
58     typedef struct {
59     stackitem *head; /* Head of the stack */
60     hashtbl symbols; /* Hash table of all variable bindings */
61 teddy 1.33 int err; /* Error flag */
62 masse 1.46 int non_eval_flag;
63 teddy 1.28 } environment;
64    
65     /* A type for pointers to external functions */
66     typedef void (*funcp)(environment *); /* funcp is a pointer to a void
67     function (environment *) */
68 masse 1.1
69 teddy 1.28 /* Initialize a newly created environment */
70     void init_env(environment *env)
71 masse 1.1 {
72 masse 1.46 int i;
73 masse 1.1
74 masse 1.46 env->err= 0;
75     env->non_eval_flag= 0;
76 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
77 teddy 1.28 env->symbols[i]= NULL;
78 masse 1.1 }
79    
80 teddy 1.48 void printerr(const char* in_string) {
81     fprintf(stderr, "Err: %s\n", in_string);
82     }
83    
84     /* Throw away a value */
85     void free_val(value *val){
86     stackitem *item, *temp;
87    
88     val->refcount--; /* Decrease the reference count */
89     if(val->refcount == 0){
90     switch (val->type){ /* and free the contents if necessary */
91     case string:
92     free(val->content.ptr);
93     break;
94     case list: /* lists needs to be freed recursively */
95     item=val->content.ptr;
96     while(item != NULL) { /* for all stack items */
97     free_val(item->item); /* free the value */
98     temp=item->next; /* save next ptr */
99     free(item); /* free the stackitem */
100     item=temp; /* go to next stackitem */
101     }
102     free(val); /* Free the actual list value */
103     break;
104     default:
105     break;
106     }
107     }
108     }
109    
110     /* Discard the top element of the stack. */
111     extern void toss(environment *env)
112     {
113     stackitem *temp= env->head;
114    
115     if((env->head)==NULL) {
116     printerr("Too Few Arguments");
117     env->err=1;
118     return;
119     }
120    
121     free_val(env->head->item); /* Free the value */
122     env->head= env->head->next; /* Remove the top stack item */
123     free(temp); /* Free the old top stack item */
124     }
125    
126 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
127 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
128 masse 1.1 {
129 masse 1.46 int i= 0;
130     unsigned int out_hash= 0;
131 teddy 1.18 char key= '\0';
132 teddy 1.28 symbol **position;
133 masse 1.1
134 masse 1.16 while(1){ /* Hash in_string */
135 masse 1.1 key= in_string[i++];
136     if(key=='\0')
137     break;
138     out_hash= out_hash*32+key;
139     }
140    
141     out_hash= out_hash%HASHTBLSIZE;
142     position= &(in_hashtbl[out_hash]);
143    
144 masse 1.25 while(1){
145 teddy 1.18 if(*position==NULL) /* If empty */
146 masse 1.1 return position;
147    
148 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
149 masse 1.1 return position;
150    
151 masse 1.16 position= &((*position)->next); /* Try next */
152 masse 1.1 }
153     }
154    
155 masse 1.14 /* Generic push function. */
156 teddy 1.35 void push(stackitem** stack_head, stackitem* in_item)
157 masse 1.1 {
158     in_item->next= *stack_head;
159     *stack_head= in_item;
160     }
161    
162 teddy 1.29 /* Push a value onto the stack */
163     void push_val(stackitem **stack_head, value *val)
164     {
165     stackitem *new_item= malloc(sizeof(stackitem));
166     new_item->item= val;
167     val->refcount++;
168     push(stack_head, new_item);
169     }
170    
171 teddy 1.28 /* Push an integer onto the stack. */
172 teddy 1.35 void push_int(stackitem **stack_head, int in_val)
173 masse 1.1 {
174 teddy 1.28 value *new_value= malloc(sizeof(value));
175     stackitem *new_item= malloc(sizeof(stackitem));
176     new_item->item= new_value;
177    
178     new_value->content.val= in_val;
179     new_value->type= integer;
180     new_value->refcount=1;
181 masse 1.1
182     push(stack_head, new_item);
183     }
184    
185 masse 1.14 /* Copy a string onto the stack. */
186 teddy 1.35 void push_cstring(stackitem **stack_head, const char *in_string)
187 masse 1.1 {
188 teddy 1.28 value *new_value= malloc(sizeof(value));
189     stackitem *new_item= malloc(sizeof(stackitem));
190     new_item->item=new_value;
191    
192     new_value->content.ptr= malloc(strlen(in_string)+1);
193     strcpy(new_value->content.ptr, in_string);
194     new_value->type= string;
195     new_value->refcount=1;
196 masse 1.1
197     push(stack_head, new_item);
198     }
199    
200 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
201     char *mangle_(const char *old_string){
202     char validchars[]
203     ="0123456789abcdef";
204     char *new_string, *current;
205    
206     new_string=malloc(strlen(old_string)+4);
207     strcpy(new_string, "sx_"); /* Stack eXternal */
208     current=new_string+3;
209     while(old_string[0] != '\0'){
210     current[0]=validchars[old_string[0]/16];
211     current[1]=validchars[old_string[0]%16];
212     current+=2;
213     old_string++;
214     }
215     current[0]='\0';
216    
217     return new_string; /* The caller must free() it */
218     }
219    
220     extern void mangle(environment *env){
221     value *new_value;
222     char *new_string;
223    
224     if((env->head)==NULL) {
225     printerr("Too Few Arguments");
226     env->err=1;
227     return;
228     }
229    
230     if(env->head->item->type!=string) {
231     printerr("Bad Argument Type");
232     env->err=2;
233     return;
234     }
235    
236     new_string= mangle_((const char *)(env->head->item->content.ptr));
237    
238     toss(env);
239     if(env->err) return;
240    
241     new_value= malloc(sizeof(value));
242     new_value->content.ptr= new_string;
243     new_value->type= string;
244     new_value->refcount=1;
245    
246     push_val(&(env->head), new_value);
247     }
248    
249 teddy 1.28 /* Push a symbol onto the stack. */
250 teddy 1.35 void push_sym(environment *env, const char *in_string)
251 masse 1.1 {
252 teddy 1.28 stackitem *new_item; /* The new stack item */
253     /* ...which will contain... */
254     value *new_value; /* A new symbol value */
255     /* ...which might point to... */
256 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
257 teddy 1.28 /* ...which, if possible, will be bound to... */
258     value *new_fvalue; /* (if needed) A new function value */
259     /* ...which will point to... */
260     void *funcptr; /* A function pointer */
261    
262     static void *handle= NULL; /* Dynamic linker handle */
263 teddy 1.48 const char *dlerr; /* Dynamic linker error */
264     char *mangled; /* Mangled function name */
265 teddy 1.28
266     /* Create a new stack item containing a new value */
267     new_item= malloc(sizeof(stackitem));
268     new_value= malloc(sizeof(value));
269     new_item->item=new_value;
270    
271     /* The new value is a symbol */
272     new_value->type= symb;
273     new_value->refcount= 1;
274    
275     /* Look up the symbol name in the hash table */
276 teddy 1.29 new_symbol= hash(env->symbols, in_string);
277     new_value->content.ptr= *new_symbol;
278 teddy 1.28
279 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
280 teddy 1.28
281     /* Create a new symbol */
282 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
283 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
284     (*new_symbol)->next= NULL;
285     (*new_symbol)->id= malloc(strlen(in_string)+1);
286     strcpy((*new_symbol)->id, in_string);
287 masse 1.1
288 teddy 1.28 /* Intern the new symbol in the hash table */
289 teddy 1.29 new_value->content.ptr= *new_symbol;
290 masse 1.1
291 teddy 1.28 /* Try to load the symbol name as an external function, to see if
292     we should bind the symbol to a new function pointer value */
293 masse 1.16 if(handle==NULL) /* If no handle */
294 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
295 masse 1.6
296 teddy 1.28 funcptr= dlsym(handle, in_string); /* Get function pointer */
297 teddy 1.48 dlerr=dlerror();
298     if(dlerr != NULL) { /* If no function was found */
299     mangled=mangle_(in_string);
300     funcptr= dlsym(handle, mangled); /* try mangling it */
301     free(mangled);
302     dlerr=dlerror();
303     }
304     if(dlerr==NULL) { /* If a function was found */
305 teddy 1.28 new_fvalue= malloc(sizeof(value)); /* Create a new value */
306     new_fvalue->type=func; /* The new value is a function pointer */
307     new_fvalue->content.ptr=funcptr; /* Store function pointer */
308 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
309     function value */
310 teddy 1.28 new_fvalue->refcount= 1;
311     }
312 masse 1.1 }
313 teddy 1.28 push(&(env->head), new_item);
314 masse 1.1 }
315    
316 masse 1.14 /* Print newline. */
317 masse 1.34 extern void nl()
318 masse 1.8 {
319     printf("\n");
320     }
321 masse 1.1
322 teddy 1.37 /* Gets the type of a value */
323     extern void type(environment *env){
324     int typenum;
325    
326     if((env->head)==NULL) {
327     printerr("Too Few Arguments");
328     env->err=1;
329     return;
330     }
331     typenum=env->head->item->type;
332     toss(env);
333     switch(typenum){
334     case integer:
335     push_sym(env, "integer");
336     break;
337     case string:
338     push_sym(env, "string");
339     break;
340     case symb:
341     push_sym(env, "symbol");
342     break;
343     case func:
344     push_sym(env, "function");
345     break;
346     case list:
347     push_sym(env, "list");
348     break;
349     default:
350     push_sym(env, "unknown");
351     break;
352     }
353     }
354    
355 masse 1.14 /* Prints the top element of the stack. */
356 teddy 1.28 void print_h(stackitem *stack_head)
357 masse 1.8 {
358 teddy 1.28 switch(stack_head->item->type) {
359     case integer:
360     printf("%d", stack_head->item->content.val);
361 teddy 1.2 break;
362     case string:
363 teddy 1.28 printf("\"%s\"", (char*)stack_head->item->content.ptr);
364 teddy 1.2 break;
365 teddy 1.28 case symb:
366 teddy 1.45 printf("%s", ((symbol *)(stack_head->item->content.ptr))->id);
367 masse 1.6 break;
368 teddy 1.35 case func:
369     printf("#<function %p>", (funcp)(stack_head->item->content.ptr));
370     break;
371     case list:
372 teddy 1.38 /* A list is just a stack, so make stack_head point to it */
373     stack_head=(stackitem *)(stack_head->item->content.ptr);
374     printf("[ ");
375     while(stack_head != NULL) {
376     print_h(stack_head);
377     printf(" ");
378     stack_head=stack_head->next;
379     }
380 teddy 1.39 printf("]");
381 teddy 1.35 break;
382 masse 1.7 default:
383 teddy 1.38 printf("#<unknown %p>", (stack_head->item->content.ptr));
384 teddy 1.2 break;
385     }
386 masse 1.1 }
387    
388 teddy 1.28 extern void print_(environment *env) {
389 teddy 1.35 if(env->head==NULL) {
390 teddy 1.36 printerr("Too Few Arguments");
391 teddy 1.35 env->err=1;
392     return;
393     }
394 teddy 1.28 print_h(env->head);
395     }
396    
397 masse 1.14 /* Prints the top element of the stack and then discards it. */
398 teddy 1.28 extern void print(environment *env)
399 masse 1.8 {
400 teddy 1.28 print_(env);
401 teddy 1.35 if(env->err) return;
402 teddy 1.28 toss(env);
403 masse 1.8 }
404    
405 masse 1.14 /* Only to be called by function printstack. */
406 teddy 1.28 void print_st(stackitem *stack_head, long counter)
407 masse 1.8 {
408     if(stack_head->next != NULL)
409     print_st(stack_head->next, counter+1);
410     printf("%ld: ", counter);
411 teddy 1.28 print_h(stack_head);
412 masse 1.8 nl();
413     }
414    
415 masse 1.14 /* Prints the stack. */
416 teddy 1.28 extern void printstack(environment *env)
417 masse 1.1 {
418 teddy 1.35 if(env->head == NULL) {
419     return;
420 masse 1.1 }
421 teddy 1.35 print_st(env->head, 1);
422     nl();
423 masse 1.1 }
424    
425 masse 1.26 /* Swap the two top elements on the stack. */
426 teddy 1.28 extern void swap(environment *env)
427 masse 1.26 {
428 teddy 1.28 stackitem *temp= env->head;
429 masse 1.26
430 masse 1.46 if(env->head==NULL || env->head->next==NULL) {
431 teddy 1.36 printerr("Too Few Arguments");
432 teddy 1.35 env->err=1;
433 masse 1.26 return;
434 teddy 1.28 }
435 masse 1.26
436 teddy 1.28 env->head= env->head->next;
437     temp->next= env->head->next;
438     env->head->next= temp;
439 masse 1.26 }
440    
441 teddy 1.33 /* Recall a value from a symbol, if bound */
442 teddy 1.31 extern void rcl(environment *env)
443     {
444     value *val;
445    
446     if(env->head == NULL) {
447 teddy 1.36 printerr("Too Few Arguments");
448 teddy 1.35 env->err=1;
449 teddy 1.31 return;
450     }
451    
452     if(env->head->item->type!=symb) {
453 teddy 1.36 printerr("Bad Argument Type");
454     env->err=2;
455 teddy 1.31 return;
456     }
457 teddy 1.35
458 teddy 1.31 val=((symbol *)(env->head->item->content.ptr))->val;
459 teddy 1.33 if(val == NULL){
460 teddy 1.36 printerr("Unbound Variable");
461     env->err=3;
462 teddy 1.33 return;
463     }
464 teddy 1.31 toss(env); /* toss the symbol */
465 teddy 1.35 if(env->err) return;
466 teddy 1.31 push_val(&(env->head), val); /* Return its bound value */
467     }
468 masse 1.26
469 masse 1.46 void stack_read(environment*, char*);
470    
471 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
472     function value, and if it is, toss the symbol and execute the
473     function. */
474 teddy 1.28 extern void eval(environment *env)
475 masse 1.1 {
476     funcp in_func;
477 masse 1.44 value* temp_val;
478     stackitem* iterator;
479 masse 1.47 char* temp_string;
480 masse 1.44
481 teddy 1.29 if(env->head==NULL) {
482 teddy 1.36 printerr("Too Few Arguments");
483 teddy 1.35 env->err=1;
484 masse 1.1 return;
485 masse 1.17 }
486 masse 1.1
487 masse 1.46 switch(env->head->item->type) {
488     /* if it's a symbol */
489     case symb:
490 teddy 1.35 rcl(env); /* get its contents */
491     if(env->err) return;
492     if(env->head->item->type!=symb){ /* don't recurse symbols */
493     eval(env); /* evaluate the value */
494 teddy 1.29 return;
495     }
496 masse 1.46 break;
497 masse 1.22
498 masse 1.46 /* If it's a lone function value, run it */
499     case func:
500 teddy 1.29 in_func= (funcp)(env->head->item->content.ptr);
501 teddy 1.28 toss(env);
502 teddy 1.35 if(env->err) return;
503 teddy 1.28 (*in_func)(env);
504 masse 1.46 break;
505 masse 1.44
506 masse 1.46 /* If it's a list */
507     case list:
508 masse 1.44 temp_val= env->head->item;
509     env->head->item->refcount++;
510     toss(env);
511     if(env->err) return;
512     iterator= (stackitem*)temp_val->content.ptr;
513     while(iterator!=NULL && iterator->item!=NULL) {
514     push_val(&(env->head), iterator->item);
515     if(env->head->item->type==symb
516     && strcmp(";", ((symbol*)(env->head->item->content.ptr))->id)==0) {
517     toss(env);
518     if(env->err) return;
519     eval(env);
520 masse 1.46 if(env->err) return;
521 masse 1.44 }
522     iterator= iterator->next;
523     }
524     free_val(temp_val);
525 masse 1.46 break;
526    
527     /* If it's a string */
528     case string:
529     temp_val= env->head->item;
530     env->head->item->refcount++;
531     toss(env);
532     if(env->err) return;
533 masse 1.47 temp_string= malloc(strlen((char*)temp_val->content.ptr)+5);
534 masse 1.49 strcpy(temp_string, "[ ");
535 masse 1.47 strcat(temp_string, (char*)temp_val->content.ptr);
536     strcat(temp_string, " ]");
537     stack_read(env, temp_string);
538 masse 1.46 eval(env);
539     if(env->err) return;
540     free_val(temp_val);
541 masse 1.47 free(temp_string);
542 masse 1.46 break;
543    
544     default:
545 masse 1.26 }
546 masse 1.1 }
547    
548 masse 1.44 /* Reverse (flip) a list */
549 teddy 1.40 extern void rev(environment *env){
550     stackitem *old_head, *new_head, *item;
551    
552     if((env->head)==NULL) {
553     printerr("Too Few Arguments");
554     env->err=1;
555     return;
556     }
557    
558     if(env->head->item->type!=list) {
559     printerr("Bad Argument Type");
560     env->err=2;
561     return;
562     }
563    
564     old_head=(stackitem *)(env->head->item->content.ptr);
565     new_head=NULL;
566     while(old_head != NULL){
567     item=old_head;
568     old_head=old_head->next;
569     item->next=new_head;
570     new_head=item;
571     }
572     env->head->item->content.ptr=new_head;
573     }
574    
575 masse 1.19 /* Make a list. */
576 teddy 1.28 extern void pack(environment *env)
577 masse 1.19 {
578     void* delimiter;
579 teddy 1.28 stackitem *iterator, *temp;
580     value *pack;
581 masse 1.19
582 teddy 1.28 delimiter= env->head->item->content.ptr; /* Get delimiter */
583     toss(env);
584 masse 1.19
585 teddy 1.28 iterator= env->head;
586 masse 1.19
587 teddy 1.28 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
588 masse 1.24 temp= NULL;
589 teddy 1.28 toss(env);
590 masse 1.24 } else {
591     /* Search for first delimiter */
592 teddy 1.28 while(iterator->next!=NULL
593     && iterator->next->item->content.ptr!=delimiter)
594 masse 1.24 iterator= iterator->next;
595    
596     /* Extract list */
597 teddy 1.28 temp= env->head;
598     env->head= iterator->next;
599 masse 1.24 iterator->next= NULL;
600    
601 teddy 1.28 if(env->head!=NULL)
602     toss(env);
603 masse 1.24 }
604 masse 1.19
605     /* Push list */
606 teddy 1.28 pack= malloc(sizeof(value));
607 masse 1.19 pack->type= list;
608     pack->content.ptr= temp;
609 teddy 1.28 pack->refcount= 1;
610    
611     temp= malloc(sizeof(stackitem));
612     temp->item= pack;
613 masse 1.19
614 teddy 1.28 push(&(env->head), temp);
615 teddy 1.40 rev(env);
616 masse 1.19 }
617    
618 masse 1.14 /* Parse input. */
619 teddy 1.37 void stack_read(environment *env, char *in_line)
620 masse 1.1 {
621     char *temp, *rest;
622     int itemp;
623     size_t inlength= strlen(in_line)+1;
624     int convert= 0;
625    
626     temp= malloc(inlength);
627     rest= malloc(inlength);
628    
629 masse 1.15 do {
630 masse 1.43 /* If comment */
631     if((convert= sscanf(in_line, "#%[^\n\r]", rest))) {
632     free(temp); free(rest);
633     return;
634     }
635    
636 masse 1.16 /* If string */
637 masse 1.15 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
638 teddy 1.28 push_cstring(&(env->head), temp);
639 masse 1.15 break;
640     }
641 teddy 1.28 /* If integer */
642 masse 1.15 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
643 teddy 1.29 push_int(&(env->head), itemp);
644 masse 1.15 break;
645     }
646 masse 1.16 /* Escape ';' with '\' */
647 masse 1.15 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
648 teddy 1.28 temp[1]= '\0';
649     push_sym(env, temp);
650 masse 1.15 break;
651     }
652 masse 1.16 /* If symbol */
653 masse 1.34 if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {
654 teddy 1.28 push_sym(env, temp);
655 masse 1.15 break;
656     }
657 masse 1.19 /* If single char */
658     if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
659     if(*temp==';') {
660 masse 1.46 if(!env->non_eval_flag) {
661 teddy 1.28 eval(env); /* Evaluate top element */
662 masse 1.20 break;
663     }
664    
665 teddy 1.28 push_sym(env, ";");
666 masse 1.19 break;
667     }
668    
669     if(*temp==']') {
670 teddy 1.28 push_sym(env, "[");
671     pack(env);
672 masse 1.46 if(env->non_eval_flag)
673     env->non_eval_flag--;
674 masse 1.20 break;
675     }
676    
677     if(*temp=='[') {
678 teddy 1.28 push_sym(env, "[");
679 masse 1.46 env->non_eval_flag++;
680 masse 1.19 break;
681     }
682 masse 1.15 }
683     } while(0);
684    
685 masse 1.1 free(temp);
686    
687     if(convert<2) {
688     free(rest);
689 teddy 1.37 return;
690 masse 1.1 }
691    
692 teddy 1.28 stack_read(env, rest);
693 masse 1.1
694     free(rest);
695 masse 1.7 }
696 masse 1.1
697 masse 1.16 /* Relocate elements of the list on the stack. */
698 teddy 1.28 extern void expand(environment *env)
699 masse 1.1 {
700 masse 1.8 stackitem *temp, *new_head;
701    
702 masse 1.16 /* Is top element a list? */
703 teddy 1.36 if(env->head==NULL) {
704     printerr("Too Few Arguments");
705 teddy 1.35 env->err=1;
706 masse 1.8 return;
707 masse 1.17 }
708 teddy 1.36 if(env->head->item->type!=list) {
709     printerr("Bad Argument Type");
710     env->err=2;
711     return;
712     }
713 masse 1.43
714     rev(env);
715    
716     if(env->err)
717     return;
718 masse 1.8
719 masse 1.16 /* The first list element is the new stack head */
720 teddy 1.28 new_head= temp= env->head->item->content.ptr;
721 masse 1.8
722 teddy 1.28 env->head->item->refcount++;
723     toss(env);
724 masse 1.24
725 teddy 1.28 /* Find the end of the list */
726 masse 1.8 while(temp->next!=NULL)
727     temp= temp->next;
728    
729 teddy 1.28 /* Connect the tail of the list with the old stack head */
730     temp->next= env->head;
731     env->head= new_head; /* ...and voila! */
732    
733 teddy 1.5 }
734 masse 1.11
735 masse 1.14 /* Compares two elements by reference. */
736 teddy 1.28 extern void eq(environment *env)
737 masse 1.11 {
738     void *left, *right;
739     int result;
740    
741 teddy 1.28 if((env->head)==NULL || env->head->next==NULL) {
742 teddy 1.36 printerr("Too Few Arguments");
743 teddy 1.35 env->err=1;
744 masse 1.11 return;
745 masse 1.17 }
746 masse 1.11
747 teddy 1.28 left= env->head->item->content.ptr;
748     swap(env);
749     right= env->head->item->content.ptr;
750 masse 1.11 result= (left==right);
751    
752 teddy 1.28 toss(env); toss(env);
753 teddy 1.29 push_int(&(env->head), result);
754 masse 1.11 }
755    
756 masse 1.14 /* Negates the top element on the stack. */
757 teddy 1.28 extern void not(environment *env)
758 masse 1.11 {
759 teddy 1.28 int val;
760 masse 1.11
761 teddy 1.36 if((env->head)==NULL) {
762     printerr("Too Few Arguments");
763 teddy 1.35 env->err=1;
764 masse 1.11 return;
765 masse 1.17 }
766 masse 1.11
767 teddy 1.36 if(env->head->item->type!=integer) {
768     printerr("Bad Argument Type");
769     env->err=2;
770     return;
771     }
772    
773 teddy 1.28 val= env->head->item->content.val;
774     toss(env);
775 teddy 1.29 push_int(&(env->head), !val);
776 masse 1.11 }
777    
778 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
779     same. */
780 teddy 1.28 extern void neq(environment *env)
781 masse 1.11 {
782 teddy 1.28 eq(env);
783     not(env);
784 masse 1.11 }
785 masse 1.12
786 masse 1.14 /* Give a symbol some content. */
787 teddy 1.28 extern void def(environment *env)
788 masse 1.12 {
789 teddy 1.28 symbol *sym;
790 masse 1.12
791 teddy 1.28 /* Needs two values on the stack, the top one must be a symbol */
792 teddy 1.36 if(env->head==NULL || env->head->next==NULL) {
793     printerr("Too Few Arguments");
794 teddy 1.35 env->err=1;
795 masse 1.12 return;
796 masse 1.17 }
797 masse 1.12
798 teddy 1.36 if(env->head->item->type!=symb) {
799     printerr("Bad Argument Type");
800     env->err=2;
801     return;
802     }
803    
804 teddy 1.28 /* long names are a pain */
805     sym=env->head->item->content.ptr;
806    
807     /* if the symbol was bound to something else, throw it away */
808     if(sym->val != NULL)
809     free_val(sym->val);
810    
811     /* Bind the symbol to the value */
812     sym->val= env->head->next->item;
813     sym->val->refcount++; /* Increase the reference counter */
814 masse 1.12
815 teddy 1.28 toss(env); toss(env);
816 masse 1.12 }
817 masse 1.10
818 masse 1.14 /* Quit stack. */
819 teddy 1.28 extern void quit(environment *env)
820 teddy 1.5 {
821     exit(EXIT_SUCCESS);
822 masse 1.24 }
823    
824     /* Clear stack */
825 teddy 1.28 extern void clear(environment *env)
826 masse 1.24 {
827 teddy 1.28 while(env->head!=NULL)
828     toss(env);
829 masse 1.1 }
830    
831 teddy 1.33 /* List all defined words */
832 masse 1.32 extern void words(environment *env)
833     {
834     symbol *temp;
835     int i;
836    
837     for(i= 0; i<HASHTBLSIZE; i++) {
838     temp= env->symbols[i];
839     while(temp!=NULL) {
840     printf("%s\n", temp->id);
841     temp= temp->next;
842     }
843     }
844     }
845 masse 1.34
846     /* Forgets a symbol (remove it from the hash table) */
847     extern void forget(environment *env)
848     {
849     char* sym_id;
850     stackitem *stack_head= env->head;
851     symbol **hash_entry, *temp;
852    
853 teddy 1.36 if(stack_head==NULL) {
854     printerr("Too Few Arguments");
855     env->err=1;
856     return;
857     }
858    
859     if(stack_head->item->type!=symb) {
860     printerr("Bad Argument Type");
861     env->err=2;
862 masse 1.34 return;
863     }
864    
865     sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
866     toss(env);
867    
868     hash_entry= hash(env->symbols, sym_id);
869     temp= *hash_entry;
870     *hash_entry= (*hash_entry)->next;
871    
872     if(temp->val!=NULL) {
873     free_val(temp->val);
874     }
875     free(temp->id);
876     free(temp);
877 teddy 1.36 }
878    
879     /* Returns the current error number to the stack */
880     extern void errn(environment *env){
881     push_int(&(env->head), env->err);
882     }
883 masse 1.32
884 masse 1.1 int main()
885     {
886 teddy 1.28 environment myenv;
887 masse 1.1 char in_string[100];
888    
889 teddy 1.28 init_env(&myenv);
890 masse 1.1
891     printf("okidok\n ");
892    
893     while(fgets(in_string, 100, stdin) != NULL) {
894 teddy 1.28 stack_read(&myenv, in_string);
895 teddy 1.35 if(myenv.err) {
896     printf("(error %d) ", myenv.err);
897     myenv.err=0;
898     }
899 masse 1.1 printf("okidok\n ");
900     }
901 teddy 1.41 quit(&myenv);
902 teddy 1.42 return EXIT_FAILURE;
903 teddy 1.48 }
904    
905     /* + */
906     extern void sx_2b(environment *env) {
907     int a, b;
908 masse 1.49 size_t len;
909     char* new_string;
910     value *a_val, *b_val;
911 teddy 1.48
912     if((env->head)==NULL || env->head->next==NULL) {
913     printerr("Too Few Arguments");
914     env->err=1;
915 masse 1.49 return;
916     }
917    
918     if(env->head->item->type==string
919     && env->head->next->item->type==string) {
920     a_val= env->head->item;
921     b_val= env->head->next->item;
922     a_val->refcount++;
923     b_val->refcount++;
924     toss(env); if(env->err) return;
925     toss(env); if(env->err) return;
926     len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
927     new_string= malloc(len);
928     strcpy(new_string, b_val->content.ptr);
929     strcat(new_string, a_val->content.ptr);
930     free_val(a_val); free_val(b_val);
931     push_cstring(&(env->head), new_string);
932     free(new_string);
933 teddy 1.48 return;
934     }
935    
936     if(env->head->item->type!=integer
937     || env->head->next->item->type!=integer) {
938     printerr("Bad Argument Type");
939     env->err=2;
940     return;
941     }
942     a=env->head->item->content.val;
943     toss(env);
944     if(env->err) return;
945     b=env->head->item->content.val;
946     toss(env);
947     if(env->err) return;
948     push_int(&(env->head), a+b);
949 masse 1.1 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26