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

Diff of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.23 by masse, Sat Feb 2 18:36:19 2002 UTC revision 1.125 by teddy, Sun Mar 31 02:19:54 2002 UTC
# Line 1  Line 1 
1  /* printf */  /* -*- coding: utf-8; -*- */
2    /*
3        stack - an interactive interpreter for a stack-based language
4        Copyright (C) 2002  Mats Alritzson and Teddy Hogeborn
5    
6        This program is free software; you can redistribute it and/or modify
7        it under the terms of the GNU General Public License as published by
8        the Free Software Foundation; either version 2 of the License, or
9        (at your option) any later version.
10    
11        This program is distributed in the hope that it will be useful,
12        but WITHOUT ANY WARRANTY; without even the implied warranty of
13        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14        GNU General Public License for more details.
15    
16        You should have received a copy of the GNU General Public License
17        along with this program; if not, write to the Free Software
18        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19    
20        Authors: Mats Alritzson <masse@fukt.bth.se>
21                 Teddy Hogeborn <teddy@fukt.bth.se>
22    */
23    
24    #define CAR(X) ((X)->content.c->car)
25    #define CDR(X) ((X)->content.c->cdr)
26    
27    /* printf, sscanf, fgets, fprintf, fopen, perror */
28  #include <stdio.h>  #include <stdio.h>
29  /* EXIT_SUCCESS */  /* exit, EXIT_SUCCESS, malloc, free */
30  #include <stdlib.h>  #include <stdlib.h>
31  /* NULL */  /* NULL */
32  #include <stddef.h>  #include <stddef.h>
33  /* dlopen, dlsym, dlerror */  /* dlopen, dlsym, dlerror */
34  #include <dlfcn.h>  #include <dlfcn.h>
35    /* strcmp, strcpy, strlen, strcat, strdup */
36    #include <string.h>
37    /* getopt, STDIN_FILENO, STDOUT_FILENO, usleep */
38    #include <unistd.h>
39    /* EX_NOINPUT, EX_USAGE */
40    #include <sysexits.h>
41  /* assert */  /* assert */
42  #include <assert.h>  #include <assert.h>
43    
44  #define HASHTBLSIZE 65536  #ifdef __linux__
45    /* mtrace, muntrace */
46    #include <mcheck.h>
47    /* ioctl */
48    #include <sys/ioctl.h>
49    /* KDMKTONE */
50    #include <linux/kd.h>
51    #endif /* __linux__ */
52    
53    #include "stack.h"
54    
55    /* Initialize a newly created environment */
56    void init_env(environment *env)
57    {
58      int i;
59    
60      env->gc_limit= 400000;
61      env->gc_count= 0;
62      env->gc_ref= NULL;
63    
64  typedef struct stack_item    env->head= new_val(env);
65  {    for(i= 0; i<HASHTBLSIZE; i++)
66    enum {      env->symbols[i]= NULL;
67      value,                      /* Integer */    env->err= 0;
68      string,    env->in_string= NULL;
69      ref,                        /* Reference (to an element in the    env->free_string= NULL;
70                                     hash table) */    env->inputstream= stdin;
71      func,                       /* Function pointer */    env->interactive= 1;
72      symbol,  }
     list  
   } type;                       /* Type of stack element */  
   
   union {  
     void* ptr;                  /* Pointer to the content */  
     int val;                    /* ...or an integer */  
   } content;                    /* Stores a pointer or an integer */  
   
   char* id;                     /* Symbol name */  
   struct stack_item* next;      /* Next element */  
 } stackitem;  
   
   
 typedef stackitem* hashtbl[HASHTBLSIZE]; /* Hash table declaration */  
 typedef void (*funcp)(stackitem**); /* funcp is a pointer to a  
                                        void function (stackitem **) */  
73    
74  /* Initialize a newly created hash table. */  void printerr(const char* in_string)
 void init_hashtbl(hashtbl out_hash)  
75  {  {
76    long i;    fprintf(stderr, "Err: %s\n", in_string);
77    }
78    
79    for(i= 0; i<HASHTBLSIZE; i++)  /* Discard the top element of the stack. */
80      out_hash[i]= NULL;  extern void toss(environment *env)
81    {
82      if(env->head->type==empty) {
83        printerr("Too Few Arguments");
84        env->err= 1;
85        return;
86      }
87      
88      env->head= CDR(env->head); /* Remove the top stack item */
89  }  }
90    
91  /* Returns a pointer to an element in the hash table. */  /* Returns a pointer to a pointer to an element in the hash table. */
92  stackitem** hash(hashtbl in_hashtbl, const char* in_string)  symbol **hash(hashtbl in_hashtbl, const char *in_string)
93  {  {
94    long i= 0;    int i= 0;
95    unsigned long out_hash= 0;    unsigned int out_hash= 0;
96    char key= '\0';    char key= '\0';
97    stackitem** position;    symbol **position;
98        
99    while(1){                     /* Hash in_string */    while(1){                     /* Hash in_string */
100      key= in_string[i++];      key= in_string[i++];
# Line 64  stackitem** hash(hashtbl in_hashtbl, con Line 106  stackitem** hash(hashtbl in_hashtbl, con
106    out_hash= out_hash%HASHTBLSIZE;    out_hash= out_hash%HASHTBLSIZE;
107    position= &(in_hashtbl[out_hash]);    position= &(in_hashtbl[out_hash]);
108    
109    while(position != NULL){    while(1){
110      if(*position==NULL)         /* If empty */      if(*position==NULL)         /* If empty */
111        return position;        return position;
112            
# Line 73  stackitem** hash(hashtbl in_hashtbl, con Line 115  stackitem** hash(hashtbl in_hashtbl, con
115    
116      position= &((*position)->next); /* Try next */      position= &((*position)->next); /* Try next */
117    }    }
   return NULL;                  /* end of list reached without finding  
                                    an empty position */  
118  }  }
119    
120  /* Generic push function. */  /* Create new value */
121  int push(stackitem** stack_head, stackitem* in_item)  value* new_val(environment *env)
122  {  {
123    in_item->next= *stack_head;    value *nval= malloc(sizeof(value));
124    *stack_head= in_item;    stackitem *nitem= malloc(sizeof(stackitem));
125    return 1;  
126      assert(nval != NULL);
127      assert(nitem != NULL);
128    
129      nval->content.ptr= NULL;
130      nval->type= empty;
131    
132      nitem->item= nval;
133      nitem->next= env->gc_ref;
134    
135      env->gc_ref= nitem;
136    
137      env->gc_count += sizeof(value);
138      nval->gc.flag.mark= 0;
139      nval->gc.flag.protect= 0;
140    
141      return nval;
142  }  }
143    
144  /* Push a value on the stack. */  /* Mark values recursively.
145  int push_val(stackitem** stack_head, int in_val)     Marked values are not collected by the GC. */
146    inline void gc_mark(value *val)
147  {  {
148    stackitem* new_item= malloc(sizeof(stackitem));    if(val==NULL || val->gc.flag.mark)
149    assert(new_item != NULL);      return;
150    new_item->content.val= in_val;  
151    new_item->type= value;    val->gc.flag.mark= 1;
152    
153    push(stack_head, new_item);    if(val->type==tcons) {
154    return 1;      gc_mark(CAR(val));
155        gc_mark(CDR(val));
156      }
157  }  }
158    
159  /* Copy a string onto the stack. */  inline void gc_maybe(environment *env)
 int push_cstring(stackitem** stack_head, const char* in_string)  
160  {  {
161    stackitem* new_item= malloc(sizeof(stackitem));    if(env->gc_count < env->gc_limit)
162    new_item->content.ptr= malloc(strlen(in_string)+1);      return;
163    strcpy(new_item->content.ptr, in_string);    else
164    new_item->type= string;      return gc_init(env);
165    }
166    
167    /* Start GC */
168    extern void gc_init(environment *env)
169    {
170      stackitem *new_head= NULL, *titem;
171      symbol *tsymb;
172      int i;
173    
174      if(env->interactive)
175        printf("Garbage collecting.");
176    
177      /* Mark values on stack */
178      gc_mark(env->head);
179    
180      if(env->interactive)
181        printf(".");
182    
183    
184      /* Mark values in hashtable */
185      for(i= 0; i<HASHTBLSIZE; i++)
186        for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next)
187          if (tsymb->val != NULL)
188            gc_mark(tsymb->val);
189    
190    
191      if(env->interactive)
192        printf(".");
193    
194      env->gc_count= 0;
195    
196      while(env->gc_ref!=NULL) {    /* Sweep unused values */
197    
198        if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */
199    
200          /* Remove content */
201          switch(env->gc_ref->item->type){
202          case string:
203            free(env->gc_ref->item->content.ptr);
204            break;
205          case tcons:
206            free(env->gc_ref->item->content.c);
207            break;
208          case port:
209          case empty:
210          case integer:
211          case tfloat:
212          case func:
213          case symb:
214            /* Symbol strings are freed when walking the hash table */
215          }
216    
217          free(env->gc_ref->item);  /* Remove from gc_ref */
218          titem= env->gc_ref->next;
219          free(env->gc_ref);        /* Remove value */
220          env->gc_ref= titem;
221          continue;
222        }
223    #ifdef DEBUG
224        printf("Kept value (%p)", env->gc_ref->item);
225        if(env->gc_ref->item->gc.flag.mark)
226          printf(" (marked)");
227        if(env->gc_ref->item->gc.flag.protect)
228          printf(" (protected)");
229        switch(env->gc_ref->item->type){
230        case integer:
231          printf(" integer: %d", env->gc_ref->item->content.i);
232          break;
233        case func:
234          printf(" func: %p", env->gc_ref->item->content.ptr);
235          break;
236        case symb:
237          printf(" symb: %s", env->gc_ref->item->content.sym->id);
238          break;
239        case tcons:
240          printf(" tcons: %p\t%p", env->gc_ref->item->content.c->car,
241                 env->gc_ref->item->content.c->cdr);
242          break;
243        default:
244          printf(" <unknown %d>", (env->gc_ref->item->type));
245        }
246        printf("\n");
247    #endif /* DEBUG */
248    
249        /* Keep values */    
250        env->gc_count += sizeof(value);
251        if(env->gc_ref->item->type==string)
252          env->gc_count += strlen(env->gc_ref->item->content.ptr)+1;
253        
254        titem= env->gc_ref->next;
255        env->gc_ref->next= new_head;
256        new_head= env->gc_ref;
257        new_head->item->gc.flag.mark= 0;
258        env->gc_ref= titem;
259      }
260    
261      if (env->gc_limit < env->gc_count*2)
262        env->gc_limit= env->gc_count*2;
263    
264      env->gc_ref= new_head;
265    
266      if(env->interactive)
267        printf("done (%d bytes still allocated)\n", env->gc_count);
268    
   push(stack_head, new_item);  
   return 1;  
269  }  }
270    
271  /* Create a new hash entry. */  /* Protect values from GC */
272  int mk_hashentry(hashtbl in_hashtbl, stackitem* in_item, const char* id)  void protect(value *val)
273  {  {
274    in_item->id= malloc(strlen(id)+1);    if(val==NULL || val->gc.flag.protect)
275        return;
276    
277    strcpy(in_item->id, id);    val->gc.flag.protect= 1;
   push(hash(in_hashtbl, id), in_item);  
278    
279    return 1;    if(val->type==tcons) {
280        protect(CAR(val));
281        protect(CDR(val));
282      }
283  }  }
284    
285  /* Define a new function in the hash table. */  /* Unprotect values from GC */
286  void def_func(hashtbl in_hashtbl, funcp in_func, const char* id)  void unprotect(value *val)
287  {  {
288    stackitem* temp= malloc(sizeof(stackitem));    if(val==NULL || !(val->gc.flag.protect))
289        return;
290    
291    temp->type= func;    val->gc.flag.protect= 0;
   temp->content.ptr= in_func;  
292    
293    mk_hashentry(in_hashtbl, temp, id);    if(val->type==tcons) {
294        unprotect(CAR(val));
295        unprotect(CDR(val));
296      }
297  }  }
298    
299  /* Define a new symbol in the hash table. */  /* Push a value onto the stack */
300  void def_sym(hashtbl in_hashtbl, const char* id)  void push_val(environment *env, value *val)
301  {  {
302    stackitem* temp= malloc(sizeof(stackitem));    value *new_value= new_val(env);
303      
304    temp->type= symbol;    new_value->content.c= malloc(sizeof(pair));
305    mk_hashentry(in_hashtbl, temp, id);    assert(new_value->content.c!=NULL);
306      env->gc_count += sizeof(pair);
307      new_value->type= tcons;
308      CAR(new_value)= val;
309      CDR(new_value)= env->head;
310      env->head= new_value;
311  }  }
312    
313  /* Push a reference to an entry in the hash table onto the stack. */  /* Push an integer onto the stack */
314  int push_ref(stackitem** stack_head, hashtbl in_hash, const char* in_string)  void push_int(environment *env, int in_val)
315  {  {
316    static void* handle= NULL;    value *new_value= new_val(env);
317    void* symbol;    
318      new_value->content.i= in_val;
319      new_value->type= integer;
320    
321    stackitem* new_item= malloc(sizeof(stackitem));    push_val(env, new_value);
322    new_item->content.ptr= *hash(in_hash, in_string);  }
   new_item->type= ref;  
323    
324    if(new_item->content.ptr==NULL) { /* If hash entry empty */  /* Push a floating point number onto the stack */
325      if(handle==NULL)            /* If no handle */  void push_float(environment *env, float in_val)
326        handle= dlopen(NULL, RTLD_LAZY);      {
327      value *new_value= new_val(env);
328    
329      symbol= dlsym(handle, in_string); /* Get function pointer */    new_value->content.f= in_val;
330      if(dlerror()==NULL)         /* If existing function pointer */    new_value->type= tfloat;
       def_func(in_hash, symbol, in_string); /* Store function pointer */  
     else  
       def_sym(in_hash, in_string); /* Make symbol */  
         
     new_item->content.ptr= *hash(in_hash, in_string); /* The new reference  
                                                          shouldn't point at  
                                                          NULL */  
     new_item->type= ref;  
   }  
331    
332    push(stack_head, new_item);    push_val(env, new_value);
   return 1;  
333  }  }
334    
335  void printerr(const char* in_string) {  /* Copy a string onto the stack. */
336    fprintf(stderr, "Err: %s\n", in_string);  void push_cstring(environment *env, const char *in_string)
337    {
338      value *new_value= new_val(env);
339      int length= strlen(in_string)+1;
340    
341      new_value->content.ptr= malloc(length);
342      assert(new_value != NULL);
343      env->gc_count += length;
344      strcpy(new_value->content.ptr, in_string);
345      new_value->type= string;
346    
347      push_val(env, new_value);
348    }
349    
350    /* Mangle a symbol name to a valid C identifier name */
351    char *mangle_str(const char *old_string)
352    {
353      char validchars[]= "0123456789abcdef";
354      char *new_string, *current;
355    
356      new_string= malloc((strlen(old_string)*2)+4);
357      assert(new_string != NULL);
358      strcpy(new_string, "sx_");    /* Stack eXternal */
359      current= new_string+3;
360      while(old_string[0] != '\0'){
361        current[0]= validchars[(unsigned char)(old_string[0])/16];
362        current[1]= validchars[(unsigned char)(old_string[0])%16];
363        current+= 2;
364        old_string++;
365      }
366      current[0]= '\0';
367    
368      return new_string;            /* The caller must free() it */
369  }  }
370    
371  /* Discard the top element of the stack. */  extern void mangle(environment *env)
 extern void toss(stackitem** stack_head)  
