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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.111 - (hide annotations)
Sat Mar 16 19:09:54 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.110: +75 -65 lines
File MIME type: text/plain
The empty list and the indicator of the end of a list is no longer a
value* which is NULL, but the "empty list" value, a type of its own.
All affected functions changed.

stack.h (value.type): New type, "empty".
(environment): Comments added.

stack.c (print_h): Print improper lists correctly.
(rev): Don't bother reversing an empty list value.
(forget): Eliminate unnecessary variable "stack_head".
(copying): Fixed centering of first line.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26