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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.90 - (hide annotations)
Thu Mar 7 01:21:07 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.89: +113 -61 lines
File MIME type: text/plain
(protect, unprotect): New functions to protect values from GC.

1 teddy 1.84 /* printf, sscanf, fgets, fprintf, fopen, perror */
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 teddy 1.84 /* getopt, STDIN_FILENO, STDOUT_FILENO */
12     #include <unistd.h>
13     /* EX_NOINPUT, EX_USAGE */
14     #include <sysexits.h>
15 masse 1.83 /* mtrace, muntrace */
16     #include <mcheck.h>
17 masse 1.1
18 teddy 1.88 #include "stack.h"
19 masse 1.1
20 teddy 1.28 /* Initialize a newly created environment */
21     void init_env(environment *env)
22 masse 1.1 {
23 masse 1.46 int i;
24 masse 1.1
25 masse 1.87 env->gc_limit= 20;
26     env->gc_count= 0;
27 masse 1.90 env->gc_ref= NULL;
28     env->gc_protect= NULL;
29 masse 1.87
30 teddy 1.84 env->head= NULL;
31 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
32 teddy 1.28 env->symbols[i]= NULL;
33 teddy 1.84 env->err= 0;
34     env->in_string= NULL;
35     env->free_string= NULL;
36     env->inputstream= stdin;
37     env->interactive= 1;
38 masse 1.1 }
39    
40 teddy 1.48 void printerr(const char* in_string) {
41     fprintf(stderr, "Err: %s\n", in_string);
42     }
43    
44     /* Discard the top element of the stack. */
45     extern void toss(environment *env)
46     {
47     stackitem *temp= env->head;
48    
49     if((env->head)==NULL) {
50     printerr("Too Few Arguments");
51 masse 1.90 env->err= 1;
52 teddy 1.48 return;
53     }
54    
55     env->head= env->head->next; /* Remove the top stack item */
56     free(temp); /* Free the old top stack item */
57 masse 1.90
58     gc_init(env);
59 teddy 1.48 }
60    
61 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
62 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
63 masse 1.1 {
64 masse 1.46 int i= 0;
65     unsigned int out_hash= 0;
66 teddy 1.18 char key= '\0';
67 teddy 1.28 symbol **position;
68 masse 1.1
69 masse 1.16 while(1){ /* Hash in_string */
70 masse 1.1 key= in_string[i++];
71     if(key=='\0')
72     break;
73     out_hash= out_hash*32+key;
74     }
75    
76     out_hash= out_hash%HASHTBLSIZE;
77     position= &(in_hashtbl[out_hash]);
78    
79 masse 1.25 while(1){
80 teddy 1.18 if(*position==NULL) /* If empty */
81 masse 1.1 return position;
82    
83 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
84 masse 1.1 return position;
85    
86 masse 1.16 position= &((*position)->next); /* Try next */
87 masse 1.1 }
88     }
89    
90 masse 1.87 value* new_val(environment *env) {
91     value *nval= malloc(sizeof(value));
92     stackitem *nitem= malloc(sizeof(stackitem));
93    
94     nval->content.ptr= NULL;
95 masse 1.90 protect(env, nval);
96    
97     gc_init(env);
98 masse 1.87
99     nitem->item= nval;
100     nitem->next= env->gc_ref;
101     env->gc_ref= nitem;
102    
103     env->gc_count++;
104 masse 1.90 unprotect(env);
105 masse 1.87
106     return nval;
107     }
108    
109     void gc_mark(value *val) {
110     stackitem *iterator;
111    
112     if(val==NULL || val->gc_garb==0)
113     return;
114    
115     val->gc_garb= 0;
116    
117     if(val->type==list) {
118     iterator= val->content.ptr;
119    
120     while(iterator!=NULL) {
121     gc_mark(iterator->item);
122     iterator= iterator->next;
123     }
124     }
125     }
126    
127     extern void gc_init(environment *env) {
128     stackitem *new_head= NULL, *titem, *iterator= env->gc_ref;
129     symbol *tsymb;
130     int i;
131    
132 masse 1.89 if(env->gc_count < env->gc_limit)
133     return;
134    
135 masse 1.87 while(iterator!=NULL) {
136     iterator->item->gc_garb= 1;
137     iterator= iterator->next;
138     }
139    
140     /* Mark */
141 masse 1.90 iterator= env->gc_protect;
142     while(iterator!=NULL) {
143     gc_mark(iterator->item);
144     iterator= iterator->next;
145     }
146    
147 masse 1.87 iterator= env->head;
148     while(iterator!=NULL) {
149     gc_mark(iterator->item);
150     iterator= iterator->next;
151     }
152    
153     for(i= 0; i<HASHTBLSIZE; i++) {
154     tsymb= env->symbols[i];
155     while(tsymb!=NULL) {
156     gc_mark(tsymb->val);
157     tsymb= tsymb->next;
158     }
159     }
160    
161     env->gc_count= 0;
162    
163     /* Sweep */
164     while(env->gc_ref!=NULL) {
165 masse 1.90
166 masse 1.87 if(env->gc_ref->item->gc_garb) {
167     switch(env->gc_ref->item->type) {
168     case string:
169     free(env->gc_ref->item->content.ptr);
170     break;
171     case integer:
172     break;
173     case list:
174     while(env->gc_ref->item->content.ptr!=NULL) {
175     titem= env->gc_ref->item->content.ptr;
176     env->gc_ref->item->content.ptr= titem->next;
177     free(titem);
178     }
179     break;
180     default:
181     break;
182     }
183     free(env->gc_ref->item);
184     titem= env->gc_ref->next;
185     free(env->gc_ref);
186     env->gc_ref= titem;
187     } else {
188     titem= env->gc_ref->next;
189     env->gc_ref->next= new_head;
190     new_head= env->gc_ref;
191     env->gc_ref= titem;
192     env->gc_count++;
193     }
194     }
195    
196 masse 1.89 env->gc_limit= env->gc_count*2;
197 masse 1.87 env->gc_ref= new_head;
198     }
199    
200 masse 1.90 void protect(environment *env, value *val)
201     {
202     stackitem *new_item= malloc(sizeof(stackitem));
203     new_item->item= val;
204     new_item->next= env->gc_protect;
205     env->gc_protect= new_item;
206     }
207    
208     void unprotect(environment *env)
209     {
210     stackitem *temp= env->gc_protect;
211     env->gc_protect= env->gc_protect->next;
212     free(temp);
213     }
214    
215 teddy 1.29 /* Push a value onto the stack */
216 masse 1.72 void push_val(environment *env, value *val)
217 teddy 1.29 {
218     stackitem *new_item= malloc(sizeof(stackitem));
219     new_item->item= val;
220 masse 1.75 new_item->next= env->head;
221     env->head= new_item;
222 teddy 1.29 }
223    
224 teddy 1.28 /* Push an integer onto the stack. */
225 masse 1.72 void push_int(environment *env, int in_val)
226 masse 1.1 {
227 masse 1.87 value *new_value= new_val(env);
228 teddy 1.28
229     new_value->content.val= in_val;
230     new_value->type= integer;
231 masse 1.1
232 masse 1.75 push_val(env, new_value);
233 masse 1.1 }
234    
235 masse 1.14 /* Copy a string onto the stack. */
236 masse 1.72 void push_cstring(environment *env, const char *in_string)
237 masse 1.1 {
238 masse 1.87 value *new_value= new_val(env);
239 teddy 1.28
240     new_value->content.ptr= malloc(strlen(in_string)+1);
241     strcpy(new_value->content.ptr, in_string);
242     new_value->type= string;
243 masse 1.1
244 masse 1.75 push_val(env, new_value);
245 masse 1.1 }
246    
247 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
248 teddy 1.51 char *mangle_str(const char *old_string){
249 masse 1.90 char validchars[]= "0123456789abcdef";
250 teddy 1.48 char *new_string, *current;
251    
252 masse 1.90 new_string= malloc((strlen(old_string)*2)+4);
253 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
254 masse 1.90 current= new_string+3;
255 teddy 1.48 while(old_string[0] != '\0'){
256 masse 1.90 current[0]= validchars[(unsigned char)(old_string[0])/16];
257     current[1]= validchars[(unsigned char)(old_string[0])%16];
258     current+= 2;
259 teddy 1.48 old_string++;
260     }
261 masse 1.90 current[0]= '\0';
262 teddy 1.48
263     return new_string; /* The caller must free() it */
264     }
265    
266     extern void mangle(environment *env){
267     char *new_string;
268    
269     if((env->head)==NULL) {
270     printerr("Too Few Arguments");
271 masse 1.90 env->err= 1;
272 teddy 1.48 return;
273     }
274    
275     if(env->head->item->type!=string) {
276     printerr("Bad Argument Type");
277 masse 1.90 env->err= 2;
278 teddy 1.48 return;
279     }
280    
281 teddy 1.51 new_string= mangle_str((const char *)(env->head->item->content.ptr));
282 teddy 1.48
283     toss(env);
284     if(env->err) return;
285    
286 masse 1.81 push_cstring(env, new_string);
287 teddy 1.48 }
288    
289 teddy 1.28 /* Push a symbol onto the stack. */
290 teddy 1.35 void push_sym(environment *env, const char *in_string)
291 masse 1.1 {
292 teddy 1.28 value *new_value; /* A new symbol value */
293     /* ...which might point to... */
294 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
295 teddy 1.28 /* ...which, if possible, will be bound to... */
296     value *new_fvalue; /* (if needed) A new function value */
297     /* ...which will point to... */
298     void *funcptr; /* A function pointer */
299    
300     static void *handle= NULL; /* Dynamic linker handle */
301 teddy 1.48 const char *dlerr; /* Dynamic linker error */
302     char *mangled; /* Mangled function name */
303 teddy 1.28
304 masse 1.87 new_value= new_val(env);
305 teddy 1.28
306     /* The new value is a symbol */
307     new_value->type= symb;
308    
309     /* Look up the symbol name in the hash table */
310 teddy 1.29 new_symbol= hash(env->symbols, in_string);
311     new_value->content.ptr= *new_symbol;
312 teddy 1.28
313 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
314 teddy 1.28
315     /* Create a new symbol */
316 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
317 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
318     (*new_symbol)->next= NULL;
319     (*new_symbol)->id= malloc(strlen(in_string)+1);
320     strcpy((*new_symbol)->id, in_string);
321 masse 1.1
322 teddy 1.28 /* Intern the new symbol in the hash table */
323 teddy 1.29 new_value->content.ptr= *new_symbol;
324 masse 1.1
325 teddy 1.28 /* Try to load the symbol name as an external function, to see if
326     we should bind the symbol to a new function pointer value */
327 masse 1.16 if(handle==NULL) /* If no handle */
328 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
329 masse 1.6
330 masse 1.90 mangled= mangle_str(in_string); /* mangle the name */
331 teddy 1.86 funcptr= dlsym(handle, mangled); /* and try to find it */
332     free(mangled);
333 masse 1.90 dlerr= dlerror();
334 teddy 1.48 if(dlerr != NULL) { /* If no function was found */
335 teddy 1.86 funcptr= dlsym(handle, in_string); /* Get function pointer */
336 masse 1.90 dlerr= dlerror();
337 teddy 1.48 }
338     if(dlerr==NULL) { /* If a function was found */
339 masse 1.87 new_fvalue= new_val(env); /* Create a new value */
340 masse 1.90 new_fvalue->type= func; /* The new value is a function pointer */
341     new_fvalue->content.ptr= funcptr; /* Store function pointer */
342 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
343     function value */
344 teddy 1.28 }
345 masse 1.1 }
346 masse 1.75 push_val(env, new_value);
347 masse 1.1 }
348    
349 masse 1.14 /* Print newline. */
350 masse 1.34 extern void nl()
351 masse 1.8 {
352     printf("\n");
353     }
354 masse 1.1
355 teddy 1.37 /* Gets the type of a value */
356     extern void type(environment *env){
357     int typenum;
358    
359     if((env->head)==NULL) {
360     printerr("Too Few Arguments");
361     env->err=1;
362     return;
363     }
364     typenum=env->head->item->type;
365     toss(env);
366     switch(typenum){
367     case integer:
368     push_sym(env, "integer");
369     break;
370     case string:
371     push_sym(env, "string");
372     break;
373     case symb:
374     push_sym(env, "symbol");
375     break;
376     case func:
377     push_sym(env, "function");
378     break;
379     case list:
380     push_sym(env, "list");
381     break;
382     }
383     }
384    
385 masse 1.14 /* Prints the top element of the stack. */
386 teddy 1.80 void print_h(stackitem *stack_head, int noquote)
387 masse 1.8 {
388 teddy 1.28 switch(stack_head->item->type) {
389     case integer:
390     printf("%d", stack_head->item->content.val);
391 teddy 1.2 break;
392     case string:
393 teddy 1.80 if(noquote)
394     printf("%s", (char*)stack_head->item->content.ptr);
395     else
396     printf("\"%s\"", (char*)stack_head->item->content.ptr);
397 teddy 1.2 break;
398 teddy 1.28 case symb:
399 teddy 1.45 printf("%s", ((symbol *)(stack_head->item->content.ptr))->id);
400 masse 1.6 break;
401 teddy 1.35 case func:
402     printf("#<function %p>", (funcp)(stack_head->item->content.ptr));
403     break;
404     case list:
405 teddy 1.38 /* A list is just a stack, so make stack_head point to it */
406     stack_head=(stackitem *)(stack_head->item->content.ptr);
407     printf("[ ");
408     while(stack_head != NULL) {
409 teddy 1.80 print_h(stack_head, noquote);
410 teddy 1.38 printf(" ");
411     stack_head=stack_head->next;
412     }
413 teddy 1.39 printf("]");
414 teddy 1.35 break;
415 teddy 1.2 }
416 masse 1.1 }
417    
418 teddy 1.28 extern void print_(environment *env) {
419 teddy 1.35 if(env->head==NULL) {
420 teddy 1.36 printerr("Too Few Arguments");
421 teddy 1.35 env->err=1;
422     return;
423     }
424 teddy 1.80 print_h(env->head, 0);
425     nl();
426 teddy 1.28 }
427    
428 masse 1.14 /* Prints the top element of the stack and then discards it. */
429 teddy 1.28 extern void print(environment *env)
430 masse 1.8 {
431 teddy 1.28 print_(env);
432 teddy 1.35 if(env->err) return;
433 teddy 1.28 toss(env);
434 masse 1.8 }
435    
436 teddy 1.80 extern void princ_(environment *env) {
437     if(env->head==NULL) {
438     printerr("Too Few Arguments");
439     env->err=1;
440     return;
441     }
442     print_h(env->head, 1);
443     }
444    
445     /* Prints the top element of the stack and then discards it. */
446     extern void princ(environment *env)
447     {
448     princ_(env);
449     if(env->err) return;
450     toss(env);
451     }
452    
453 masse 1.14 /* Only to be called by function printstack. */
454 teddy 1.28 void print_st(stackitem *stack_head, long counter)
455 masse 1.8 {
456     if(stack_head->next != NULL)
457     print_st(stack_head->next, counter+1);
458     printf("%ld: ", counter);
459 teddy 1.80 print_h(stack_head, 0);
460 masse 1.8 nl();
461     }
462    
463 masse 1.14 /* Prints the stack. */
464 teddy 1.28 extern void printstack(environment *env)
465 masse 1.1 {
466 teddy 1.35 if(env->head == NULL) {
467 teddy 1.80 printf("Stack Empty\n");
468 teddy 1.35 return;
469 masse 1.1 }
470 teddy 1.35 print_st(env->head, 1);
471 masse 1.1 }
472    
473 masse 1.26 /* Swap the two top elements on the stack. */
474 teddy 1.28 extern void swap(environment *env)
475 masse 1.26 {
476 teddy 1.28 stackitem *temp= env->head;
477 masse 1.26
478 masse 1.46 if(env->head==NULL || env->head->next==NULL) {
479 teddy 1.36 printerr("Too Few Arguments");
480 teddy 1.35 env->err=1;
481 masse 1.26 return;
482 teddy 1.28 }
483 masse 1.26
484 teddy 1.28 env->head= env->head->next;
485     temp->next= env->head->next;
486     env->head->next= temp;
487 masse 1.26 }
488    
489 teddy 1.56 /* Rotate the first three elements on the stack. */
490     extern void rot(environment *env)
491     {
492     stackitem *temp= env->head;
493    
494     if(env->head==NULL || env->head->next==NULL
495     || env->head->next->next==NULL) {
496     printerr("Too Few Arguments");
497     env->err=1;
498     return;
499     }
500    
501     env->head= env->head->next->next;
502     temp->next->next= env->head->next;
503     env->head->next= temp;
504     }
505    
506 teddy 1.33 /* Recall a value from a symbol, if bound */
507 teddy 1.31 extern void rcl(environment *env)
508     {
509     value *val;
510    
511     if(env->head == NULL) {
512 teddy 1.36 printerr("Too Few Arguments");
513 teddy 1.35 env->err=1;
514 teddy 1.31 return;
515     }
516    
517     if(env->head->item->type!=symb) {
518 teddy 1.36 printerr("Bad Argument Type");
519     env->err=2;
520 teddy 1.31 return;
521     }
522 teddy 1.35
523 teddy 1.31 val=((symbol *)(env->head->item->content.ptr))->val;
524 teddy 1.33 if(val == NULL){
525 teddy 1.36 printerr("Unbound Variable");
526     env->err=3;
527 teddy 1.33 return;
528     }
529 masse 1.90 protect(env, val);
530 teddy 1.31 toss(env); /* toss the symbol */
531 teddy 1.35 if(env->err) return;
532 masse 1.72 push_val(env, val); /* Return its bound value */
533 masse 1.90 unprotect(env);
534 teddy 1.31 }
535 masse 1.26
536 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
537     function value, and if it is, toss the symbol and execute the
538     function. */
539 teddy 1.28 extern void eval(environment *env)
540 masse 1.1 {
541     funcp in_func;
542 masse 1.44 value* temp_val;
543     stackitem* iterator;
544    
545 teddy 1.80 eval_start:
546    
547 teddy 1.29 if(env->head==NULL) {
548 teddy 1.36 printerr("Too Few Arguments");
549 teddy 1.35 env->err=1;
550 masse 1.1 return;
551 masse 1.17 }
552 masse 1.1
553 masse 1.46 switch(env->head->item->type) {
554     /* if it's a symbol */
555     case symb:
556 teddy 1.35 rcl(env); /* get its contents */
557     if(env->err) return;
558     if(env->head->item->type!=symb){ /* don't recurse symbols */
559 teddy 1.64 goto eval_start;
560 teddy 1.29 }
561 teddy 1.59 return;
562 masse 1.22
563 masse 1.46 /* If it's a lone function value, run it */
564     case func:
565 teddy 1.29 in_func= (funcp)(env->head->item->content.ptr);
566 teddy 1.28 toss(env);
567 teddy 1.35 if(env->err) return;
568 masse 1.89 return in_func(env);
569 masse 1.44
570 masse 1.46 /* If it's a list */
571     case list:
572 masse 1.44 temp_val= env->head->item;
573 masse 1.90 protect(env, temp_val);
574 masse 1.44 toss(env);
575     if(env->err) return;
576     iterator= (stackitem*)temp_val->content.ptr;
577 masse 1.90 unprotect(env);
578    
579 teddy 1.59 while(iterator!=NULL) {
580 masse 1.72 push_val(env, iterator->item);
581 masse 1.90
582 masse 1.44 if(env->head->item->type==symb
583     && strcmp(";", ((symbol*)(env->head->item->content.ptr))->id)==0) {
584     toss(env);
585     if(env->err) return;
586 masse 1.90
587 teddy 1.59 if(iterator->next == NULL){
588 teddy 1.64 goto eval_start;
589 teddy 1.59 }
590 masse 1.44 eval(env);
591 masse 1.46 if(env->err) return;
592 masse 1.44 }
593     iterator= iterator->next;
594     }
595 teddy 1.59 return;
596 masse 1.46
597 masse 1.71 default:
598 teddy 1.59 return;
599 masse 1.26 }
600 masse 1.1 }
601    
602 masse 1.44 /* Reverse (flip) a list */
603 teddy 1.40 extern void rev(environment *env){
604 teddy 1.78 stackitem *old_head, *new_head, *item;
605 teddy 1.40
606     if((env->head)==NULL) {
607     printerr("Too Few Arguments");
608 masse 1.90 env->err= 1;
609 teddy 1.40 return;
610     }
611    
612     if(env->head->item->type!=list) {
613     printerr("Bad Argument Type");
614 masse 1.90 env->err= 2;
615 teddy 1.40 return;
616     }
617    
618 masse 1.90 old_head= (stackitem *)(env->head->item->content.ptr);
619     new_head= NULL;
620 teddy 1.78 while(old_head != NULL){
621 masse 1.90 item= old_head;
622     old_head= old_head->next;
623     item->next= new_head;
624     new_head= item;
625 teddy 1.40 }
626 masse 1.90 env->head->item->content.ptr= new_head;
627 teddy 1.40 }
628    
629 masse 1.19 /* Make a list. */
630 teddy 1.28 extern void pack(environment *env)
631 masse 1.19 {
632 teddy 1.28 stackitem *iterator, *temp;
633     value *pack;
634 masse 1.19
635 teddy 1.28 iterator= env->head;
636 masse 1.19
637 masse 1.73 if(iterator==NULL
638     || (iterator->item->type==symb
639     && ((symbol*)(iterator->item->content.ptr))->id[0]=='[')) {
640 masse 1.24 temp= NULL;
641 teddy 1.28 toss(env);
642 masse 1.24 } else {
643     /* Search for first delimiter */
644 teddy 1.28 while(iterator->next!=NULL
645 masse 1.73 && (iterator->next->item->type!=symb
646     || ((symbol*)(iterator->next->item->content.ptr))->id[0]!='['))
647 masse 1.24 iterator= iterator->next;
648    
649     /* Extract list */
650 teddy 1.28 temp= env->head;
651     env->head= iterator->next;
652 masse 1.24 iterator->next= NULL;
653    
654 teddy 1.28 if(env->head!=NULL)
655     toss(env);
656 masse 1.24 }
657 masse 1.19
658     /* Push list */
659 masse 1.87 pack= new_val(env);
660 masse 1.19 pack->type= list;
661     pack->content.ptr= temp;
662 teddy 1.28
663 masse 1.74 push_val(env, pack);
664 teddy 1.40 rev(env);
665 masse 1.19 }
666    
667 masse 1.16 /* Relocate elements of the list on the stack. */
668 teddy 1.28 extern void expand(environment *env)
669 masse 1.1 {
670 masse 1.8 stackitem *temp, *new_head;
671    
672 masse 1.16 /* Is top element a list? */
673 teddy 1.36 if(env->head==NULL) {
674     printerr("Too Few Arguments");
675 masse 1.90 env->err= 1;
676 masse 1.8 return;
677 masse 1.17 }
678 teddy 1.36 if(env->head->item->type!=list) {
679     printerr("Bad Argument Type");
680 masse 1.90 env->err= 2;
681 teddy 1.36 return;
682     }
683 masse 1.43
684     rev(env);
685    
686     if(env->err)
687     return;
688 masse 1.8
689 masse 1.16 /* The first list element is the new stack head */
690 teddy 1.28 new_head= temp= env->head->item->content.ptr;
691 masse 1.8
692 teddy 1.28 toss(env);
693 masse 1.24
694 teddy 1.28 /* Find the end of the list */
695 masse 1.8 while(temp->next!=NULL)
696     temp= temp->next;
697    
698 teddy 1.28 /* Connect the tail of the list with the old stack head */
699     temp->next= env->head;
700     env->head= new_head; /* ...and voila! */
701    
702 teddy 1.5 }
703 masse 1.11
704 masse 1.14 /* Compares two elements by reference. */
705 teddy 1.28 extern void eq(environment *env)
706 masse 1.11 {
707     void *left, *right;
708     int result;
709    
710 teddy 1.28 if((env->head)==NULL || env->head->next==NULL) {
711 teddy 1.36 printerr("Too Few Arguments");
712 masse 1.90 env->err= 1;
713 masse 1.11 return;
714 masse 1.17 }
715 masse 1.11
716 teddy 1.28 left= env->head->item->content.ptr;
717     swap(env);
718     right= env->head->item->content.ptr;
719 masse 1.11 result= (left==right);
720    
721 teddy 1.28 toss(env); toss(env);
722 masse 1.72 push_int(env, result);
723 masse 1.11 }
724    
725 masse 1.14 /* Negates the top element on the stack. */
726 teddy 1.28 extern void not(environment *env)
727 masse 1.11 {
728 teddy 1.28 int val;
729 masse 1.11
730 teddy 1.36 if((env->head)==NULL) {
731     printerr("Too Few Arguments");
732 masse 1.90 env->err= 1;
733 masse 1.11 return;
734 masse 1.17 }
735 masse 1.11
736 teddy 1.36 if(env->head->item->type!=integer) {
737     printerr("Bad Argument Type");
738 masse 1.90 env->err= 2;
739 teddy 1.36 return;
740     }
741    
742 teddy 1.28 val= env->head->item->content.val;
743     toss(env);
744 masse 1.72 push_int(env, !val);
745 masse 1.11 }
746    
747 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
748     same. */
749 teddy 1.28 extern void neq(environment *env)
750 masse 1.11 {
751 teddy 1.28 eq(env);
752     not(env);
753 masse 1.11 }
754 masse 1.12
755 masse 1.14 /* Give a symbol some content. */
756 teddy 1.28 extern void def(environment *env)
757 masse 1.12 {
758 teddy 1.28 symbol *sym;
759 masse 1.12
760 teddy 1.28 /* Needs two values on the stack, the top one must be a symbol */
761 teddy 1.36 if(env->head==NULL || env->head->next==NULL) {
762     printerr("Too Few Arguments");
763 masse 1.90 env->err= 1;
764 masse 1.12 return;
765 masse 1.17 }
766 masse 1.12
767 teddy 1.36 if(env->head->item->type!=symb) {
768     printerr("Bad Argument Type");
769 masse 1.90 env->err= 2;
770 teddy 1.36 return;
771     }
772    
773 teddy 1.28 /* long names are a pain */
774 masse 1.90 sym= env->head->item->content.ptr;
775 teddy 1.28
776     /* Bind the symbol to the value */
777     sym->val= env->head->next->item;
778 masse 1.12
779 teddy 1.28 toss(env); toss(env);
780 masse 1.12 }
781 masse 1.10
782 masse 1.14 /* Quit stack. */
783 teddy 1.28 extern void quit(environment *env)
784 teddy 1.5 {
785 teddy 1.77 long i;
786    
787     clear(env);
788 masse 1.83
789 teddy 1.77 if (env->err) return;
790     for(i= 0; i<HASHTBLSIZE; i++) {
791 masse 1.79 while(env->symbols[i]!= NULL) {
792 teddy 1.77 forget_sym(&(env->symbols[i]));
793     }
794 teddy 1.80 env->symbols[i]= NULL;
795 teddy 1.77 }
796 masse 1.83
797 masse 1.90 env->gc_limit= 0;
798 masse 1.87 gc_init(env);
799    
800 masse 1.83 if(env->free_string!=NULL)
801     free(env->free_string);
802    
803     muntrace();
804    
805 teddy 1.5 exit(EXIT_SUCCESS);
806 masse 1.24 }
807    
808     /* Clear stack */
809 teddy 1.28 extern void clear(environment *env)
810 masse 1.24 {
811 teddy 1.28 while(env->head!=NULL)
812     toss(env);
813 masse 1.1 }
814    
815 teddy 1.33 /* List all defined words */
816 masse 1.32 extern void words(environment *env)
817     {
818     symbol *temp;
819     int i;
820    
821     for(i= 0; i<HASHTBLSIZE; i++) {
822     temp= env->symbols[i];
823     while(temp!=NULL) {
824     printf("%s\n", temp->id);
825     temp= temp->next;
826     }
827     }
828     }
829 masse 1.34
830 teddy 1.77 /* Internal forget function */
831     void forget_sym(symbol **hash_entry) {
832     symbol *temp;
833    
834     temp= *hash_entry;
835     *hash_entry= (*hash_entry)->next;
836    
837     free(temp->id);
838     free(temp);
839     }
840    
841 masse 1.34 /* Forgets a symbol (remove it from the hash table) */
842     extern void forget(environment *env)
843     {
844     char* sym_id;
845     stackitem *stack_head= env->head;
846    
847 teddy 1.36 if(stack_head==NULL) {
848     printerr("Too Few Arguments");
849     env->err=1;
850     return;
851     }
852    
853     if(stack_head->item->type!=symb) {
854     printerr("Bad Argument Type");
855     env->err=2;
856 masse 1.34 return;
857     }
858    
859     sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
860     toss(env);
861    
862 teddy 1.77 return forget_sym(hash(env->symbols, sym_id));
863 teddy 1.36 }
864    
865     /* Returns the current error number to the stack */
866     extern void errn(environment *env){
867 masse 1.72 push_int(env, env->err);
868 teddy 1.36 }
869 masse 1.69
870 teddy 1.84 int main(int argc, char **argv)
871 masse 1.1 {
872 teddy 1.28 environment myenv;
873 masse 1.1
874 teddy 1.84 int c; /* getopt option character */
875    
876 masse 1.83 mtrace();
877    
878 teddy 1.28 init_env(&myenv);
879 masse 1.1
880 teddy 1.84 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
881    
882     while ((c = getopt (argc, argv, "i")) != -1)
883     switch (c)
884     {
885     case 'i':
886     myenv.interactive = 1;
887     break;
888     case '?':
889     fprintf (stderr,
890     "Unknown option character `\\x%x'.\n",
891     optopt);
892     return EX_USAGE;
893     default:
894     abort ();
895     }
896    
897     if (optind < argc) {
898     myenv.interactive = 0;
899     myenv.inputstream= fopen(argv[optind], "r");
900     if(myenv.inputstream== NULL) {
901     perror(argv[0]);
902     exit (EX_NOINPUT);
903     }
904     }
905    
906 masse 1.69 while(1) {
907 teddy 1.85 if(myenv.in_string==NULL) {
908     if (myenv.interactive) {
909     if(myenv.err) {
910     printf("(error %d)\n", myenv.err);
911     }
912     nl();
913     printstack(&myenv);
914     printf("> ");
915     }
916     myenv.err=0;
917 teddy 1.80 }
918 teddy 1.84 sx_72656164(&myenv);
919 teddy 1.85 if (myenv.err==4) {
920     return EX_NOINPUT;
921 masse 1.71 } else if(myenv.head!=NULL
922     && myenv.head->item->type==symb
923 masse 1.69 && ((symbol*)(myenv.head->item->content.ptr))->id[0]==';') {
924     toss(&myenv); /* No error check in main */
925     eval(&myenv);
926 teddy 1.35 }
927 masse 1.89 gc_init(&myenv);
928 masse 1.1 }
929 teddy 1.41 quit(&myenv);
930 teddy 1.42 return EXIT_FAILURE;
931 teddy 1.48 }
932    
933 teddy 1.85 /* "+" */
934 teddy 1.48 extern void sx_2b(environment *env) {
935     int a, b;
936 masse 1.49 size_t len;
937     char* new_string;
938     value *a_val, *b_val;
939 teddy 1.48
940     if((env->head)==NULL || env->head->next==NULL) {
941     printerr("Too Few Arguments");
942 masse 1.90 env->err= 1;
943 masse 1.49 return;
944     }
945    
946     if(env->head->item->type==string
947     && env->head->next->item->type==string) {
948     a_val= env->head->item;
949     b_val= env->head->next->item;
950 masse 1.90 protect(env, a_val); protect(env, b_val);
951 masse 1.49 toss(env); if(env->err) return;
952     toss(env); if(env->err) return;
953     len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
954     new_string= malloc(len);
955     strcpy(new_string, b_val->content.ptr);
956     strcat(new_string, a_val->content.ptr);
957 masse 1.72 push_cstring(env, new_string);
958 masse 1.90 unprotect(env); unprotect(env);
959 masse 1.49 free(new_string);
960 teddy 1.48 return;
961     }
962    
963     if(env->head->item->type!=integer
964     || env->head->next->item->type!=integer) {
965     printerr("Bad Argument Type");
966     env->err=2;
967     return;
968     }
969 masse 1.90 a= env->head->item->content.val;
970 masse 1.87 toss(env); if(env->err) return;
971    
972 masse 1.90 b= env->head->item->content.val;
973 masse 1.87 toss(env); if(env->err) return;
974     push_int(env, a+b);
975 masse 1.1 }
976 teddy 1.55
977 teddy 1.85 /* "-" */
978 teddy 1.60 extern void sx_2d(environment *env) {
979 teddy 1.62 int a, b;
980 teddy 1.60
981     if((env->head)==NULL || env->head->next==NULL) {
982     printerr("Too Few Arguments");
983     env->err=1;
984     return;
985     }
986    
987     if(env->head->item->type!=integer
988     || env->head->next->item->type!=integer) {
989     printerr("Bad Argument Type");
990     env->err=2;
991     return;
992     }
993 masse 1.90
994 teddy 1.60 a=env->head->item->content.val;
995 masse 1.87 toss(env); if(env->err) return;
996     b=env->head->item->content.val;
997     toss(env); if(env->err) return;
998     push_int(env, b-a);
999 teddy 1.60 }
1000    
1001 teddy 1.85 /* ">" */
1002 teddy 1.61 extern void sx_3e(environment *env) {
1003 teddy 1.62 int a, b;
1004 teddy 1.61
1005     if((env->head)==NULL || env->head->next==NULL) {
1006     printerr("Too Few Arguments");
1007     env->err=1;
1008     return;
1009     }
1010    
1011     if(env->head->item->type!=integer
1012     || env->head->next->item->type!=integer) {
1013     printerr("Bad Argument Type");
1014     env->err=2;
1015     return;
1016     }
1017 masse 1.90
1018 teddy 1.61 a=env->head->item->content.val;
1019 masse 1.87 toss(env); if(env->err) return;
1020     b=env->head->item->content.val;
1021     toss(env); if(env->err) return;
1022     push_int(env, b>a);
1023 teddy 1.61 }
1024    
1025 teddy 1.55 /* Return copy of a value */
1026 masse 1.87 value *copy_val(environment *env, value *old_value){
1027 teddy 1.55 stackitem *old_item, *new_item, *prev_item;
1028    
1029 masse 1.90 value *new_value= new_val(env);
1030 teddy 1.55
1031 masse 1.90 protect(env, old_value);
1032     new_value->type= old_value->type;
1033 masse 1.87
1034 teddy 1.55 switch(old_value->type){
1035     case integer:
1036 masse 1.90 new_value->content.val= old_value->content.val;
1037 teddy 1.55 break;
1038     case string:
1039 masse 1.90 (char *)(new_value->content.ptr)=
1040     strdup((char *)(old_value->content.ptr));
1041 teddy 1.55 break;
1042     case func:
1043     case symb:
1044 masse 1.90 new_value->content.ptr= old_value->content.ptr;
1045 teddy 1.55 break;
1046     case list:
1047 masse 1.90 new_value->content.ptr= NULL;
1048 teddy 1.55
1049 masse 1.90 prev_item= NULL;
1050     old_item= (stackitem*)(old_value->content.ptr);
1051 teddy 1.55
1052     while(old_item != NULL) { /* While list is not empty */
1053     new_item= malloc(sizeof(stackitem));
1054 masse 1.90 new_item->item= copy_val(env, old_item->item); /* recurse */
1055     new_item->next= NULL;
1056 teddy 1.55 if(prev_item != NULL) /* If this wasn't the first item */
1057 masse 1.90 prev_item->next= new_item; /* point the previous item to the
1058 teddy 1.55 new item */
1059     else
1060 masse 1.90 new_value->content.ptr= new_item;
1061     old_item= old_item->next;
1062     prev_item= new_item;
1063 teddy 1.55 }
1064     break;
1065     }
1066 masse 1.90
1067     unprotect(env);
1068    
1069 teddy 1.55 return new_value;
1070     }
1071    
1072 teddy 1.84 /* "dup"; duplicates an item on the stack */
1073     extern void sx_647570(environment *env) {
1074 teddy 1.55 if((env->head)==NULL) {
1075     printerr("Too Few Arguments");
1076 masse 1.90 env->err= 1;
1077 teddy 1.55 return;
1078     }
1079 masse 1.87 push_val(env, copy_val(env, env->head->item));
1080 teddy 1.55 }
1081 teddy 1.56
1082 teddy 1.59 /* "if", If-Then */
1083 masse 1.57 extern void sx_6966(environment *env) {
1084 teddy 1.56
1085     int truth;
1086    
1087     if((env->head)==NULL || env->head->next==NULL) {
1088     printerr("Too Few Arguments");
1089 masse 1.90 env->err= 1;
1090 teddy 1.56 return;
1091     }
1092    
1093     if(env->head->next->item->type != integer) {
1094     printerr("Bad Argument Type");
1095     env->err=2;
1096     return;
1097     }
1098    
1099     swap(env);
1100     if(env->err) return;
1101    
1102     truth=env->head->item->content.val;
1103    
1104     toss(env);
1105     if(env->err) return;
1106    
1107     if(truth)
1108     eval(env);
1109     else
1110     toss(env);
1111     }
1112    
1113     /* If-Then-Else */
1114 masse 1.57 extern void ifelse(environment *env) {
1115 teddy 1.56
1116     int truth;
1117    
1118     if((env->head)==NULL || env->head->next==NULL
1119     || env->head->next->next==NULL) {
1120     printerr("Too Few Arguments");
1121     env->err=1;
1122     return;
1123     }
1124    
1125     if(env->head->next->next->item->type != integer) {
1126     printerr("Bad Argument Type");
1127     env->err=2;
1128     return;
1129     }
1130    
1131     rot(env);
1132     if(env->err) return;
1133    
1134     truth=env->head->item->content.val;
1135    
1136     toss(env);
1137     if(env->err) return;
1138    
1139     if(!truth)
1140     swap(env);
1141     if(env->err) return;
1142    
1143     toss(env);
1144     if(env->err) return;
1145    
1146     eval(env);
1147 masse 1.58 }
1148    
1149 teddy 1.85 /* "while" */
1150 masse 1.58 extern void sx_7768696c65(environment *env) {
1151    
1152     int truth;
1153 masse 1.63 value *loop, *test;
1154 masse 1.58
1155     if((env->head)==NULL || env->head->next==NULL) {
1156     printerr("Too Few Arguments");
1157     env->err=1;
1158     return;
1159     }
1160    
1161 masse 1.63 loop= env->head->item;
1162 masse 1.90 protect(env, loop);
1163 masse 1.63 toss(env); if(env->err) return;
1164    
1165     test= env->head->item;
1166 masse 1.90 protect(env, test);
1167 masse 1.63 toss(env); if(env->err) return;
1168    
1169 masse 1.58 do {
1170 masse 1.72 push_val(env, test);
1171 masse 1.63 eval(env);
1172 masse 1.58
1173     if(env->head->item->type != integer) {
1174     printerr("Bad Argument Type");
1175 masse 1.90 env->err= 2;
1176 masse 1.58 return;
1177     }
1178    
1179     truth= env->head->item->content.val;
1180     toss(env); if(env->err) return;
1181    
1182     if(truth) {
1183 masse 1.72 push_val(env, loop);
1184 masse 1.58 eval(env);
1185     } else {
1186     toss(env);
1187     }
1188    
1189     } while(truth);
1190 masse 1.90
1191     unprotect(env); unprotect(env);
1192 teddy 1.56 }
1193 masse 1.65
1194 masse 1.89
1195     /* "for"; for-loop */
1196 masse 1.65 extern void sx_666f72(environment *env) {
1197 masse 1.89 value *loop;
1198     int foo1, foo2;
1199    
1200     if(env->head==NULL || env->head->next==NULL
1201     || env->head->next->next==NULL) {
1202     printerr("Too Few Arguments");
1203     env->err= 1;
1204     return;
1205     }
1206    
1207     if(env->head->next->item->type!=integer
1208     || env->head->next->next->item->type!=integer) {
1209     printerr("Bad Argument Type");
1210     env->err= 2;
1211     return;
1212     }
1213    
1214     loop= env->head->item;
1215 masse 1.90 protect(env, loop);
1216 masse 1.89 toss(env); if(env->err) return;
1217    
1218     foo2= env->head->item->content.val;
1219     toss(env); if(env->err) return;
1220    
1221     foo1= env->head->item->content.val;
1222     toss(env); if(env->err) return;
1223    
1224     if(foo1<=foo2) {
1225     while(foo1<=foo2) {
1226     push_int(env, foo1);
1227     push_val(env, loop);
1228     eval(env); if(env->err) return;
1229     foo1++;
1230     }
1231     } else {
1232     while(foo1>=foo2) {
1233     push_int(env, foo1);
1234     push_val(env, loop);
1235     eval(env); if(env->err) return;
1236     foo1--;
1237     }
1238     }
1239 masse 1.90 unprotect(env);
1240 masse 1.89 }
1241    
1242     /* Variant of for-loop */
1243     extern void foreach(environment *env) {
1244 masse 1.65
1245     value *loop, *foo;
1246     stackitem *iterator;
1247    
1248     if((env->head)==NULL || env->head->next==NULL) {
1249     printerr("Too Few Arguments");
1250 masse 1.90 env->err= 1;
1251 masse 1.65 return;
1252     }
1253    
1254     if(env->head->next->item->type != list) {
1255     printerr("Bad Argument Type");
1256 masse 1.90 env->err= 2;
1257 masse 1.65 return;
1258     }
1259    
1260     loop= env->head->item;
1261 masse 1.90 protect(env, loop);
1262 masse 1.65 toss(env); if(env->err) return;
1263    
1264     foo= env->head->item;
1265 masse 1.90 protect(env, foo);
1266 masse 1.65 toss(env); if(env->err) return;
1267    
1268     iterator= foo->content.ptr;
1269    
1270     while(iterator!=NULL) {
1271 masse 1.72 push_val(env, iterator->item);
1272     push_val(env, loop);
1273 masse 1.65 eval(env); if(env->err) return;
1274     iterator= iterator->next;
1275     }
1276 masse 1.90 unprotect(env); unprotect(env);
1277 masse 1.65 }
1278 masse 1.66
1279 teddy 1.85 /* "to" */
1280 masse 1.66 extern void to(environment *env) {
1281     int i, start, ending;
1282 masse 1.74 stackitem *temp_head;
1283     value *temp_val;
1284 masse 1.66
1285     if((env->head)==NULL || env->head->next==NULL) {
1286     printerr("Too Few Arguments");
1287     env->err=1;
1288     return;
1289     }
1290    
1291     if(env->head->item->type!=integer
1292     || env->head->next->item->type!=integer) {
1293     printerr("Bad Argument Type");
1294     env->err=2;
1295     return;
1296     }
1297    
1298     ending= env->head->item->content.val;
1299     toss(env); if(env->err) return;
1300     start= env->head->item->content.val;
1301     toss(env); if(env->err) return;
1302    
1303 masse 1.74 temp_head= env->head;
1304     env->head= NULL;
1305 masse 1.66
1306 masse 1.67 if(ending>=start) {
1307 masse 1.74 for(i= ending; i>=start; i--)
1308 masse 1.72 push_int(env, i);
1309 masse 1.67 } else {
1310 masse 1.74 for(i= ending; i<=start; i++)
1311 masse 1.72 push_int(env, i);
1312 masse 1.67 }
1313 masse 1.66
1314 masse 1.87 temp_val= new_val(env);
1315 masse 1.74 temp_val->content.ptr= env->head;
1316     temp_val->type= list;
1317     env->head= temp_head;
1318     push_val(env, temp_val);
1319 masse 1.66 }
1320 masse 1.68
1321     /* Read a string */
1322     extern void readline(environment *env) {
1323     char in_string[101];
1324    
1325 teddy 1.84 if(fgets(in_string, 100, env->inputstream)==NULL)
1326     push_cstring(env, "");
1327     else
1328     push_cstring(env, in_string);
1329 masse 1.68 }
1330    
1331 teddy 1.84 /* "read"; Read a value and place on stack */
1332     extern void sx_72656164(environment *env) {
1333 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1334     const char strform[]= "\"%[^\"]\"%n";
1335     const char intform[]= "%i%n";
1336     const char blankform[]= "%*[ \t]%n";
1337 masse 1.90 const char ebrackform[]= "]%n";
1338     const char semicform[]= ";%n";
1339     const char bbrackform[]= "[%n";
1340 masse 1.68
1341 teddy 1.78 int itemp, readlength= -1;
1342 masse 1.68 static int depth= 0;
1343 masse 1.83 char *match;
1344 masse 1.68 size_t inlength;
1345    
1346 masse 1.70 if(env->in_string==NULL) {
1347 teddy 1.84 if(depth > 0 && env->interactive) {
1348 teddy 1.80 printf("]> ");
1349     }
1350 masse 1.68 readline(env); if(env->err) return;
1351 teddy 1.84
1352     if(((char *)(env->head->item->content.ptr))[0]=='\0'){
1353 teddy 1.85 env->err= 4; /* "" means EOF */
1354 teddy 1.84 return;
1355     }
1356 masse 1.68
1357 masse 1.70 env->in_string= malloc(strlen(env->head->item->content.ptr)+1);
1358 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
1359 masse 1.70 strcpy(env->in_string, env->head->item->content.ptr);
1360 masse 1.68 toss(env); if(env->err) return;
1361     }
1362    
1363 masse 1.70 inlength= strlen(env->in_string)+1;
1364 masse 1.68 match= malloc(inlength);
1365    
1366 teddy 1.78 if(sscanf(env->in_string, blankform, &readlength)!=EOF
1367     && readlength != -1) {
1368 masse 1.71 ;
1369 teddy 1.78 } else if(sscanf(env->in_string, intform, &itemp, &readlength) != EOF
1370     && readlength != -1) {
1371 masse 1.72 push_int(env, itemp);
1372 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1373     && readlength != -1) {
1374 masse 1.72 push_cstring(env, match);
1375 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1376     && readlength != -1) {
1377 masse 1.68 push_sym(env, match);
1378 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1379     && readlength != -1) {
1380 masse 1.68 pack(env); if(env->err) return;
1381 teddy 1.78 if(depth != 0) depth--;
1382     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1383     && readlength != -1) {
1384 masse 1.68 push_sym(env, ";");
1385 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1386     && readlength != -1) {
1387 masse 1.68 push_sym(env, "[");
1388     depth++;
1389     } else {
1390 teddy 1.78 free(env->free_string);
1391     env->in_string = env->free_string = NULL;
1392     }
1393     if ( env->in_string != NULL) {
1394     env->in_string += readlength;
1395 masse 1.68 }
1396 masse 1.83
1397     free(match);
1398 masse 1.68
1399 masse 1.71 if(depth)
1400 teddy 1.84 return sx_72656164(env);
1401 masse 1.68 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26