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

Diff of /stack/stack.c

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

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

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.112

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26