"Fossies" - the Fresh Open Source Software Archive

Member "bc-1.06.95/dc/eval.c" (4 Jun 2006, 21654 Bytes) of package /linux/misc/old/bc-1.06.95.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "eval.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.07_vs_1.07.1.

    1 /*
    2  * evaluate the dc language, from a FILE* or a string
    3  *
    4  * Copyright (C) 1994, 1997, 1998, 2000, 2003, 2005, 2006 Free Software
    5  * Foundation, Inc.
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; either version 2, or (at your option)
   10  * any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, you can either send email to this
   19  * program's author (see below) or write to:
   20  *   The Free Software Foundation, Inc.
   21  *   51 Franklin Street, Fifth Floor
   22  *   Boston, MA 02110-1301  USA
   23  */
   24 
   25 /* This is the only module which knows about the dc input language */
   26 
   27 #include "config.h"
   28 
   29 #include <stdio.h>
   30 #ifdef HAVE_STRING_H
   31 # include <string.h>    /* memchr */
   32 #else
   33 # ifdef HAVE_MEMORY_H
   34 #  include <memory.h>   /* memchr, maybe */
   35 # else
   36 #  ifdef HAVE_STRINGS_H
   37 #   include <strings.h> /* memchr, maybe */
   38 #  endif
   39 #endif
   40 #endif
   41 #include <signal.h>
   42 #include "dc.h"
   43 #include "dc-proto.h"
   44 
   45 typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
   46 
   47 typedef enum {
   48     DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
   49     DC_EATONE,      /* caller needs to eat the lookahead char */
   50     DC_EVALREG,     /* caller needs to eval the string named by `peekc' */
   51     DC_EVALTOS,     /* caller needs to eval the string on top of the stack */
   52     DC_QUIT,        /* quit out of unwind_depth levels of evaluation */
   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 */
   58 
   59     DC_EOF_ERROR    /* unexpected end of input; abort current eval */
   60 } dc_status;
   61 
   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) */
   65 
   66 /* for Quitting evaluations */
   67 static int unwind_depth=0;
   68 
   69 /* for handling SIGINT properly */
   70 static volatile sig_atomic_t interrupt_seen=0;
   71 
   72 /* if true, active Quit will not exit program */
   73 static dc_boolean unwind_noexit=DC_FALSE;
   74 
   75 /*
   76  * Used to synchronize lookahead on stdin for '?' command.
   77  * If set to EOF then lookahead is used up.
   78  */
   79 static int stdin_lookahead=EOF;
   80 
   81 
   82 /* input_fil and input_str are passed as arguments to dc_getnum */
   83 
   84 /* used by the input_* functions: */
   85 static FILE *input_fil_fp;
   86 static const char *input_str_string;
   87 
   88 /* Since we have a need for two characters of pushback, and
   89  * ungetc() only guarantees one, we place the second pushback here
   90  */
   91 static int input_pushback;
   92 
   93 /* passed as an argument to dc_getnum */
   94 static int
   95 input_fil DC_DECLVOID()
   96 {
   97     if (input_pushback != EOF){
   98         int c = input_pushback;
   99         input_pushback = EOF;
  100         return c;
  101     }
  102     return getc(input_fil_fp);
  103 }
  104 
  105 /* passed as an argument to dc_getnum */
  106 static int
  107 input_str DC_DECLVOID()
  108 {
  109     if (*input_str_string == '\0')
  110         return EOF;
  111     return *input_str_string++;
  112 }
  113 
  114 
  115 
  116 /* takes a string and evals it; frees the string when done */
  117 /* Wrapper around dc_evalstr to avoid duplicating the free call
  118  * at all possible return points.
  119  */
  120 static int
  121 dc_eval_and_free_str DC_DECLARG((string))
  122     dc_data *string DC_DECLEND
  123 {
  124     dc_status status;
  125 
  126     status = dc_evalstr(string);
  127     if (string->dc_type == DC_STRING)
  128         dc_free_str(&string->v.string);
  129     return status;
  130 }
  131 
  132 
  133 /* notice when an interrupt event happens */
  134 static void
  135 dc_trap_interrupt DC_DECLARG((signo))
  136     int signo DC_DECLEND
  137 {
  138     signal(signo, dc_trap_interrupt);
  139     interrupt_seen = 1;
  140 }
  141 
  142 
  143 /* step pointer past next end-of-line (or to end-of-string) */
  144 static const char *
  145 skip_past_eol DC_DECLARG((strptr, strend))
  146     const char *strptr DC_DECLSEP
  147     const char *strend DC_DECLEND
  148 {
  149     const char *p = memchr(strptr, '\n', (size_t)(strend-strptr));
  150     if (p != NULL)
  151         return p+1;
  152     return strend;
  153 }
  154 
  155 
  156 /* dc_func does the grunt work of figuring out what each input
  157  * character means; used by both dc_evalstr and dc_evalfile
  158  *
  159  * c -> the "current" input character under consideration
  160  * peekc -> the lookahead input character
  161  * negcmp -> negate comparison test (for <,=,> commands)
  162  */
  163 static dc_status
  164 dc_func DC_DECLARG((c, peekc, negcmp))
  165     int c DC_DECLSEP
  166     int peekc DC_DECLSEP
  167     int negcmp DC_DECLEND
  168 {
  169     dc_data datum;
  170     int tmpint;
  171 
  172     switch (c){
  173     case '_': case '.':
  174     case '0': case '1': case '2': case '3':
  175     case '4': case '5': case '6': case '7':
  176     case '8': case '9': case 'A': case 'B':
  177     case 'C': case 'D': case 'E': case 'F':
  178         return DC_INT;
  179     case ' ':
  180     case '\t':
  181     case '\n':
  182         /* standard command separators */
  183         break;
  184 
  185     case '+':   /* add top two stack elements */
  186         dc_binop(dc_add, dc_scale);
  187         break;
  188     case '-':   /* subtract top two stack elements */
  189         dc_binop(dc_sub, dc_scale);
  190         break;
  191     case '*':   /* multiply top two stack elements */
  192         dc_binop(dc_mul, dc_scale);
  193         break;
  194     case '/':   /* divide top two stack elements */
  195         dc_binop(dc_div, dc_scale);
  196         break;
  197     case '%':
  198         /* take the remainder from division of the top two stack elements */
  199         dc_binop(dc_rem, dc_scale);
  200         break;
  201     case '~':
  202         /* Do division on the top two stack elements.  Return the
  203          * quotient as next-to-top of stack and the remainder as
  204          * top-of-stack.
  205          */
  206         dc_binop2(dc_divrem, dc_scale);
  207         break;
  208     case '|':
  209         /* Consider the top three elements of the stack as (base, exp, mod),
  210          * where mod is top-of-stack, exp is next-to-top, and base is
  211          * second-from-top. Mod must be non-zero, exp must be non-negative,
  212          * and all three must be integers. Push the result of raising
  213          * base to the exp power, reduced modulo mod. If we had base in
  214          * register b, exp in register e, and mod in register m then this
  215          * is conceptually equivalent to "lble^lm%", but it is implemented
  216          * in a more efficient manner, and can handle arbritrarily large
  217          * values for exp.
  218          */
  219         dc_triop(dc_modexp, dc_scale);
  220         break;
  221     case '^':   /* exponientiation of the top two stack elements */
  222         dc_binop(dc_exp, dc_scale);
  223         break;
  224     case '<':
  225         /* eval register named by peekc if
  226          * less-than holds for top two stack elements
  227          */
  228         if (peekc == EOF)
  229             return DC_EOF_ERROR;
  230         if ( (dc_cmpop() <  0) == (negcmp==0) )
  231             return DC_EVALREG;
  232         return DC_EATONE;
  233     case '=':
  234         /* eval register named by peekc if
  235          * equal-to holds for top two stack elements
  236          */
  237         if (peekc == EOF)
  238             return DC_EOF_ERROR;
  239         if ( (dc_cmpop() == 0) == (negcmp==0) )
  240             return DC_EVALREG;
  241         return DC_EATONE;
  242     case '>':
  243         /* eval register named by peekc if
  244          * greater-than holds for top two stack elements
  245          */
  246         if (peekc == EOF)
  247             return DC_EOF_ERROR;
  248         if ( (dc_cmpop() >  0) == (negcmp==0) )
  249             return DC_EVALREG;
  250         return DC_EATONE;
  251     case '?':   /* read a line from standard-input and eval it */
  252         if (stdin_lookahead != EOF){
  253             ungetc(stdin_lookahead, stdin);
  254             stdin_lookahead = EOF;
  255         }
  256         datum = dc_readstring(stdin, '\n', '\n');
  257         if (ferror(stdin))
  258             return DC_EOF_ERROR;
  259         dc_push(datum);
  260         return DC_EVALTOS;
  261     case '[':   /* read to balancing ']' into a dc_str */
  262         return DC_STR;
  263     case '!':   /* read to newline and call system() on resulting string */
  264         if (peekc == '<' || peekc == '=' || peekc == '>')
  265             return DC_NEGCMP;
  266         return DC_SYSTEM;
  267     case '#':   /* comment; skip remainder of current line */
  268         return DC_COMMENT;
  269 
  270     case 'a':   /* Convert top of stack to an ascii character. */
  271         if (dc_pop(&datum) == DC_SUCCESS){
  272             char tmps;
  273             if (datum.dc_type == DC_NUMBER){
  274                 tmps = (char) dc_num2int(datum.v.number, DC_TOSS);
  275             }else if (datum.dc_type == DC_STRING){
  276                 tmps = *dc_str2charp(datum.v.string);
  277                 dc_free_str(&datum.v.string);
  278             }else{
  279                 dc_garbage("at top of stack", -1);
  280             }
  281             dc_push(dc_makestring(&tmps, 1));
  282         }
  283         break;
  284     case 'c':   /* clear whole stack */
  285         dc_clear_stack();
  286         break;
  287     case 'd':   /* duplicate the datum on the top of stack */
  288         if (dc_top_of_stack(&datum) == DC_SUCCESS)
  289             dc_push(dc_dup(datum));
  290         break;
  291     case 'f':   /* print list of all stack items */
  292         dc_printall(dc_obase);
  293         break;
  294     case 'i':   /* set input base to value on top of stack */
  295         if (dc_pop(&datum) == DC_SUCCESS){
  296             tmpint = 0;
  297             if (datum.dc_type == DC_NUMBER)
  298                 tmpint = dc_num2int(datum.v.number, DC_TOSS);
  299             if (2 <= tmpint  &&  tmpint <= DC_IBASE_MAX)
  300                 dc_ibase = tmpint;
  301             else
  302                 fprintf(stderr,
  303                         "%s: input base must be a number \
  304 between 2 and %d (inclusive)\n",
  305                         progname, DC_IBASE_MAX);
  306         }
  307         break;
  308     case 'k':   /* set scale to value on top of stack */
  309         if (dc_pop(&datum) == DC_SUCCESS){
  310             tmpint = -1;
  311             if (datum.dc_type == DC_NUMBER)
  312                 tmpint = dc_num2int(datum.v.number, DC_TOSS);
  313             if ( ! (tmpint >= 0) )
  314                 fprintf(stderr,
  315                         "%s: scale must be a nonnegative number\n",
  316                         progname);
  317             else
  318                 dc_scale = tmpint;
  319         }
  320         break;
  321     case 'l':   /* "load" -- push value on top of register stack named
  322                  * by peekc onto top of evaluation stack; does not
  323                  * modify the register stack
  324                  */
  325         if (peekc == EOF)
  326             return DC_EOF_ERROR;
  327         if (dc_register_get(peekc, &datum) == DC_SUCCESS)
  328             dc_push(datum);
  329         return DC_EATONE;
  330     case 'n':   /* print the value popped off of top-of-stack;
  331                  * do not add a trailing newline
  332                  */
  333         if (dc_pop(&datum) == DC_SUCCESS)
  334             dc_print(datum, dc_obase, DC_NONL, DC_TOSS);
  335         break;
  336     case 'o':   /* set output base to value on top of stack */
  337         if (dc_pop(&datum) == DC_SUCCESS){
  338             tmpint = 0;
  339             if (datum.dc_type == DC_NUMBER)
  340                 tmpint = dc_num2int(datum.v.number, DC_TOSS);
  341             if ( ! (tmpint > 1) )
  342                 fprintf(stderr,
  343                         "%s: output base must be a number greater than 1\n",
  344                         progname);
  345             else
  346                 dc_obase = tmpint;
  347         }
  348         break;
  349     case 'p':   /* print the datum on the top of stack,
  350                  * with a trailing newline
  351                  */
  352         if (dc_top_of_stack(&datum) == DC_SUCCESS)
  353             dc_print(datum, dc_obase, DC_WITHNL, DC_KEEP);
  354         break;
  355     case 'q':   /* quit two levels of evaluation, posibly exiting program */
  356         unwind_depth = 1; /* the return below is the first level of returns */
  357         unwind_noexit = DC_FALSE;
  358         return DC_QUIT;
  359     case 'r':   /* rotate (swap) the top two elements on the stack
  360                  */
  361         if (dc_pop(&datum) == DC_SUCCESS){
  362             dc_data datum2;
  363             int two_status;
  364             two_status = dc_pop(&datum2);
  365             dc_push(datum);
  366             if (two_status == DC_SUCCESS)
  367                 dc_push(datum2);
  368         }
  369         break;
  370     case 's':   /* "store" -- replace top of register stack named
  371                  * by peekc with the value popped from the top
  372                  * of the evaluation stack
  373                  */
  374         if (peekc == EOF)
  375             return DC_EOF_ERROR;
  376         if (dc_pop(&datum) == DC_SUCCESS)
  377             dc_register_set(peekc, datum);
  378         return DC_EATONE;
  379     case 'v':   /* replace top of stack with its square root */
  380         if (dc_pop(&datum) == DC_SUCCESS){
  381             dc_num tmpnum;
  382             if (datum.dc_type != DC_NUMBER){
  383                 fprintf(stderr,
  384                         "%s: square root of nonnumeric attempted\n",
  385                         progname);
  386             }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
  387                 dc_free_num(&datum.v.number);
  388                 datum.v.number = tmpnum;
  389                 dc_push(datum);
  390             }
  391         }
  392         break;
  393     case 'x':   /* eval the datum popped from top of stack */
  394         return DC_EVALTOS;
  395     case 'z':   /* push the current stack depth onto the top of stack */
  396         dc_push(dc_int2data(dc_tell_stackdepth()));
  397         break;
  398 
  399     case 'I':   /* push the current input base onto the stack */
  400         dc_push(dc_int2data(dc_ibase));
  401         break;
  402     case 'K':   /* push the current scale onto the stack */
  403         dc_push(dc_int2data(dc_scale));
  404         break;
  405     case 'L':   /* pop a value off of register stack named by peekc
  406                  * and push it onto the evaluation stack
  407                  */
  408         if (peekc == EOF)
  409             return DC_EOF_ERROR;
  410         if (dc_register_pop(peekc, &datum) == DC_SUCCESS)
  411             dc_push(datum);
  412         return DC_EATONE;
  413     case 'O':   /* push the current output base onto the stack */
  414         dc_push(dc_int2data(dc_obase));
  415         break;
  416     case 'P':
  417         /* Pop the value off the top of a stack.  If it is
  418          * a number, dump out the integer portion of its
  419          * absolute value as a "base UCHAR_MAX+1" byte stream;
  420          * if it is a string, just print it.
  421          * In either case, do not append a trailing newline.
  422          */
  423         if (dc_pop(&datum) == DC_SUCCESS){
  424             if (datum.dc_type == DC_NUMBER)
  425                 dc_dump_num(datum.v.number, DC_TOSS);
  426             else if (datum.dc_type == DC_STRING)
  427                 dc_out_str(datum.v.string, DC_NONL, DC_TOSS);
  428             else
  429                 dc_garbage("at top of stack", -1);
  430         }
  431         break;
  432     case 'Q':   /* quit out of top-of-stack nested evals;
  433                  * pops value from stack;
  434                  * does not exit program (stops short if necessary)
  435                  */
  436         if (dc_pop(&datum) == DC_SUCCESS){
  437             unwind_depth = 0;
  438             unwind_noexit = DC_TRUE;
  439             if (datum.dc_type == DC_NUMBER)
  440                 unwind_depth = dc_num2int(datum.v.number, DC_TOSS);
  441             if (unwind_depth-- > 0)
  442                 return DC_QUIT;
  443             unwind_depth = 0;   /* paranoia */
  444             fprintf(stderr,
  445                     "%s: Q command requires a number >= 1\n",
  446                     progname);
  447         }
  448         break;
  449 #if 0
  450     case 'R':   /* pop a value off of the evaluation stack,;
  451                  * rotate the top remaining stack elements that many
  452                  * places forward (negative numbers mean rotate
  453                  * backward).
  454                  */
  455         if (dc_pop(&datum) == DC_SUCCESS){
  456             tmpint = 0;
  457             if (datum.dc_type == DC_NUMBER)
  458                 tmpint = dc_num2int(datum.v.number, DC_TOSS);
  459             dc_stack_rotate(tmpint);
  460         }
  461         break;
  462 #endif
  463     case 'S':   /* pop a value off of the evaluation stack
  464                  * and push it onto the register stack named by peekc
  465                  */
  466         if (peekc == EOF)
  467             return DC_EOF_ERROR;
  468         if (dc_pop(&datum) == DC_SUCCESS)
  469             dc_register_push(peekc, datum);
  470         return DC_EATONE;
  471     case 'X':   /* replace the number on top-of-stack with its scale factor */
  472         if (dc_pop(&datum) == DC_SUCCESS){
  473             tmpint = 0;
  474             if (datum.dc_type == DC_NUMBER)
  475                 tmpint = dc_tell_scale(datum.v.number, DC_TOSS);
  476             dc_push(dc_int2data(tmpint));
  477         }
  478         break;
  479     case 'Z':   /* replace the datum on the top-of-stack with its length */
  480         if (dc_pop(&datum) == DC_SUCCESS)
  481             dc_push(dc_int2data(dc_tell_length(datum, DC_TOSS)));
  482         break;
  483 
  484     case ':':   /* store into array */
  485         if (peekc == EOF)
  486             return DC_EOF_ERROR;
  487         if (dc_pop(&datum) == DC_SUCCESS){
  488             tmpint = -1;
  489             if (datum.dc_type == DC_NUMBER)
  490                 tmpint = dc_num2int(datum.v.number, DC_TOSS);
  491             if (dc_pop(&datum) == DC_SUCCESS){
  492                 if (tmpint < 0)
  493                     fprintf(stderr,
  494                             "%s: array index must be a nonnegative integer\n",
  495                             progname);
  496                 else
  497                     dc_array_set(peekc, tmpint, datum);
  498             }
  499         }
  500         return DC_EATONE;
  501     case ';':   /* retreive from array */
  502         if (peekc == EOF)
  503             return DC_EOF_ERROR;
  504         if (dc_pop(&datum) == DC_SUCCESS){
  505             tmpint = -1;
  506             if (datum.dc_type == DC_NUMBER)
  507                 tmpint = dc_num2int(datum.v.number, DC_TOSS);
  508             if (tmpint < 0)
  509                 fprintf(stderr,
  510                         "%s: array index must be a nonnegative integer\n",
  511                         progname);
  512             else
  513                 dc_push(dc_array_get(peekc, tmpint));
  514         }
  515         return DC_EATONE;
  516 
  517     default:    /* What did that user mean? */
  518         fprintf(stderr, "%s: ", progname);
  519         dc_show_id(stdout, c, " unimplemented\n");
  520         break;
  521     }
  522     return DC_OKAY;
  523 }
  524 
  525 
  526 /* takes a string and evals it */
  527 int
  528 dc_evalstr DC_DECLARG((string))
  529     dc_data *string DC_DECLEND
  530 {
  531     const char *s;
  532     const char *end;
  533     const char *p;
  534     size_t len;
  535     int c;
  536     int peekc;
  537     int count;
  538     int negcmp;
  539     int next_negcmp = 0;
  540     int tail_depth = 1; /* how much tail recursion is active */
  541     dc_data evalstr;
  542 
  543     if (string->dc_type != DC_STRING){
  544         fprintf(stderr,
  545                 "%s: eval called with non-string argument\n",
  546                 progname);
  547         return DC_OKAY;
  548     }
  549     interrupt_seen = 0;
  550     s = dc_str2charp(string->v.string);
  551     end = s + dc_strlen(string->v.string);
  552     while (s < end && interrupt_seen==0){
  553         c = *(const unsigned char *)s++;
  554         peekc = EOF;
  555         if (s < end)
  556             peekc = *(const unsigned char *)s;
  557         negcmp = next_negcmp;
  558         next_negcmp = 0;
  559         switch (dc_func(c, peekc, negcmp)){
  560         case DC_OKAY:
  561             break;
  562         case DC_EATONE:
  563             if (peekc != EOF)
  564                 ++s;
  565             break;
  566         case DC_EVALREG:
  567             /*commands which return this guarantee that peekc!=EOF*/
  568             ++s;
  569             if (dc_register_get(peekc, &evalstr) != DC_SUCCESS)
  570                 break;
  571             dc_push(evalstr);
  572             /*@fallthrough@*/
  573         case DC_EVALTOS:
  574             /*skip trailing whitespace to assist tail-recursion detection*/
  575             while (s<end && (*s==' '||*s=='\t'||*s=='\n'||*s=='#')){
  576                 if (*s++ == '#')
  577                     s = skip_past_eol(s, end);
  578             }
  579             if (dc_pop(&evalstr) == DC_SUCCESS){
  580                 if (evalstr.dc_type == DC_NUMBER){
  581                     dc_push(evalstr);
  582                     return DC_OKAY;
  583                 }else if (evalstr.dc_type != DC_STRING){
  584                     dc_garbage("at top of stack", -1);
  585                 }else if (s == end){
  586                     /*handle tail recursion*/
  587                     dc_free_str(&string->v.string);
  588                     *string = evalstr;
  589                     s = dc_str2charp(string->v.string);
  590                     end = s + dc_strlen(string->v.string);
  591                     ++tail_depth;
  592                 }else if (dc_eval_and_free_str(&evalstr) == DC_QUIT){
  593                     if (unwind_depth > 0){
  594                         --unwind_depth;
  595                         return DC_QUIT;
  596                     }
  597                     return DC_OKAY;
  598                 }
  599             }
  600             break;
  601         case DC_QUIT:
  602             if (unwind_depth >= tail_depth){
  603                 unwind_depth -= tail_depth;
  604                 return DC_QUIT;
  605             }
  606             return DC_OKAY;
  607 
  608         case DC_INT:
  609             input_str_string = s - 1;
  610             dc_push(dc_getnum(input_str, dc_ibase, &peekc));
  611             s = input_str_string;
  612             if (peekc != EOF)
  613                 --s;
  614             break;
  615         case DC_STR:
  616             count = 1;
  617             for (p=s; p<end && count>0; ++p)
  618                 if (*p == ']')
  619                     --count;
  620                 else if (*p == '[')
  621                     ++count;
  622             len = (size_t) (p - s);
  623             dc_push(dc_makestring(s, len-1));
  624             s = p;
  625             break;
  626         case DC_SYSTEM:
  627             s = dc_system(s);
  628             /*@fallthrough@*/
  629         case DC_COMMENT:
  630             s = skip_past_eol(s, end);
  631             break;
  632         case DC_NEGCMP:
  633             next_negcmp = 1;
  634             break;
  635 
  636         case DC_EOF_ERROR:
  637             if (ferror(stdin)) {
  638                 fprintf(stderr, "%s: ", progname);
  639                 perror("error reading stdin");
  640                 return DC_FAIL;
  641             }
  642             fprintf(stderr, "%s: unexpected EOS\n", progname);
  643             return DC_OKAY;
  644         }
  645     }
  646     return DC_OKAY;
  647 }
  648 
  649 
  650 /* This is the main function of the whole DC program.
  651  * Reads the file described by fp, calls dc_func to do
  652  * the dirty work, and takes care of dc_func's shortcomings.
  653  */
  654 int
  655 dc_evalfile DC_DECLARG((fp))
  656     FILE *fp DC_DECLEND
  657 {
  658     int c;
  659     int peekc;
  660     int negcmp;
  661     int next_negcmp = 0;
  662     dc_data datum;
  663 
  664     signal(SIGINT, dc_trap_interrupt);
  665     stdin_lookahead = EOF;
  666     for (c=getc(fp); c!=EOF; c=peekc){
  667         peekc = getc(fp);
  668         /*
  669          * The following if() is the only place where ``stdin_lookahead''
  670          * might be set to other than EOF:
  671          */
  672         if (fp == stdin)
  673             stdin_lookahead = peekc;
  674         /*
  675          * In the switch(), cases which naturally update peekc
  676          * (unconditionally) do not have to update or reference
  677          * stdin_lookahead; other functions use the predicate:
  678          *    stdin_lookahead != peekc  &&  fp == stdin
  679          * to recognize the case where:
  680          *   a) stdin_lookahead == EOF (stdin and peekc are not in sync)
  681          *   b) peekc != EOF (resync is possible)
  682          *   c) fp == stdin (resync is relevant)
  683          * The whole stdin_lookahead complication arises because the
  684          * '?' command may be invoked from an arbritrarily deeply
  685          * nested dc_evalstr(), '?' reads exclusively from stdin,
  686          * and this winds up making peekc invalid when fp==stdin.
  687          */
  688         negcmp = next_negcmp;
  689         next_negcmp = 0;
  690         switch (dc_func(c, peekc, negcmp)){
  691         case DC_OKAY:
  692             if (stdin_lookahead != peekc  &&  fp == stdin)
  693                 peekc = getc(fp);
  694             break;
  695         case DC_EATONE:
  696             peekc = getc(fp);
  697             break;
  698         case DC_EVALREG:
  699             /*commands which send us here shall guarantee that peekc!=EOF*/
  700             c = peekc;
  701             peekc = getc(fp);
  702             stdin_lookahead = peekc;
  703             if (dc_register_get(c, &datum) != DC_SUCCESS)
  704                 break;
  705             dc_push(datum);
  706             /*@fallthrough@*/
  707         case DC_EVALTOS:
  708             if (stdin_lookahead != peekc  &&  fp == stdin)
  709                 peekc = getc(fp);
  710             if (dc_pop(&datum) == DC_SUCCESS){
  711                 if (datum.dc_type == DC_NUMBER){
  712                     dc_push(datum);
  713                 }else if (datum.dc_type == DC_STRING){
  714                     if (dc_eval_and_free_str(&datum) == DC_QUIT){
  715                         if (unwind_noexit != DC_TRUE)
  716                             return DC_SUCCESS;
  717                         fprintf(stderr, "%s: Q command argument exceeded \
  718 string execution depth\n", progname);
  719                     }
  720                 }else{
  721                     dc_garbage("at top of stack", -1);
  722                 }
  723             }
  724             break;
  725         case DC_QUIT:
  726             if (unwind_noexit != DC_TRUE)
  727                 return DC_SUCCESS;
  728             fprintf(stderr,
  729                     "%s: Q command argument exceeded string execution depth\n",
  730                     progname);
  731             if (stdin_lookahead != peekc  &&  fp == stdin)
  732                 peekc = getc(fp);
  733             break;
  734 
  735         case DC_INT:
  736             input_fil_fp = fp;
  737             input_pushback = c;
  738             ungetc(peekc, fp);
  739             dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
  740             if (ferror(fp))
  741                 goto error_fail;
  742             break;
  743         case DC_STR:
  744             ungetc(peekc, fp);
  745             datum = dc_readstring(fp, '[', ']');
  746             if (ferror(fp))
  747                 goto error_fail;
  748             dc_push(datum);
  749             peekc = getc(fp);
  750             break;
  751         case DC_SYSTEM:
  752             ungetc(peekc, fp);
  753             datum = dc_readstring(stdin, '\n', '\n');
  754             if (ferror(stdin))
  755                 goto error_fail;
  756             (void)dc_system(dc_str2charp(datum.v.string));
  757             dc_free_str(&datum.v.string);
  758             peekc = getc(fp);
  759             break;
  760         case DC_COMMENT:
  761             while (peekc!=EOF && peekc!='\n')
  762                 peekc = getc(fp);
  763             if (peekc != EOF)
  764                 peekc = getc(fp);
  765             break;
  766         case DC_NEGCMP:
  767             next_negcmp = 1;
  768             break;
  769 
  770         case DC_EOF_ERROR:
  771             if (ferror(fp))
  772                 goto error_fail;
  773             fprintf(stderr, "%s: unexpected EOF\n", progname);
  774             return DC_FAIL;
  775         }
  776     }
  777     if (!ferror(fp))
  778         return DC_SUCCESS;
  779 
  780 error_fail:
  781     fprintf(stderr, "%s: ", progname);
  782     perror("error reading input");
  783     return DC_FAIL;
  784 }
  785 
  786 
  787 /*
  788  * Local Variables:
  789  * mode: C
  790  * tab-width: 4
  791  * End:
  792  * vi: set ts=4 :
  793  */