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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.95 - (hide annotations)
Sun Mar 10 06:34:01 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.94: +123 -63 lines
File MIME type: text/plain
Cosmetic changes.
stack.c (to): Rewritten to mimic behaviour of "pack".

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26