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)
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 */
30 # include <string.h> /* memchr */
33 # include <memory.h> /* memchr, maybe */
35 # ifdef HAVE_STRINGS_H
36 # include <strings.h> /* memchr, maybe */
43 typedef enum {DC_FALSE
, DC_TRUE
} dc_boolean
;
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 */
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 */
92 input_fil
DC_DECLVOID()
94 if (input_pushback
!= EOF
){
95 int c
= input_pushback
;
99 return getc(input_fil_fp
);
102 /* passed as an argument to dc_getnum */
104 input_str
DC_DECLVOID()
106 if (!*input_str_string
)
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.
118 dc_eval_and_free_str
DC_DECLARG((string
))
119 dc_data string DC_DECLEND
123 status
= dc_evalstr(string
);
124 if (string
.dc_type
== DC_STRING
)
125 dc_free_str(&string
.v
.string
);
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)
138 dc_func
DC_DECLARG((c
, peekc
, negcmp
))
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.
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':
161 /* standard command separators */
164 case '+': /* add top two stack elements */
165 dc_binop(dc_add
, dc_scale
);
167 case '-': /* subtract top two stack elements */
168 dc_binop(dc_sub
, dc_scale
);
170 case '*': /* multiply top two stack elements */
171 dc_binop(dc_mul
, dc_scale
);
173 case '/': /* divide top two stack elements */
174 dc_binop(dc_div
, dc_scale
);
177 /* take the remainder from division of the top two stack elements */
178 dc_binop(dc_rem
, dc_scale
);
181 /* Do division on the top two stack elements. Return the
182 * quotient as next-to-top of stack and the remainder as
185 dc_binop2(dc_divrem
, dc_scale
);
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
198 dc_triop(dc_modexp
, dc_scale
);
200 case '^': /* exponientiation of the top two stack elements */
201 dc_binop(dc_exp
, dc_scale
);
204 /* eval register named by peekc if
205 * less-than holds for top two stack elements
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
)
215 /* eval register named by peekc if
216 * equal-to holds for top two stack elements
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
)
226 /* eval register named by peekc if
227 * greater-than holds for top two stack elements
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
)
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
)
244 case '[': /* read to balancing ']' into a dc_str */
246 case '!': /* read to newline and call system() on resulting string */
247 if (peekc
== '<' || peekc
== '=' || peekc
== '>')
250 case '#': /* comment; skip remainder of current line */
253 case 'a': /* Convert top of stack to an ascii character. */
254 if (dc_pop(&datum
) == DC_SUCCESS
){
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
);
262 dc_garbage("at top of stack", -1);
264 dc_push(dc_makestring(&tmps
, 1));
267 case 'c': /* clear whole stack */
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
));
274 case 'f': /* print list of all stack items */
275 dc_printall(dc_obase
);
277 case 'i': /* set input base to value on top of stack */
278 if (dc_pop(&datum
) == DC_SUCCESS
){
280 if (datum
.dc_type
== DC_NUMBER
)
281 tmpint
= dc_num2int(datum
.v
.number
, DC_TOSS
);
282 if ( ! (2 <= tmpint
&& tmpint
<= DC_IBASE_MAX
) )
284 "%s: input base must be a number \
285 between 2 and %d (inclusive)\n",
286 progname
, DC_IBASE_MAX
);
291 case 'k': /* set scale to value on top of stack */
292 if (dc_pop(&datum
) == DC_SUCCESS
){
294 if (datum
.dc_type
== DC_NUMBER
)
295 tmpint
= dc_num2int(datum
.v
.number
, DC_TOSS
);
296 if ( ! (tmpint
>= 0) )
298 "%s: scale must be a nonnegative number\n",
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
310 if (dc_register_get(peekc
, &datum
) == DC_SUCCESS
)
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
);
319 case 'o': /* set output base to value on top of stack */
320 if (dc_pop(&datum
) == DC_SUCCESS
){
322 if (datum
.dc_type
== DC_NUMBER
)
323 tmpint
= dc_num2int(datum
.v
.number
, DC_TOSS
);
324 if ( ! (tmpint
> 1) )
326 "%s: output base must be a number greater than 1\n",
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
);
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
;
342 case 'r': /* rotate (swap) the top two elements on the stack
344 if (dc_pop(&datum
) == DC_SUCCESS
) {
347 two_status
= dc_pop(&datum2
);
349 if (two_status
== DC_SUCCESS
)
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
359 if (dc_pop(&datum
) == DC_SUCCESS
)
360 dc_register_set(peekc
, datum
);
362 case 'v': /* replace top of stack with its square root */
363 if (dc_pop(&datum
) == DC_SUCCESS
){
365 if (datum
.dc_type
!= DC_NUMBER
){
367 "%s: square root of nonnumeric attempted\n",
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
;
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
)
381 }else if (datum
.dc_type
== DC_NUMBER
){
384 dc_garbage("at top of stack", -1);
388 case 'z': /* push the current stack depth onto the top of stack */
389 dc_push(dc_int2data(dc_tell_stackdepth()));
392 case 'I': /* push the current input base onto the stack */
393 dc_push(dc_int2data(dc_ibase
));
395 case 'K': /* push the current scale onto the stack */
396 dc_push(dc_int2data(dc_scale
));
398 case 'L': /* pop a value off of register stack named by peekc
399 * and push it onto the evaluation stack
403 if (dc_register_pop(peekc
, &datum
) == DC_SUCCESS
)
406 case 'O': /* push the current output base onto the stack */
407 dc_push(dc_int2data(dc_obase
));
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
);
422 dc_garbage("at top of stack", -1);
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
){
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)
436 unwind_depth
= 0; /* paranoia */
438 "%s: Q command requires a number >= 1\n",
443 case 'R': /* pop a value off of the evaluation stack,;
445 remaining stack elements that many
446 * places forward (negative numbers mean rotate
449 if (dc_pop(&datum
) == DC_SUCCESS
){
451 if (datum
.dc_type
== DC_NUMBER
)
452 tmpint
= dc_num2int(datum
.v
.number
, DC_TOSS
);
453 dc_stack_rotate(tmpint
);
457 case 'S': /* pop a value off of the evaluation stack
458 * and push it onto the register stack named by peekc
462 if (dc_pop(&datum
) == DC_SUCCESS
)
463 dc_register_push(peekc
, datum
);
465 case 'X': /* replace the number on top-of-stack with its scale factor */
466 if (dc_pop(&datum
) == DC_SUCCESS
){
468 if (datum
.dc_type
== DC_NUMBER
)
469 tmpint
= dc_tell_scale(datum
.v
.number
, DC_TOSS
);
470 dc_push(dc_int2data(tmpint
));
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
)));
478 case ':': /* store into array */
481 if (dc_pop(&datum
) == DC_SUCCESS
){
483 if (datum
.dc_type
== DC_NUMBER
)
484 tmpint
= dc_num2int(datum
.v
.number
, DC_TOSS
);
485 if (dc_pop(&datum
) == DC_SUCCESS
){
488 "%s: array index must be a nonnegative integer\n",
491 dc_array_set(peekc
, tmpint
, datum
);
495 case ';': /* retreive from array */
498 if (dc_pop(&datum
) == DC_SUCCESS
){
500 if (datum
.dc_type
== DC_NUMBER
)
501 tmpint
= dc_num2int(datum
.v
.number
, DC_TOSS
);
504 "%s: array index must be a nonnegative integer\n",
507 dc_push(dc_array_get(peekc
, tmpint
));
511 default: /* What did that user mean? */
512 fprintf(stderr
, "%s: ", progname
);
513 dc_show_id(stdout
, c
, " unimplemented\n");
520 /* takes a string and evals it */
522 dc_evalstr
DC_DECLARG((string
))
523 dc_data string DC_DECLEND
535 if (string
.dc_type
!= DC_STRING
){
537 "%s: eval called with non-string argument\n",
541 s
= dc_str2charp(string
.v
.string
);
542 end
= s
+ dc_strlen(string
.v
.string
);
544 c
= *(const unsigned char *)s
++;
547 peekc
= *(const unsigned char *)s
;
548 negcmp
= next_negcmp
;
550 switch (dc_func(c
, peekc
, negcmp
)){
558 if (unwind_depth
> 0){
565 input_str_string
= s
- 1;
566 dc_push(dc_getnum(input_str
, dc_ibase
, &peekc
));
567 s
= input_str_string
;
573 for (p
=s
; p
<end
&& count
>0; ++p
)
579 dc_push(dc_makestring(s
, len
-1));
585 s
= memchr(s
, '\n', (size_t)(end
-s
));
596 fprintf(stderr
, "%s: unexpected EOS\n", progname
);
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
))
618 stdin_lookahead
= EOF
;
619 for (c
=getc(fp
); c
!=EOF
; c
=peekc
){
622 * The following if() is the only place where ``stdin_lookahead''
623 * might be set to other than EOF:
626 stdin_lookahead
= peekc
;
627 negcmp
= next_negcmp
;
629 switch (dc_func(c
, peekc
, negcmp
)){
631 if (stdin_lookahead
!= peekc
&& fp
== stdin
)
638 if (unwind_noexit
!= DC_TRUE
)
641 "%s: Q command argument exceeded string execution depth\n",
643 if (stdin_lookahead
!= peekc
&& fp
== stdin
)
651 dc_push(dc_getnum(input_fil
, dc_ibase
, &peekc
));
655 datum
= dc_readstring(fp
, '[', ']');
661 datum
= dc_readstring(stdin
, '\n', '\n');
662 (void)dc_system(dc_str2charp(datum
.v
.string
));
663 dc_free_str(&datum
.v
.string
);
667 while (peekc
!=EOF
&& peekc
!='\n')
677 fprintf(stderr
, "%s: unexpected EOF\n", progname
);