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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (show annotations)
Tue Feb 5 23:26:46 2002 UTC (22 years, 2 months ago) by masse
Branch: MAIN
Changes since 1.33: +28 -2 lines
File MIME type: text/plain
Added funtion 'forget'.

1 /* printf */
2 #include <stdio.h>
3 /* EXIT_SUCCESS */
4 #include <stdlib.h>
5 /* NULL */
6 #include <stddef.h>
7 /* dlopen, dlsym, dlerror */
8 #include <dlfcn.h>
9 /* assert */
10 #include <assert.h>
11
12 #define HASHTBLSIZE 65536
13
14 /* First, define some types. */
15
16 /* A value of some type */
17 typedef struct {
18 enum {
19 integer,
20 string,
21 ref, /* Reference (to an element in the
22 hash table) */
23 func, /* Function pointer */
24 symb,
25 list
26 } type; /* Type of stack element */
27
28 union {
29 void *ptr; /* Pointer to the content */
30 int val; /* ...or an integer */
31 } content; /* Stores a pointer or an integer */
32
33 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 } stackitem;
55
56 /* 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 int err; /* Error flag */
62 } environment;
63
64 /* A type for pointers to external functions */
65 typedef void (*funcp)(environment *); /* funcp is a pointer to a void
66 function (environment *) */
67
68 /* Initialize a newly created environment */
69 void init_env(environment *env)
70 {
71 long i;
72
73 for(i= 0; i<HASHTBLSIZE; i++)
74 env->symbols[i]= NULL;
75 }
76
77 /* Returns a pointer to a pointer to an element in the hash table. */
78 symbol **hash(hashtbl in_hashtbl, const char *in_string)
79 {
80 long i= 0;
81 unsigned long out_hash= 0;
82 char key= '\0';
83 symbol **position;
84
85 while(1){ /* Hash in_string */
86 key= in_string[i++];
87 if(key=='\0')
88 break;
89 out_hash= out_hash*32+key;
90 }
91
92 out_hash= out_hash%HASHTBLSIZE;
93 position= &(in_hashtbl[out_hash]);
94
95 while(1){
96 if(*position==NULL) /* If empty */
97 return position;
98
99 if(strcmp(in_string, (*position)->id)==0) /* If match */
100 return position;
101
102 position= &((*position)->next); /* Try next */
103 }
104 }
105
106 /* Generic push function. */
107 int push(stackitem** stack_head, stackitem* in_item)
108 {
109 in_item->next= *stack_head;
110 *stack_head= in_item;
111 return 1;
112 }
113
114 /* Push a value onto the stack */
115 void push_val(stackitem **stack_head, value *val)
116 {
117 stackitem *new_item= malloc(sizeof(stackitem));
118 new_item->item= val;
119 val->refcount++;
120 push(stack_head, new_item);
121 }
122
123 /* Push an integer onto the stack. */
124 int push_int(stackitem **stack_head, int in_val)
125 {
126 value *new_value= malloc(sizeof(value));
127 stackitem *new_item= malloc(sizeof(stackitem));
128 new_item->item= new_value;
129
130 new_value->content.val= in_val;
131 new_value->type= integer;
132 new_value->refcount=1;
133
134 push(stack_head, new_item);
135 return 1;
136 }
137
138 /* Copy a string onto the stack. */
139 int push_cstring(stackitem **stack_head, const char *in_string)
140 {
141 value *new_value= malloc(sizeof(value));
142 stackitem *new_item= malloc(sizeof(stackitem));
143 new_item->item=new_value;
144
145 new_value->content.ptr= malloc(strlen(in_string)+1);
146 strcpy(new_value->content.ptr, in_string);
147 new_value->type= string;
148 new_value->refcount=1;
149
150 push(stack_head, new_item);
151 return 1;
152 }
153
154 /* Push a symbol onto the stack. */
155 int push_sym(environment *env, const char *in_string)
156 {
157 stackitem *new_item; /* The new stack item */
158 /* ...which will contain... */
159 value *new_value; /* A new symbol value */
160 /* ...which might point to... */
161 symbol **new_symbol; /* (if needed) A new actual symbol */
162 /* ...which, if possible, will be bound to... */
163 value *new_fvalue; /* (if needed) A new function value */
164 /* ...which will point to... */
165 void *funcptr; /* A function pointer */
166
167 static void *handle= NULL; /* Dynamic linker handle */
168
169 /* Create a new stack item containing a new value */
170 new_item= malloc(sizeof(stackitem));
171 new_value= malloc(sizeof(value));
172 new_item->item=new_value;
173
174 /* The new value is a symbol */
175 new_value->type= symb;
176 new_value->refcount= 1;
177
178 /* Look up the symbol name in the hash table */
179 new_symbol= hash(env->symbols, in_string);
180 new_value->content.ptr= *new_symbol;
181
182 if(*new_symbol==NULL) { /* If symbol was undefined */
183
184 /* Create a new symbol */
185 (*new_symbol)= malloc(sizeof(symbol));
186 (*new_symbol)->val= NULL; /* undefined value */
187 (*new_symbol)->next= NULL;
188 (*new_symbol)->id= malloc(strlen(in_string)+1);
189 strcpy((*new_symbol)->id, in_string);
190
191 /* Intern the new symbol in the hash table */
192 new_value->content.ptr= *new_symbol;
193
194 /* Try to load the symbol name as an external function, to see if
195 we should bind the symbol to a new function pointer value */
196 if(handle==NULL) /* If no handle */
197 handle= dlopen(NULL, RTLD_LAZY);
198
199 funcptr= dlsym(handle, in_string); /* Get function pointer */
200 if(dlerror()==NULL) { /* If a function was found */
201 new_fvalue= malloc(sizeof(value)); /* Create a new value */
202 new_fvalue->type=func; /* The new value is a function pointer */
203 new_fvalue->content.ptr=funcptr; /* Store function pointer */
204 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
205 function value */
206 new_fvalue->refcount= 1;
207 }
208 }
209 push(&(env->head), new_item);
210 return 1;
211 }
212
213 void printerr(const char* in_string) {
214 fprintf(stderr, "Err: %s\n", in_string);
215 }
216
217 /* Throw away a value */
218 void free_val(value *val){
219 stackitem *item, *temp;
220
221 val->refcount--; /* Decrease the reference count */
222 if(val->refcount == 0){
223 switch (val->type){ /* and free the contents if necessary */
224 case string:
225 free(val->content.ptr);
226 case list: /* lists needs to be freed recursively */
227 item=val->content.ptr;
228 while(item != NULL) { /* for all stack items */
229 free_val(item->item); /* free the value */
230 temp=item->next; /* save next ptr */
231 free(item); /* free the stackitem */
232 item=temp; /* go to next stackitem */
233 }
234 free(val); /* Free the actual list value */
235 break;
236 default:
237 break;
238 }
239 }
240 }
241
242 /* Discard the top element of the stack. */
243 extern void toss(environment *env)
244 {
245 stackitem *temp= env->head;
246
247 if((env->head)==NULL) {
248 printerr("Stack empty");
249 return;
250 }
251
252 free_val(env->head->item); /* Free the value */
253 env->head= env->head->next; /* Remove the top stack item */
254 free(temp); /* Free the old top stack item */
255 }
256
257 /* Print newline. */
258 extern void nl()
259 {
260 printf("\n");
261 }
262
263 /* Prints the top element of the stack. */
264 void print_h(stackitem *stack_head)
265 {
266
267 if(stack_head==NULL) {
268 printerr("Stack empty");
269 return;
270 }
271
272 switch(stack_head->item->type) {
273 case integer:
274 printf("%d", stack_head->item->content.val);
275 break;
276 case string:
277 printf("\"%s\"", (char*)stack_head->item->content.ptr);
278 break;
279 case symb:
280 printf("'%s'", ((symbol *)(stack_head->item->content.ptr))->id);
281 break;
282 default:
283 printf("%p", (funcp)(stack_head->item->content.ptr));
284 break;
285 }
286 }
287
288 extern void print_(environment *env) {
289 print_h(env->head);
290 }
291
292 /* Prints the top element of the stack and then discards it. */
293 extern void print(environment *env)
294 {
295 print_(env);
296 toss(env);
297 }
298
299 /* Only to be called by function printstack. */
300 void print_st(stackitem *stack_head, long counter)
301 {
302 if(stack_head->next != NULL)
303 print_st(stack_head->next, counter+1);
304 printf("%ld: ", counter);
305 print_h(stack_head);
306 nl();
307 }
308
309
310
311 /* Prints the stack. */
312 extern void printstack(environment *env)
313 {
314 if(env->head != NULL) {
315 print_st(env->head, 1);
316 nl();
317 } else {
318 printerr("Stack empty");
319 }
320 }
321
322 /* Swap the two top elements on the stack. */
323 extern void swap(environment *env)
324 {
325 stackitem *temp= env->head;
326
327 if((env->head)==NULL) {
328 printerr("Stack empty");
329 return;
330 }
331
332 if(env->head->next==NULL) {
333 printerr("Not enough arguments");
334 return;
335 }
336
337 env->head= env->head->next;
338 temp->next= env->head->next;
339 env->head->next= temp;
340 }
341
342 stackitem* copy(stackitem* in_item)
343 {
344 stackitem *out_item= malloc(sizeof(stackitem));
345
346 memcpy(out_item, in_item, sizeof(stackitem));
347 out_item->next= NULL;
348
349 return out_item;
350 }
351
352 /* Recall a value from a symbol, if bound */
353 extern void rcl(environment *env)
354 {
355 value *val;
356
357 if(env->head == NULL) {
358 printerr("Stack empty");
359 return;
360 }
361
362 if(env->head->item->type!=symb) {
363 printerr("Not a symbol");
364 return;
365 }
366 val=((symbol *)(env->head->item->content.ptr))->val;
367 if(val == NULL){
368 printerr("Unbound variable");
369 return;
370 }
371 toss(env); /* toss the symbol */
372 push_val(&(env->head), val); /* Return its bound value */
373 }
374
375 /* If the top element is a symbol, determine if it's bound to a
376 function value, and if it is, toss the symbol and execute the
377 function. */
378 extern void eval(environment *env)
379 {
380 funcp in_func;
381 value* val;
382 if(env->head==NULL) {
383 printerr("Stack empty");
384 return;
385 }
386
387 /* if it's a symbol */
388 if(env->head->item->type==symb) {
389
390 /* If it's not bound to anything */
391 if (((symbol *)(env->head->item->content.ptr))->val == NULL) {
392 printerr("Unbound variable");
393 return;
394 }
395
396 /* If it contains a function */
397 if (((symbol *)(env->head->item->content.ptr))->val->type == func) {
398 in_func=
399 (funcp)(((symbol *)(env->head->item->content.ptr))->val->content.ptr);
400 toss(env);
401 (*in_func)(env); /* Run the function */
402 return;
403 } else { /* If it's not a function */
404 val=((symbol *)(env->head->item->content.ptr))->val;
405 toss(env); /* toss the symbol */
406 push_val(&(env->head), val); /* Return its bound value */
407 }
408 }
409
410 /* If it's a lone function value, run it */
411 if(env->head->item->type==func) {
412 in_func= (funcp)(env->head->item->content.ptr);
413 toss(env);
414 (*in_func)(env);
415 return;
416 }
417
418 }
419
420 /* Make a list. */
421 extern void pack(environment *env)
422 {
423 void* delimiter;
424 stackitem *iterator, *temp;
425 value *pack;
426
427 delimiter= env->head->item->content.ptr; /* Get delimiter */
428 toss(env);
429
430 iterator= env->head;
431
432 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
433 temp= NULL;
434 toss(env);
435 } else {
436 /* Search for first delimiter */
437 while(iterator->next!=NULL
438 && iterator->next->item->content.ptr!=delimiter)
439 iterator= iterator->next;
440
441 /* Extract list */
442 temp= env->head;
443 env->head= iterator->next;
444 iterator->next= NULL;
445
446 if(env->head!=NULL)
447 toss(env);
448 }
449
450 /* Push list */
451 pack= malloc(sizeof(value));
452 pack->type= list;
453 pack->content.ptr= temp;
454 pack->refcount= 1;
455
456 temp= malloc(sizeof(stackitem));
457 temp->item= pack;
458
459 push(&(env->head), temp);
460 }
461
462 /* Parse input. */
463 int stack_read(environment *env, char *in_line)
464 {
465 char *temp, *rest;
466 int itemp;
467 size_t inlength= strlen(in_line)+1;
468 int convert= 0;
469 static int non_eval_flag= 0;
470
471 temp= malloc(inlength);
472 rest= malloc(inlength);
473
474 do {
475 /* If string */
476 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
477 push_cstring(&(env->head), temp);
478 break;
479 }
480 /* If integer */
481 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
482 push_int(&(env->head), itemp);
483 break;
484 }
485 /* Escape ';' with '\' */
486 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
487 temp[1]= '\0';
488 push_sym(env, temp);
489 break;
490 }
491 /* If symbol */
492 if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {
493 push_sym(env, temp);
494 break;
495 }
496 /* If single char */
497 if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
498 if(*temp==';') {
499 if(!non_eval_flag) {
500 eval(env); /* Evaluate top element */
501 break;
502 }
503
504 push_sym(env, ";");
505 break;
506 }
507
508 if(*temp==']') {
509 push_sym(env, "[");
510 pack(env);
511 if(non_eval_flag!=0)
512 non_eval_flag--;
513 break;
514 }
515
516 if(*temp=='[') {
517 push_sym(env, "[");
518 non_eval_flag++;
519 break;
520 }
521 }
522 } while(0);
523
524
525 free(temp);
526
527 if(convert<2) {
528 free(rest);
529 return 0;
530 }
531
532 stack_read(env, rest);
533
534 free(rest);
535 return 1;
536 }
537
538 /* Relocate elements of the list on the stack. */
539 extern void expand(environment *env)
540 {
541 stackitem *temp, *new_head;
542
543 /* Is top element a list? */
544 if(env->head==NULL || env->head->item->type!=list) {
545 printerr("Stack empty or not a list");
546 return;
547 }
548
549 /* The first list element is the new stack head */
550 new_head= temp= env->head->item->content.ptr;
551
552 env->head->item->refcount++;
553 toss(env);
554
555 /* Find the end of the list */
556 while(temp->next!=NULL)
557 temp= temp->next;
558
559 /* Connect the tail of the list with the old stack head */
560 temp->next= env->head;
561 env->head= new_head; /* ...and voila! */
562
563 }
564
565 /* Compares two elements by reference. */
566 extern void eq(environment *env)
567 {
568 void *left, *right;
569 int result;
570
571 if((env->head)==NULL || env->head->next==NULL) {
572 printerr("Not enough elements to compare");
573 return;
574 }
575
576 left= env->head->item->content.ptr;
577 swap(env);
578 right= env->head->item->content.ptr;
579 result= (left==right);
580
581 toss(env); toss(env);
582 push_int(&(env->head), result);
583 }
584
585 /* Negates the top element on the stack. */
586 extern void not(environment *env)
587 {
588 int val;
589
590 if((env->head)==NULL || env->head->item->type!=integer) {
591 printerr("Stack empty or element is not a integer");
592 return;
593 }
594
595 val= env->head->item->content.val;
596 toss(env);
597 push_int(&(env->head), !val);
598 }
599
600 /* Compares the two top elements on the stack and return 0 if they're the
601 same. */
602 extern void neq(environment *env)
603 {
604 eq(env);
605 not(env);
606 }
607
608 /* Give a symbol some content. */
609 extern void def(environment *env)
610 {
611 symbol *sym;
612
613 /* Needs two values on the stack, the top one must be a symbol */
614 if(env->head==NULL || env->head->next==NULL
615 || env->head->item->type!=symb) {
616 printerr("Define what?");
617 return;
618 }
619
620 /* long names are a pain */
621 sym=env->head->item->content.ptr;
622
623 /* if the symbol was bound to something else, throw it away */
624 if(sym->val != NULL)
625 free_val(sym->val);
626
627 /* Bind the symbol to the value */
628 sym->val= env->head->next->item;
629 sym->val->refcount++; /* Increase the reference counter */
630
631 toss(env); toss(env);
632 }
633
634 /* Quit stack. */
635 extern void quit(environment *env)
636 {
637 exit(EXIT_SUCCESS);
638 }
639
640 /* Clear stack */
641 extern void clear(environment *env)
642 {
643 while(env->head!=NULL)
644 toss(env);
645 }
646
647 /* List all defined words */
648 extern void words(environment *env)
649 {
650 symbol *temp;
651 int i;
652
653 for(i= 0; i<HASHTBLSIZE; i++) {
654 temp= env->symbols[i];
655 while(temp!=NULL) {
656 printf("%s\n", temp->id);
657 temp= temp->next;
658 }
659 }
660 }
661
662 /* Forgets a symbol (remove it from the hash table) */
663 extern void forget(environment *env)
664 {
665 char* sym_id;
666 stackitem *stack_head= env->head;
667 symbol **hash_entry, *temp;
668
669 if(stack_head==NULL || stack_head->item->type!=symb) {
670 printerr("Stack empty or not a symbol");
671 return;
672 }
673
674 sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
675 toss(env);
676
677 hash_entry= hash(env->symbols, sym_id);
678 temp= *hash_entry;
679 *hash_entry= (*hash_entry)->next;
680
681 if(temp->val!=NULL) {
682 free_val(temp->val);
683 }
684 free(temp->id);
685 free(temp);
686 }
687
688 int main()
689 {
690 environment myenv;
691 char in_string[100];
692
693 init_env(&myenv);
694
695 printf("okidok\n ");
696
697 while(fgets(in_string, 100, stdin) != NULL) {
698 stack_read(&myenv, in_string);
699 printf("okidok\n ");
700 }
701
702 exit(EXIT_SUCCESS);
703 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26