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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.104 - (hide annotations)
Tue Mar 12 14:06:05 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.103: +272 -294 lines
File MIME type: text/plain
stack.c:
(CAR, CDR): New macros. All callers changed.

stack.h:
(environment.head): Changed type to "*value". All callers changed.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26