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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.108 - (hide annotations)
Tue Mar 12 22:03:21 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.107: +8 -4 lines
File MIME type: text/plain
Makefile (LDFLAGS): Include commented-out alternate setting.
stack.c (new_val): New values are integers.
(push_val): Check malloc return value.
(copy_val): Don't protect new_val.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26