home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / calculat / rpn30src.zip / PROCESS.C < prev    next >
Text File  |  1990-05-30  |  23KB  |  792 lines

  1. /**
  2.  ** process -- Decide what to do with an input character, and do it.
  3.  **
  4.  ** Process() attempts to treat the actual calculator logic as
  5.  ** a Mealy-machine DFA (outputs associated with transitions).
  6.  ** The calculator really resides in those outputs; the state only
  7.  ** serves to determine how the input characters are treated.
  8.  ** The EXPONENT state (added 90.01.01) actually makes it a pushdown
  9.  ** automaton, but a fixed-push one that could be converted back to
  10.  ** a DFA if desired.  (The single recursive call is more efficient.)
  11.  **
  12.  ** The GETNUM state is the workhorse; this state builds up input
  13.  ** numbers.  A non-number terminates number entry and either causes
  14.  ** some calculator action, or moves to the GETFUNC state or one of
  15.  ** the Memory states.  The PRECISION and BASE states are special cases
  16.  ** that interrupt number entry without terminating it.
  17.  **
  18.  ** EXPONENT state is really a variant of the GETNUM state, but it
  19.  ** functions like the PRECISION and BASE states in using metanumbers
  20.  ** --- here, they represent the power-of-10 exponent.  The calculator
  21.  ** gets out of this state by going through state GETNUM and using
  22.  ** process() recursively to process the character.
  23.  **
  24.  ** The <ESCAPE> character is treated specially; whatever the state,
  25.  ** it either turns off the Help window or forces the DFA into the
  26.  ** GETNUM state.  An <ESCAPE> followed by a "Clear X" effectively
  27.  ** re-initializes the DFA (although not the calculator).
  28.  **
  29.  ** If "init" is detected in GETFUNC, process() returns an INITialize
  30.  ** flag to the main() function.  A Quit character (in GETNUM)
  31.  ** causes process() to return a QUIT flag.  A <CTRL>-x character yields
  32.  ** an ABORT flag, which means "Quit but leave the windows visible".
  33.  **
  34.  ** 90.05.28 v3.0
  35.  **    matherr() moved to a separate file.  Matherr() can't catch
  36.  **    arithmetic (divide-by-0) errors; signal(SIG_FPE) used as well.
  37.  **    Add_ok() and other tests for arith. errors are gone (except
  38.  **    one use of mul_ok()) since signal() works.
  39.  **    More constants added (see ftns.c).
  40.  **    Linear regression/interpolation (see ftns.c).
  41.  **    Ftn keys handled specially (outside any state) and moved to main().
  42.  **    Nullary functions put into a lookup table, like the unary ones.
  43.  **    Lotsa code rearrangement in general.
  44.  ** 90.05.02 v2.3 - fix Register 0 bug, hex digit bug.
  45.  **    The hex-digit fix involves storing legal digit-characters in
  46.  **    an array and checking it; this results in dispensing with the
  47.  **    isnum() testing in favor of a value() function that returns
  48.  **    a character's digit value or -1 if it isn't a digit.  (The
  49.  **    meta-numbers use isdigit() since they're restricted to Base 10.)
  50.  **
  51.  ** 90.01.01
  52.  **/
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <ctype.h>
  56. #include <math.h>
  57. #include <float.h>
  58. #include "rpn.h"
  59. #include "display.h"    /** for display-stack width vs. precision **/
  60. #include "rpnio.h"    /** for special-key definitions **/
  61. #include "ftns.h"
  62. #include "debug.h"
  63.  
  64.  
  65. /** Possible states for the calculator automaton... **/
  66. typedef enum {
  67.     GETNUM, GETFUNC, PRECISION, BASE, EXPONENT,
  68.     STORE, STOREP, STOREM, STORET, STORED, RECALL
  69. } input_states ;
  70.  
  71. static input_states state;  /** This one is a biggie :-) **/
  72. static int    meta_num;   /** workspace for memory addresses, etc. **/
  73. static int    meta_neg;   /** sign of meta_num (for exponents) **/
  74. static int      wholenum;   /** "Is this a whole digit or decimal digit?" **/
  75. static double   num_divider;/** keeps track of decimal place     **/
  76.                             /**   when entering non-whole digits **/
  77. static char    *functend;   /** current position in 'thisfunct' string **/
  78.  
  79. static int    value(int);    /* test & return a key's digit-value */
  80. static int    try_metanum(int);
  81. static int    good_mem(int);
  82. static void   do_funct(char *);
  83. static void   clear_vars(void);
  84. #define     flush_thisfunct()    (*(functend = thisfunct) = '\0')
  85. #define     safe_len()        (functend < (thisfunct + NAME_LEN-1))
  86.  
  87.  
  88. /* / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / */
  89.  
  90. static void do_ftn_2(char *fn)
  91. {
  92.     if (savefile)
  93.     close_savefile();
  94.     else {
  95.     open_savefile(fn);
  96.     strncpy(filename, fn, 12);
  97.     }
  98. }
  99.  
  100. /* / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / */
  101. /*
  102. | Append the supplied string to `thisfunct' at wherever functend points.
  103. */
  104. static void append_functend(char *src)
  105. {
  106.     while ( '\0' != (*functend = *src++) )
  107.     functend++;
  108. }
  109.  
  110. /*
  111. | Append `ch' to `thisfunct' at wherever functend points.
  112. */
  113. static void cat_functend(int ch)
  114. {
  115.     DBG_FPRINTF((errfile,"cat_functend ch: %c/%d;  %p/%p\n"
  116.         "thisfunct: %s, length %d; ",
  117.         ch,ch, thisfunct, functend, thisfunct,strlen(thisfunct)));
  118.  
  119.     *(functend++) = ch;
  120.     *functend = '\0';
  121.  
  122.     DBG_FPRINTF((errfile,"%p/%p, thisfunct: %s, length %d\n",
  123.         thisfunct, functend, thisfunct,strlen(thisfunct)));
  124. }
  125.  
  126. /* / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / */
  127.  
  128. int process(int ch)
  129. {
  130.     double temp;    /* Intermediate & temp. values */
  131.     long double ltemp;
  132.     int val;        /* digit-value */
  133.  
  134.     /*
  135.     | First check some keys whose meanings are state-invariant but
  136.     | which affect (or are affected by) the DFA state...
  137.     */
  138.  
  139.     if (ch == 0x1b) {       /* <ESCAPE> */
  140.         if (help_flag >= 0) {
  141.         help_flag = 3;
  142.             toggle_help();
  143.         } else {
  144.         /** Most of the clear_state() function, except  **/
  145.         /** that stacklift & number entry are unchanged **/
  146.         clear_vars();
  147.         }
  148.  
  149.  
  150.     } else switch (state) {
  151.     /*-------------------------------------------------------*\
  152.     | PROGRAMMING WARNING:                      |
  153.     | Process() should return *immediately* after this switch |
  154.     | statement; many of the cases perform their own return!  |
  155.     \*-------------------------------------------------------*/
  156.  
  157.     case GETNUM:
  158.  
  159.     DBG_FPRINTF((errfile,"GETNUM: %p/%p, xbuf: %s, xreg: %g\n",
  160.         xbuf,xbp,xbuf,xreg));
  161.  
  162.     if ( (val = value(ch)) >= 0 ) {
  163.             if (newnum) {
  164.                 if (stacklift) {
  165.                     push();
  166.                 }
  167.                 if (wholenum) {
  168.             xreg = val;
  169.                 } else {
  170.             num_ct = 1;
  171.                     num_divider = 1.0 / (double)base;
  172.             xreg = val * num_divider;
  173.                 }
  174.                 if (negative) {
  175.                      xreg = -xreg;
  176.                 }
  177.                 stacklift = newnum = FALSE;
  178.             } else {
  179.                 if (wholenum) {
  180.                     xreg = (xreg * (double)base) +
  181.                 ( negative ? -val : val );
  182.                 } else {
  183.             ++num_ct;
  184.                     num_divider /= (double)base;
  185.             temp = val * num_divider;
  186.             if (negative)
  187.             xreg -= temp;
  188.             else
  189.             xreg += temp;
  190.                 }
  191.             }
  192.  
  193.         } else {            /** not a number... **/
  194.             switch (ch) {
  195.             case '.':                /**...GETNUM state **/
  196.                 wholenum = FALSE;
  197.                 if (newnum) {
  198.                     if (stacklift)
  199.                         push();
  200.                     xreg = 0.0;
  201.                     stacklift = newnum = FALSE;
  202.                 }
  203.                 break;
  204.  
  205.             case 'E':                /**...GETNUM state **/
  206.         append_functend("exponent  ");
  207.                 if (newnum) {
  208.                     if (stacklift)
  209.                         push();
  210.                     xreg = 1.0;
  211.                     stacklift = newnum = FALSE;
  212.                 }
  213.                 meta_neg = meta_num = 0;
  214.         state = EXPONENT;
  215.                 break;
  216.  
  217.             case DEL:            /** Del on numeric keypad **/
  218.             case '\b':
  219.                 if (!newnum) {        /** kill last digit... **/
  220.                     if (wholenum) {
  221.             xreg = (double)(floor(xreg / (double)base));
  222.                     } else {
  223.             num_divider *= (double)base;
  224.             temp = (double)(floor(xreg / num_divider));
  225.             xreg = temp * num_divider;
  226.             --num_ct;
  227.             if (0 == num_ct)
  228.                 wholenum = TRUE;
  229.             }
  230.                     break;
  231.                 }
  232.                 /** else FALLTHROUGH to Clear-X... **/
  233.             case 'C':
  234.                 xreg = 0.0;
  235.                 clear_state("Clr X");
  236.                 stacklift = FALSE;  /** Next number overwrites X reg. **/
  237.                 break;
  238.  
  239.             case '+':                /**...GETNUM state **/
  240.         temp = yreg + xreg;
  241.         pop();
  242.         xreg = temp;
  243.         clear_state("+");
  244.                 break;
  245.             case '-':
  246.         temp = yreg - xreg;
  247.         pop();
  248.         xreg = temp;
  249.         clear_state("-");
  250.                 break;
  251.             case '*':
  252.         temp = yreg * xreg;
  253.         pop();
  254.         xreg = temp;
  255.                 clear_state("*");
  256.                 break;
  257.             case '/':
  258.         temp = yreg / xreg;
  259.         pop();
  260.         xreg = temp;
  261.                 clear_state("/");
  262.                 break;
  263.         case '%':
  264.         temp = 0.01 * xreg;
  265.         temp = yreg * temp;
  266.         shift_lastx();
  267.         xreg = temp;
  268.                 clear_state("%");
  269.                 break;
  270.             case '^':
  271.                 power();
  272.                 break;
  273.  
  274.             case 'X':                /**...GETNUM state **/
  275.                 temp = yreg;
  276.                 yreg = xreg;
  277.                 xreg = temp;
  278.                 clear_state("X \x1D Y");
  279.                 break;
  280.  
  281.             case 'I':
  282.         shift_lastx();
  283.                 if (xreg == 0.0) {
  284.             prterr("Inverse", "of zero");
  285.                 } else {
  286.                     xreg = (double)1.0 / xreg;
  287.                 }
  288.                 clear_state("Inverse( X )");
  289.                 break;
  290.  
  291.             case '!':
  292.         shift_lastx();
  293.                 xreg = fact(xreg);
  294.                 clear_state("factorial");
  295.                 break;
  296.  
  297.             case 'L':                /**...GETNUM state **/
  298.                 push();
  299.                 xreg = lastx;
  300.                 clear_state("Last X");
  301.                 break;
  302.  
  303.             case 'N':
  304.             case '\'':
  305.                 xreg = -xreg;
  306.                 negative = !negative;
  307.                 strcpy(lastfunct, (negative ? "Negate (-)" : "Negate (+)"));
  308.                 if (newnum)
  309.             stacklift = TRUE;
  310.         flush_thisfunct();
  311.                 break;
  312.  
  313.             case ']':       /** quick form of 'sum+' Summing function **/
  314.                 sumplus();
  315.                 break;
  316.             case '[':       /** quick form of 'sum-' Un-Summing function **/
  317.                 summinus();
  318.                 break;
  319.  
  320.             case 0x04:        /** <ctrl>-D **/
  321.         trig_mode = DEGREES;
  322.         clear_state("Degrees mode");
  323.                 break;
  324.             case 0x12:        /** <ctrl>-R **/
  325.         trig_mode = RADIANS;
  326.         clear_state("Radians mode");
  327.                 break;
  328.  
  329.             case '\r':
  330.         case ' ':
  331.                 push();
  332.                 clear_state("Enter");
  333.                 stacklift = FALSE;  /** Next number overwrites X reg. **/
  334.                 break;
  335.  
  336.             case UARR:        /** UpArrow on numeric keypad **/
  337.                 ru();
  338.                 break;
  339.             case DARR:        /** DownArrow on numeric keypad **/
  340.                 rd();
  341.                 break;
  342.  
  343.             case 'R':        /** quick form of 'rcl' **/
  344.         append_functend("Recall ");
  345.                 meta_neg = meta_num = 0;
  346.                 state = RECALL;
  347.                 break;
  348.             case 'S':        /** quick form of 'sto' **/
  349.         append_functend("Store ");
  350.                 meta_neg = meta_num = 0;
  351.                 state = STORE;
  352.                 break;
  353.  
  354.             case 'P':
  355.         append_functend("Prec. ");
  356.                 meta_neg = meta_num = 0;
  357.                 state = PRECISION;
  358.                 break;
  359.  
  360.             case 'B':                /**...GETNUM state **/
  361.         append_functend("Base ");
  362.                 meta_neg = meta_num = 0;
  363.                 state = BASE;
  364.                 break;
  365.  
  366.         case FTN_2:
  367.         do_ftn_2(default_save);
  368.                 break;
  369.  
  370.             default:
  371.         cat_functend(ch);
  372.                 state = GETFUNC;
  373.             }
  374.     }
  375.     break;  /** ...from GETNUM state **/
  376.  
  377.     case EXPONENT:
  378.         if (try_metanum(ch) == TRUE) {
  379.             break;
  380.         }
  381.     if (ch == '\'' || ch == 'N') {    /** change sign of exponent **/
  382.         meta_neg = !meta_neg;
  383.         *(thisfunct+9) = (meta_neg  ?  '-'  :  ' ');
  384.         break;
  385.     }
  386.     /*
  387.     | ...else finish entering the number, and recursively process
  388.     | this character as a number-entry terminator...
  389.     */
  390.     if (meta_neg)
  391.         meta_num = -meta_num;
  392.     xreg *= p10((double)meta_num);
  393.     state = GETNUM;
  394.     return process(ch);    /** return DIRECTLY from here **/
  395.  
  396.  
  397.     case GETFUNC:
  398.         if (ch == '\r') {
  399.             if (strcmp(thisfunct,"init") == 0) {
  400.  
  401.                 return INIT_VAL;            /** Re-initialize **/
  402.  
  403.             } else {
  404.                 do_funct(thisfunct);
  405.             }
  406.  
  407.         } else if (ch == DEL || ch == '\b') {    /* Delete or Backspace? */
  408.             if (functend != thisfunct) {
  409.                 *(--functend) = '\0';      /* Backspace & delete a char. */
  410.             }
  411.             if (functend == thisfunct) {
  412.                 state = GETNUM;
  413.             }
  414.         } else if (ch == FTN_2) {        /** Save results **/
  415.         do_ftn_2(thisfunct);
  416.         clear_state(thisfunct);
  417.         }
  418.     else {
  419.         if (safe_len()) {
  420.         cat_functend(ch);
  421.             } else {
  422.                 prterr("ftn name", "too long");
  423.             }
  424.             if (strcmp(thisfunct,"rcl") == 0) {
  425.                 meta_neg = meta_num = 0;
  426.                 state = RECALL;
  427.             } else if (strcmp(thisfunct,"sto") == 0) {
  428.                 meta_neg = meta_num = 0;
  429.                 state = STORE;
  430.             }
  431.         }
  432.         break;  /** ...from GETFUNC **/
  433.  
  434.     case RECALL:
  435.         if (ch == 's') {
  436.             if (meta_num == 0) {
  437.                 xreg = memory[11];
  438.                 yreg = memory[12];
  439.         append_functend("sums");
  440.                 clear_state(thisfunct);
  441.             } else {
  442.                 prterr("mem-addr", "invalid char");
  443.                 clear_state(lastfunct);
  444.             }
  445.             break;
  446.         }
  447.         if (try_metanum(ch) == TRUE) {
  448.             break;
  449.         }
  450.         if (good_mem(ch) == TRUE) {
  451.             push();
  452.             xreg = memory[meta_num];
  453.             clear_state(thisfunct);
  454.         }
  455.         break;
  456.  
  457.     case STORE:
  458.         if (ch == '+' || ch == '-' ||ch == '*' || ch == '/') {
  459.         cat_functend(ch);
  460.             state = ((ch == '+') ? STOREP :
  461.                     ((ch == '-') ? STOREM :
  462.                     ((ch == '*') ? STORET : STORED)));
  463.             break;
  464.         }
  465.         if (try_metanum(ch) == TRUE) {
  466.             break;
  467.         }
  468.         if (good_mem(ch) == TRUE) {
  469.             memory[meta_num] = xreg;
  470.             clear_state(thisfunct);
  471.         }
  472.         break;
  473.  
  474.     case STOREP:
  475.         if (try_metanum(ch) == TRUE) {
  476.             break;
  477.         }
  478.         if (good_mem(ch) == TRUE) {
  479.         ltemp = memory[meta_num] + xreg;
  480.         memory[meta_num] = ltemp;
  481.         clear_state(thisfunct);
  482.         }
  483.         break;
  484.  
  485.     case STOREM:
  486.         if (try_metanum(ch) == TRUE) {
  487.             break;
  488.         }
  489.         if (good_mem(ch) == TRUE) {
  490.         ltemp = memory[meta_num] - xreg;
  491.         memory[meta_num] = ltemp;
  492.         clear_state(thisfunct);
  493.         }
  494.         break;
  495.  
  496.     case STORET:
  497.         if (try_metanum(ch) == TRUE) {
  498.             break;
  499.         }
  500.         if (good_mem(ch) == TRUE) {
  501.         ltemp = memory[meta_num] * xreg;
  502.         memory[meta_num] = ltemp;
  503.         clear_state(thisfunct);
  504.         }
  505.         break;
  506.  
  507.     case STORED:
  508.         if (try_metanum(ch) == TRUE) {
  509.             break;
  510.         }
  511.         if (good_mem(ch) == TRUE) {
  512.         ltemp = memory[meta_num] / xreg;
  513.         memory[meta_num] = ltemp;
  514.         clear_state(thisfunct);
  515.         }
  516.         break;
  517.  
  518.     /*
  519.     | Precision and Base are specified in "metanumbers" which are
  520.     | always entered as base 10, so "ch" is checked against 0..9
  521.     | These two states are combined for efficiency, because they
  522.     | are so similar --- they are also alike in being "display-control"
  523.     | states rather than normal calculator-operation states.
  524.     */
  525.     case PRECISION:
  526.     case BASE:
  527.         if (try_metanum(ch) == TRUE) {
  528.         break;        /** Finish the case here **/
  529.         }
  530.     /** ...else not a digit, so finish off state **/
  531.     if (ch == '\r') {
  532.  
  533.         if (state == BASE) {
  534.         if (meta_num <= MAX_BASE) {
  535.             base = meta_num;
  536.             show_base(0);
  537.         } else {
  538.             prterr("base", "too large");
  539.             show_base(1);
  540.         }
  541.         } else {    /** ...must be PRECISION state **/
  542.         pre = min((STK_WIDTH - STK_MARKS), meta_num);
  543.         }
  544.  
  545.     } else {
  546.         prterr((state == BASE ? "base" : "precision"), "invalid char");
  547.         stack_popped = 0;
  548.     }
  549.     flush_thisfunct();
  550.     state = GETNUM;
  551.     break;
  552.  
  553.     default:            /** We should never get here! **/
  554.         base = 10;
  555.         show_base(1);
  556.         xreg = (double)state;
  557.         prterr("machine", "unknown state");
  558.         return ABORT_VAL;
  559.     }
  560.  
  561.     return OK_VAL;
  562. }
  563.  
  564. /**\/\/\/\/\/\  end of process()  /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\**/
  565.  
  566.  
  567. /*---------------------------------------------------------------------*\
  568. | do_funct() is a series of tests, trying to match the function name.    |
  569. | if any test succeeds, the function is performed and do_funct()    |
  570. | immediately returns (thus no "else" clauses).  If all tests fail,    |
  571. | the default code at the end is performed.                |
  572. \* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  573. static void do_funct(char *name)
  574. {
  575.     int addr;
  576.     f_ptr p;    /** for unary functions **/
  577.     vf_ptr vp;    /** for void/null-ary functions **/
  578.  
  579.     /*
  580.     | According to the manual, pi doesn't save Last X; so none of
  581.     | these constants do.  (fixed in v1.1; add'l constants v3.0)
  582.     */
  583.     for (addr = 0; addr < NUM_CONSTS; ++addr) {
  584.     if (0 == strcmp(name, constants[addr].name)) {
  585.         push();
  586.             xreg = constants[addr].val;
  587.             clear_state(name);
  588.             return;
  589.     }
  590.     }
  591.  
  592.     if (strcmp(name,"clrstk") == 0) {
  593.         xreg = yreg = zreg = treg = 0.0;
  594.         clear_state(name);
  595.         return;
  596.     }
  597.     if (strcmp(name,"clrblk") == 0) {
  598.     clrreg((int)yreg, (int)xreg);
  599.         clear_state(name);
  600.         return;
  601.     }
  602.     if (strcmp(name,"clrreg") == 0) {
  603.     clrreg(0, MEMSIZE-1);
  604.         clear_state(name);
  605.         return;
  606.     }
  607.     if (strcmp(name,"clrsum") == 0) {
  608.     clrreg(10, 19);
  609.     memory[19] = memory[18] = ONE;    /** geometric means start at 1 **/
  610.         clear_state(name);
  611.         return;
  612.     }
  613.     if (strcmp(name,"clrlin") == 0) {
  614.     clrreg(B0, COV);
  615.     clear_state(name);
  616.         return;
  617.     }
  618.  
  619. /*-----------------------------------------------------*/
  620.  
  621.     if ((vp = funct_0(name)) != (vf_ptr)NULL) {
  622.     shift_lastx();
  623.         (*vp)();    /** These functions clear_state() themselves **/
  624.         return;
  625.     }
  626.  
  627.     if ((p = funct_1(name,I_TRIG)) != (f_ptr)NULL) {
  628.     shift_lastx();
  629.     xreg = (*p)(xreg);
  630.     if ((trig_mode == DEGREES) && !math_error)
  631.         xreg *= RAD_TO_DEG;
  632.         clear_state(name);
  633.         return;
  634.     }
  635.  
  636.     if ((p = funct_1(name,TRIG)) != (f_ptr)NULL) {
  637.     shift_lastx();
  638.     if (trig_mode == DEGREES)
  639.         xreg *= DEG_TO_RAD;
  640.         xreg = (*p)(xreg);
  641.     if (math_error && (trig_mode == DEGREES))
  642.         xreg *= RAD_TO_DEG;
  643.         clear_state(name);
  644.         return;
  645.     }
  646.  
  647.     if ((p = funct_1(name,UNARY)) != (f_ptr)NULL) {
  648.     shift_lastx();
  649.         xreg = (*p)(xreg);
  650.         clear_state(name);
  651.         return;
  652.     }
  653.  
  654.     /*
  655.     | ...ELSE...
  656.     */
  657.     strncat(thisfunct, " unknown", NAME_LEN - 1 - strlen(thisfunct));
  658.     clear_state(thisfunct);
  659.     return;
  660. }
  661.  
  662. /* / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / */
  663.  
  664. /**
  665.  ** Try_metanum() tests whether a character is a legitimate meta-number,
  666.  ** processes it if it is, and reports the test result back to the caller.
  667.  ** Meta-numbers are used to specify display precision and base, exponents,
  668.  ** and memory addresses.  They are always in base 10.
  669.  **/
  670. static int try_metanum(int ch)
  671. {
  672.     if (isdigit(ch)) {
  673.         meta_num = meta_num * 10  +  (ch - '0');
  674.         if (safe_len()) {
  675.         DBG_FPRINTF((errfile,"meta_num: %d, ch: %c/%d\n",meta_num,ch,ch));
  676.         cat_functend(ch);
  677.         } else {
  678.             prterr("metanumber", "too long");
  679.         }
  680.         return TRUE;
  681.     }
  682.     return FALSE;
  683. }
  684.  
  685. /* / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / */
  686. /**
  687.  ** Good_mem() sets up the memory address if ch is 'i' or '\r'.
  688.  ** If ch or the address is invalid it emits an error message.
  689.  ** Then it reports the outcome to its caller.
  690.  **
  691.  ** v2.3 - (Mike Mueller?) reports that the "out of range" error message 
  692.  **    gets corrupted.  So we try some hacks to fix this.
  693.  ** v3.0 ... the hacks reportedly work.   yippee.
  694.  **/
  695. const char oor_msg[] = "out of range";
  696. const char ic_msg[] = "invalid char";
  697.  
  698. static int good_mem(int ch)
  699. {
  700.     char *errptr;
  701.  
  702.     switch (ch) {
  703.     case 'i':
  704.         meta_num = memory[0];
  705.     cat_functend(ch);
  706.         /* FALLTHROUGH... */
  707.     case '\r':
  708.         if (meta_num >= 0  &&  meta_num < MEMSIZE) {
  709.  
  710.             return TRUE;
  711.         }
  712.         errptr = (char *)oor_msg;
  713.         break;
  714.     default:
  715.         errptr = (char *)ic_msg;
  716.     }
  717.     prterr("mem-addr", errptr);
  718.     clear_state(lastfunct);
  719.     return FALSE;
  720. }
  721.  
  722. /* / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / */
  723.  
  724. static int value(int c)
  725. {
  726.     int v;
  727.     for (v = 0; v < base; ++v) {
  728.     if (c == digits[v])
  729.         return v;
  730.     }
  731.     return -1;
  732. }
  733.  
  734. /**\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\**/
  735.  
  736. void pop(void)
  737. {
  738.     shift_lastx();
  739.     xreg = yreg;
  740.     yreg = zreg;
  741.     zreg = treg;
  742.     stack_popped = 1;
  743. }
  744.  
  745. void push(void)
  746. {
  747.     treg = zreg;
  748.     zreg = yreg;
  749.     yreg = xreg;
  750. }
  751. /**\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\**/
  752.  
  753. static void clear_vars(void)
  754. {
  755.     flush_thisfunct();
  756.     state = GETNUM;
  757.     math_error = stack_popped = 0;
  758. }
  759.  
  760. /**\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\**/
  761.  
  762. void clear_state(char *label)
  763. {
  764.     if (label != lastfunct)
  765.         strncpy(lastfunct, label, NAME_LEN-1);
  766.     stacklift = newnum = wholenum = TRUE;
  767.     negative = FALSE;
  768.     num_ct = 0;
  769.     num_divider = 1.0;
  770.     clear_vars();
  771.     if (savefile)
  772.     write_save = TRUE;    /* Flag save-file output for display() */
  773. }
  774.  
  775. /**\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\**/
  776.  
  777. /*
  778. | called by main() to initialize the calculator machinery
  779. */
  780. void init_machine(void)
  781. {
  782.     notation = 0;
  783.     pre = 3;
  784.     base = 10;
  785.     trig_mode = DEGREES;
  786.     negative = FALSE;
  787.     _fpreset();        /** reset the math chip **/
  788.     clear_state("------");
  789. }
  790.  
  791. /**\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\**/
  792.