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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.36 - (show annotations)
Wed Feb 6 00:52:31 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.35: +50 -22 lines
File MIME type: text/plain
Standardized all error messages.
(errn): New function to get error number.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26