Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / bc / dc / eval.c
blob21592d932ae6a6231b625dc264f7d1b8398f14bc
1 /*
2 * evaluate the dc language, from a FILE* or a string
4 * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can either send email to this
18 * program's author (see below) or write to:
19 * The Free Software Foundation, Inc.
20 * 59 Temple Place, Suite 330
21 * Boston, MA 02111 USA
24 /* This is the only module which knows about the dc input language */
26 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_STRING_H
30 # include <string.h> /* memchr */
31 #else
32 # ifdef HAVE_MEMORY_H
33 # include <memory.h> /* memchr, maybe */
34 # else
35 # ifdef HAVE_STRINGS_H
36 # include <strings.h> /* memchr, maybe */
37 # endif
38 #endif
39 #endif
40 #include "dc.h"
41 #include "dc-proto.h"
43 typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
45 typedef enum {
46 DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
47 DC_EATONE, /* caller needs to eat the lookahead char */
48 DC_QUIT, /* quit out of unwind_depth levels of evaluation */
50 /* with the following return values, the caller does not have to
51 * fret about stdin_lookahead's value
53 DC_INT, /* caller needs to parse a dc_num from input stream */
54 DC_STR, /* caller needs to parse a dc_str from input stream */
55 DC_SYSTEM, /* caller needs to run a system() on next input line */
56 DC_COMMENT, /* caller needs to skip to the next input line */
57 DC_NEGCMP, /* caller needs to re-call dc_func() with `negcmp' set */
59 DC_EOF_ERROR /* unexpected end of input; abort current eval */
60 } dc_status;
62 static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */
63 static int dc_obase=10; /* output base, 2 <= dc_obase */
64 static int dc_scale=0; /* scale (see user documentaton) */
66 /* for Quitting evaluations */
67 static int unwind_depth=0;
69 /* if true, active Quit will not exit program */
70 static dc_boolean unwind_noexit=DC_FALSE;
73 * Used to synchronize lookahead on stdin for '?' command.
74 * If set to EOF then lookahead is used up.
76 static int stdin_lookahead=EOF;
79 /* input_fil and input_str are passed as arguments to dc_getnum */
81 /* used by the input_* functions: */
82 static FILE *input_fil_fp;
83 static const char *input_str_string;
85 /* Since we have a need for two characters of pushback, and
86 * ungetc() only guarantees one, we place the second pushback here
88 static int input_pushback;
90 /* passed as an argument to dc_getnum */
91 static int
92 input_fil DC_DECLVOID()
94 if (input_pushback != EOF){
95 int c = input_pushback;
96 input_pushback = EOF;
97 return c;
99 return getc(input_fil_fp);
102 /* passed as an argument to dc_getnum */
103 static int
104 input_str DC_DECLVOID()
106 if (!*input_str_string)
107 return EOF;
108 return *input_str_string++;
113 /* takes a string and evals it; frees the string when done */
114 /* Wrapper around dc_evalstr to avoid duplicating the free call
115 * at all possible return points.
117 static int
118 dc_eval_and_free_str DC_DECLARG((string))
119 dc_data string DC_DECLEND
121 dc_status status;
123 status = dc_evalstr(string);
124 if (string.dc_type == DC_STRING)
125 dc_free_str(&string.v.string);
126 return status;
130 /* dc_func does the grunt work of figuring out what each input
131 * character means; used by both dc_evalstr and dc_evalfile
133 * c -> the "current" input character under consideration
134 * peekc -> the lookahead input character
135 * negcmp -> negate comparison test (for <,=,> commands)
137 static dc_status
138 dc_func DC_DECLARG((c, peekc, negcmp))
139 int c DC_DECLSEP
140 int peekc DC_DECLSEP
141 int negcmp DC_DECLEND
143 /* we occasionally need these for temporary data */
144 /* Despite the GNU coding standards, it is much easier
145 * to have these declared once here, since this function
146 * is just one big switch statement.
148 dc_data datum;
149 int tmpint;
151 switch (c){
152 case '_': case '.':
153 case '0': case '1': case '2': case '3':
154 case '4': case '5': case '6': case '7':
155 case '8': case '9': case 'A': case 'B':
156 case 'C': case 'D': case 'E': case 'F':
157 return DC_INT;
158 case ' ':
159 case '\t':
160 case '\n':
161 /* standard command separators */
162 break;
164 case '+': /* add top two stack elements */
165 dc_binop(dc_add, dc_scale);
166 break;
167 case '-': /* subtract top two stack elements */
168 dc_binop(dc_sub, dc_scale);
169 break;
170 case '*': /* multiply top two stack elements */
171 dc_binop(dc_mul, dc_scale);
172 break;
173 case '/': /* divide top two stack elements */
174 dc_binop(dc_div, dc_scale);
175 break;
176 case '%':
177 /* take the remainder from division of the top two stack elements */
178 dc_binop(dc_rem, dc_scale);
179 break;
180 case '~':
181 /* Do division on the top two stack elements. Return the
182 * quotient as next-to-top of stack and the remainder as
183 * top-of-stack.
185 dc_binop2(dc_divrem, dc_scale);
186 break;
187 case '|':
188 /* Consider the top three elements of the stack as (base, exp, mod),
189 * where mod is top-of-stack, exp is next-to-top, and base is
190 * second-from-top. Mod must be non-zero, exp must be non-negative,
191 * and all three must be integers. Push the result of raising
192 * base to the exp power, reduced modulo mod. If we had base in
193 * register b, exp in register e, and mod in register m then this
194 * is conceptually equivalent to "lble^lm%", but it is implemented
195 * in a more efficient manner, and can handle arbritrarily large
196 * values for exp.
198 dc_triop(dc_modexp, dc_scale);
199 break;
200 case '^': /* exponientiation of the top two stack elements */
201 dc_binop(dc_exp, dc_scale);
202 break;
203 case '<':
204 /* eval register named by peekc if
205 * less-than holds for top two stack elements
207 if (peekc == EOF)
208 return DC_EOF_ERROR;
209 if ( (dc_cmpop() < 0) == !negcmp )
210 if (dc_register_get(peekc, &datum) == DC_SUCCESS)
211 if (dc_eval_and_free_str(datum) == DC_QUIT)
212 return DC_QUIT;
213 return DC_EATONE;
214 case '=':
215 /* eval register named by peekc if
216 * equal-to holds for top two stack elements
218 if (peekc == EOF)
219 return DC_EOF_ERROR;
220 if ( (dc_cmpop() == 0) == !negcmp )
221 if (dc_register_get(peekc, &datum) == DC_SUCCESS)
222 if (dc_eval_and_free_str(datum) == DC_QUIT)
223 return DC_QUIT;
224 return DC_EATONE;
225 case '>':
226 /* eval register named by peekc if
227 * greater-than holds for top two stack elements
229 if (peekc == EOF)
230 return DC_EOF_ERROR;
231 if ( (dc_cmpop() > 0) == !negcmp )
232 if (dc_register_get(peekc, &datum) == DC_SUCCESS)
233 if (dc_eval_and_free_str(datum) == DC_QUIT)
234 return DC_QUIT;
235 return DC_EATONE;
236 case '?': /* read a line from standard-input and eval it */
237 if (stdin_lookahead != EOF){
238 ungetc(stdin_lookahead, stdin);
239 stdin_lookahead = EOF;
241 if (dc_eval_and_free_str(dc_readstring(stdin, '\n', '\n')) == DC_QUIT)
242 return DC_QUIT;
243 return DC_OKAY;
244 case '[': /* read to balancing ']' into a dc_str */
245 return DC_STR;
246 case '!': /* read to newline and call system() on resulting string */
247 if (peekc == '<' || peekc == '=' || peekc == '>')
248 return DC_NEGCMP;
249 return DC_SYSTEM;
250 case '#': /* comment; skip remainder of current line */
251 return DC_COMMENT;
253 case 'a': /* Convert top of stack to an ascii character. */
254 if (dc_pop(&datum) == DC_SUCCESS){
255 char tmps;
256 if (datum.dc_type == DC_NUMBER){
257 tmps = (char) dc_num2int(datum.v.number, DC_TOSS);
258 }else if (datum.dc_type == DC_STRING){
259 tmps = *dc_str2charp(datum.v.string);
260 dc_free_str(&datum.v.string);
261 }else{
262 dc_garbage("at top of stack", -1);
264 dc_push(dc_makestring(&tmps, 1));
266 break;
267 case 'c': /* clear whole stack */
268 dc_clear_stack();
269 break;
270 case 'd': /* duplicate the datum on the top of stack */
271 if (dc_top_of_stack(&datum) == DC_SUCCESS)
272 dc_push(dc_dup(datum));
273 break;
274 case 'f': /* print list of all stack items */
275 dc_printall(dc_obase);
276 break;
277 case 'i': /* set input base to value on top of stack */
278 if (dc_pop(&datum) == DC_SUCCESS){
279 tmpint = 0;
280 if (datum.dc_type == DC_NUMBER)
281 tmpint = dc_num2int(datum.v.number, DC_TOSS);
282 if ( ! (2 <= tmpint && tmpint <= DC_IBASE_MAX) )
283 fprintf(stderr,
284 "%s: input base must be a number \
285 between 2 and %d (inclusive)\n",
286 progname, DC_IBASE_MAX);
287 else
288 dc_ibase = tmpint;
290 break;
291 case 'k': /* set scale to value on top of stack */
292 if (dc_pop(&datum) == DC_SUCCESS){
293 tmpint = -1;
294 if (datum.dc_type == DC_NUMBER)
295 tmpint = dc_num2int(datum.v.number, DC_TOSS);
296 if ( ! (tmpint >= 0) )
297 fprintf(stderr,
298 "%s: scale must be a nonnegative number\n",
299 progname);
300 else
301 dc_scale = tmpint;
303 break;
304 case 'l': /* "load" -- push value on top of register stack named
305 * by peekc onto top of evaluation stack; does not
306 * modify the register stack
308 if (peekc == EOF)
309 return DC_EOF_ERROR;
310 if (dc_register_get(peekc, &datum) == DC_SUCCESS)
311 dc_push(datum);
312 return DC_EATONE;
313 case 'n': /* print the value popped off of top-of-stack;
314 * do not add a trailing newline
316 if (dc_pop(&datum) == DC_SUCCESS)
317 dc_print(datum, dc_obase, DC_NONL, DC_TOSS);
318 break;
319 case 'o': /* set output base to value on top of stack */
320 if (dc_pop(&datum) == DC_SUCCESS){
321 tmpint = 0;
322 if (datum.dc_type == DC_NUMBER)
323 tmpint = dc_num2int(datum.v.number, DC_TOSS);
324 if ( ! (tmpint > 1) )
325 fprintf(stderr,
326 "%s: output base must be a number greater than 1\n",
327 progname);
328 else
329 dc_obase = tmpint;
331 break;
332 case 'p': /* print the datum on the top of stack,
333 * with a trailing newline
335 if (dc_top_of_stack(&datum) == DC_SUCCESS)
336 dc_print(datum, dc_obase, DC_WITHNL, DC_KEEP);
337 break;
338 case 'q': /* quit two levels of evaluation, posibly exiting program */
339 unwind_depth = 1; /* the return below is the first level of returns */
340 unwind_noexit = DC_FALSE;
341 return DC_QUIT;
342 case 'r': /* rotate (swap) the top two elements on the stack
344 if (dc_pop(&datum) == DC_SUCCESS) {
345 dc_data datum2;
346 int two_status;
347 two_status = dc_pop(&datum2);
348 dc_push(datum);
349 if (two_status == DC_SUCCESS)
350 dc_push(datum2);
352 break;
353 case 's': /* "store" -- replace top of register stack named
354 * by peekc with the value popped from the top
355 * of the evaluation stack
357 if (peekc == EOF)
358 return DC_EOF_ERROR;
359 if (dc_pop(&datum) == DC_SUCCESS)
360 dc_register_set(peekc, datum);
361 return DC_EATONE;
362 case 'v': /* replace top of stack with its square root */
363 if (dc_pop(&datum) == DC_SUCCESS){
364 dc_num tmpnum;
365 if (datum.dc_type != DC_NUMBER){
366 fprintf(stderr,
367 "%s: square root of nonnumeric attempted\n",
368 progname);
369 }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
370 dc_free_num(&datum.v.number);
371 datum.v.number = tmpnum;
372 dc_push(datum);
375 break;
376 case 'x': /* eval the datum popped from top of stack */
377 if (dc_pop(&datum) == DC_SUCCESS){
378 if (datum.dc_type == DC_STRING){
379 if (dc_eval_and_free_str(datum) == DC_QUIT)
380 return DC_QUIT;
381 }else if (datum.dc_type == DC_NUMBER){
382 dc_push(datum);
383 }else{
384 dc_garbage("at top of stack", -1);
387 break;
388 case 'z': /* push the current stack depth onto the top of stack */
389 dc_push(dc_int2data(dc_tell_stackdepth()));
390 break;
392 case 'I': /* push the current input base onto the stack */
393 dc_push(dc_int2data(dc_ibase));
394 break;
395 case 'K': /* push the current scale onto the stack */
396 dc_push(dc_int2data(dc_scale));
397 break;
398 case 'L': /* pop a value off of register stack named by peekc
399 * and push it onto the evaluation stack
401 if (peekc == EOF)
402 return DC_EOF_ERROR;
403 if (dc_register_pop(peekc, &datum) == DC_SUCCESS)
404 dc_push(datum);
405 return DC_EATONE;
406 case 'O': /* push the current output base onto the stack */
407 dc_push(dc_int2data(dc_obase));
408 break;
409 case 'P':
410 /* Pop the value off the top of a stack. If it is
411 * a number, dump out the integer portion of its
412 * absolute value as a "base UCHAR_MAX+1" byte stream;
413 * if it is a string, just print it.
414 * In either case, do not append a trailing newline.
416 if (dc_pop(&datum) == DC_SUCCESS){
417 if (datum.dc_type == DC_NUMBER)
418 dc_dump_num(datum.v.number, DC_TOSS);
419 else if (datum.dc_type == DC_STRING)
420 dc_out_str(datum.v.string, DC_NONL, DC_TOSS);
421 else
422 dc_garbage("at top of stack", -1);
424 break;
425 case 'Q': /* quit out of top-of-stack nested evals;
426 * pops value from stack;
427 * does not exit program (stops short if necessary)
429 if (dc_pop(&datum) == DC_SUCCESS){
430 unwind_depth = 0;
431 unwind_noexit = DC_TRUE;
432 if (datum.dc_type == DC_NUMBER)
433 unwind_depth = dc_num2int(datum.v.number, DC_TOSS);
434 if (unwind_depth-- > 0)
435 return DC_QUIT;
436 unwind_depth = 0; /* paranoia */
437 fprintf(stderr,
438 "%s: Q command requires a number >= 1\n",
439 progname);
441 break;
442 #if 0
443 case 'R': /* pop a value off of the evaluation stack,;
444 * rotate the top
445 remaining stack elements that many
446 * places forward (negative numbers mean rotate
447 * backward).
449 if (dc_pop(&datum) == DC_SUCCESS){
450 tmpint = 0;
451 if (datum.dc_type == DC_NUMBER)
452 tmpint = dc_num2int(datum.v.number, DC_TOSS);
453 dc_stack_rotate(tmpint);
455 break;
456 #endif
457 case 'S': /* pop a value off of the evaluation stack
458 * and push it onto the register stack named by peekc
460 if (peekc == EOF)
461 return DC_EOF_ERROR;
462 if (dc_pop(&datum) == DC_SUCCESS)
463 dc_register_push(peekc, datum);
464 return DC_EATONE;
465 case 'X': /* replace the number on top-of-stack with its scale factor */
466 if (dc_pop(&datum) == DC_SUCCESS){
467 tmpint = 0;
468 if (datum.dc_type == DC_NUMBER)
469 tmpint = dc_tell_scale(datum.v.number, DC_TOSS);
470 dc_push(dc_int2data(tmpint));
472 break;
473 case 'Z': /* replace the datum on the top-of-stack with its length */
474 if (dc_pop(&datum) == DC_SUCCESS)
475 dc_push(dc_int2data(dc_tell_length(datum, DC_TOSS)));
476 break;
478 case ':': /* store into array */
479 if (peekc == EOF)
480 return DC_EOF_ERROR;
481 if (dc_pop(&datum) == DC_SUCCESS){
482 tmpint = -1;
483 if (datum.dc_type == DC_NUMBER)
484 tmpint = dc_num2int(datum.v.number, DC_TOSS);
485 if (dc_pop(&datum) == DC_SUCCESS){
486 if (tmpint < 0)
487 fprintf(stderr,
488 "%s: array index must be a nonnegative integer\n",
489 progname);
490 else
491 dc_array_set(peekc, tmpint, datum);
494 return DC_EATONE;
495 case ';': /* retreive from array */
496 if (peekc == EOF)
497 return DC_EOF_ERROR;
498 if (dc_pop(&datum) == DC_SUCCESS){
499 tmpint = -1;
500 if (datum.dc_type == DC_NUMBER)
501 tmpint = dc_num2int(datum.v.number, DC_TOSS);
502 if (tmpint < 0)
503 fprintf(stderr,
504 "%s: array index must be a nonnegative integer\n",
505 progname);
506 else
507 dc_push(dc_array_get(peekc, tmpint));
509 return DC_EATONE;
511 default: /* What did that user mean? */
512 fprintf(stderr, "%s: ", progname);
513 dc_show_id(stdout, c, " unimplemented\n");
514 break;
516 return DC_OKAY;
520 /* takes a string and evals it */
522 dc_evalstr DC_DECLARG((string))
523 dc_data string DC_DECLEND
525 const char *s;
526 const char *end;
527 const char *p;
528 size_t len;
529 int c;
530 int peekc;
531 int count;
532 int negcmp;
533 int next_negcmp = 0;
535 if (string.dc_type != DC_STRING){
536 fprintf(stderr,
537 "%s: eval called with non-string argument\n",
538 progname);
539 return DC_OKAY;
541 s = dc_str2charp(string.v.string);
542 end = s + dc_strlen(string.v.string);
543 while (s < end){
544 c = *(const unsigned char *)s++;
545 peekc = EOF;
546 if (s < end)
547 peekc = *(const unsigned char *)s;
548 negcmp = next_negcmp;
549 next_negcmp = 0;
550 switch (dc_func(c, peekc, negcmp)){
551 case DC_OKAY:
552 break;
553 case DC_EATONE:
554 if (peekc != EOF)
555 ++s;
556 break;
557 case DC_QUIT:
558 if (unwind_depth > 0){
559 --unwind_depth;
560 return DC_QUIT;
562 return DC_OKAY;
564 case DC_INT:
565 input_str_string = s - 1;
566 dc_push(dc_getnum(input_str, dc_ibase, &peekc));
567 s = input_str_string;
568 if (peekc != EOF)
569 --s;
570 break;
571 case DC_STR:
572 count = 1;
573 for (p=s; p<end && count>0; ++p)
574 if (*p == ']')
575 --count;
576 else if (*p == '[')
577 ++count;
578 len = p - s;
579 dc_push(dc_makestring(s, len-1));
580 s = p;
581 break;
582 case DC_SYSTEM:
583 s = dc_system(s);
584 case DC_COMMENT:
585 s = memchr(s, '\n', (size_t)(end-s));
586 if (!s)
587 s = end;
588 else
589 ++s;
590 break;
591 case DC_NEGCMP:
592 next_negcmp = 1;
593 break;
595 case DC_EOF_ERROR:
596 fprintf(stderr, "%s: unexpected EOS\n", progname);
597 return DC_OKAY;
600 return DC_OKAY;
604 /* This is the main function of the whole DC program.
605 * Reads the file described by fp, calls dc_func to do
606 * the dirty work, and takes care of dc_func's shortcomings.
609 dc_evalfile DC_DECLARG((fp))
610 FILE *fp DC_DECLEND
612 int c;
613 int peekc;
614 int negcmp;
615 int next_negcmp = 0;
616 dc_data datum;
618 stdin_lookahead = EOF;
619 for (c=getc(fp); c!=EOF; c=peekc){
620 peekc = getc(fp);
622 * The following if() is the only place where ``stdin_lookahead''
623 * might be set to other than EOF:
625 if (fp == stdin)
626 stdin_lookahead = peekc;
627 negcmp = next_negcmp;
628 next_negcmp = 0;
629 switch (dc_func(c, peekc, negcmp)){
630 case DC_OKAY:
631 if (stdin_lookahead != peekc && fp == stdin)
632 peekc = getc(fp);
633 break;
634 case DC_EATONE:
635 peekc = getc(fp);
636 break;
637 case DC_QUIT:
638 if (unwind_noexit != DC_TRUE)
639 return DC_SUCCESS;
640 fprintf(stderr,
641 "%s: Q command argument exceeded string execution depth\n",
642 progname);
643 if (stdin_lookahead != peekc && fp == stdin)
644 peekc = getc(fp);
645 break;
647 case DC_INT:
648 input_fil_fp = fp;
649 input_pushback = c;
650 ungetc(peekc, fp);
651 dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
652 break;
653 case DC_STR:
654 ungetc(peekc, fp);
655 datum = dc_readstring(fp, '[', ']');
656 dc_push(datum);
657 peekc = getc(fp);
658 break;
659 case DC_SYSTEM:
660 ungetc(peekc, fp);
661 datum = dc_readstring(stdin, '\n', '\n');
662 (void)dc_system(dc_str2charp(datum.v.string));
663 dc_free_str(&datum.v.string);
664 peekc = getc(fp);
665 break;
666 case DC_COMMENT:
667 while (peekc!=EOF && peekc!='\n')
668 peekc = getc(fp);
669 if (peekc != EOF)
670 peekc = getc(fp);
671 break;
672 case DC_NEGCMP:
673 next_negcmp = 1;
674 break;
676 case DC_EOF_ERROR:
677 fprintf(stderr, "%s: unexpected EOF\n", progname);
678 return DC_FAIL;
681 return DC_SUCCESS;