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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (show annotations)
Mon Feb 4 21:47:26 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.27: +276 -208 lines
File MIME type: text/plain
Major data structure overhaul.  Everything changed.

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 } 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
67 /* Initialize a newly created environment */
68 void init_env(environment *env)
69 {
70 long i;
71
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 int push(stackitem** stack_head, stackitem* in_item)
107 {
108 in_item->next= *stack_head;
109 *stack_head= in_item;
110 return 1;
111 }
112
113 /* Push an integer onto the stack. */
114 int push_val(stackitem **stack_head, int in_val)
115 {
116 value *new_value= malloc(sizeof(value));
117 stackitem *new_item= malloc(sizeof(stackitem));
118 new_item->item= new_value;
119
120 new_value->content.val= in_val;
121 new_value->type= integer;
122 new_value->refcount=1;
123
124 push(stack_head, new_item);
125 return 1;
126 }
127
128 /* Copy a string onto the stack. */
129 int push_cstring(stackitem **stack_head, const char *in_string)
130 {
131 value *new_value= malloc(sizeof(value));
132 stackitem *new_item= malloc(sizeof(stackitem));
133 new_item->item=new_value;
134
135 new_value->content.ptr= malloc(strlen(in_string)+1);
136 strcpy(new_value->content.ptr, in_string);
137 new_value->type= string;
138 new_value->refcount=1;
139
140 push(stack_head, new_item);
141 return 1;
142 }
143
144 /* Push a symbol onto the stack. */
145 int push_sym(environment *env, const char *in_string)
146 {
147 stackitem *new_item; /* The new stack item */
148 /* ...which will contain... */
149 value *new_value; /* A new symbol value */
150 /* ...which might point to... */
151 symbol *new_symbol; /* (if needed) A new actual symbol */
152 /* ...which, if possible, will be bound to... */
153 value *new_fvalue; /* (if needed) A new function value */
154 /* ...which will point to... */
155 void *funcptr; /* A function pointer */
156
157 static void *handle= NULL; /* Dynamic linker handle */
158
159 /* Create a new stack item containing a new value */
160 new_item= malloc(sizeof(stackitem));
161 new_value= malloc(sizeof(value));
162 new_item->item=new_value;
163
164 /* The new value is a symbol */
165 new_value->type= symb;
166 new_value->refcount= 1;
167
168 /* Look up the symbol name in the hash table */
169 new_value->content.ptr= *hash(env->symbols, in_string);
170
171 if(new_value->content.ptr==NULL) { /* If symbol was undefined */
172
173 /* Create a new symbol */
174 new_symbol= malloc(sizeof(symbol));
175 new_symbol->val= NULL; /* undefined value */
176 new_symbol->next= NULL;
177 new_symbol->id= malloc(strlen(in_string)+1);
178 strcpy(new_symbol->id, in_string);
179
180 /* Intern the new symbol in the hash table */
181 new_value->content.ptr= new_symbol;
182
183 /* Try to load the symbol name as an external function, to see if
184 we should bind the symbol to a new function pointer value */
185 if(handle==NULL) /* If no handle */
186 handle= dlopen(NULL, RTLD_LAZY);
187
188 funcptr= dlsym(handle, in_string); /* Get function pointer */
189 if(dlerror()==NULL) { /* If a function was found */
190 new_fvalue= malloc(sizeof(value)); /* Create a new value */
191 new_fvalue->type=func; /* The new value is a function pointer */
192 new_fvalue->content.ptr=funcptr; /* Store function pointer */
193 new_symbol->val= new_fvalue; /* Bind the symbol to the new
194 function value */
195 new_fvalue->refcount= 1;
196 }
197 }
198 push(&(env->head), new_item);
199 return 1;
200 }
201
202 void printerr(const char* in_string) {
203 fprintf(stderr, "Err: %s\n", in_string);
204 }
205
206 /* Throw away a value */
207 void free_val(value *val){
208 stackitem *item, *temp;
209
210 val->refcount--; /* Decrease the reference count */
211 if(val->refcount == 0){
212 switch (val->type){ /* and free the contents if necessary */
213 case string:
214 free(val->content.ptr);
215 case list: /* lists needs to be freed recursively */
216 item=val->content.ptr;
217 while(item != NULL) { /* for all stack items */
218 free_val(item->item); /* free the value */
219 temp=item->next; /* save next ptr */
220 free(item); /* free the stackitem */
221 item=temp; /* go to next stackitem */
222 }
223 free(val); /* Free the actual list value */
224 break;
225 default:
226 break;
227 }
228 }
229 }
230
231 /* Discard the top element of the stack. */
232 extern void toss(environment *env)
233 {
234 stackitem *temp= env->head;
235
236 if((env->head)==NULL) {
237 printerr("Stack empty");
238 return;
239 }
240
241 free_val(env->head->item); /* Free the value */
242 env->head= env->head->next; /* Remove the top stack item */
243 free(temp); /* Free the old top stack item */
244 }
245
246 /* Print newline. */
247 extern void nl()
248 {
249 printf("\n");
250 }
251
252 /* Prints the top element of the stack. */
253 void print_h(stackitem *stack_head)
254 {
255
256 if(stack_head==NULL) {
257 printerr("Stack empty");
258 return;
259 }
260
261 switch(stack_head->item->type) {
262 case integer:
263 printf("%d", stack_head->item->content.val);
264 break;
265 case string:
266 printf("\"%s\"", (char*)stack_head->item->content.ptr);
267 break;
268 case symb:
269 printf("'%s'", ((symbol *)(stack_head->item->content.ptr))->id);
270 break;
271 default:
272 printf("%p", (funcp)(stack_head->item->content.ptr));
273 break;
274 }
275 }
276
277 extern void print_(environment *env) {
278 print_h(env->head);
279 }
280
281 /* Prints the top element of the stack and then discards it. */
282 extern void print(environment *env)
283 {
284 print_(env);
285 toss(env);
286 }
287
288 /* Only to be called by function printstack. */
289 void print_st(stackitem *stack_head, long counter)
290 {
291 if(stack_head->next != NULL)
292 print_st(stack_head->next, counter+1);
293 printf("%ld: ", counter);
294 print_h(stack_head);
295 nl();
296 }
297
298
299
300 /* Prints the stack. */
301 extern void printstack(environment *env)
302 {
303 if(env->head != NULL) {
304 print_st(env->head, 1);
305 nl();
306 } else {
307 printerr("Stack empty");
308 }
309 }
310
311 /* Swap the two top elements on the stack. */
312 extern void swap(environment *env)
313 {
314 stackitem *temp= env->head;
315
316 if((env->head)==NULL) {
317 printerr("Stack empty");
318 return;
319 }
320
321 if(env->head->next==NULL) {
322 printerr("Not enough arguments");
323 return;
324 }
325
326 env->head= env->head->next;
327 temp->next= env->head->next;
328 env->head->next= temp;
329 }
330
331 stackitem* copy(stackitem* in_item)
332 {
333 stackitem *out_item= malloc(sizeof(stackitem));
334
335 memcpy(out_item, in_item, sizeof(stackitem));
336 out_item->next= NULL;
337
338 return out_item;
339 }
340
341
342 /* If the top element is a reference, determine if it's a reference to a
343 function, and if it is, toss the reference and execute the function. */
344 extern void eval(environment *env)
345 {
346 funcp in_func;
347 stackitem* temp= env->head;
348
349 if(temp==NULL) {
350 printerr("Stack empty");
351 return;
352 }
353
354 if(temp->item->type==symb
355 && ((symbol *)(temp->item->content.ptr))->val != NULL
356 && ((symbol *)(temp->item->content.ptr))->val->type == func) {
357 in_func= (funcp)(((symbol *)(temp->item->content.ptr))->val->content.ptr);
358 toss(env);
359 (*in_func)(env);
360 return;
361 }
362
363
364 if(temp->item->type==func) {
365 in_func= (funcp)(temp->item->content.ptr);
366 toss(env);
367 (*in_func)(env);
368 return;
369 }
370
371 push(&(env->head), copy(temp));
372 swap(env);
373 toss(env);
374 }
375
376 /* Make a list. */
377 extern void pack(environment *env)
378 {
379 void* delimiter;
380 stackitem *iterator, *temp;
381 value *pack;
382
383 delimiter= env->head->item->content.ptr; /* Get delimiter */
384 toss(env);
385
386 iterator= env->head;
387
388 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
389 temp= NULL;
390 toss(env);
391 } else {
392 /* Search for first delimiter */
393 while(iterator->next!=NULL
394 && iterator->next->item->content.ptr!=delimiter)
395 iterator= iterator->next;
396
397 /* Extract list */
398 temp= env->head;
399 env->head= iterator->next;
400 iterator->next= NULL;
401
402 if(env->head!=NULL)
403 toss(env);
404 }
405
406 /* Push list */
407 pack= malloc(sizeof(value));
408 pack->type= list;
409 pack->content.ptr= temp;
410 pack->refcount= 1;
411
412 temp= malloc(sizeof(stackitem));
413 temp->item= pack;
414
415 push(&(env->head), temp);
416 }
417
418 /* Parse input. */
419 int stack_read(environment *env, char *in_line)
420 {
421 char *temp, *rest;
422 int itemp;
423 size_t inlength= strlen(in_line)+1;
424 int convert= 0;
425 static int non_eval_flag= 0;
426
427 temp= malloc(inlength);
428 rest= malloc(inlength);
429
430 do {
431 /* If string */
432 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
433 push_cstring(&(env->head), temp);
434 break;
435 }
436 /* If integer */
437 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
438 push_val(&(env->head), itemp);
439 break;
440 }
441 /* Escape ';' with '\' */
442 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
443 temp[1]= '\0';
444 push_sym(env, temp);
445 break;
446 }
447 /* If symbol */
448 if((convert= sscanf(in_line, "%[^][ ;\n\r_]%[^\n\r]", temp, rest))) {
449 push_sym(env, temp);
450 break;
451 }
452 /* If single char */
453 if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
454 if(*temp==';') {
455 if(!non_eval_flag) {
456 eval(env); /* Evaluate top element */
457 break;
458 }
459
460 push_sym(env, ";");
461 break;
462 }
463
464 if(*temp==']') {
465 push_sym(env, "[");
466 pack(env);
467 if(non_eval_flag!=0)
468 non_eval_flag--;
469 break;
470 }
471
472 if(*temp=='[') {
473 push_sym(env, "[");
474 non_eval_flag++;
475 break;
476 }
477 }
478 } while(0);
479
480
481 free(temp);
482
483 if(convert<2) {
484 free(rest);
485 return 0;
486 }
487
488 stack_read(env, rest);
489
490 free(rest);
491 return 1;
492 }
493
494 /* Relocate elements of the list on the stack. */
495 extern void expand(environment *env)
496 {
497 stackitem *temp, *new_head;
498
499 /* Is top element a list? */
500 if(env->head==NULL || env->head->item->type!=list) {
501 printerr("Stack empty or not a list");
502 return;
503 }
504
505 /* The first list element is the new stack head */
506 new_head= temp= env->head->item->content.ptr;
507
508 env->head->item->refcount++;
509 toss(env);
510
511 /* Find the end of the list */
512 while(temp->next!=NULL)
513 temp= temp->next;
514
515 /* Connect the tail of the list with the old stack head */
516 temp->next= env->head;
517 env->head= new_head; /* ...and voila! */
518
519 }
520
521 /* Compares two elements by reference. */
522 extern void eq(environment *env)
523 {
524 void *left, *right;
525 int result;
526
527 if((env->head)==NULL || env->head->next==NULL) {
528 printerr("Not enough elements to compare");
529 return;
530 }
531
532 left= env->head->item->content.ptr;
533 swap(env);
534 right= env->head->item->content.ptr;
535 result= (left==right);
536
537 toss(env); toss(env);
538 push_val(&(env->head), result);
539 }
540
541 /* Negates the top element on the stack. */
542 extern void not(environment *env)
543 {
544 int val;
545
546 if((env->head)==NULL || env->head->item->type!=integer) {
547 printerr("Stack empty or element is not a integer");
548 return;
549 }
550
551 val= env->head->item->content.val;
552 toss(env);
553 push_val(&(env->head), !val);
554 }
555
556 /* Compares the two top elements on the stack and return 0 if they're the
557 same. */
558 extern void neq(environment *env)
559 {
560 eq(env);
561 not(env);
562 }
563
564 /* Give a symbol some content. */
565 extern void def(environment *env)
566 {
567 symbol *sym;
568
569 /* Needs two values on the stack, the top one must be a symbol */
570 if(env->head==NULL || env->head->next==NULL
571 || env->head->item->type!=symb) {
572 printerr("Define what?");
573 return;
574 }
575
576 /* long names are a pain */
577 sym=env->head->item->content.ptr;
578
579 /* if the symbol was bound to something else, throw it away */
580 if(sym->val != NULL)
581 free_val(sym->val);
582
583 /* Bind the symbol to the value */
584 sym->val= env->head->next->item;
585 sym->val->refcount++; /* Increase the reference counter */
586
587 toss(env); toss(env);
588 }
589
590 /* Quit stack. */
591 extern void quit(environment *env)
592 {
593 exit(EXIT_SUCCESS);
594 }
595
596 /* Clear stack */
597 extern void clear(environment *env)
598 {
599 while(env->head!=NULL)
600 toss(env);
601 }
602
603 int main()
604 {
605 environment myenv;
606 char in_string[100];
607
608 init_env(&myenv);
609
610 printf("okidok\n ");
611
612 while(fgets(in_string, 100, stdin) != NULL) {
613 stack_read(&myenv, in_string);
614 printf("okidok\n ");
615 }
616
617 exit(EXIT_SUCCESS);
618 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26