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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.55 - (hide annotations)
Fri Feb 8 00:59:34 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.54: +55 -0 lines
File MIME type: text/plain
(copy_val): New function; makes a copy of a value.
(dup): New function; uses 'copy_val' to make a copy of an item on the stack.

1 teddy 1.52 /* printf, sscanf, fgets, fprintf */
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 masse 1.1
12     #define HASHTBLSIZE 65536
13    
14 teddy 1.28 /* First, define some types. */
15    
16     /* A value of some type */
17     typedef struct {
18 masse 1.16 enum {
19 teddy 1.28 integer,
20 teddy 1.18 string,
21 masse 1.16 func, /* Function pointer */
22 teddy 1.28 symb,
23 masse 1.16 list
24 teddy 1.18 } type; /* Type of stack element */
25    
26 masse 1.1 union {
27 teddy 1.28 void *ptr; /* Pointer to the content */
28 masse 1.16 int val; /* ...or an integer */
29     } content; /* Stores a pointer or an integer */
30 masse 1.1
31 teddy 1.28 int refcount; /* Reference counter */
32    
33     } value;
34    
35     /* A symbol with a name and possible value */
36     /* (These do not need reference counters, they are kept unique by
37     hashing.) */
38     typedef struct symbol_struct {
39     char *id; /* Symbol name */
40     value *val; /* The value (if any) bound to it */
41     struct symbol_struct *next; /* In case of hashing conflicts, a */
42     } symbol; /* symbol is a kind of stack item. */
43    
44     /* A type for a hash table for symbols */
45     typedef symbol *hashtbl[HASHTBLSIZE]; /* Hash table declaration */
46    
47     /* An item (value) on a stack */
48     typedef struct stackitem_struct
49     {
50     value *item; /* The value on the stack */
51     struct stackitem_struct *next; /* Next item */
52 masse 1.1 } stackitem;
53    
54 teddy 1.28 /* An environment; gives access to the stack and a hash table of
55     defined symbols */
56     typedef struct {
57     stackitem *head; /* Head of the stack */
58     hashtbl symbols; /* Hash table of all variable bindings */
59 teddy 1.33 int err; /* Error flag */
60 masse 1.46 int non_eval_flag;
61 teddy 1.28 } environment;
62    
63     /* A type for pointers to external functions */
64     typedef void (*funcp)(environment *); /* funcp is a pointer to a void
65     function (environment *) */
66 masse 1.1
67 teddy 1.28 /* Initialize a newly created environment */
68     void init_env(environment *env)
69 masse 1.1 {
70 masse 1.46 int i;
71 masse 1.1
72 masse 1.46 env->err= 0;
73     env->non_eval_flag= 0;
74 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
75 teddy 1.28 env->symbols[i]= NULL;
76 masse 1.1 }
77    
78 teddy 1.48 void printerr(const char* in_string) {
79     fprintf(stderr, "Err: %s\n", in_string);
80     }
81    
82     /* Throw away a value */
83     void free_val(value *val){
84     stackitem *item, *temp;
85    
86     val->refcount--; /* Decrease the reference count */
87     if(val->refcount == 0){
88     switch (val->type){ /* and free the contents if necessary */
89     case string:
90     free(val->content.ptr);
91     break;
92     case list: /* lists needs to be freed recursively */
93     item=val->content.ptr;
94     while(item != NULL) { /* for all stack items */
95     free_val(item->item); /* free the value */
96     temp=item->next; /* save next ptr */
97     free(item); /* free the stackitem */
98     item=temp; /* go to next stackitem */
99     }
100     free(val); /* Free the actual list value */
101     break;
102 teddy 1.54 case integer:
103     case func:
104     case symb:
105 teddy 1.48 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 teddy 1.51 char *mangle_str(const char *old_string){
202 teddy 1.48 char validchars[]
203     ="0123456789abcdef";
204     char *new_string, *current;
205    
206 teddy 1.50 new_string=malloc((strlen(old_string)*2)+4);
207 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
208     current=new_string+3;
209     while(old_string[0] != '\0'){
210 teddy 1.53 current[0]=validchars[(unsigned char)(old_string[0])/16];
211     current[1]=validchars[(unsigned char)(old_string[0])%16];
212 teddy 1.48 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 teddy 1.51 new_string= mangle_str((const char *)(env->head->item->content.ptr));
237 teddy 1.48
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 teddy 1.51 mangled=mangle_str(in_string);
300 teddy 1.48 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 teddy 1.54 case integer:
545     break;
546 masse 1.26 }
547 masse 1.1 }
548    
549 masse 1.44 /* Reverse (flip) a list */
550 teddy 1.40 extern void rev(environment *env){
551     stackitem *old_head, *new_head, *item;
552    
553     if((env->head)==NULL) {
554     printerr("Too Few Arguments");
555     env->err=1;
556     return;
557     }
558    
559     if(env->head->item->type!=list) {
560     printerr("Bad Argument Type");
561     env->err=2;
562     return;
563     }
564    
565     old_head=(stackitem *)(env->head->item->content.ptr);
566     new_head=NULL;
567     while(old_head != NULL){
568     item=old_head;
569     old_head=old_head->next;
570     item->next=new_head;
571     new_head=item;
572     }
573     env->head->item->content.ptr=new_head;
574     }
575    
576 masse 1.19 /* Make a list. */
577 teddy 1.28 extern void pack(environment *env)
578 masse 1.19 {
579     void* delimiter;
580 teddy 1.28 stackitem *iterator, *temp;
581     value *pack;
582 masse 1.19
583 teddy 1.28 delimiter= env->head->item->content.ptr; /* Get delimiter */
584     toss(env);
585 masse 1.19
586 teddy 1.28 iterator= env->head;
587 masse 1.19
588 teddy 1.28 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
589 masse 1.24 temp= NULL;
590 teddy 1.28 toss(env);
591 masse 1.24 } else {
592     /* Search for first delimiter */
593 teddy 1.28 while(iterator->next!=NULL
594     && iterator->next->item->content.ptr!=delimiter)
595 masse 1.24 iterator= iterator->next;
596    
597     /* Extract list */
598 teddy 1.28 temp= env->head;
599     env->head= iterator->next;
600 masse 1.24 iterator->next= NULL;
601    
602 teddy 1.28 if(env->head!=NULL)
603     toss(env);
604 masse 1.24 }
605 masse 1.19
606     /* Push list */
607 teddy 1.28 pack= malloc(sizeof(value));
608 masse 1.19 pack->type= list;
609     pack->content.ptr= temp;
610 teddy 1.28 pack->refcount= 1;
611    
612     temp= malloc(sizeof(stackitem));
613     temp->item= pack;
614 masse 1.19
615 teddy 1.28 push(&(env->head), temp);
616 teddy 1.40 rev(env);
617 masse 1.19 }
618    
619 masse 1.14 /* Parse input. */
620 teddy 1.37 void stack_read(environment *env, char *in_line)
621 masse 1.1 {
622     char *temp, *rest;
623     int itemp;
624     size_t inlength= strlen(in_line)+1;
625     int convert= 0;
626    
627     temp= malloc(inlength);
628     rest= malloc(inlength);
629    
630 masse 1.15 do {
631 masse 1.43 /* If comment */
632     if((convert= sscanf(in_line, "#%[^\n\r]", rest))) {
633     free(temp); free(rest);
634     return;
635     }
636    
637 masse 1.16 /* If string */
638 masse 1.15 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
639 teddy 1.28 push_cstring(&(env->head), temp);
640 masse 1.15 break;
641     }
642 teddy 1.28 /* If integer */
643 masse 1.15 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
644 teddy 1.29 push_int(&(env->head), itemp);
645 masse 1.15 break;
646     }
647 masse 1.16 /* Escape ';' with '\' */
648 masse 1.15 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
649 teddy 1.28 temp[1]= '\0';
650     push_sym(env, temp);
651 masse 1.15 break;
652     }
653 masse 1.16 /* If symbol */
654 masse 1.34 if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {
655 teddy 1.28 push_sym(env, temp);
656 masse 1.15 break;
657     }
658 masse 1.19 /* If single char */
659     if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
660     if(*temp==';') {
661 masse 1.46 if(!env->non_eval_flag) {
662 teddy 1.28 eval(env); /* Evaluate top element */
663 masse 1.20 break;
664     }
665    
666 teddy 1.28 push_sym(env, ";");
667 masse 1.19 break;
668     }
669    
670     if(*temp==']') {
671 teddy 1.28 push_sym(env, "[");
672     pack(env);
673 masse 1.46 if(env->non_eval_flag)
674     env->non_eval_flag--;
675 masse 1.20 break;
676     }
677    
678     if(*temp=='[') {
679 teddy 1.28 push_sym(env, "[");
680 masse 1.46 env->non_eval_flag++;
681 masse 1.19 break;
682     }
683 masse 1.15 }
684     } while(0);
685    
686 masse 1.1 free(temp);
687    
688     if(convert<2) {
689     free(rest);
690 teddy 1.37 return;
691 masse 1.1 }
692    
693 teddy 1.28 stack_read(env, rest);
694 masse 1.1
695     free(rest);
696 masse 1.7 }
697 masse 1.1
698 masse 1.16 /* Relocate elements of the list on the stack. */
699 teddy 1.28 extern void expand(environment *env)
700 masse 1.1 {
701 masse 1.8 stackitem *temp, *new_head;
702    
703 masse 1.16 /* Is top element a list? */
704 teddy 1.36 if(env->head==NULL) {
705     printerr("Too Few Arguments");
706 teddy 1.35 env->err=1;
707 masse 1.8 return;
708 masse 1.17 }
709 teddy 1.36 if(env->head->item->type!=list) {
710     printerr("Bad Argument Type");
711     env->err=2;
712     return;
713     }
714 masse 1.43
715     rev(env);
716    
717     if(env->err)
718     return;
719 masse 1.8
720 masse 1.16 /* The first list element is the new stack head */
721 teddy 1.28 new_head= temp= env->head->item->content.ptr;
722 masse 1.8
723 teddy 1.28 env->head->item->refcount++;
724     toss(env);
725 masse 1.24
726 teddy 1.28 /* Find the end of the list */
727 masse 1.8 while(temp->next!=NULL)
728     temp= temp->next;
729    
730 teddy 1.28 /* Connect the tail of the list with the old stack head */
731     temp->next= env->head;
732     env->head= new_head; /* ...and voila! */
733    
734 teddy 1.5 }
735 masse 1.11
736 masse 1.14 /* Compares two elements by reference. */
737 teddy 1.28 extern void eq(environment *env)
738 masse 1.11 {
739     void *left, *right;
740     int result;
741    
742 teddy 1.28 if((env->head)==NULL || env->head->next==NULL) {
743 teddy 1.36 printerr("Too Few Arguments");
744 teddy 1.35 env->err=1;
745 masse 1.11 return;
746 masse 1.17 }
747 masse 1.11
748 teddy 1.28 left= env->head->item->content.ptr;
749     swap(env);
750     right= env->head->item->content.ptr;
751 masse 1.11 result= (left==right);
752    
753 teddy 1.28 toss(env); toss(env);
754 teddy 1.29 push_int(&(env->head), result);
755 masse 1.11 }
756    
757 masse 1.14 /* Negates the top element on the stack. */
758 teddy 1.28 extern void not(environment *env)
759 masse 1.11 {
760 teddy 1.28 int val;
761 masse 1.11
762 teddy 1.36 if((env->head)==NULL) {
763     printerr("Too Few Arguments");
764 teddy 1.35 env->err=1;
765 masse 1.11 return;
766 masse 1.17 }
767 masse 1.11
768 teddy 1.36 if(env->head->item->type!=integer) {
769     printerr("Bad Argument Type");
770     env->err=2;
771     return;
772     }
773    
774 teddy 1.28 val= env->head->item->content.val;
775     toss(env);
776 teddy 1.29 push_int(&(env->head), !val);
777 masse 1.11 }
778    
779 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
780     same. */
781 teddy 1.28 extern void neq(environment *env)
782 masse 1.11 {
783 teddy 1.28 eq(env);
784     not(env);
785 masse 1.11 }
786 masse 1.12
787 masse 1.14 /* Give a symbol some content. */
788 teddy 1.28 extern void def(environment *env)
789 masse 1.12 {
790 teddy 1.28 symbol *sym;
791 masse 1.12
792 teddy 1.28 /* Needs two values on the stack, the top one must be a symbol */
793 teddy 1.36 if(env->head==NULL || env->head->next==NULL) {
794     printerr("Too Few Arguments");
795 teddy 1.35 env->err=1;
796 masse 1.12 return;
797 masse 1.17 }
798 masse 1.12
799 teddy 1.36 if(env->head->item->type!=symb) {
800     printerr("Bad Argument Type");
801     env->err=2;
802     return;
803     }
804    
805 teddy 1.28 /* long names are a pain */
806     sym=env->head->item->content.ptr;
807    
808     /* if the symbol was bound to something else, throw it away */
809     if(sym->val != NULL)
810     free_val(sym->val);
811    
812     /* Bind the symbol to the value */
813     sym->val= env->head->next->item;
814     sym->val->refcount++; /* Increase the reference counter */
815 masse 1.12
816 teddy 1.28 toss(env); toss(env);
817 masse 1.12 }
818 masse 1.10
819 masse 1.14 /* Quit stack. */
820 teddy 1.28 extern void quit(environment *env)
821 teddy 1.5 {
822     exit(EXIT_SUCCESS);
823 masse 1.24 }
824    
825     /* Clear stack */
826 teddy 1.28 extern void clear(environment *env)
827 masse 1.24 {
828 teddy 1.28 while(env->head!=NULL)
829     toss(env);
830 masse 1.1 }
831    
832 teddy 1.33 /* List all defined words */
833 masse 1.32 extern void words(environment *env)
834     {
835     symbol *temp;
836     int i;
837    
838     for(i= 0; i<HASHTBLSIZE; i++) {
839     temp= env->symbols[i];
840     while(temp!=NULL) {
841     printf("%s\n", temp->id);
842     temp= temp->next;
843     }
844     }
845     }
846 masse 1.34
847     /* Forgets a symbol (remove it from the hash table) */
848     extern void forget(environment *env)
849     {
850     char* sym_id;
851     stackitem *stack_head= env->head;
852     symbol **hash_entry, *temp;
853    
854 teddy 1.36 if(stack_head==NULL) {
855     printerr("Too Few Arguments");
856     env->err=1;
857     return;
858     }
859    
860     if(stack_head->item->type!=symb) {
861     printerr("Bad Argument Type");
862     env->err=2;
863 masse 1.34 return;
864     }
865    
866     sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
867     toss(env);
868    
869     hash_entry= hash(env->symbols, sym_id);
870     temp= *hash_entry;
871     *hash_entry= (*hash_entry)->next;
872    
873     if(temp->val!=NULL) {
874     free_val(temp->val);
875     }
876     free(temp->id);
877     free(temp);
878 teddy 1.36 }
879    
880     /* Returns the current error number to the stack */
881     extern void errn(environment *env){
882     push_int(&(env->head), env->err);
883     }
884 masse 1.32
885 masse 1.1 int main()
886     {
887 teddy 1.28 environment myenv;
888 masse 1.1 char in_string[100];
889    
890 teddy 1.28 init_env(&myenv);
891 masse 1.1
892     printf("okidok\n ");
893    
894     while(fgets(in_string, 100, stdin) != NULL) {
895 teddy 1.28 stack_read(&myenv, in_string);
896 teddy 1.35 if(myenv.err) {
897     printf("(error %d) ", myenv.err);
898     myenv.err=0;
899     }
900 masse 1.1 printf("okidok\n ");
901     }
902 teddy 1.41 quit(&myenv);
903 teddy 1.42 return EXIT_FAILURE;
904 teddy 1.48 }
905    
906     /* + */
907     extern void sx_2b(environment *env) {
908     int a, b;
909 masse 1.49 size_t len;
910     char* new_string;
911     value *a_val, *b_val;
912 teddy 1.48
913     if((env->head)==NULL || env->head->next==NULL) {
914     printerr("Too Few Arguments");
915     env->err=1;
916 masse 1.49 return;
917     }
918    
919     if(env->head->item->type==string
920     && env->head->next->item->type==string) {
921     a_val= env->head->item;
922     b_val= env->head->next->item;
923     a_val->refcount++;
924     b_val->refcount++;
925     toss(env); if(env->err) return;
926     toss(env); if(env->err) return;
927     len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
928     new_string= malloc(len);
929     strcpy(new_string, b_val->content.ptr);
930     strcat(new_string, a_val->content.ptr);
931     free_val(a_val); free_val(b_val);
932     push_cstring(&(env->head), new_string);
933     free(new_string);
934 teddy 1.48 return;
935     }
936    
937     if(env->head->item->type!=integer
938     || env->head->next->item->type!=integer) {
939     printerr("Bad Argument Type");
940     env->err=2;
941     return;
942     }
943     a=env->head->item->content.val;
944     toss(env);
945     if(env->err) return;
946     b=env->head->item->content.val;
947     toss(env);
948     if(env->err) return;
949     push_int(&(env->head), a+b);
950 masse 1.1 }
951 teddy 1.55
952     /* Return copy of a value */
953     value *copy_val(value *old_value){
954     stackitem *old_item, *new_item, *prev_item;
955    
956     value *new_value=malloc(sizeof(value));
957    
958     new_value->type=old_value->type;
959     new_value->refcount=0; /* This is increased if/when this
960     value is referenced somewhere, like
961     in a stack item or a variable */
962     switch(old_value->type){
963     case integer:
964     new_value->content.val=old_value->content.val;
965     break;
966     case string:
967     (char *)(new_value->content.ptr)
968     = strdup((char *)(old_value->content.ptr));
969     break;
970     case func:
971     case symb:
972     new_value->content.ptr=old_value->content.ptr;
973     break;
974     case list:
975     new_value->content.ptr=NULL;
976    
977     prev_item=NULL;
978     old_item=(stackitem *)(old_value->content.ptr);
979    
980     while(old_item != NULL) { /* While list is not empty */
981     new_item= malloc(sizeof(stackitem));
982     new_item->item=copy_val(old_item->item); /* recurse */
983     new_item->next=NULL;
984     if(prev_item != NULL) /* If this wasn't the first item */
985     prev_item->next=new_item; /* point the previous item to the
986     new item */
987     else
988     new_value->content.ptr=new_item;
989     old_item=old_item->next;
990     prev_item=new_item;
991     }
992     break;
993     }
994     return new_value;
995     }
996    
997     /* duplicates an item on the stack */
998     extern void dup(environment *env) {
999     if((env->head)==NULL) {
1000     printerr("Too Few Arguments");
1001     env->err=1;
1002     return;
1003     }
1004     push_val(&(env->head), copy_val(env->head->item));
1005     }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26