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