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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.107 - (hide annotations)
Tue Mar 12 21:05:11 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.106: +10 -1 lines
File MIME type: text/plain
stack.c (beep): #ifdef'ed out if not linux.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26