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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.101 - (hide annotations)
Sun Mar 10 13:00:01 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.100: +9 -4 lines
File MIME type: text/plain
stack.c (gc_init): printf format bug fix.
(gc_init): Also decrease gc_count by length of strings.
(push_cstring): Increase gc_count by string length.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26