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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.109 - (hide annotations)
Thu Mar 14 10:39:11 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.108: +26 -3 lines
File MIME type: text/plain
stack.c:
(sx_656c7365): "else" now requires a "then".
(then): New function.

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.109 printf("Stack version $Revision: 1.108 $\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 masse 1.109 || CDR(CDR(env->head))==NULL || CDR(CDR(CDR(env->head)))==NULL
1380     || CDR(CDR(CDR(CDR(env->head))))==NULL) {
1381     printerr("Too Few Arguments");
1382     env->err= 1;
1383     return;
1384     }
1385    
1386     if(CAR(CDR(env->head))->type!=symb
1387     || strcmp(CAR(CDR(env->head))->content.sym->id, "then")!=0
1388     || CAR(CDR(CDR(CDR(env->head))))->type!=symb
1389     || strcmp(CAR(CDR(CDR(CDR(env->head))))->content.sym->id, "if")!=0) {
1390     printerr("Bad Argument Type");
1391     env->err= 2;
1392     return;
1393     }
1394    
1395     swap(env); toss(env); rot(env); toss(env);
1396     ifelse(env);
1397     }
1398    
1399     extern void then(environment *env)
1400     {
1401     if(env->head==NULL || CDR(env->head)==NULL
1402     || CDR(CDR(env->head))==NULL) {
1403 masse 1.106 printerr("Too Few Arguments");
1404     env->err= 1;
1405     return;
1406     }
1407    
1408     if(CAR(CDR(env->head))->type!=symb
1409     || strcmp(CAR(CDR(env->head))->content.sym->id, "if")!=0) {
1410     printerr("Bad Argument Type");
1411     env->err= 2;
1412     return;
1413     }
1414    
1415     swap(env); toss(env);
1416 masse 1.109 sx_6966(env);
1417 masse 1.58 }
1418    
1419 teddy 1.85 /* "while" */
1420 masse 1.95 extern void sx_7768696c65(environment *env)
1421     {
1422 masse 1.58 int truth;
1423 masse 1.63 value *loop, *test;
1424 masse 1.58
1425 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
1426 masse 1.58 printerr("Too Few Arguments");
1427 masse 1.102 env->err= 1;
1428 masse 1.58 return;
1429     }
1430    
1431 masse 1.104 loop= CAR(env->head);
1432 masse 1.98 protect(loop);
1433 masse 1.63 toss(env); if(env->err) return;
1434    
1435 masse 1.104 test= CAR(env->head);
1436 masse 1.98 protect(test);
1437 masse 1.63 toss(env); if(env->err) return;
1438    
1439 masse 1.58 do {
1440 masse 1.72 push_val(env, test);
1441 masse 1.63 eval(env);
1442 masse 1.58
1443 masse 1.104 if(CAR(env->head)->type != integer) {
1444 masse 1.58 printerr("Bad Argument Type");
1445 masse 1.90 env->err= 2;
1446 masse 1.58 return;
1447     }
1448    
1449 masse 1.104 truth= CAR(env->head)->content.i;
1450 masse 1.58 toss(env); if(env->err) return;
1451    
1452     if(truth) {
1453 masse 1.72 push_val(env, loop);
1454 masse 1.58 eval(env);
1455     } else {
1456     toss(env);
1457     }
1458    
1459     } while(truth);
1460 masse 1.90
1461 masse 1.98 unprotect(loop); unprotect(test);
1462 teddy 1.56 }
1463 masse 1.65
1464 masse 1.89
1465     /* "for"; for-loop */
1466 masse 1.95 extern void sx_666f72(environment *env)
1467     {
1468 masse 1.89 value *loop;
1469     int foo1, foo2;
1470    
1471 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL
1472     || CDR(CDR(env->head))==NULL) {
1473 masse 1.89 printerr("Too Few Arguments");
1474     env->err= 1;
1475     return;
1476     }
1477    
1478 masse 1.104 if(CAR(CDR(env->head))->type!=integer
1479     || CAR(CDR(CDR(env->head)))->type!=integer) {
1480 masse 1.89 printerr("Bad Argument Type");
1481     env->err= 2;
1482     return;
1483     }
1484    
1485 masse 1.104 loop= CAR(env->head);
1486 masse 1.98 protect(loop);
1487 masse 1.89 toss(env); if(env->err) return;
1488    
1489 masse 1.104 foo2= CAR(env->head)->content.i;
1490 masse 1.89 toss(env); if(env->err) return;
1491    
1492 masse 1.104 foo1= CAR(env->head)->content.i;
1493 masse 1.89 toss(env); if(env->err) return;
1494    
1495     if(foo1<=foo2) {
1496     while(foo1<=foo2) {
1497     push_int(env, foo1);
1498     push_val(env, loop);
1499     eval(env); if(env->err) return;
1500     foo1++;
1501     }
1502     } else {
1503     while(foo1>=foo2) {
1504     push_int(env, foo1);
1505     push_val(env, loop);
1506     eval(env); if(env->err) return;
1507     foo1--;
1508     }
1509     }
1510 masse 1.98 unprotect(loop);
1511 masse 1.89 }
1512    
1513     /* Variant of for-loop */
1514 masse 1.95 extern void foreach(environment *env)
1515     {
1516 masse 1.65 value *loop, *foo;
1517 masse 1.104 value *iterator;
1518 masse 1.65
1519 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
1520 masse 1.65 printerr("Too Few Arguments");
1521 masse 1.90 env->err= 1;
1522 masse 1.65 return;
1523     }
1524    
1525 masse 1.104 if(CAR(CDR(env->head))->type!=tcons) {
1526 masse 1.65 printerr("Bad Argument Type");
1527 masse 1.90 env->err= 2;
1528 masse 1.65 return;
1529     }
1530    
1531 masse 1.104 loop= CAR(env->head);
1532 masse 1.98 protect(loop);
1533 masse 1.65 toss(env); if(env->err) return;
1534    
1535 masse 1.104 foo= CAR(env->head);
1536 masse 1.98 protect(foo);
1537 masse 1.65 toss(env); if(env->err) return;
1538    
1539 masse 1.104 iterator= foo;
1540 masse 1.65
1541     while(iterator!=NULL) {
1542 masse 1.104 push_val(env, CAR(iterator));
1543 masse 1.72 push_val(env, loop);
1544 masse 1.65 eval(env); if(env->err) return;
1545 masse 1.105 if (iterator->type == tcons){
1546 masse 1.104 iterator= CDR(iterator);
1547 teddy 1.103 } else {
1548     printerr("Bad Argument Type"); /* Improper list */
1549     env->err= 2;
1550     break;
1551     }
1552 masse 1.65 }
1553 masse 1.98 unprotect(loop); unprotect(foo);
1554 masse 1.65 }
1555 masse 1.66
1556 teddy 1.85 /* "to" */
1557 masse 1.95 extern void to(environment *env)
1558     {
1559     int ending, start, i;
1560 masse 1.104 value *iterator, *temp;
1561 masse 1.95
1562 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
1563 masse 1.66 printerr("Too Few Arguments");
1564 masse 1.102 env->err= 1;
1565 masse 1.66 return;
1566     }
1567    
1568 masse 1.104 if(CAR(env->head)->type!=integer
1569     || CAR(CDR(env->head))->type!=integer) {
1570 masse 1.66 printerr("Bad Argument Type");
1571 masse 1.102 env->err= 2;
1572 masse 1.66 return;
1573     }
1574    
1575 masse 1.104 ending= CAR(env->head)->content.i;
1576 masse 1.66 toss(env); if(env->err) return;
1577 masse 1.104 start= CAR(env->head)->content.i;
1578 masse 1.66 toss(env); if(env->err) return;
1579    
1580 masse 1.95 push_sym(env, "[");
1581 masse 1.66
1582 masse 1.67 if(ending>=start) {
1583 masse 1.74 for(i= ending; i>=start; i--)
1584 masse 1.72 push_int(env, i);
1585 masse 1.67 } else {
1586 masse 1.74 for(i= ending; i<=start; i++)
1587 masse 1.72 push_int(env, i);
1588 masse 1.67 }
1589 masse 1.66
1590 masse 1.95 iterator= env->head;
1591 masse 1.93
1592 masse 1.95 if(iterator==NULL
1593 masse 1.104 || (CAR(iterator)->type==symb
1594 masse 1.105 && CAR(iterator)->content.sym->id[0]=='[')) {
1595 masse 1.95 temp= NULL;
1596     toss(env);
1597     } else {
1598     /* Search for first delimiter */
1599 masse 1.105 while(CDR(iterator)!=NULL
1600 masse 1.104 && (CAR(CDR(iterator))->type!=symb
1601 masse 1.105 || CAR(CDR(iterator))->content.sym->id[0]!='['))
1602 masse 1.104 iterator= CDR(iterator);
1603 masse 1.95
1604     /* Extract list */
1605     temp= env->head;
1606 masse 1.104 env->head= CDR(iterator);
1607     CDR(iterator)= NULL;
1608 masse 1.95
1609     if(env->head!=NULL)
1610     toss(env);
1611     }
1612    
1613     /* Push list */
1614 masse 1.104 push_val(env, temp);
1615 masse 1.66 }
1616 masse 1.68
1617     /* Read a string */
1618 masse 1.95 extern void readline(environment *env)
1619     {
1620 masse 1.68 char in_string[101];
1621    
1622 teddy 1.84 if(fgets(in_string, 100, env->inputstream)==NULL)
1623     push_cstring(env, "");
1624     else
1625     push_cstring(env, in_string);
1626 masse 1.68 }
1627    
1628 teddy 1.84 /* "read"; Read a value and place on stack */
1629 masse 1.95 extern void sx_72656164(environment *env)
1630     {
1631 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1632     const char strform[]= "\"%[^\"]\"%n";
1633     const char intform[]= "%i%n";
1634 masse 1.93 const char fltform[]= "%f%n";
1635 teddy 1.78 const char blankform[]= "%*[ \t]%n";
1636 masse 1.90 const char ebrackform[]= "]%n";
1637     const char semicform[]= ";%n";
1638     const char bbrackform[]= "[%n";
1639 masse 1.68
1640 teddy 1.78 int itemp, readlength= -1;
1641 masse 1.93 int count= -1;
1642     float ftemp;
1643 masse 1.68 static int depth= 0;
1644 masse 1.93 char *match, *ctemp;
1645 masse 1.68 size_t inlength;
1646    
1647 masse 1.70 if(env->in_string==NULL) {
1648 teddy 1.84 if(depth > 0 && env->interactive) {
1649 teddy 1.80 printf("]> ");
1650     }
1651 masse 1.68 readline(env); if(env->err) return;
1652 teddy 1.84
1653 masse 1.104 if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1654 teddy 1.85 env->err= 4; /* "" means EOF */
1655 teddy 1.84 return;
1656     }
1657 masse 1.68
1658 masse 1.104 env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1659 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
1660 masse 1.104 strcpy(env->in_string, CAR(env->head)->content.ptr);
1661 masse 1.68 toss(env); if(env->err) return;
1662     }
1663    
1664 masse 1.70 inlength= strlen(env->in_string)+1;
1665 masse 1.68 match= malloc(inlength);
1666    
1667 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
1668 teddy 1.78 && readlength != -1) {
1669 masse 1.71 ;
1670 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
1671 teddy 1.78 && readlength != -1) {
1672 masse 1.93 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
1673     && count==readlength) {
1674     push_int(env, itemp);
1675     } else {
1676     push_float(env, ftemp);
1677     }
1678 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1679     && readlength != -1) {
1680 masse 1.72 push_cstring(env, match);
1681 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1682     && readlength != -1) {
1683 masse 1.68 push_sym(env, match);
1684 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1685     && readlength != -1) {
1686 masse 1.68 pack(env); if(env->err) return;
1687 teddy 1.78 if(depth != 0) depth--;
1688     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1689     && readlength != -1) {
1690 masse 1.68 push_sym(env, ";");
1691 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1692     && readlength != -1) {
1693 masse 1.68 push_sym(env, "[");
1694     depth++;
1695     } else {
1696 teddy 1.78 free(env->free_string);
1697     env->in_string = env->free_string = NULL;
1698     }
1699 masse 1.93 if (env->in_string != NULL) {
1700 teddy 1.78 env->in_string += readlength;
1701 masse 1.68 }
1702 masse 1.83
1703     free(match);
1704 masse 1.68
1705 masse 1.71 if(depth)
1706 teddy 1.84 return sx_72656164(env);
1707 teddy 1.91 }
1708    
1709 masse 1.107 #ifdef __linux__
1710 masse 1.95 extern void beep(environment *env)
1711     {
1712 teddy 1.91 int freq, dur, period, ticks;
1713    
1714 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
1715 teddy 1.91 printerr("Too Few Arguments");
1716 masse 1.102 env->err= 1;
1717 teddy 1.91 return;
1718     }
1719    
1720 masse 1.104 if(CAR(env->head)->type!=integer
1721     || CAR(CDR(env->head))->type!=integer) {
1722 teddy 1.91 printerr("Bad Argument Type");
1723 masse 1.102 env->err= 2;
1724 teddy 1.91 return;
1725     }
1726    
1727 masse 1.104 dur= CAR(env->head)->content.i;
1728 teddy 1.91 toss(env);
1729 masse 1.104 freq= CAR(env->head)->content.i;
1730 teddy 1.91 toss(env);
1731    
1732 masse 1.102 period= 1193180/freq; /* convert freq from Hz to period
1733 teddy 1.91 length */
1734 masse 1.102 ticks= dur*.001193180; /* convert duration from µseconds to
1735 teddy 1.91 timer ticks */
1736    
1737     /* ticks=dur/1000; */
1738    
1739 masse 1.102 /* if (ioctl(STDOUT_FILENO, KDMKTONE, (125<<16) + 0x637)==0) */
1740 teddy 1.91 switch (ioctl(STDOUT_FILENO, KDMKTONE, (ticks<<16) | period)){
1741     case 0:
1742     usleep(dur);
1743     return;
1744     case -1:
1745     perror("beep");
1746 masse 1.102 env->err= 5;
1747 teddy 1.91 return;
1748     default:
1749     abort();
1750     }
1751 masse 1.95 }
1752 masse 1.107 #endif /* __linux__ */
1753 teddy 1.91
1754     /* "wait" */
1755 masse 1.95 extern void sx_77616974(environment *env)
1756     {
1757 teddy 1.91 int dur;
1758    
1759 masse 1.102 if(env->head==NULL) {
1760 teddy 1.91 printerr("Too Few Arguments");
1761 masse 1.102 env->err= 1;
1762 teddy 1.91 return;
1763     }
1764    
1765 masse 1.104 if(CAR(env->head)->type!=integer) {
1766 teddy 1.91 printerr("Bad Argument Type");
1767 masse 1.102 env->err= 2;
1768 teddy 1.91 return;
1769     }
1770    
1771 masse 1.104 dur= CAR(env->head)->content.i;
1772 teddy 1.91 toss(env);
1773    
1774     usleep(dur);
1775 masse 1.95 }
1776 teddy 1.91
1777 masse 1.95 extern void copying(environment *env)
1778     {
1779 teddy 1.91 printf("GNU GENERAL PUBLIC LICENSE\n\
1780     Version 2, June 1991\n\
1781     \n\
1782     Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
1783     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
1784     Everyone is permitted to copy and distribute verbatim copies\n\
1785     of this license document, but changing it is not allowed.\n\
1786     \n\
1787     Preamble\n\
1788     \n\
1789     The licenses for most software are designed to take away your\n\
1790     freedom to share and change it. By contrast, the GNU General Public\n\
1791     License is intended to guarantee your freedom to share and change free\n\
1792     software--to make sure the software is free for all its users. This\n\
1793     General Public License applies to most of the Free Software\n\
1794     Foundation's software and to any other program whose authors commit to\n\
1795     using it. (Some other Free Software Foundation software is covered by\n\
1796     the GNU Library General Public License instead.) You can apply it to\n\
1797     your programs, too.\n\
1798     \n\
1799     When we speak of free software, we are referring to freedom, not\n\
1800     price. Our General Public Licenses are designed to make sure that you\n\
1801     have the freedom to distribute copies of free software (and charge for\n\
1802     this service if you wish), that you receive source code or can get it\n\
1803     if you want it, that you can change the software or use pieces of it\n\
1804     in new free programs; and that you know you can do these things.\n\
1805     \n\
1806     To protect your rights, we need to make restrictions that forbid\n\
1807     anyone to deny you these rights or to ask you to surrender the rights.\n\
1808     These restrictions translate to certain responsibilities for you if you\n\
1809     distribute copies of the software, or if you modify it.\n\
1810     \n\
1811     For example, if you distribute copies of such a program, whether\n\
1812     gratis or for a fee, you must give the recipients all the rights that\n\
1813     you have. You must make sure that they, too, receive or can get the\n\
1814     source code. And you must show them these terms so they know their\n\
1815     rights.\n\
1816     \n\
1817     We protect your rights with two steps: (1) copyright the software, and\n\
1818     (2) offer you this license which gives you legal permission to copy,\n\
1819     distribute and/or modify the software.\n\
1820     \n\
1821     Also, for each author's protection and ours, we want to make certain\n\
1822     that everyone understands that there is no warranty for this free\n\
1823     software. If the software is modified by someone else and passed on, we\n\
1824     want its recipients to know that what they have is not the original, so\n\
1825     that any problems introduced by others will not reflect on the original\n\
1826     authors' reputations.\n\
1827     \n\
1828     Finally, any free program is threatened constantly by software\n\
1829     patents. We wish to avoid the danger that redistributors of a free\n\
1830     program will individually obtain patent licenses, in effect making the\n\
1831     program proprietary. To prevent this, we have made it clear that any\n\
1832     patent must be licensed for everyone's free use or not licensed at all.\n\
1833     \n\
1834     The precise terms and conditions for copying, distribution and\n\
1835     modification follow.\n\
1836     \n\
1837     GNU GENERAL PUBLIC LICENSE\n\
1838     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
1839     \n\
1840     0. This License applies to any program or other work which contains\n\
1841     a notice placed by the copyright holder saying it may be distributed\n\
1842     under the terms of this General Public License. The \"Program\", below,\n\
1843     refers to any such program or work, and a \"work based on the Program\"\n\
1844     means either the Program or any derivative work under copyright law:\n\
1845     that is to say, a work containing the Program or a portion of it,\n\
1846     either verbatim or with modifications and/or translated into another\n\
1847     language. (Hereinafter, translation is included without limitation in\n\
1848     the term \"modification\".) Each licensee is addressed as \"you\".\n\
1849     \n\
1850     Activities other than copying, distribution and modification are not\n\
1851     covered by this License; they are outside its scope. The act of\n\
1852     running the Program is not restricted, and the output from the Program\n\
1853     is covered only if its contents constitute a work based on the\n\
1854     Program (independent of having been made by running the Program).\n\
1855     Whether that is true depends on what the Program does.\n\
1856     \n\
1857     1. You may copy and distribute verbatim copies of the Program's\n\
1858     source code as you receive it, in any medium, provided that you\n\
1859     conspicuously and appropriately publish on each copy an appropriate\n\
1860     copyright notice and disclaimer of warranty; keep intact all the\n\
1861     notices that refer to this License and to the absence of any warranty;\n\
1862     and give any other recipients of the Program a copy of this License\n\
1863     along with the Program.\n\
1864     \n\
1865     You may charge a fee for the physical act of transferring a copy, and\n\
1866     you may at your option offer warranty protection in exchange for a fee.\n\
1867     \n\
1868     2. You may modify your copy or copies of the Program or any portion\n\
1869     of it, thus forming a work based on the Program, and copy and\n\
1870     distribute such modifications or work under the terms of Section 1\n\
1871     above, provided that you also meet all of these conditions:\n\
1872     \n\
1873     a) You must cause the modified files to carry prominent notices\n\
1874     stating that you changed the files and the date of any change.\n\
1875     \n\
1876     b) You must cause any work that you distribute or publish, that in\n\
1877     whole or in part contains or is derived from the Program or any\n\
1878     part thereof, to be licensed as a whole at no charge to all third\n\
1879     parties under the terms of this License.\n\
1880     \n\
1881     c) If the modified program normally reads commands interactively\n\
1882     when run, you must cause it, when started running for such\n\
1883     interactive use in the most ordinary way, to print or display an\n\
1884     announcement including an appropriate copyright notice and a\n\
1885     notice that there is no warranty (or else, saying that you provide\n\
1886     a warranty) and that users may redistribute the program under\n\
1887     these conditions, and telling the user how to view a copy of this\n\
1888     License. (Exception: if the Program itself is interactive but\n\
1889     does not normally print such an announcement, your work based on\n\
1890     the Program is not required to print an announcement.)\n\
1891     \n\
1892     These requirements apply to the modified work as a whole. If\n\
1893     identifiable sections of that work are not derived from the Program,\n\
1894     and can be reasonably considered independent and separate works in\n\
1895     themselves, then this License, and its terms, do not apply to those\n\
1896     sections when you distribute them as separate works. But when you\n\
1897     distribute the same sections as part of a whole which is a work based\n\
1898     on the Program, the distribution of the whole must be on the terms of\n\
1899     this License, whose permissions for other licensees extend to the\n\
1900     entire whole, and thus to each and every part regardless of who wrote it.\n\
1901     \n\
1902     Thus, it is not the intent of this section to claim rights or contest\n\
1903     your rights to work written entirely by you; rather, the intent is to\n\
1904     exercise the right to control the distribution of derivative or\n\
1905     collective works based on the Program.\n\
1906     \n\
1907     In addition, mere aggregation of another work not based on the Program\n\
1908     with the Program (or with a work based on the Program) on a volume of\n\
1909     a storage or distribution medium does not bring the other work under\n\
1910     the scope of this License.\n\
1911     \n\
1912     3. You may copy and distribute the Program (or a work based on it,\n\
1913     under Section 2) in object code or executable form under the terms of\n\
1914     Sections 1 and 2 above provided that you also do one of the following:\n\
1915     \n\
1916     a) Accompany it with the complete corresponding machine-readable\n\
1917     source code, which must be distributed under the terms of Sections\n\
1918     1 and 2 above on a medium customarily used for software interchange; or,\n\
1919     \n\
1920     b) Accompany it with a written offer, valid for at least three\n\
1921     years, to give any third party, for a charge no more than your\n\
1922     cost of physically performing source distribution, a complete\n\
1923     machine-readable copy of the corresponding source code, to be\n\
1924     distributed under the terms of Sections 1 and 2 above on a medium\n\
1925     customarily used for software interchange; or,\n\
1926     \n\
1927     c) Accompany it with the information you received as to the offer\n\
1928     to distribute corresponding source code. (This alternative is\n\
1929     allowed only for noncommercial distribution and only if you\n\
1930     received the program in object code or executable form with such\n\
1931     an offer, in accord with Subsection b above.)\n\
1932     \n\
1933     The source code for a work means the preferred form of the work for\n\
1934     making modifications to it. For an executable work, complete source\n\
1935     code means all the source code for all modules it contains, plus any\n\
1936     associated interface definition files, plus the scripts used to\n\
1937     control compilation and installation of the executable. However, as a\n\
1938     special exception, the source code distributed need not include\n\
1939     anything that is normally distributed (in either source or binary\n\
1940     form) with the major components (compiler, kernel, and so on) of the\n\
1941     operating system on which the executable runs, unless that component\n\
1942     itself accompanies the executable.\n\
1943     \n\
1944     If distribution of executable or object code is made by offering\n\
1945     access to copy from a designated place, then offering equivalent\n\
1946     access to copy the source code from the same place counts as\n\
1947     distribution of the source code, even though third parties are not\n\
1948     compelled to copy the source along with the object code.\n\
1949     \n\
1950     4. You may not copy, modify, sublicense, or distribute the Program\n\
1951     except as expressly provided under this License. Any attempt\n\
1952     otherwise to copy, modify, sublicense or distribute the Program is\n\
1953     void, and will automatically terminate your rights under this License.\n\
1954     However, parties who have received copies, or rights, from you under\n\
1955     this License will not have their licenses terminated so long as such\n\
1956     parties remain in full compliance.\n\
1957     \n\
1958     5. You are not required to accept this License, since you have not\n\
1959     signed it. However, nothing else grants you permission to modify or\n\
1960     distribute the Program or its derivative works. These actions are\n\
1961     prohibited by law if you do not accept this License. Therefore, by\n\
1962     modifying or distributing the Program (or any work based on the\n\
1963     Program), you indicate your acceptance of this License to do so, and\n\
1964     all its terms and conditions for copying, distributing or modifying\n\
1965     the Program or works based on it.\n\
1966     \n\
1967     6. Each time you redistribute the Program (or any work based on the\n\
1968     Program), the recipient automatically receives a license from the\n\
1969     original licensor to copy, distribute or modify the Program subject to\n\
1970     these terms and conditions. You may not impose any further\n\
1971     restrictions on the recipients' exercise of the rights granted herein.\n\
1972     You are not responsible for enforcing compliance by third parties to\n\
1973     this License.\n\
1974     \n\
1975     7. If, as a consequence of a court judgment or allegation of patent\n\
1976     infringement or for any other reason (not limited to patent issues),\n\
1977     conditions are imposed on you (whether by court order, agreement or\n\
1978     otherwise) that contradict the conditions of this License, they do not\n\
1979     excuse you from the conditions of this License. If you cannot\n\
1980     distribute so as to satisfy simultaneously your obligations under this\n\
1981     License and any other pertinent obligations, then as a consequence you\n\
1982     may not distribute the Program at all. For example, if a patent\n\
1983     license would not permit royalty-free redistribution of the Program by\n\
1984     all those who receive copies directly or indirectly through you, then\n\
1985     the only way you could satisfy both it and this License would be to\n\
1986     refrain entirely from distribution of the Program.\n\
1987     \n\
1988     If any portion of this section is held invalid or unenforceable under\n\
1989     any particular circumstance, the balance of the section is intended to\n\
1990     apply and the section as a whole is intended to apply in other\n\
1991     circumstances.\n\
1992     \n\
1993     It is not the purpose of this section to induce you to infringe any\n\
1994     patents or other property right claims or to contest validity of any\n\
1995     such claims; this section has the sole purpose of protecting the\n\
1996     integrity of the free software distribution system, which is\n\
1997     implemented by public license practices. Many people have made\n\
1998     generous contributions to the wide range of software distributed\n\
1999     through that system in reliance on consistent application of that\n\
2000     system; it is up to the author/donor to decide if he or she is willing\n\
2001     to distribute software through any other system and a licensee cannot\n\
2002     impose that choice.\n\
2003     \n\
2004     This section is intended to make thoroughly clear what is believed to\n\
2005     be a consequence of the rest of this License.\n\
2006     \n\
2007     8. If the distribution and/or use of the Program is restricted in\n\
2008     certain countries either by patents or by copyrighted interfaces, the\n\
2009     original copyright holder who places the Program under this License\n\
2010     may add an explicit geographical distribution limitation excluding\n\
2011     those countries, so that distribution is permitted only in or among\n\
2012     countries not thus excluded. In such case, this License incorporates\n\
2013     the limitation as if written in the body of this License.\n\
2014     \n\
2015     9. The Free Software Foundation may publish revised and/or new versions\n\
2016     of the General Public License from time to time. Such new versions will\n\
2017     be similar in spirit to the present version, but may differ in detail to\n\
2018     address new problems or concerns.\n\
2019     \n\
2020     Each version is given a distinguishing version number. If the Program\n\
2021     specifies a version number of this License which applies to it and \"any\n\
2022     later version\", you have the option of following the terms and conditions\n\
2023     either of that version or of any later version published by the Free\n\
2024     Software Foundation. If the Program does not specify a version number of\n\
2025     this License, you may choose any version ever published by the Free Software\n\
2026     Foundation.\n\
2027     \n\
2028     10. If you wish to incorporate parts of the Program into other free\n\
2029     programs whose distribution conditions are different, write to the author\n\
2030     to ask for permission. For software which is copyrighted by the Free\n\
2031     Software Foundation, write to the Free Software Foundation; we sometimes\n\
2032     make exceptions for this. Our decision will be guided by the two goals\n\
2033     of preserving the free status of all derivatives of our free software and\n\
2034     of promoting the sharing and reuse of software generally.\n");
2035     }
2036    
2037 masse 1.95 extern void warranty(environment *env)
2038     {
2039 teddy 1.91 printf(" NO WARRANTY\n\
2040     \n\
2041     11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
2042     FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
2043     OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
2044     PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
2045     OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
2046     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
2047     TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
2048     PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
2049     REPAIR OR CORRECTION.\n\
2050     \n\
2051     12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
2052     WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
2053     REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
2054     INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
2055     OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
2056     TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
2057     YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
2058     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
2059     POSSIBILITY OF SUCH DAMAGES.\n");
2060 masse 1.92 }
2061    
2062     /* "*" */
2063     extern void sx_2a(environment *env)
2064     {
2065     int a, b;
2066 masse 1.93 float fa, fb;
2067 masse 1.92
2068 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
2069 masse 1.92 printerr("Too Few Arguments");
2070 masse 1.102 env->err= 1;
2071 masse 1.92 return;
2072     }
2073    
2074 masse 1.104 if(CAR(env->head)->type==integer
2075     && CAR(CDR(env->head))->type==integer) {
2076     a= CAR(env->head)->content.i;
2077 masse 1.93 toss(env); if(env->err) return;
2078 masse 1.104 b= CAR(env->head)->content.i;
2079 masse 1.93 toss(env); if(env->err) return;
2080     push_int(env, b*a);
2081    
2082     return;
2083     }
2084    
2085 masse 1.104 if(CAR(env->head)->type==tfloat
2086     && CAR(CDR(env->head))->type==tfloat) {
2087     fa= CAR(env->head)->content.f;
2088 masse 1.93 toss(env); if(env->err) return;
2089 masse 1.104 fb= CAR(env->head)->content.f;
2090 masse 1.93 toss(env); if(env->err) return;
2091     push_float(env, fb*fa);
2092    
2093     return;
2094     }
2095    
2096 masse 1.104 if(CAR(env->head)->type==tfloat
2097     && CAR(CDR(env->head))->type==integer) {
2098     fa= CAR(env->head)->content.f;
2099 masse 1.93 toss(env); if(env->err) return;
2100 masse 1.104 b= CAR(env->head)->content.i;
2101 masse 1.93 toss(env); if(env->err) return;
2102     push_float(env, b*fa);
2103    
2104     return;
2105     }
2106    
2107 masse 1.104 if(CAR(env->head)->type==integer
2108     && CAR(CDR(env->head))->type==tfloat) {
2109     a= CAR(env->head)->content.i;
2110 masse 1.93 toss(env); if(env->err) return;
2111 masse 1.104 fb= CAR(env->head)->content.f;
2112 masse 1.93 toss(env); if(env->err) return;
2113     push_float(env, fb*a);
2114    
2115 masse 1.92 return;
2116     }
2117    
2118 masse 1.93 printerr("Bad Argument Type");
2119 masse 1.102 env->err= 2;
2120 masse 1.92 }
2121    
2122     /* "/" */
2123     extern void sx_2f(environment *env)
2124     {
2125     int a, b;
2126 masse 1.93 float fa, fb;
2127 masse 1.92
2128 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
2129 masse 1.92 printerr("Too Few Arguments");
2130 masse 1.102 env->err= 1;
2131 masse 1.92 return;
2132     }
2133    
2134 masse 1.104 if(CAR(env->head)->type==integer
2135     && CAR(CDR(env->head))->type==integer) {
2136     a= CAR(env->head)->content.i;
2137 masse 1.93 toss(env); if(env->err) return;
2138 masse 1.104 b= CAR(env->head)->content.i;
2139 masse 1.93 toss(env); if(env->err) return;
2140     push_float(env, b/a);
2141    
2142     return;
2143     }
2144    
2145 masse 1.104 if(CAR(env->head)->type==tfloat
2146     && CAR(CDR(env->head))->type==tfloat) {
2147     fa= CAR(env->head)->content.f;
2148 masse 1.93 toss(env); if(env->err) return;
2149 masse 1.104 fb= CAR(env->head)->content.f;
2150 masse 1.93 toss(env); if(env->err) return;
2151     push_float(env, fb/fa);
2152    
2153     return;
2154     }
2155    
2156 masse 1.104 if(CAR(env->head)->type==tfloat
2157     && CAR(CDR(env->head))->type==integer) {
2158     fa= CAR(env->head)->content.f;
2159 masse 1.93 toss(env); if(env->err) return;
2160 masse 1.104 b= CAR(env->head)->content.i;
2161 masse 1.93 toss(env); if(env->err) return;
2162     push_float(env, b/fa);
2163    
2164     return;
2165     }
2166    
2167 masse 1.104 if(CAR(env->head)->type==integer
2168     && CAR(CDR(env->head))->type==tfloat) {
2169     a= CAR(env->head)->content.i;
2170 masse 1.93 toss(env); if(env->err) return;
2171 masse 1.104 fb= CAR(env->head)->content.f;
2172 masse 1.93 toss(env); if(env->err) return;
2173     push_float(env, fb/a);
2174    
2175 masse 1.92 return;
2176     }
2177    
2178 masse 1.93 printerr("Bad Argument Type");
2179 masse 1.102 env->err= 2;
2180 masse 1.92 }
2181    
2182     /* "mod" */
2183     extern void mod(environment *env)
2184     {
2185     int a, b;
2186    
2187 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
2188 masse 1.92 printerr("Too Few Arguments");
2189 masse 1.94 env->err= 1;
2190 masse 1.92 return;
2191     }
2192    
2193 masse 1.104 if(CAR(env->head)->type==integer
2194     && CAR(CDR(env->head))->type==integer) {
2195     a= CAR(env->head)->content.i;
2196 masse 1.93 toss(env); if(env->err) return;
2197 masse 1.104 b= CAR(env->head)->content.i;
2198 masse 1.93 toss(env); if(env->err) return;
2199     push_int(env, b%a);
2200    
2201 masse 1.92 return;
2202     }
2203    
2204 masse 1.93 printerr("Bad Argument Type");
2205 masse 1.102 env->err= 2;
2206 masse 1.94 }
2207    
2208     /* "div" */
2209     extern void sx_646976(environment *env)
2210     {
2211     int a, b;
2212    
2213 masse 1.104 if(env->head==NULL || CDR(env->head)==NULL) {
2214 masse 1.94 printerr("Too Few Arguments");
2215     env->err= 1;
2216     return;
2217     }
2218    
2219 masse 1.104 if(CAR(env->head)->type==integer
2220     && CAR(CDR(env->head))->type==integer) {
2221     a= CAR(env->head)->content.i;
2222 masse 1.94 toss(env); if(env->err) return;
2223 masse 1.104 b= CAR(env->head)->content.i;
2224 masse 1.94 toss(env); if(env->err) return;
2225     push_int(env, (int)b/a);
2226    
2227     return;
2228     }
2229    
2230     printerr("Bad Argument Type");
2231     env->err= 2;
2232 masse 1.68 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26