372  {  {
373    stackitem* temp= *stack_head;    char *new_string;
374    
375    if((*stack_head)==NULL) {    if(env->head->type==empty) {
376      printerr("Stack empty");      printerr("Too Few Arguments");
377        env->err= 1;
378      return;      return;
379    }    }
     
   if((*stack_head)->type==string)  
     free((*stack_head)->content.ptr);  
380    
381    *stack_head= (*stack_head)->next;    if(CAR(env->head)->type!=string) {
382    free(temp);      printerr("Bad Argument Type");
383        env->err= 2;
384        return;
385      }
386    
387      new_string=
388        mangle_str((const char *)(CAR(env->head)->content.ptr));
389    
390      toss(env);
391      if(env->err) return;
392    
393      push_cstring(env, new_string);
394    }
395    
396    /* Push a symbol onto the stack. */
397    void push_sym(environment *env, const char *in_string)
398    {
399      value *new_value;             /* A new symbol value */
400      /* ...which might point to... */
401      symbol **new_symbol;          /* (if needed) A new actual symbol */
402      /* ...which, if possible, will be bound to... */
403      value *new_fvalue;            /* (if needed) A new function value */
404      /* ...which will point to... */
405      void *funcptr;                /* A function pointer */
406    
407      static void *handle= NULL;    /* Dynamic linker handle */
408      const char *dlerr;            /* Dynamic linker error */
409      char *mangled;                /* Mangled function name */
410    
411      new_value= new_val(env);
412      protect(new_value);
413      new_fvalue= new_val(env);
414      protect(new_fvalue);
415    
416      /* The new value is a symbol */
417      new_value->type= symb;
418    
419      /* Look up the symbol name in the hash table */
420      new_symbol= hash(env->symbols, in_string);
421      new_value->content.ptr= *new_symbol;
422    
423      if(*new_symbol==NULL) { /* If symbol was undefined */
424    
425        /* Create a new symbol */
426        (*new_symbol)= malloc(sizeof(symbol));
427        assert((*new_symbol) != NULL);
428        (*new_symbol)->val= NULL;   /* undefined value */
429        (*new_symbol)->next= NULL;
430        (*new_symbol)->id= malloc(strlen(in_string)+1);
431        assert((*new_symbol)->id != NULL);
432        strcpy((*new_symbol)->id, in_string);
433    
434        /* Intern the new symbol in the hash table */
435        new_value->content.ptr= *new_symbol;
436    
437        /* Try to load the symbol name as an external function, to see if
438           we should bind the symbol to a new function pointer value */
439        if(handle==NULL)            /* If no handle */
440          handle= dlopen(NULL, RTLD_LAZY);
441    
442        mangled= mangle_str(in_string); /* mangle the name */
443        funcptr= dlsym(handle, mangled); /* and try to find it */
444    
445        dlerr= dlerror();
446        if(dlerr != NULL) {         /* If no function was found */
447          funcptr= dlsym(handle, in_string); /* Get function pointer */
448          dlerr= dlerror();
449        }
450    
451        if(dlerr==NULL) {           /* If a function was found */
452          new_fvalue->type= func;   /* The new value is a function pointer */
453          new_fvalue->content.ptr= funcptr; /* Store function pointer */
454          (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
455                                             function value */
456        }
457    
458        free(mangled);
459      }
460    
461      push_val(env, new_value);
462      unprotect(new_value); unprotect(new_fvalue);
463  }  }
464    
465  /* Print newline. */  /* Print newline. */
466  extern void nl()  extern void nl(environment *env)
467  {  {
468    printf("\n");    printf("\n");
469  }  }
470    
471  /* Prints the top element of the stack. */  /* Print a newline to a port */
472  extern void print_(stackitem** stack_head)  extern void nlport(environment *env)
473  {  {
474    stackitem* temp= *stack_head;    if(env->head->type==empty) {
475        printerr("Too Few Arguments");
476        env->err= 1;
477        return;
478      }
479    
480      if(CAR(env->head)->type!=port) {
481        printerr("Bad Argument Type");
482        env->err= 2;
483        return;
484      }
485    
486    if(temp==NULL) {    if(fprintf(CAR(env->head)->content.p, "\n") < 0){
487      printerr("Stack empty");      perror("nl");
488        env->err= 5;
489      return;      return;
490    }    }
491      toss(env);
492    }
493    
494    while(temp->type==ref)  /* Gets the type of a value */
495      temp= temp->content.ptr;  extern void type(environment *env)
496    {
497      if(env->head->type==empty) {
498        printerr("Too Few Arguments");
499        env->err= 1;
500        return;
501      }
502    
503    switch(temp->type) {    switch(CAR(env->head)->type){
504    case value:    case empty:
505      printf("%d", temp->content.val);      push_sym(env, "empty");
506        break;
507      case integer:
508        push_sym(env, "integer");
509        break;
510      case tfloat:
511        push_sym(env, "float");
512      break;      break;
513    case string:    case string:
514      printf("\"%s\"", (char*)temp->content.ptr);      push_sym(env, "string");
515      break;      break;
516    case symbol:    case symb:
517      printf("%s", temp->id);      push_sym(env, "symbol");
518      break;      break;
519    default:    case func:
520      printf("%p", temp->content.ptr);      push_sym(env, "function");
521        break;
522      case tcons:
523        push_sym(env, "pair");
524        break;
525      case port:
526        push_sym(env, "port");
527        break;
528      }
529      swap(env);
530      if (env->err) return;
531      toss(env);
532    }
533    
534    /* Print a value */
535    void print_val(environment *env, value *val, int noquote, stackitem *stack, FILE *stream)
536    {
537      stackitem *titem, *tstack;
538      int depth;
539    
540      switch(val->type) {
541      case empty:
542        if(fprintf(stream, "[]") < 0){
543          perror("print_val");
544          env->err= 5;
545          return;
546        }
547        break;
548      case integer:
549        if(fprintf(stream, "%d", val->content.i) < 0){
550          perror("print_val");
551          env->err= 5;
552          return;
553        }
554        break;
555      case tfloat:
556        if(fprintf(stream, "%f", val->content.f) < 0){
557          perror("print_val");
558          env->err= 5;
559          return;
560        }
561        break;
562      case string:
563        if(noquote){
564          if(fprintf(stream, "%s", (char*)(val->content.ptr)) < 0){
565            perror("print_val");
566            env->err= 5;
567            return;
568          }
569        } else {                    /* quote */
570          if(fprintf(stream, "\"%s\"", (char*)(val->content.ptr)) < 0){
571            perror("print_val");
572            env->err= 5;
573            return;
574          }
575        }
576        break;
577      case symb:
578        if(fprintf(stream, "%s", val->content.sym->id) < 0){
579          perror("print_val");
580          env->err= 5;
581          return;
582        }
583        break;
584      case func:
585        if(fprintf(stream, "#<function %p>", (funcp)(val->content.ptr)) < 0){
586          perror("print_val");
587          env->err= 5;
588          return;
589        }
590        break;
591      case port:
592        if(fprintf(stream, "#<port %p>", (funcp)(val->content.p)) < 0){
593          perror("print_val");
594          env->err= 5;
595          return;
596        }
597        break;
598      case tcons:
599        if(fprintf(stream, "[ ") < 0){
600          perror("print_val");
601          env->err= 5;
602          return;
603        }
604        tstack= stack;
605        do {
606          titem=malloc(sizeof(stackitem));
607          assert(titem != NULL);
608          titem->item=val;
609          titem->next=tstack;
610          tstack=titem;             /* Put it on the stack */
611          /* Search a stack of values being printed to see if we are already
612             printing this value */
613          titem=tstack;
614          depth=0;
615          while(titem != NULL && titem->item != CAR(val)){
616            titem=titem->next;
617            depth++;
618          }
619          if(titem != NULL){        /* If we found it on the stack, */
620            if(fprintf(stream, "#%d#", depth) < 0){ /* print a depth reference */
621              perror("print_val");
622              env->err= 5;
623              free(titem);
624              return;
625            }
626          } else {
627            print_val(env, CAR(val), noquote, tstack, stream);
628          }
629          val= CDR(val);
630          switch(val->type){
631          case empty:
632            break;
633          case tcons:
634            /* Search a stack of values being printed to see if we are already
635               printing this value */
636            titem=tstack;
637            depth=0;
638            while(titem != NULL && titem->item != val){
639              titem=titem->next;
640              depth++;
641            }
642            if(titem != NULL){      /* If we found it on the stack, */
643              if(fprintf(stream, " . #%d#", depth) < 0){ /* print a depth reference */
644                perror("print_val");
645                env->err= 5;
646                goto printval_end;
647              }
648            } else {
649              if(fprintf(stream, " ") < 0){
650                perror("print_val");
651                env->err= 5;
652                goto printval_end;
653              }
654            }
655            break;
656          default:
657            if(fprintf(stream, " . ") < 0){ /* Improper list */
658              perror("print_val");
659              env->err= 5;
660              goto printval_end;
661            }
662            print_val(env, val, noquote, tstack, stream);
663          }
664        } while(val->type == tcons && titem == NULL);
665    
666      printval_end:
667    
668        titem=tstack;
669        while(titem != stack){
670          tstack=titem->next;
671          free(titem);
672          titem=tstack;
673        }
674    
675        if(! (env->err)){
676          if(fprintf(stream, " ]") < 0){
677            perror("print_val");
678            env->err= 5;
679          }
680        }
681      break;      break;
682    }    }
683  }  }
684    
685  /* Prints the top element of the stack and then discards it. */  /* Print the top element of the stack but don't discard it */
686  extern void print(stackitem** stack_head)  extern void print_(environment *env)
687  {  {
688    print_(stack_head);    if(env->head->type==empty) {
689    toss(stack_head);      printerr("Too Few Arguments");
690        env->err= 1;
691        return;
692      }
693      print_val(env, CAR(env->head), 0, NULL, stdout);
694      if(env->err) return;
695      nl(env);
696  }  }
697    
698  /* Only to be called by function printstack. */  /* Prints the top element of the stack */
699  void print_st(stackitem* stack_head, long counter)  extern void print(environment *env)
700  {  {
701    if(stack_head->next != NULL)    print_(env);
702      print_st(stack_head->next, counter+1);    if(env->err) return;
703      toss(env);
704    }
705    
706    /* Print the top element of the stack without quotes, but don't
707       discard it. */
708    extern void princ_(environment *env)
709    {
710      if(env->head->type==empty) {
711        printerr("Too Few Arguments");
712        env->err= 1;
713        return;
714      }
715      print_val(env, CAR(env->head), 1, NULL, stdout);
716    }
717    
718    /* Prints the top element of the stack without quotes. */
719    extern void princ(environment *env)
720    {
721      princ_(env);
722      if(env->err) return;
723      toss(env);
724    }
725    
726    /* Print a value to a port, but don't discard it */
727    extern void printport_(environment *env)
728    {
729      if(env->head->type==empty ||  CDR(env->head)->type == empty) {
730        printerr("Too Few Arguments");
731        env->err= 1;
732        return;
733      }
734    
735      if(CAR(env->head)->type!=port) {
736        printerr("Bad Argument Type");
737        env->err= 2;
738        return;
739      }
740    
741      print_val(env, CAR(CDR(env->head)), 0, NULL, CAR(env->head)->content.p);
742      if(env->err) return;
743      nlport(env);
744    }
745    
746    /* Print a value to a port */
747    extern void printport(environment *env)
748    {
749      printport_(env);
750      if(env->err) return;
751      toss(env);
752    }
753    
754    /* Print, without quotes, to a port, a value, but don't discard it. */
755    extern void princport_(environment *env)
756    {
757      if(env->head->type==empty ||  CDR(env->head)->type == empty) {
758        printerr("Too Few Arguments");
759        env->err= 1;
760        return;
761      }
762    
763      if(CAR(env->head)->type!=port) {
764        printerr("Bad Argument Type");
765        env->err= 2;
766        return;
767      }
768    
769      print_val(env, CAR(CDR(env->head)), 1, NULL, CAR(env->head)->content.p);
770      toss(env); if(env->err) return;
771    }
772    
773    /* Print, without quotes, to a port, the top element. */
774    extern void princport(environment *env)
775    {
776      princport_(env);
777      if(env->err) return;
778      toss(env);
779    }
780    
781    /* Only to be called by itself function printstack. */
782    void print_st(environment *env, value *stack_head, long counter)
783    {
784      if(CDR(stack_head)->type != empty)
785        print_st(env, CDR(stack_head), counter+1);
786    printf("%ld: ", counter);    printf("%ld: ", counter);
787    print_(&stack_head);    print_val(env, CAR(stack_head), 0, NULL, stdout);
788    nl();    nl(env);
789  }  }
790    
791  /* Prints the stack. */  /* Prints the stack. */
792  extern void printstack(stackitem** stack_head)  extern void printstack(environment *env)
793  {  {
794    if(*stack_head != NULL) {    if(env->head->type == empty) {
795      print_st(*stack_head, 1);      printf("Stack Empty\n");
796      nl();      return;
   } else {  
     printerr("Stack empty");  
797    }    }
798    
799      print_st(env, env->head, 1);
800  }  }
801    
802  /* If the top element is a reference, determine if it's a reference to a  /* Swap the two top elements on the stack. */
803     function, and if it is, toss the reference and execute the function. */  extern void swap(environment *env)
 extern void eval(stackitem** stack_head)  
804  {  {
805    funcp in_func;    value *temp= env->head;
806    stackitem* temp= *stack_head;    
807      if(env->head->type == empty || CDR(env->head)->type == empty) {
808        printerr("Too Few Arguments");
809        env->err=1;
810        return;
811      }
812    
813      env->head= CDR(env->head);
814      CDR(temp)= CDR(env->head);
815      CDR(env->head)= temp;
816    }
817    
818    if(temp==NULL) {  /* Rotate the first three elements on the stack. */
819      printerr("Stack empty");  extern void rot(environment *env)
820    {
821      value *temp= env->head;
822      
823      if(env->head->type == empty || CDR(env->head)->type == empty
824         || CDR(CDR(env->head))->type == empty) {
825        printerr("Too Few Arguments");
826        env->err= 1;
827      return;      return;
828    }    }
829      
830      env->head= CDR(CDR(env->head));
831      CDR(CDR(temp))= CDR(env->head);
832      CDR(env->head)= temp;
833    }
834    
835    while(temp->type==ref)  /* Recall a value from a symbol, if bound */
836      temp= temp->content.ptr;  extern void rcl(environment *env)
837    {
838      value *val;
839    
840    if(temp->type==func) {    if(env->head->type==empty) {
841      in_func= (funcp)(temp->content.ptr);      printerr("Too Few Arguments");
842      toss(stack_head);      env->err= 1;
     (*in_func)(stack_head);  
843      return;      return;
844    }    }
845    
846      if(CAR(env->head)->type!=symb) {
847        printerr("Bad Argument Type");
848        env->err= 2;
849        return;
850      }
851    
852      val= CAR(env->head)->content.sym->val;
853      if(val == NULL){
854        printerr("Unbound Variable");
855        env->err= 3;
856        return;
857      }
858      push_val(env, val);           /* Return the symbol's bound value */
859      swap(env);
860      if(env->err) return;
861      toss(env);                    /* toss the symbol */
862      if(env->err) return;
863    }
864    
865    /* If the top element is a symbol, determine if it's bound to a
866       function value, and if it is, toss the symbol and execute the
867       function. */
868    extern void eval(environment *env)
869    {
870      funcp in_func;
871      value* temp_val;
872      value* iterator;
873    
874     eval_start:
875    
876      gc_maybe(env);
877    
878      if(env->head->type==empty) {
879        printerr("Too Few Arguments");
880        env->err= 1;
881        return;
882      }
883    
884      switch(CAR(env->head)->type) {
885        /* if it's a symbol */
886      case symb:
887        rcl(env);                   /* get its contents */
888        if(env->err) return;
889        if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
890          goto eval_start;
891        }
892        return;
893    
894        /* If it's a lone function value, run it */
895      case func:
896        in_func= (funcp)(CAR(env->head)->content.ptr);
897        toss(env);
898        if(env->err) return;
899        return in_func(env);
900    
901        /* If it's a list */
902      case tcons:
903        temp_val= CAR(env->head);
904        protect(temp_val);
905    
906        toss(env); if(env->err) return;
907        iterator= temp_val;
908            
909    printerr("Couldn't evaluate");      while(iterator->type != empty) {
910          push_val(env, CAR(iterator));
911          
912          if(CAR(env->head)->type==symb
913             && CAR(env->head)->content.sym->id[0]==';') {
914            toss(env);
915            if(env->err) return;
916            
917            if(CDR(iterator)->type == empty){
918              goto eval_start;
919            }
920            eval(env);
921            if(env->err) return;
922          }
923          if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
924            iterator= CDR(iterator);
925          else {
926            printerr("Bad Argument Type"); /* Improper list */
927            env->err= 2;
928            return;
929          }
930        }
931        unprotect(temp_val);
932        return;
933    
934      case empty:
935        toss(env);
936      case integer:
937      case tfloat:
938      case string:
939      case port:
940        return;
941      }
942  }  }
943    
944  /* Make a list. */  /* Reverse (flip) a list */
945  extern void pack(stackitem** stack_head)  extern void rev(environment *env)
946  {  {
947    void* delimiter;    value *old_head, *new_head, *item;
   stackitem *iterator, *temp, *pack;  
948    
949    if((*stack_head)==NULL) {    if(env->head->type==empty) {
950      printerr("Stack empty");      printerr("Too Few Arguments");
951        env->err= 1;
952      return;      return;
953    }    }
954    
955    delimiter= (*stack_head)->content.ptr; /* Get delimiter */    if(CAR(env->head)->type==empty)
956    toss(stack_head);      return;                     /* Don't reverse an empty list */
957    
958    iterator= *stack_head;    if(CAR(env->head)->type!=tcons) {
959        printerr("Bad Argument Type");
960        env->err= 2;
961        return;
962      }
963    
964    /* Search for first delimiter */    old_head= CAR(env->head);
965    while(iterator->next!=NULL && iterator->next->content.ptr!=delimiter)    new_head= new_val(env);
966      iterator= iterator->next;    while(old_head->type != empty) {
967        item= old_head;
968        old_head= CDR(old_head);
969        CDR(item)= new_head;
970        new_head= item;
971      }
972      CAR(env->head)= new_head;
973    }
974    
975    /* Extract list */  /* Make a list. */
976    temp= *stack_head;  extern void pack(environment *env)
977    *stack_head= iterator->next;  {
978    iterator->next= NULL;    value *iterator, *temp, *ending;
979      
980    if(*stack_head!=NULL && (*stack_head)->content.ptr==delimiter)    ending=new_val(env);
981      toss(stack_head);  
982      iterator= env->head;
983      if(iterator->type == empty
984         || (CAR(iterator)->type==symb
985         && CAR(iterator)->content.sym->id[0]=='[')) {
986        temp= ending;
987        toss(env);
988      } else {
989        /* Search for first delimiter */
990        while(CDR(iterator)->type != empty
991              && (CAR(CDR(iterator))->type!=symb
992               || CAR(CDR(iterator))->content.sym->id[0]!='['))
993          iterator= CDR(iterator);
994        
995        /* Extract list */
996        temp= env->head;
997        env->head= CDR(iterator);
998        CDR(iterator)= ending;
999    
1000        if(env->head->type != empty)
1001          toss(env);
1002      }
1003    
1004    /* Push list */    /* Push list */
   pack= malloc(sizeof(stackitem));  
   pack->type= list;  
   pack->content.ptr= temp;  
1005    
1006    push(stack_head, pack);    push_val(env, temp);
1007      rev(env);
1008  }  }
1009    
1010  /* Parse input. */  /* Relocate elements of the list on the stack. */
1011  int stack_read(stackitem** stack_head, hashtbl in_hash, char* in_line)  extern void expand(environment *env)
1012  {  {
1013    char *temp, *rest;    value *temp, *new_head;
1014    int itemp;  
1015    size_t inlength= strlen(in_line)+1;    /* Is top element a list? */
1016    int convert= 0;    if(env->head->type==empty) {
1017    static int non_eval_flag= 0;      printerr("Too Few Arguments");
1018        env->err= 1;
1019        return;
1020      }
1021    
1022    temp= malloc(inlength);    if(CAR(env->head)->type!=tcons) {
1023    rest= malloc(inlength);      printerr("Bad Argument Type");
1024        env->err= 2;
1025        return;
1026      }
1027    
1028    do {    rev(env);
1029      /* If string */  
1030      if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {    if(env->err)
1031        push_cstring(stack_head, temp);      return;
1032        break;  
1033      /* The first list element is the new stack head */
1034      new_head= temp= CAR(env->head);
1035    
1036      toss(env);
1037    
1038      /* Find the end of the list */
1039      while(CDR(temp)->type != empty) {
1040        if (CDR(temp)->type == tcons)
1041          temp= CDR(temp);
1042        else {
1043          printerr("Bad Argument Type"); /* Improper list */
1044          env->err= 2;
1045          return;
1046      }      }
1047      /* If value */    }
1048      if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {  
1049        push_val(stack_head, itemp);    /* Connect the tail of the list with the old stack head */
1050        break;    CDR(temp)= env->head;
1051      env->head= new_head;          /* ...and voila! */
1052    
1053    }
1054    
1055    /* Compares two elements by reference. */
1056    extern void eq(environment *env)
1057    {
1058      void *left, *right;
1059    
1060      if(env->head->type==empty || CDR(env->head)->type==empty) {
1061        printerr("Too Few Arguments");
1062        env->err= 1;
1063        return;
1064      }
1065    
1066      left= CAR(env->head)->content.ptr;
1067      right= CAR(CDR(env->head))->content.ptr;
1068      toss(env); toss(env);
1069    
1070      push_int(env, left==right);
1071    }
1072    
1073    /* Negates the top element on the stack. */
1074    extern void not(environment *env)
1075    {
1076      int val;
1077    
1078      if(env->head->type==empty) {
1079        printerr("Too Few Arguments");
1080        env->err= 1;
1081        return;
1082      }
1083    
1084      if(CAR(env->head)->type!=integer) {
1085        printerr("Bad Argument Type");
1086        env->err= 2;
1087        return;
1088      }
1089    
1090      val= CAR(env->head)->content.i;
1091      toss(env);
1092      push_int(env, !val);
1093    }
1094    
1095    /* Compares the two top elements on the stack and return 0 if they're the
1096       same. */
1097    extern void neq(environment *env)
1098    {
1099      eq(env);
1100      not(env);
1101    }
1102    
1103    /* Give a symbol some content. */
1104    extern void def(environment *env)
1105    {
1106      symbol *sym;
1107    
1108      /* Needs two values on the stack, the top one must be a symbol */
1109      if(env->head->type==empty || CDR(env->head)->type==empty) {
1110        printerr("Too Few Arguments");
1111        env->err= 1;
1112        return;
1113      }
1114    
1115      if(CAR(env->head)->type!=symb) {
1116        printerr("Bad Argument Type");
1117        env->err= 2;
1118        return;
1119      }
1120    
1121      /* long names are a pain */
1122      sym= CAR(env->head)->content.ptr;
1123    
1124      /* Bind the symbol to the value */
1125      sym->val= CAR(CDR(env->head));
1126    
1127      toss(env); toss(env);
1128    }
1129    
1130    /* Quit stack. */
1131    extern void quit(environment *env)
1132    {
1133      int i;
1134    
1135      clear(env);
1136    
1137      if (env->err) return;
1138      for(i= 0; i<HASHTBLSIZE; i++) {
1139        while(env->symbols[i]!= NULL) {
1140          forget_sym(&(env->symbols[i]));
1141      }      }
1142      /* Escape ';' with '\' */      env->symbols[i]= NULL;
1143      if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {    }
1144        temp[1]= '\0';  
1145        push_ref(stack_head, in_hash, temp);    env->gc_limit= 0;
1146        break;    gc_maybe(env);
1147      }  
1148      /* If symbol */    words(env);
1149      if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {  
1150          push_ref(stack_head, in_hash, temp);    if(env->free_string!=NULL)
1151          break;      free(env->free_string);
1152      
1153    #ifdef __linux__
1154      muntrace();
1155    #endif
1156    
1157      exit(EXIT_SUCCESS);
1158    }
1159    
1160    /* Clear stack */
1161    extern void clear(environment *env)
1162    {
1163      while(env->head->type != empty)
1164        toss(env);
1165    }
1166    
1167    /* List all defined words */
1168    extern void words(environment *env)
1169    {
1170      symbol *temp;
1171      int i;
1172      
1173      for(i= 0; i<HASHTBLSIZE; i++) {
1174        temp= env->symbols[i];
1175        while(temp!=NULL) {
1176    #ifdef DEBUG
1177          if (temp->val != NULL && temp->val->gc.flag.protect)
1178            printf("(protected) ");
1179    #endif /* DEBUG */
1180          printf("%s\n", temp->id);
1181          temp= temp->next;
1182      }      }
1183      /* If single char */    }
1184      if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {  }
1185        if(*temp==';') {  
1186          if(!non_eval_flag) {  /* Internal forget function */
1187            eval(stack_head);             /* Evaluate top element */  void forget_sym(symbol **hash_entry)
1188            break;  {
1189          }    symbol *temp;
1190            
1191          push_ref(stack_head, in_hash, ";");    temp= *hash_entry;
1192          break;    *hash_entry= (*hash_entry)->next;
1193        }    
1194      free(temp->id);
1195      free(temp);
1196    }
1197    
1198    /* Forgets a symbol (remove it from the hash table) */
1199    extern void forget(environment *env)
1200    {
1201      char* sym_id;
1202    
1203      if(env->head->type==empty) {
1204        printerr("Too Few Arguments");
1205        env->err= 1;
1206        return;
1207      }
1208      
1209      if(CAR(env->head)->type!=symb) {
1210        printerr("Bad Argument Type");
1211        env->err= 2;
1212        return;
1213      }
1214    
1215      sym_id= CAR(env->head)->content.sym->id;
1216      toss(env);
1217    
1218        if(*temp==']') {    return forget_sym(hash(env->symbols, sym_id));
1219          push_ref(stack_head, in_hash, "[");  }
1220          pack(stack_head);  
1221          if(non_eval_flag!=0)  /* Returns the current error number to the stack */
1222            non_eval_flag--;  extern void errn(environment *env)
1223    {
1224      push_int(env, env->err);
1225    }
1226    
1227    int main(int argc, char **argv)
1228    {
1229      environment myenv;
1230    
1231      int c;                        /* getopt option character */
1232    
1233    #ifdef __linux__
1234      mtrace();
1235    #endif
1236    
1237      init_env(&myenv);
1238    
1239      myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
1240    
1241      while ((c = getopt (argc, argv, "i")) != -1)
1242        switch (c)
1243          {
1244          case 'i':
1245            myenv.interactive = 1;
1246          break;          break;
1247          case '?':
1248            fprintf (stderr,
1249                     "Unknown option character '\\x%x'.\n",
1250                     optopt);
1251            return EX_USAGE;
1252          default:
1253            abort ();
1254        }        }
1255      
1256      if (optind < argc) {
1257        myenv.interactive = 0;
1258        myenv.inputstream= fopen(argv[optind], "r");
1259        if(myenv.inputstream== NULL) {
1260          perror(argv[0]);
1261          exit (EX_NOINPUT);
1262        }
1263      }
1264    
1265        if(*temp=='[') {    if(myenv.interactive) {
1266          push_ref(stack_head, in_hash, "[");      printf("Stack version $Revision$\n\
1267          non_eval_flag++;  Copyright (C) 2002  Mats Alritzson and Teddy Hogeborn\n\
1268          break;  Stack comes with ABSOLUTELY NO WARRANTY; for details type 'warranty;'.\n\
1269    This is free software, and you are welcome to redistribute it\n\
1270    under certain conditions; type 'copying;' for details.\n");
1271      }
1272    
1273      while(1) {
1274        if(myenv.in_string==NULL) {
1275          if (myenv.interactive) {
1276            if(myenv.err) {
1277              printf("(error %d)\n", myenv.err);
1278              myenv.err= 0;
1279            }
1280            nl(&myenv);
1281            printstack(&myenv);
1282            printf("> ");
1283        }        }
1284          myenv.err=0;
1285        }
1286        sx_72656164(&myenv);        /* "read" */
1287        if (myenv.err) {            /* EOF or other error */
1288          myenv.err=0;
1289          quit(&myenv);
1290        } else if(myenv.head->type!=empty
1291                  && CAR(myenv.head)->type==symb
1292                  && CAR(myenv.head)->content.sym->id[0] == ';') {
1293          toss(&myenv); if(myenv.err) continue;
1294          eval(&myenv);
1295        } else {
1296          gc_maybe(&myenv);
1297      }      }
1298    } while(0);    }
1299      quit(&myenv);
1300      return EXIT_FAILURE;
1301    }
1302    
1303    /* "+" */
1304    extern void sx_2b(environment *env)
1305    {
1306      int a, b;
1307      float fa, fb;
1308      size_t len;
1309      char* new_string;
1310      value *a_val, *b_val;
1311    
1312      if(env->head->type==empty || CDR(env->head)->type==empty) {
1313        printerr("Too Few Arguments");
1314        env->err= 1;
1315        return;
1316      }
1317    
1318    free(temp);    if(CAR(env->head)->type==string
1319         && CAR(CDR(env->head))->type==string) {
1320        a_val= CAR(env->head);
1321        b_val= CAR(CDR(env->head));
1322        protect(a_val); protect(b_val);
1323        toss(env); if(env->err) return;
1324        toss(env); if(env->err) return;
1325        len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
1326        new_string= malloc(len);
1327        assert(new_string != NULL);
1328        strcpy(new_string, b_val->content.ptr);
1329        strcat(new_string, a_val->content.ptr);
1330        push_cstring(env, new_string);
1331        unprotect(a_val); unprotect(b_val);
1332        free(new_string);
1333        
1334        return;
1335      }
1336      
1337      if(CAR(env->head)->type==integer
1338         && CAR(CDR(env->head))->type==integer) {
1339        a= CAR(env->head)->content.i;
1340        toss(env); if(env->err) return;
1341        b= CAR(env->head)->content.i;
1342        toss(env); if(env->err) return;
1343        push_int(env, b+a);
1344    
1345        return;
1346      }
1347    
1348      if(CAR(env->head)->type==tfloat
1349         && CAR(CDR(env->head))->type==tfloat) {
1350        fa= CAR(env->head)->content.f;
1351        toss(env); if(env->err) return;
1352        fb= CAR(env->head)->content.f;
1353        toss(env); if(env->err) return;
1354        push_float(env, fb+fa);
1355        
1356        return;
1357      }
1358    
1359      if(CAR(env->head)->type==tfloat
1360         && CAR(CDR(env->head))->type==integer) {
1361        fa= CAR(env->head)->content.f;
1362        toss(env); if(env->err) return;
1363        b= CAR(env->head)->content.i;
1364        toss(env); if(env->err) return;
1365        push_float(env, b+fa);
1366        
1367        return;
1368      }
1369    
1370      if(CAR(env->head)->type==integer
1371         && CAR(CDR(env->head))->type==tfloat) {
1372        a= CAR(env->head)->content.i;
1373        toss(env); if(env->err) return;
1374        fb= CAR(env->head)->content.f;
1375        toss(env); if(env->err) return;
1376        push_float(env, fb+a);
1377    
1378        return;
1379      }
1380    
1381      printerr("Bad Argument Type");
1382      env->err=2;
1383    }
1384    
1385    if(convert<2) {  /* "-" */
1386      free(rest);  extern void sx_2d(environment *env)
1387      return 0;  {
1388      int a, b;
1389      float fa, fb;
1390    
1391      if(env->head->type==empty || CDR(env->head)->type==empty) {
1392        printerr("Too Few Arguments");
1393        env->err=1;
1394        return;
1395    }    }
     
   stack_read(stack_head, in_hash, rest);  
1396        
1397    free(rest);    if(CAR(env->head)->type==integer
1398    return 1;       && CAR(CDR(env->head))->type==integer) {
1399        a= CAR(env->head)->content.i;
1400        toss(env); if(env->err) return;
1401        b= CAR(env->head)->content.i;
1402        toss(env); if(env->err) return;
1403        push_int(env, b-a);
1404    
1405        return;
1406      }
1407    
1408      if(CAR(env->head)->type==tfloat
1409         && CAR(CDR(env->head))->type==tfloat) {
1410        fa= CAR(env->head)->content.f;
1411        toss(env); if(env->err) return;
1412        fb= CAR(env->head)->content.f;
1413        toss(env); if(env->err) return;
1414        push_float(env, fb-fa);
1415        
1416        return;
1417      }
1418    
1419      if(CAR(env->head)->type==tfloat
1420         && CAR(CDR(env->head))->type==integer) {
1421        fa= CAR(env->head)->content.f;
1422        toss(env); if(env->err) return;
1423        b= CAR(env->head)->content.i;
1424        toss(env); if(env->err) return;
1425        push_float(env, b-fa);
1426        
1427        return;
1428      }
1429    
1430      if(CAR(env->head)->type==integer
1431         && CAR(CDR(env->head))->type==tfloat) {
1432        a= CAR(env->head)->content.i;
1433        toss(env); if(env->err) return;
1434        fb= CAR(env->head)->content.f;
1435        toss(env); if(env->err) return;
1436        push_float(env, fb-a);
1437    
1438        return;
1439      }
1440    
1441      printerr("Bad Argument Type");
1442      env->err=2;
1443  }  }
1444    
1445  /* Relocate elements of the list on the stack. */  /* ">" */
1446  extern void expand(stackitem** stack_head)  extern void sx_3e(environment *env)
1447  {  {
1448    stackitem *temp, *new_head;    int a, b;
1449      float fa, fb;
1450    
1451    /* Is top element a list? */    if(env->head->type==empty || CDR(env->head)->type==empty) {
1452    if((*stack_head)==NULL || (*stack_head)->type!=list) {      printerr("Too Few Arguments");
1453      printerr("Stack empty or not a list");      env->err= 1;
1454      return;      return;
1455    }    }
1456      
1457      if(CAR(env->head)->type==integer
1458         && CAR(CDR(env->head))->type==integer) {
1459        a= CAR(env->head)->content.i;
1460        toss(env); if(env->err) return;
1461        b= CAR(env->head)->content.i;
1462        toss(env); if(env->err) return;
1463        push_int(env, b>a);
1464    
1465    /* The first list element is the new stack head */      return;
1466    new_head= temp= (*stack_head)->content.ptr;    }
   toss(stack_head);  
1467    
1468    /* Search the end of the list */    if(CAR(env->head)->type==tfloat
1469    while(temp->next!=NULL)       && CAR(CDR(env->head))->type==tfloat) {
1470      temp= temp->next;      fa= CAR(env->head)->content.f;
1471        toss(env); if(env->err) return;
1472    /* Connect the the tail of the list with the old stack head */      fb= CAR(env->head)->content.f;
1473    temp->next= *stack_head;      toss(env); if(env->err) return;
1474    *stack_head= new_head;        /* ...and voila! */      push_int(env, fb>fa);
1475        
1476        return;
1477      }
1478    
1479      if(CAR(env->head)->type==tfloat
1480         && CAR(CDR(env->head))->type==integer) {
1481        fa= CAR(env->head)->content.f;
1482        toss(env); if(env->err) return;
1483        b= CAR(env->head)->content.i;
1484        toss(env); if(env->err) return;
1485        push_int(env, b>fa);
1486        
1487        return;
1488      }
1489    
1490      if(CAR(env->head)->type==integer
1491         && CAR(CDR(env->head))->type==tfloat) {
1492        a= CAR(env->head)->content.i;
1493        toss(env); if(env->err) return;
1494        fb= CAR(env->head)->content.f;
1495        toss(env); if(env->err) return;
1496        push_int(env, fb>a);
1497    
1498        return;
1499      }
1500    
1501      printerr("Bad Argument Type");
1502      env->err= 2;
1503  }  }
1504    
1505  /* Swap the two top elements on the stack. */  /* "<" */
1506  extern void swap(stackitem** stack_head)  extern void sx_3c(environment *env)
1507    {
1508      swap(env); if(env->err) return;
1509      sx_3e(env);
1510    }
1511    
1512    /* "<=" */
1513    extern void sx_3c3d(environment *env)
1514    {
1515      sx_3e(env); if(env->err) return;
1516      not(env);
1517    }
1518    
1519    /* ">=" */
1520    extern void sx_3e3d(environment *env)
1521    {
1522      sx_3c(env); if(env->err) return;
1523      not(env);
1524    }
1525    
1526    /* Return copy of a value */
1527    value *copy_val(environment *env, value *old_value)
1528    {
1529      value *new_value;
1530    
1531      if(old_value==NULL)
1532        return NULL;
1533    
1534      new_value= new_val(env);
1535      new_value->type= old_value->type;
1536    
1537      switch(old_value->type){
1538      case tfloat:
1539      case integer:
1540      case func:
1541      case symb:
1542      case empty:
1543      case port:
1544        new_value->content= old_value->content;
1545        break;
1546      case string:
1547        (char *)(new_value->content.ptr)=
1548          strdup((char *)(old_value->content.ptr));
1549        break;
1550      case tcons:
1551    
1552        new_value->content.c= malloc(sizeof(pair));
1553        assert(new_value->content.c!=NULL);
1554        env->gc_count += sizeof(pair);
1555    
1556        CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
1557        CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
1558        break;
1559      }
1560    
1561      return new_value;
1562    }
1563    
1564    /* "dup"; duplicates an item on the stack */
1565    extern void sx_647570(environment *env)
1566  {  {
1567    stackitem* temp= (*stack_head);    if(env->head->type==empty) {
1568        printerr("Too Few Arguments");
1569        env->err= 1;
1570        return;
1571      }
1572      push_val(env, copy_val(env, CAR(env->head)));
1573    }
1574    
1575    /* "if", If-Then */
1576    extern void sx_6966(environment *env)
1577    {
1578      int truth;
1579    
1580      if(env->head->type==empty || CDR(env->head)->type==empty) {
1581        printerr("Too Few Arguments");
1582        env->err= 1;
1583        return;
1584      }
1585    
1586      if(CAR(CDR(env->head))->type != integer) {
1587        printerr("Bad Argument Type");
1588        env->err= 2;
1589        return;
1590      }
1591      
1592      swap(env);
1593      if(env->err) return;
1594        
1595    if((*stack_head)==NULL) {    truth= CAR(env->head)->content.i;
1596      printerr("Stack empty");  
1597      toss(env);
1598      if(env->err) return;
1599    
1600      if(truth)
1601        eval(env);
1602      else
1603        toss(env);
1604    }
1605    
1606    /* If-Then-Else */
1607    extern void ifelse(environment *env)
1608    {
1609      int truth;
1610    
1611      if(env->head->type==empty || CDR(env->head)->type==empty
1612         || CDR(CDR(env->head))->type==empty) {
1613        printerr("Too Few Arguments");
1614        env->err= 1;
1615      return;      return;
1616    }    }
1617    
1618    if((*stack_head)->next==NULL)    if(CAR(CDR(CDR(env->head)))->type!=integer) {
1619        printerr("Bad Argument Type");
1620        env->err= 2;
1621      return;      return;
1622      }
1623      
1624      rot(env);
1625      if(env->err) return;
1626      
1627      truth= CAR(env->head)->content.i;
1628    
1629    *stack_head= (*stack_head)->next;    toss(env);
1630    temp->next= (*stack_head)->next;    if(env->err) return;
   (*stack_head)->next= temp;  
 }  
1631    
1632  /* Compares two elements by reference. */    if(!truth)
1633  extern void eq(stackitem** stack_head)      swap(env);
1634      if(env->err) return;
1635    
1636      toss(env);
1637      if(env->err) return;
1638    
1639      eval(env);
1640    }
1641    
1642    /* "else" */
1643    extern void sx_656c7365(environment *env)
1644  {  {
1645    void *left, *right;    if(env->head->type==empty || CDR(env->head)->type==empty
1646    int result;       || CDR(CDR(env->head))->type==empty || CDR(CDR(CDR(env->head)))->type==empty
1647         || CDR(CDR(CDR(CDR(env->head))))->type==empty) {
1648        printerr("Too Few Arguments");
1649        env->err= 1;
1650        return;
1651      }
1652    
1653      if(CAR(CDR(env->head))->type!=symb
1654         || strcmp(CAR(CDR(env->head))->content.sym->id, "then")!=0
1655         || CAR(CDR(CDR(CDR(env->head))))->type!=symb
1656         || strcmp(CAR(CDR(CDR(CDR(env->head))))->content.sym->id, "if")!=0) {
1657        printerr("Bad Argument Type");
1658        env->err= 2;
1659        return;
1660      }
1661    
1662      swap(env); toss(env); rot(env); toss(env);
1663      ifelse(env);
1664    }
1665    
1666    extern void then(environment *env)
1667    {
1668      if(env->head->type==empty || CDR(env->head)->type==empty
1669         || CDR(CDR(env->head))->type==empty) {
1670        printerr("Too Few Arguments");
1671        env->err= 1;
1672        return;
1673      }
1674    
1675    if((*stack_head)==NULL || (*stack_head)->next==NULL) {    if(CAR(CDR(env->head))->type!=symb
1676      printerr("Not enough elements to compare");       || strcmp(CAR(CDR(env->head))->content.sym->id, "if")!=0) {
1677        printerr("Bad Argument Type");
1678        env->err= 2;
1679      return;      return;
1680    }    }
1681    
1682    left= (*stack_head)->content.ptr;    swap(env); toss(env);
1683    swap(stack_head);    sx_6966(env);
1684    right= (*stack_head)->content.ptr;  }
1685    result= (left==right);  
1686    /* "while" */
1687    extern void sx_7768696c65(environment *env)
1688    {
1689      int truth;
1690      value *loop, *test;
1691    
1692      if(env->head->type==empty || CDR(env->head)->type==empty) {
1693        printerr("Too Few Arguments");
1694        env->err= 1;
1695        return;
1696      }
1697    
1698      loop= CAR(env->head);
1699      protect(loop);
1700      toss(env); if(env->err) return;
1701    
1702      test= CAR(env->head);
1703      protect(test);
1704      toss(env); if(env->err) return;
1705    
1706      do {
1707        push_val(env, test);
1708        eval(env);
1709        
1710        if(CAR(env->head)->type != integer) {
1711          printerr("Bad Argument Type");
1712          env->err= 2;
1713          return;
1714        }
1715        
1716        truth= CAR(env->head)->content.i;
1717        toss(env); if(env->err) return;
1718        
1719        if(truth) {
1720          push_val(env, loop);
1721          eval(env);
1722        } else {
1723          toss(env);
1724        }
1725        
1726    toss(stack_head); toss(stack_head);    } while(truth);
1727    push_val(stack_head, (left==right));  
1728      unprotect(loop); unprotect(test);
1729  }  }
1730    
1731  /* Negates the top element on the stack. */  
1732  extern void not(stackitem** stack_head)  /* "for"; for-loop */
1733    extern void sx_666f72(environment *env)
1734  {  {
1735    int value;    value *loop;
1736      int foo1, foo2;
1737    
1738      if(env->head->type==empty || CDR(env->head)->type==empty
1739         || CDR(CDR(env->head))->type==empty) {
1740        printerr("Too Few Arguments");
1741        env->err= 1;
1742        return;
1743      }
1744    
1745    if((*stack_head)==NULL || (*stack_head)->type!=value) {    if(CAR(CDR(env->head))->type!=integer
1746      printerr("Stack empty or element is not a value");       || CAR(CDR(CDR(env->head)))->type!=integer) {
1747        printerr("Bad Argument Type");
1748        env->err= 2;
1749      return;      return;
1750    }    }
1751    
1752    value= (*stack_head)->content.val;    loop= CAR(env->head);
1753    toss(stack_head);    protect(loop);
1754    push_val(stack_head, !value);    toss(env); if(env->err) return;
1755    
1756      foo2= CAR(env->head)->content.i;
1757      toss(env); if(env->err) return;
1758    
1759      foo1= CAR(env->head)->content.i;
1760      toss(env); if(env->err) return;
1761    
1762      if(foo1<=foo2) {
1763        while(foo1<=foo2) {
1764          push_int(env, foo1);
1765          push_val(env, loop);
1766          eval(env); if(env->err) return;
1767          foo1++;
1768        }
1769      } else {
1770        while(foo1>=foo2) {
1771          push_int(env, foo1);
1772          push_val(env, loop);
1773          eval(env); if(env->err) return;
1774          foo1--;
1775        }
1776      }
1777      unprotect(loop);
1778  }  }
1779    
1780  /* Compares the two top elements on the stack and return 0 if they're the  /* Variant of for-loop */
1781     same. */  extern void foreach(environment *env)
1782  extern void neq(stackitem** stack_head)  {  
1783      value *loop, *foo;
1784      value *iterator;
1785      
1786      if(env->head->type==empty || CDR(env->head)->type==empty) {
1787        printerr("Too Few Arguments");
1788        env->err= 1;
1789        return;
1790      }
1791    
1792      if(CAR(CDR(env->head))->type!=tcons) {
1793        printerr("Bad Argument Type");
1794        env->err= 2;
1795        return;
1796      }
1797    
1798      loop= CAR(env->head);
1799      protect(loop);
1800      toss(env); if(env->err) return;
1801    
1802      foo= CAR(env->head);
1803      protect(foo);
1804      toss(env); if(env->err) return;
1805    
1806      iterator= foo;
1807    
1808      while(iterator->type!=empty) {
1809        push_val(env, CAR(iterator));
1810        push_val(env, loop);
1811        eval(env); if(env->err) return;
1812        if (iterator->type == tcons){
1813          iterator= CDR(iterator);
1814        } else {
1815          printerr("Bad Argument Type"); /* Improper list */
1816          env->err= 2;
1817          break;
1818        }
1819      }
1820      unprotect(loop); unprotect(foo);
1821    }
1822    
1823    /* "to" */
1824    extern void to(environment *env)
1825  {  {
1826    eq(stack_head);    int ending, start, i;
1827    not(stack_head);    value *iterator, *temp, *end;
1828    
1829      end= new_val(env);
1830    
1831      if(env->head->type==empty || CDR(env->head)->type==empty) {
1832        printerr("Too Few Arguments");
1833        env->err= 1;
1834        return;
1835      }
1836    
1837      if(CAR(env->head)->type!=integer
1838         || CAR(CDR(env->head))->type!=integer) {
1839        printerr("Bad Argument Type");
1840        env->err= 2;
1841        return;
1842      }
1843    
1844      ending= CAR(env->head)->content.i;
1845      toss(env); if(env->err) return;
1846      start= CAR(env->head)->content.i;
1847      toss(env); if(env->err) return;
1848    
1849      push_sym(env, "[");
1850    
1851      if(ending>=start) {
1852        for(i= ending; i>=start; i--)
1853          push_int(env, i);
1854      } else {
1855        for(i= ending; i<=start; i++)
1856          push_int(env, i);
1857      }
1858    
1859      iterator= env->head;
1860    
1861      if(iterator->type==empty
1862         || (CAR(iterator)->type==symb
1863             && CAR(iterator)->content.sym->id[0]=='[')) {
1864        temp= end;
1865        toss(env);
1866      } else {
1867        /* Search for first delimiter */
1868        while(CDR(iterator)->type!=empty
1869              && (CAR(CDR(iterator))->type!=symb
1870                  || CAR(CDR(iterator))->content.sym->id[0]!='['))
1871          iterator= CDR(iterator);
1872        
1873        /* Extract list */
1874        temp= env->head;
1875        env->head= CDR(iterator);
1876        CDR(iterator)= end;
1877    
1878        if(env->head->type!=empty)
1879          toss(env);
1880      }
1881    
1882      /* Push list */
1883      push_val(env, temp);
1884  }  }
1885    
1886  /* Give a symbol some content. */  /* Read a string */
1887  extern void def(stackitem** stack_head)  extern void readline(environment *env)
1888    {
1889      readlinestream(env, env->inputstream);
1890    }
1891    
1892    /* Read a string from a port */
1893    extern void readlineport(environment *env)
1894  {  {
1895    stackitem *temp, *value;    FILE *stream;
1896    
1897      if(env->head->type==empty) {
1898        printerr("Too Few Arguments");
1899        env->err= 1;
1900        return;
1901      }
1902    
1903    if(*stack_head==NULL || (*stack_head)->next==NULL    if(CAR(env->head)->type!=port) {
1904       || (*stack_head)->type!=ref) {      printerr("Bad Argument Type");
1905      printerr("Define what?");      env->err= 2;
1906      return;      return;
1907    }    }
1908    
1909    temp= (*stack_head)->content.ptr;    stream=CAR(env->head)->content.p;
1910    value= (*stack_head)->next;    readlinestream(env, stream); if(env->err) return;
   temp->content= value->content;  
   value->content.ptr=NULL;  
   temp->type= value->type;  
1911    
1912    toss(stack_head); toss(stack_head);    swap(env); if(env->err) return;
1913  }    toss(env);
1914    }
1915    
1916  /* Quit stack. */  /* read a line from a stream; used by readline */
1917  extern void quit()  void readlinestream(environment *env, FILE *stream)
1918  {  {
1919    exit(EXIT_SUCCESS);    char in_string[101];
1920    
1921      if(fgets(in_string, 100, stream)==NULL) {
1922        push_cstring(env, "");
1923        if (! feof(stream)){
1924          perror("readline");
1925          env->err= 5;
1926        }
1927      } else {
1928        push_cstring(env, in_string);
1929      }
1930    }
1931    
1932    /* "read"; Read a value and place on stack */
1933    extern void sx_72656164(environment *env)
1934    {
1935      readstream(env, env->inputstream);
1936  }  }
1937    
1938  int main()  /* "readport"; Read a value from a port and place on stack */
1939    extern void readport(environment *env)
1940  {  {
1941    stackitem* s= NULL;    FILE *stream;
   hashtbl myhash;  
   char in_string[100];  
1942    
1943    init_hashtbl(myhash);    if(env->head->type==empty) {
1944        printerr("Too Few Arguments");
1945        env->err= 1;
1946        return;
1947      }
1948    
1949      if(CAR(env->head)->type!=port) {
1950        printerr("Bad Argument Type");
1951        env->err= 2;
1952        return;
1953      }
1954    
1955      stream=CAR(env->head)->content.p;
1956      readstream(env, stream); if(env->err) return;
1957    
1958    printf("okidok\n ");    swap(env); if(env->err) return;
1959      toss(env);
1960    }
1961    
1962    /* read from a stream; used by "read" and "readport" */
1963    void readstream(environment *env, FILE *stream)
1964    {
1965      const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1966      const char strform[]= "\"%[^\"]\"%n";
1967      const char intform[]= "%i%n";
1968      const char fltform[]= "%f%n";
1969      const char blankform[]= "%*[ \t]%n";
1970      const char ebrackform[]= "]%n";
1971      const char semicform[]= ";%n";
1972      const char bbrackform[]= "[%n";
1973    
1974      int itemp, readlength= -1;
1975      int count= -1;
1976      float ftemp;
1977      static int depth= 0;
1978      char *match;
1979      size_t inlength;
1980    
1981      if(env->in_string==NULL) {
1982        if(depth > 0 && env->interactive) {
1983          printf("]> ");
1984        }
1985        readline(env); if(env->err) return;
1986    
1987    while(fgets(in_string, 100, stdin) != NULL) {      if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1988      stack_read(&s, myhash, in_string);        env->err= 4;              /* "" means EOF */
1989      printf("okidok\n ");        return;
1990        }
1991        
1992        env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1993        assert(env->in_string != NULL);
1994        env->free_string= env->in_string; /* Save the original pointer */
1995        strcpy(env->in_string, CAR(env->head)->content.ptr);
1996        toss(env); if(env->err) return;
1997      }
1998      
1999      inlength= strlen(env->in_string)+1;
2000      match= malloc(inlength);
2001      assert(match != NULL);
2002    
2003      if(sscanf(env->in_string, blankform, &readlength) != EOF
2004         && readlength != -1) {
2005        ;
2006      } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
2007                && readlength != -1) {
2008        if(sscanf(env->in_string, intform, &itemp, &count) != EOF
2009           && count==readlength) {
2010          push_int(env, itemp);
2011        } else {
2012          push_float(env, ftemp);
2013        }
2014      } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
2015                && readlength != -1) {
2016        push_cstring(env, "");
2017      } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
2018                && readlength != -1) {
2019        push_cstring(env, match);
2020      } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
2021                && readlength != -1) {
2022        push_sym(env, match);
2023      } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
2024                && readlength != -1) {
2025        pack(env); if(env->err) return;
2026        if(depth != 0) depth--;
2027      } else if(sscanf(env->in_string, semicform, &readlength) != EOF
2028                && readlength != -1) {
2029        push_sym(env, ";");
2030      } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
2031                && readlength != -1) {
2032        push_sym(env, "[");
2033        depth++;
2034      } else {
2035        free(env->free_string);
2036        env->in_string = env->free_string = NULL;
2037      }
2038      if (env->in_string != NULL) {
2039        env->in_string += readlength;
2040    }    }
2041    
2042    exit(EXIT_SUCCESS);    free(match);
2043    
2044      if(depth)
2045        return sx_72656164(env);
2046    }
2047    
2048    #ifdef __linux__
2049    extern void beep(environment *env)
2050    {
2051      int freq, dur, period, ticks;
2052    
2053      if(env->head->type==empty || CDR(env->head)->type==empty) {
2054        printerr("Too Few Arguments");
2055        env->err= 1;
2056        return;
2057      }
2058    
2059      if(CAR(env->head)->type!=integer
2060         || CAR(CDR(env->head))->type!=integer) {
2061        printerr("Bad Argument Type");
2062        env->err= 2;
2063        return;
2064      }
2065    
2066      dur= CAR(env->head)->content.i;
2067      toss(env);
2068      freq= CAR(env->head)->content.i;
2069      toss(env);
2070    
2071      period= 1193180/freq;         /* convert freq from Hz to period
2072                                       length */
2073      ticks= dur*.001193180;        /* convert duration from µseconds to
2074                                       timer ticks */
2075    
2076    /*    ticks=dur/1000; */
2077    
2078          /*  if (ioctl(STDOUT_FILENO, KDMKTONE, (125<<16) + 0x637)==0) */
2079      switch (ioctl(STDOUT_FILENO, KDMKTONE, (ticks<<16) | period)){
2080      case 0:
2081        usleep(dur);
2082        return;
2083      case -1:
2084        perror("beep");
2085        env->err= 5;
2086        return;
2087      default:
2088        abort();
2089      }
2090    }
2091    #endif /* __linux__ */
2092    
2093    /* "wait" */
2094    extern void sx_77616974(environment *env)
2095    {
2096      int dur;
2097    
2098      if(env->head->type==empty) {
2099        printerr("Too Few Arguments");
2100        env->err= 1;
2101        return;
2102      }
2103    
2104      if(CAR(env->head)->type!=integer) {
2105        printerr("Bad Argument Type");
2106        env->err= 2;
2107        return;
2108      }
2109    
2110      dur= CAR(env->head)->content.i;
2111      toss(env);
2112    
2113      usleep(dur);
2114    }
2115    
2116    extern void copying(environment *env)
2117    {
2118      printf("                  GNU GENERAL PUBLIC LICENSE\n\
2119                           Version 2, June 1991\n\
2120    \n\
2121     Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
2122         59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\
2123     Everyone is permitted to copy and distribute verbatim copies\n\
2124     of this license document, but changing it is not allowed.\n\
2125    \n\
2126                                Preamble\n\
2127    \n\
2128      The licenses for most software are designed to take away your\n\
2129    freedom to share and change it.  By contrast, the GNU General Public\n\
2130    License is intended to guarantee your freedom to share and change free\n\
2131    software--to make sure the software is free for all its users.  This\n\
2132    General Public License applies to most of the Free Software\n\
2133    Foundation's software and to any other program whose authors commit to\n\
2134    using it.  (Some other Free Software Foundation software is covered by\n\
2135    the GNU Library General Public License instead.)  You can apply it to\n\
2136    your programs, too.\n\
2137    \n\
2138      When we speak of free software, we are referring to freedom, not\n\
2139    price.  Our General Public Licenses are designed to make sure that you\n\
2140    have the freedom to distribute copies of free software (and charge for\n\
2141    this service if you wish), that you receive source code or can get it\n\
2142    if you want it, that you can change the software or use pieces of it\n\
2143    in new free programs; and that you know you can do these things.\n\
2144    \n\
2145      To protect your rights, we need to make restrictions that forbid\n\
2146    anyone to deny you these rights or to ask you to surrender the rights.\n\
2147    These restrictions translate to certain responsibilities for you if you\n\
2148    distribute copies of the software, or if you modify it.\n\
2149    \n\
2150      For example, if you distribute copies of such a program, whether\n\
2151    gratis or for a fee, you must give the recipients all the rights that\n\
2152    you have.  You must make sure that they, too, receive or can get the\n\
2153    source code.  And you must show them these terms so they know their\n\
2154    rights.\n\
2155    \n\
2156      We protect your rights with two steps: (1) copyright the software, and\n\
2157    (2) offer you this license which gives you legal permission to copy,\n\
2158    distribute and/or modify the software.\n\
2159    \n\
2160      Also, for each author's protection and ours, we want to make certain\n\
2161    that everyone understands that there is no warranty for this free\n\
2162    software.  If the software is modified by someone else and passed on, we\n\
2163    want its recipients to know that what they have is not the original, so\n\
2164    that any problems introduced by others will not reflect on the original\n\
2165    authors' reputations.\n\
2166    \n\
2167      Finally, any free program is threatened constantly by software\n\
2168    patents.  We wish to avoid the danger that redistributors of a free\n\
2169    program will individually obtain patent licenses, in effect making the\n\
2170    program proprietary.  To prevent this, we have made it clear that any\n\
2171    patent must be licensed for everyone's free use or not licensed at all.\n\
2172    \n\
2173      The precise terms and conditions for copying, distribution and\n\
2174    modification follow.\n\
2175    \n\
2176                        GNU GENERAL PUBLIC LICENSE\n\
2177       TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
2178    \n\
2179      0. This License applies to any program or other work which contains\n\
2180    a notice placed by the copyright holder saying it may be distributed\n\
2181    under the terms of this General Public License.  The \"Program\", below,\n\
2182    refers to any such program or work, and a \"work based on the Program\"\n\
2183    means either the Program or any derivative work under copyright law:\n\
2184    that is to say, a work containing the Program or a portion of it,\n\
2185    either verbatim or with modifications and/or translated into another\n\
2186    language.  (Hereinafter, translation is included without limitation in\n\
2187    the term \"modification\".)  Each licensee is addressed as \"you\".\n\
2188    \n\
2189    Activities other than copying, distribution and modification are not\n\
2190    covered by this License; they are outside its scope.  The act of\n\
2191    running the Program is not restricted, and the output from the Program\n\
2192    is covered only if its contents constitute a work based on the\n\
2193    Program (independent of having been made by running the Program).\n\
2194    Whether that is true depends on what the Program does.\n\
2195    \n\
2196      1. You may copy and distribute verbatim copies of the Program's\n\
2197    source code as you receive it, in any medium, provided that you\n\
2198    conspicuously and appropriately publish on each copy an appropriate\n\
2199    copyright notice and disclaimer of warranty; keep intact all the\n\
2200    notices that refer to this License and to the absence of any warranty;\n\
2201    and give any other recipients of the Program a copy of this License\n\
2202    along with the Program.\n\
2203    \n\
2204    You may charge a fee for the physical act of transferring a copy, and\n\
2205    you may at your option offer warranty protection in exchange for a fee.\n\
2206    \n\
2207      2. You may modify your copy or copies of the Program or any portion\n\
2208    of it, thus forming a work based on the Program, and copy and\n\
2209    distribute such modifications or work under the terms of Section 1\n\
2210    above, provided that you also meet all of these conditions:\n\
2211    \n\
2212        a) You must cause the modified files to carry prominent notices\n\
2213        stating that you changed the files and the date of any change.\n\
2214    \n\
2215        b) You must cause any work that you distribute or publish, that in\n\
2216        whole or in part contains or is derived from the Program or any\n\
2217        part thereof, to be licensed as a whole at no charge to all third\n\
2218        parties under the terms of this License.\n\
2219    \n\
2220        c) If the modified program normally reads commands interactively\n\
2221        when run, you must cause it, when started running for such\n\
2222        interactive use in the most ordinary way, to print or display an\n\
2223        announcement including an appropriate copyright notice and a\n\
2224        notice that there is no warranty (or else, saying that you provide\n\
2225        a warranty) and that users may redistribute the program under\n\
2226        these conditions, and telling the user how to view a copy of this\n\
2227        License.  (Exception: if the Program itself is interactive but\n\
2228        does not normally print such an announcement, your work based on\n\
2229        the Program is not required to print an announcement.)\n\
2230    \n\
2231    These requirements apply to the modified work as a whole.  If\n\
2232    identifiable sections of that work are not derived from the Program,\n\
2233    and can be reasonably considered independent and separate works in\n\
2234    themselves, then this License, and its terms, do not apply to those\n\
2235    sections when you distribute them as separate works.  But when you\n\
2236    distribute the same sections as part of a whole which is a work based\n\
2237    on the Program, the distribution of the whole must be on the terms of\n\
2238    this License, whose permissions for other licensees extend to the\n\
2239    entire whole, and thus to each and every part regardless of who wrote it.\n\
2240    \n\
2241    Thus, it is not the intent of this section to claim rights or contest\n\
2242    your rights to work written entirely by you; rather, the intent is to\n\
2243    exercise the right to control the distribution of derivative or\n\
2244    collective works based on the Program.\n\
2245    \n\
2246    In addition, mere aggregation of another work not based on the Program\n\
2247    with the Program (or with a work based on the Program) on a volume of\n\
2248    a storage or distribution medium does not bring the other work under\n\
2249    the scope of this License.\n\
2250    \n\
2251      3. You may copy and distribute the Program (or a work based on it,\n\
2252    under Section 2) in object code or executable form under the terms of\n\
2253    Sections 1 and 2 above provided that you also do one of the following:\n\
2254    \n\
2255        a) Accompany it with the complete corresponding machine-readable\n\
2256        source code, which must be distributed under the terms of Sections\n\
2257        1 and 2 above on a medium customarily used for software interchange; or,\n\
2258    \n\
2259        b) Accompany it with a written offer, valid for at least three\n\
2260        years, to give any third party, for a charge no more than your\n\
2261        cost of physically performing source distribution, a complete\n\
2262        machine-readable copy of the corresponding source code, to be\n\
2263        distributed under the terms of Sections 1 and 2 above on a medium\n\
2264        customarily used for software interchange; or,\n\
2265    \n\
2266        c) Accompany it with the information you received as to the offer\n\
2267        to distribute corresponding source code.  (This alternative is\n\
2268        allowed only for noncommercial distribution and only if you\n\
2269        received the program in object code or executable form with such\n\
2270        an offer, in accord with Subsection b above.)\n\
2271    \n\
2272    The source code for a work means the preferred form of the work for\n\
2273    making modifications to it.  For an executable work, complete source\n\
2274    code means all the source code for all modules it contains, plus any\n\
2275    associated interface definition files, plus the scripts used to\n\
2276    control compilation and installation of the executable.  However, as a\n\
2277    special exception, the source code distributed need not include\n\
2278    anything that is normally distributed (in either source or binary\n\
2279    form) with the major components (compiler, kernel, and so on) of the\n\
2280    operating system on which the executable runs, unless that component\n\
2281    itself accompanies the executable.\n\
2282    \n\
2283    If distribution of executable or object code is made by offering\n\
2284    access to copy from a designated place, then offering equivalent\n\
2285    access to copy the source code from the same place counts as\n\
2286    distribution of the source code, even though third parties are not\n\
2287    compelled to copy the source along with the object code.\n\
2288    \n\
2289      4. You may not copy, modify, sublicense, or distribute the Program\n\
2290    except as expressly provided under this License.  Any attempt\n\
2291    otherwise to copy, modify, sublicense or distribute the Program is\n\
2292    void, and will automatically terminate your rights under this License.\n\
2293    However, parties who have received copies, or rights, from you under\n\
2294    this License will not have their licenses terminated so long as such\n\
2295    parties remain in full compliance.\n\
2296    \n\
2297      5. You are not required to accept this License, since you have not\n\
2298    signed it.  However, nothing else grants you permission to modify or\n\
2299    distribute the Program or its derivative works.  These actions are\n\
2300    prohibited by law if you do not accept this License.  Therefore, by\n\
2301    modifying or distributing the Program (or any work based on the\n\
2302    Program), you indicate your acceptance of this License to do so, and\n\
2303    all its terms and conditions for copying, distributing or modifying\n\
2304    the Program or works based on it.\n\
2305    \n\
2306      6. Each time you redistribute the Program (or any work based on the\n\
2307    Program), the recipient automatically receives a license from the\n\
2308    original licensor to copy, distribute or modify the Program subject to\n\
2309    these terms and conditions.  You may not impose any further\n\
2310    restrictions on the recipients' exercise of the rights granted herein.\n\
2311    You are not responsible for enforcing compliance by third parties to\n\
2312    this License.\n\
2313    \n\
2314      7. If, as a consequence of a court judgment or allegation of patent\n\
2315    infringement or for any other reason (not limited to patent issues),\n\
2316    conditions are imposed on you (whether by court order, agreement or\n\
2317    otherwise) that contradict the conditions of this License, they do not\n\
2318    excuse you from the conditions of this License.  If you cannot\n\
2319    distribute so as to satisfy simultaneously your obligations under this\n\
2320    License and any other pertinent obligations, then as a consequence you\n\
2321    may not distribute the Program at all.  For example, if a patent\n\
2322    license would not permit royalty-free redistribution of the Program by\n\
2323    all those who receive copies directly or indirectly through you, then\n\
2324    the only way you could satisfy both it and this License would be to\n\
2325    refrain entirely from distribution of the Program.\n\
2326    \n\
2327    If any portion of this section is held invalid or unenforceable under\n\
2328    any particular circumstance, the balance of the section is intended to\n\
2329    apply and the section as a whole is intended to apply in other\n\
2330    circumstances.\n\
2331    \n\
2332    It is not the purpose of this section to induce you to infringe any\n\
2333    patents or other property right claims or to contest validity of any\n\
2334    such claims; this section has the sole purpose of protecting the\n\
2335    integrity of the free software distribution system, which is\n\
2336    implemented by public license practices.  Many people have made\n\
2337    generous contributions to the wide range of software distributed\n\
2338    through that system in reliance on consistent application of that\n\
2339    system; it is up to the author/donor to decide if he or she is willing\n\
2340    to distribute software through any other system and a licensee cannot\n\
2341    impose that choice.\n\
2342    \n\
2343    This section is intended to make thoroughly clear what is believed to\n\
2344    be a consequence of the rest of this License.\n\
2345    \n\
2346      8. If the distribution and/or use of the Program is restricted in\n\
2347    certain countries either by patents or by copyrighted interfaces, the\n\
2348    original copyright holder who places the Program under this License\n\
2349    may add an explicit geographical distribution limitation excluding\n\
2350    those countries, so that distribution is permitted only in or among\n\
2351    countries not thus excluded.  In such case, this License incorporates\n\
2352    the limitation as if written in the body of this License.\n\
2353    \n\
2354      9. The Free Software Foundation may publish revised and/or new versions\n\
2355    of the General Public License from time to time.  Such new versions will\n\
2356    be similar in spirit to the present version, but may differ in detail to\n\
2357    address new problems or concerns.\n\
2358    \n\
2359    Each version is given a distinguishing version number.  If the Program\n\
2360    specifies a version number of this License which applies to it and \"any\n\
2361    later version\", you have the option of following the terms and conditions\n\
2362    either of that version or of any later version published by the Free\n\
2363    Software Foundation.  If the Program does not specify a version number of\n\
2364    this License, you may choose any version ever published by the Free Software\n\
2365    Foundation.\n\
2366    \n\
2367      10. If you wish to incorporate parts of the Program into other free\n\
2368    programs whose distribution conditions are different, write to the author\n\
2369    to ask for permission.  For software which is copyrighted by the Free\n\
2370    Software Foundation, write to the Free Software Foundation; we sometimes\n\
2371    make exceptions for this.  Our decision will be guided by the two goals\n\
2372    of preserving the free status of all derivatives of our free software and\n\
2373    of promoting the sharing and reuse of software generally.\n");
2374    }
2375    
2376    extern void warranty(environment *env)
2377    {
2378      printf("                          NO WARRANTY\n\
2379    \n\
2380      11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
2381    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n\
2382    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
2383    PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
2384    OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
2385    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n\
2386    TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n\
2387    PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
2388    REPAIR OR CORRECTION.\n\
2389    \n\
2390      12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
2391    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
2392    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
2393    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
2394    OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
2395    TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
2396    YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
2397    PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
2398    POSSIBILITY OF SUCH DAMAGES.\n");
2399    }
2400    
2401    /* "*" */
2402    extern void sx_2a(environment *env)
2403    {
2404      int a, b;
2405      float fa, fb;
2406    
2407      if(env->head->type==empty || CDR(env->head)->type==empty) {
2408        printerr("Too Few Arguments");
2409        env->err= 1;
2410        return;
2411      }
2412      
2413      if(CAR(env->head)->type==integer
2414         && CAR(CDR(env->head))->type==integer) {
2415        a= CAR(env->head)->content.i;
2416        toss(env); if(env->err) return;
2417        b= CAR(env->head)->content.i;
2418        toss(env); if(env->err) return;
2419        push_int(env, b*a);
2420    
2421        return;
2422      }
2423    
2424      if(CAR(env->head)->type==tfloat
2425         && CAR(CDR(env->head))->type==tfloat) {
2426        fa= CAR(env->head)->content.f;
2427        toss(env); if(env->err) return;
2428        fb= CAR(env->head)->content.f;
2429        toss(env); if(env->err) return;
2430        push_float(env, fb*fa);
2431        
2432        return;
2433      }
2434    
2435      if(CAR(env->head)->type==tfloat
2436         && CAR(CDR(env->head))->type==integer) {
2437        fa= CAR(env->head)->content.f;
2438        toss(env); if(env->err) return;
2439        b= CAR(env->head)->content.i;
2440        toss(env); if(env->err) return;
2441        push_float(env, b*fa);
2442        
2443        return;
2444      }
2445    
2446      if(CAR(env->head)->type==integer
2447         && CAR(CDR(env->head))->type==tfloat) {
2448        a= CAR(env->head)->content.i;
2449        toss(env); if(env->err) return;
2450        fb= CAR(env->head)->content.f;
2451        toss(env); if(env->err) return;
2452        push_float(env, fb*a);
2453    
2454        return;
2455      }
2456    
2457      printerr("Bad Argument Type");
2458      env->err= 2;
2459    }
2460    
2461    /* "/" */
2462    extern void sx_2f(environment *env)
2463    {
2464      int a, b;
2465      float fa, fb;
2466    
2467      if(env->head->type==empty || CDR(env->head)->type==empty) {
2468        printerr("Too Few Arguments");
2469        env->err= 1;
2470        return;
2471      }
2472      
2473      if(CAR(env->head)->type==integer
2474         && CAR(CDR(env->head))->type==integer) {
2475        a= CAR(env->head)->content.i;
2476        toss(env); if(env->err) return;
2477        b= CAR(env->head)->content.i;
2478        toss(env); if(env->err) return;
2479        push_float(env, b/a);
2480    
2481        return;
2482      }
2483    
2484      if(CAR(env->head)->type==tfloat
2485         && CAR(CDR(env->head))->type==tfloat) {
2486        fa= CAR(env->head)->content.f;
2487        toss(env); if(env->err) return;
2488        fb= CAR(env->head)->content.f;
2489        toss(env); if(env->err) return;
2490        push_float(env, fb/fa);
2491        
2492        return;
2493      }
2494    
2495      if(CAR(env->head)->type==tfloat
2496         && CAR(CDR(env->head))->type==integer) {
2497        fa= CAR(env->head)->content.f;
2498        toss(env); if(env->err) return;
2499        b= CAR(env->head)->content.i;
2500        toss(env); if(env->err) return;
2501        push_float(env, b/fa);
2502        
2503        return;
2504      }
2505    
2506      if(CAR(env->head)->type==integer
2507         && CAR(CDR(env->head))->type==tfloat) {
2508        a= CAR(env->head)->content.i;
2509        toss(env); if(env->err) return;
2510        fb= CAR(env->head)->content.f;
2511        toss(env); if(env->err) return;
2512        push_float(env, fb/a);
2513    
2514        return;
2515      }
2516    
2517      printerr("Bad Argument Type");
2518      env->err= 2;
2519  }  }
2520    
2521  /* Local Variables: */  /* "mod" */
2522  /* compile-command:"make CFLAGS=\"-Wall -g -rdynamic -ldl\" stack" */  extern void mod(environment *env)
2523  /* End: */  {
2524      int a, b;
2525    
2526      if(env->head->type==empty || CDR(env->head)->type==empty) {
2527        printerr("Too Few Arguments");
2528        env->err= 1;
2529        return;
2530      }
2531      
2532      if(CAR(env->head)->type==integer
2533         && CAR(CDR(env->head))->type==integer) {
2534        a= CAR(env->head)->content.i;
2535        toss(env); if(env->err) return;
2536        b= CAR(env->head)->content.i;
2537        toss(env); if(env->err) return;
2538        push_int(env, b%a);
2539    
2540        return;
2541      }
2542    
2543      printerr("Bad Argument Type");
2544      env->err= 2;
2545    }
2546    
2547    /* "div" */
2548    extern void sx_646976(environment *env)
2549    {
2550      int a, b;
2551      
2552      if(env->head->type==empty || CDR(env->head)->type==empty) {
2553        printerr("Too Few Arguments");
2554        env->err= 1;
2555        return;
2556      }
2557    
2558      if(CAR(env->head)->type==integer
2559         && CAR(CDR(env->head))->type==integer) {
2560        a= CAR(env->head)->content.i;
2561        toss(env); if(env->err) return;
2562        b= CAR(env->head)->content.i;
2563        toss(env); if(env->err) return;
2564        push_int(env, (int)b/a);
2565    
2566        return;
2567      }
2568    
2569      printerr("Bad Argument Type");
2570      env->err= 2;
2571    }
2572    
2573    extern void setcar(environment *env)
2574    {
2575      if(env->head->type==empty || CDR(env->head)->type==empty) {
2576        printerr("Too Few Arguments");
2577        env->err= 1;
2578        return;
2579      }
2580    
2581      if(CDR(env->head)->type!=tcons) {
2582        printerr("Bad Argument Type");
2583        env->err= 2;
2584        return;
2585      }
2586    
2587      CAR(CAR(CDR(env->head)))=CAR(env->head);
2588      toss(env);
2589    }
2590    
2591    extern void setcdr(environment *env)
2592    {
2593      if(env->head->type==empty || CDR(env->head)->type==empty) {
2594        printerr("Too Few Arguments");
2595        env->err= 1;
2596        return;
2597      }
2598    
2599      if(CDR(env->head)->type!=tcons) {
2600        printerr("Bad Argument Type");
2601        env->err= 2;
2602        return;
2603      }
2604    
2605      CDR(CAR(CDR(env->head)))=CAR(env->head);
2606      toss(env);
2607    }
2608    
2609    extern void car(environment *env)
2610    {
2611      if(env->head->type==empty) {
2612        printerr("Too Few Arguments");
2613        env->err= 1;
2614        return;
2615      }
2616    
2617      if(CAR(env->head)->type!=tcons) {
2618        printerr("Bad Argument Type");
2619        env->err= 2;
2620        return;
2621      }
2622    
2623      CAR(env->head)=CAR(CAR(env->head));
2624    }
2625    
2626    extern void cdr(environment *env)
2627    {
2628      if(env->head->type==empty) {
2629        printerr("Too Few Arguments");
2630        env->err= 1;
2631        return;
2632      }
2633    
2634      if(CAR(env->head)->type!=tcons) {
2635        printerr("Bad Argument Type");
2636        env->err= 2;
2637        return;
2638      }
2639    
2640      CAR(env->head)=CDR(CAR(env->head));
2641    }
2642    
2643    extern void cons(environment *env)
2644    {
2645      value *val;
2646    
2647      if(env->head->type==empty || CDR(env->head)->type==empty) {
2648        printerr("Too Few Arguments");
2649        env->err= 1;
2650        return;
2651      }
2652    
2653      val=new_val(env);
2654      val->content.c= malloc(sizeof(pair));
2655      assert(val->content.c!=NULL);
2656    
2657      env->gc_count += sizeof(pair);
2658      val->type=tcons;
2659    
2660      CAR(val)= CAR(CDR(env->head));
2661      CDR(val)= CAR(env->head);
2662    
2663      push_val(env, val);
2664    
2665      swap(env); if(env->err) return;
2666      toss(env); if(env->err) return;
2667      swap(env); if(env->err) return;
2668      toss(env); if(env->err) return;
2669    }
2670    
2671    /*  2: 3                        =>                */
2672    /*  1: [ [ 1 . 2 ] [ 3 . 4 ] ]  =>  1: [ 3 . 4 ]  */
2673    extern void assq(environment *env)
2674    {
2675      assocgen(env, eq);
2676    }
2677    
2678    
2679    /* General assoc function */
2680    void assocgen(environment *env, funcp eqfunc)
2681    {
2682      value *key, *item;
2683    
2684      /* Needs two values on the stack, the top one must be an association
2685         list */
2686      if(env->head->type==empty || CDR(env->head)->type==empty) {
2687        printerr("Too Few Arguments");
2688        env->err= 1;
2689        return;
2690      }
2691    
2692      if(CAR(env->head)->type!=tcons) {
2693        printerr("Bad Argument Type");
2694        env->err= 2;
2695        return;
2696      }
2697    
2698      key=CAR(CDR(env->head));
2699      item=CAR(env->head);
2700    
2701      while(item->type == tcons){
2702        if(CAR(item)->type != tcons){
2703          printerr("Bad Argument Type");
2704          env->err= 2;
2705          return;
2706        }
2707        push_val(env, key);
2708        push_val(env, CAR(CAR(item)));
2709        eqfunc(env); if(env->err) return;
2710    
2711        /* Check the result of 'eqfunc' */
2712        if(env->head->type==empty) {
2713          printerr("Too Few Arguments");
2714          env->err= 1;
2715        return;
2716        }
2717        if(CAR(env->head)->type!=integer) {
2718          printerr("Bad Argument Type");
2719          env->err= 2;
2720          return;
2721        }
2722    
2723        if(CAR(env->head)->content.i){
2724          toss(env); if(env->err) return;
2725          break;
2726        }
2727        toss(env); if(env->err) return;
2728    
2729        if(item->type!=tcons) {
2730          printerr("Bad Argument Type");
2731          env->err= 2;
2732          return;
2733        }
2734    
2735        item=CDR(item);
2736      }
2737    
2738      if(item->type == tcons){      /* A match was found */
2739        push_val(env, CAR(item));
2740      } else {
2741        push_int(env, 0);
2742      }
2743      swap(env); if(env->err) return;
2744      toss(env); if(env->err) return;
2745      swap(env); if(env->err) return;
2746      toss(env);
2747    }
2748    
2749    /* "do" */
2750    extern void sx_646f(environment *env)
2751    {
2752      swap(env); if(env->err) return;
2753      eval(env);
2754    }
2755    
2756    /* "open" */
2757    /* 2: "file"                                    */
2758    /* 1: "r"       =>      1: #<port 0x47114711>   */
2759    extern void sx_6f70656e(environment *env)
2760    {
2761      value *new_port;
2762      FILE *stream;
2763    
2764      if(env->head->type == empty || CDR(env->head)->type == empty) {
2765        printerr("Too Few Arguments");
2766        env->err=1;
2767        return;
2768      }
2769    
2770      if(CAR(env->head)->type != string
2771         || CAR(CDR(env->head))->type != string) {
2772        printerr("Bad Argument Type");
2773        env->err= 2;
2774        return;
2775      }
2776    
2777      stream=fopen(CAR(CDR(env->head))->content.ptr,
2778                   CAR(env->head)->content.ptr);
2779    
2780      if(stream == NULL) {
2781        perror("open");
2782        env->err= 5;
2783        return;
2784      }
2785    
2786      new_port=new_val(env);
2787      new_port->type=port;
2788      new_port->content.p=stream;
2789    
2790      push_val(env, new_port);
2791    
2792      swap(env); if(env->err) return;
2793      toss(env); if(env->err) return;
2794      swap(env); if(env->err) return;
2795      toss(env);
2796    }
2797    
2798    
2799    /* "close" */
2800    extern void sx_636c6f7365(environment *env)
2801    {
2802      int ret;
2803    
2804      if(env->head->type == empty) {
2805        printerr("Too Few Arguments");
2806        env->err=1;
2807        return;
2808      }
2809    
2810      if(CAR(env->head)->type != port) {
2811        printerr("Bad Argument Type");
2812        env->err= 2;
2813        return;
2814      }
2815    
2816      ret= fclose(CAR(env->head)->content.p);
2817    
2818      if(ret != 0){
2819        perror("close");
2820        env->err= 5;
2821        return;
2822      }
2823    
2824      toss(env);
2825    }

Legend:
Removed from v.1.23  
changed lines
  Added in v.1.125

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26