home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / bwbasic.zip / src / bwb_elx.c < prev    next >
C/C++ Source or Header  |  1993-04-27  |  37KB  |  1,224 lines

  1. /****************************************************************
  2.  
  3.         bwb_elx.c       Parse Elements of Expressions
  4.                         for Bywater BASIC Interpreter
  5.  
  6.                         Copyright (c) 1992, Ted A. Campbell
  7.  
  8.                         Bywater Software
  9.                         P. O. Box 4023
  10.                         Duke Station
  11.                         Durham, NC  27706
  12.  
  13.                         email: tcamp@acpub.duke.edu
  14.  
  15.         Copyright and Permissions Information:
  16.  
  17.         All U.S. and international copyrights are claimed by the
  18.         author. The author grants permission to use this code
  19.         and software based on it under the following conditions:
  20.         (a) in general, the code and software based upon it may be
  21.         used by individuals and by non-profit organizations; (b) it
  22.         may also be utilized by governmental agencies in any country,
  23.         with the exception of military agencies; (c) the code and/or
  24.         software based upon it may not be sold for a profit without
  25.         an explicit and specific permission from the author, except
  26.         that a minimal fee may be charged for media on which it is
  27.         copied, and for copying and handling; (d) the code must be
  28.         distributed in the form in which it has been released by the
  29.         author; and (e) the code and software based upon it may not
  30.         be used for illegal activities.
  31.  
  32. ****************************************************************/
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #include <math.h>
  39.  
  40. #include "bwbasic.h"
  41. #include "bwb_mes.h"
  42.  
  43. /***************************************************************
  44.  
  45.         FUNCTION:   exp_paren()
  46.  
  47.         DESCRIPTION:  This function interprets a parenthetical
  48.         expression, calling bwb_exp() (recursively) to resolve
  49.         the internal expression.
  50.  
  51. ***************************************************************/
  52.  
  53. int
  54. exp_paren( char *expression )
  55.    {
  56.    struct exp_ese *e;
  57.    register int c;
  58.    int s_pos;                           /* position in build buffer */
  59.    int loop;
  60.    int paren_level;
  61.  
  62.    /* find a string enclosed by parentheses */
  63.  
  64.    exp_es[ exp_esc ].pos_adv = 1;       /* start beyond open paren */
  65.    s_pos = 0;
  66.    loop = TRUE;
  67.    paren_level = 1;
  68.    exp_es[ exp_esc ].string[ 0 ] = '\0';
  69.  
  70.    while( loop == TRUE )
  71.       {
  72.  
  73.       /* check the current character */
  74.  
  75.       switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  76.          {
  77.  
  78.          case '(':
  79.             ++paren_level;
  80.             exp_es[ exp_esc ].string[ s_pos ]
  81.                = expression[ exp_es[ exp_esc ].pos_adv ];
  82.             ++s_pos;
  83.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  84.             break;
  85.  
  86.          case ')':
  87.  
  88.             --paren_level;
  89.             if ( paren_level == 0 )
  90.                {
  91.                loop = FALSE;
  92.                }
  93.             else
  94.                {
  95.                exp_es[ exp_esc ].string[ s_pos ]
  96.                   = expression[ exp_es[ exp_esc ].pos_adv ];
  97.                ++s_pos;
  98.                exp_es[ exp_esc ].string[ s_pos ] = '\0';
  99.                }
  100.             break;
  101.  
  102.          case '\"':                             /* embedded string constant */
  103.             ++exp_es[ exp_esc ].pos_adv;
  104.             while ( ( expression[ exp_es[ exp_esc ].pos_adv ] != '\"' )
  105.                && ( expression[ exp_es[ exp_esc ].pos_adv ] != '\0' ) )
  106.                {
  107.                exp_es[ exp_esc ].string[ s_pos ]
  108.                   = expression[ exp_es[ exp_esc ].pos_adv ];
  109.                ++s_pos;
  110.                exp_es[ exp_esc ].string[ s_pos ] = '\0';
  111.                ++exp_es[ exp_esc ].pos_adv;
  112.                }
  113.             break;
  114.  
  115.          default:
  116.             exp_es[ exp_esc ].string[ s_pos ]
  117.                = expression[ exp_es[ exp_esc ].pos_adv ];
  118.             ++s_pos;
  119.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  120.             break;
  121.          }
  122.  
  123.       /* advance the counter */
  124.  
  125.       ++exp_es[ exp_esc ].pos_adv;
  126.  
  127.       }
  128.  
  129.    #if INTENSIVE_DEBUG
  130.    sprintf( bwb_ebuf, "in exp_paren() found internal string <%s>",
  131.       exp_es[ exp_esc ].string );
  132.    bwb_debug( bwb_ebuf );
  133.    #endif
  134.  
  135.    /* call bwb_exp() recursively to interpret this expression */
  136.  
  137.    exp_es[ exp_esc ].rec_pos = 0;
  138.    e = bwb_exp( exp_es[ exp_esc ].string, FALSE,
  139.           &( exp_es[ exp_esc ].rec_pos ) );
  140.  
  141.    /* assign operation and value at this level */
  142.  
  143.    exp_es[ exp_esc ].type = e->type;
  144.  
  145.    switch ( e->type )
  146.       {
  147.       case STRING:
  148.          exp_es[ exp_esc ].operation = CONST_STRING;
  149.          str_btob( exp_getsval( &( exp_es[ exp_esc ] )), exp_getsval( e ) );
  150.          break;
  151.       case INTEGER:
  152.          exp_es[ exp_esc ].operation = NUMBER;
  153.          exp_es[ exp_esc ].ival = exp_getival( e );
  154.          break;
  155.       case DOUBLE:
  156.          exp_es[ exp_esc ].operation = NUMBER;
  157.          exp_es[ exp_esc ].dval = exp_getdval( e );
  158.          break;
  159.       default:
  160.          exp_es[ exp_esc ].operation = NUMBER;
  161.          exp_es[ exp_esc ].fval = exp_getfval( e );
  162.          break;
  163.       }
  164.  
  165.    return TRUE;
  166.  
  167.    }
  168.  
  169. /***************************************************************
  170.  
  171.         FUNCTION:   exp_strconst()
  172.  
  173.         DESCRIPTION:  This function interprets a string
  174.         constant.
  175.  
  176. ***************************************************************/
  177.  
  178. int
  179. exp_strconst( char *expression )
  180.    {
  181.    int e_pos, s_pos;
  182.  
  183.    /* assign values to structure */
  184.  
  185.    exp_es[ exp_esc ].type = STRING;
  186.    exp_es[ exp_esc ].operation = CONST_STRING;
  187.  
  188.    /* set counters */
  189.  
  190.    s_pos = 0;
  191.    exp_es[ exp_esc ].pos_adv = e_pos = 1;
  192.    exp_es[ exp_esc ].string[ 0 ] = '\0';
  193.  
  194.    /* read the string up until the next double quotation mark */
  195.  
  196.    while( expression[ e_pos ] != '\"' )
  197.       {
  198.       exp_es[ exp_esc ].string[ s_pos ] = expression[ e_pos ];
  199.       ++e_pos;
  200.       ++s_pos;
  201.       ++exp_es[ exp_esc ].pos_adv;
  202.       exp_es[ exp_esc ].string[ s_pos ] = '\0';
  203.       if ( s_pos >= ( MAXSTRINGSIZE - 1 ) )
  204.          {
  205.          #if PROG_ERRORS
  206.          sprintf( bwb_ebuf, "string <%s> exceeds maximum size (%d) for string constant.",
  207.             expression, MAXSTRINGSIZE );
  208.          bwb_error( bwb_ebuf );
  209.          #else
  210.          bwb_error( err_overflow );
  211.          #endif
  212.          return OP_NULL;
  213.          }
  214.       }
  215.  
  216.    /* now write string over to bstring */
  217.  
  218.    str_ctob( &( exp_es[ exp_esc ].sval ), exp_es[ exp_esc ].string );
  219.  
  220.    /* advance past last double quotation mark */
  221.  
  222.    ++exp_es[ exp_esc ].pos_adv;
  223.  
  224.    /* return */
  225.  
  226.    return TRUE;
  227.  
  228.    }
  229.  
  230. /***************************************************************
  231.  
  232.         FUNCTION:   exp_numconst()
  233.  
  234.         DESCRIPTION:  This function interprets a numerical
  235.         constant.
  236.  
  237. ***************************************************************/
  238.  
  239. int
  240. exp_numconst( char *expression )
  241.    {
  242.    int base;                            /* numerical base for the constant */
  243.    static struct bwb_variable mantissa; /* mantissa of floating-point number */
  244.    static int init = FALSE;        /* is mantissa variable initialized? */
  245.    int exponent;                        /* exponent for floating point number */
  246.    int man_start;                       /* starting point of mantissa */
  247.    int s_pos;                           /* position in build string */
  248.    int build_loop;
  249.    int need_pm;
  250.    int i;
  251.    double d;
  252.    #if CHECK_RECURSION
  253.    static int in_use = FALSE;                   /* boolean: is function in use? */
  254.  
  255.    /* check recursion status */
  256.  
  257.    if ( in_use == TRUE )
  258.       {
  259.       sprintf( bwb_ebuf, "Recursion error in bwb_exp.c:exp_findop(): recursion violation." );
  260.       bwb_error( bwb_ebuf );
  261.       }
  262.  
  263.    /* reset recursion status indicator */
  264.  
  265.    else
  266.       {
  267.       in_use = TRUE;
  268.       }
  269.    #endif
  270.  
  271.    /* initialize the variable if necessary */
  272.  
  273.    #if INTENSIVE_DEBUG
  274.    strcpy( mantissa.name, "(mantissa)" );
  275.    #endif
  276.  
  277.    if ( init == FALSE )
  278.       {
  279.       init = TRUE;
  280.       var_make( &mantissa, DOUBLE );
  281.       }
  282.  
  283.    /* be sure that the array_pos[ 0 ] for mantissa is set to dim_base;
  284.       this is necessary because mantissa might be used before dim_base
  285.       is set */
  286.  
  287.    mantissa.array_pos[ 0 ] = dim_base;
  288.  
  289.    #if INTENSIVE_DEBUG
  290.    sprintf( bwb_ebuf, "in exp_numconst(): received <%s>, eval <%c>",
  291.       expression, expression[ 0 ] );
  292.    bwb_debug( bwb_ebuf );
  293.    #endif
  294.  
  295.    need_pm = FALSE;
  296.    exp_es[ exp_esc ].ival = 0;
  297.  
  298.    /* check the first character(s) to determine numerical base
  299.       and starting point of the mantissa */
  300.  
  301.    switch( expression[ 0 ] )
  302.       {
  303.       case '-':
  304.       case '+':
  305.       case '0':
  306.       case '1':
  307.       case '2':
  308.       case '3':
  309.       case '4':
  310.       case '5':
  311.       case '6':
  312.       case '7':
  313.       case '8':
  314.       case '9':
  315.       case '.':
  316.          base = 10;                     /* decimal constant */
  317.      man_start = 0;                 /* starts at position 0 */
  318.      need_pm = FALSE;
  319.          break;
  320.       case '&':                         /* hex or octal constant */
  321.          if ( ( expression[ 1 ] == 'H' ) || ( expression[ 1 ] == 'h' ))
  322.             {
  323.             base = 16;                  /* hexadecimal constant */
  324.             man_start = 2;              /* starts at position 2 */
  325.             }
  326.          else
  327.             {
  328.             base = 8;                   /* octal constant */
  329.             if ( ( expression[ 1 ] == 'O' ) || ( expression[ 1 ] == 'o' ))
  330.                {
  331.                man_start = 2;           /* starts at position 2 */
  332.                }
  333.             else
  334.                {
  335.                man_start = 1;           /* starts at position 1 */
  336.                }
  337.             }
  338.          break;
  339.       default:
  340.  
  341.          #if PROG_ERRORS
  342.          sprintf( bwb_ebuf, "expression <%s> is not a numerical constant.",
  343.             expression );
  344.          bwb_error( bwb_ebuf );
  345.          #else
  346.          bwb_error( err_syntax );
  347.          #endif
  348.          return OP_NULL;
  349.       }
  350.  
  351.    /* now build the mantissa according to the numerical base */
  352.  
  353.    switch( base )
  354.       {
  355.  
  356.       case 10:                          /* decimal constant */
  357.  
  358.          /* initialize counters */
  359.  
  360.          exp_es[ exp_esc ].pos_adv = man_start;
  361.          exp_es[ exp_esc ].type = INTEGER;
  362.          exp_es[ exp_esc ].string[ 0 ] = '\0';
  363.          s_pos = 0;
  364.          exponent = OP_NULL;
  365.          build_loop = TRUE;
  366.  
  367.          /* loop to build the string */
  368.  
  369.          while ( build_loop == TRUE )
  370.             {
  371.             switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  372.                {
  373.                case '-':                        /* prefixed plus or minus */
  374.                case '+':
  375.  
  376.                   /* in the first position, a plus or minus sign can
  377.                      be added to the beginning of the string to be
  378.                      scanned */
  379.  
  380.                   if ( exp_es[ exp_esc ].pos_adv == man_start )
  381.                      {
  382.                      exp_es[ exp_esc ].string[ s_pos ] = expression[ exp_es[ exp_esc ].pos_adv ];
  383.                      ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  384.                      ++s_pos;
  385.                      exp_es[ exp_esc ].string[ s_pos ] = '\0';
  386.                      }
  387.  
  388.                   /* but in any other position, the plus or minus sign
  389.                      must be taken as an operator and thus as terminating
  390.                      the string to be scanned */
  391.  
  392.                   else
  393.                      {
  394.                      build_loop = FALSE;
  395.                      }
  396.                   break;
  397.                case '.':                        /* note at least single precision */
  398.                   if ( exp_es[ exp_esc ].type == INTEGER )
  399.                      {
  400.                      exp_es[ exp_esc ].type = SINGLE;
  401.                      }                          /* fall through (no break) */
  402.                case '0':                        /* or ordinary digit */
  403.                case '1':
  404.                case '2':
  405.                case '3':
  406.                case '4':
  407.                case '5':
  408.                case '6':
  409.                case '7':
  410.                case '8':
  411.                case '9':
  412.                   exp_es[ exp_esc ].string[ s_pos ] = expression[ exp_es[ exp_esc ].pos_adv ];
  413.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  414.                   ++s_pos;
  415.                   exp_es[ exp_esc ].string[ s_pos ] = '\0';
  416.                   break;
  417.  
  418.                case 'E':                        /* exponential, single precision */
  419.                case 'e':
  420.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  421.                   exp_es[ exp_esc ].type = SINGLE;
  422.           exponent = TRUE;
  423.                   build_loop = FALSE;
  424.                   break;
  425.  
  426.  
  427.                case 'D':                        /* exponential, double precision */
  428.                case 'd':
  429.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  430.                   exp_es[ exp_esc ].type = DOUBLE;
  431.           exponent = TRUE;
  432.                   build_loop = FALSE;
  433.                   break;
  434.  
  435.                case SINGLE:                     /* single precision termination */
  436.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  437.                   exp_es[ exp_esc ].type = SINGLE;
  438.                   build_loop = FALSE;
  439.                   break;
  440.  
  441.                case DOUBLE:                     /* double precision termination */
  442.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  443.                   exp_es[ exp_esc ].type = DOUBLE;
  444.                   build_loop = FALSE;
  445.                   break;
  446.  
  447.                case INTEGER:                    /* integer precision termination */
  448.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  449.                   exp_es[ exp_esc ].type = INTEGER;
  450.                   build_loop = FALSE;
  451.                   break;
  452.  
  453.                default:                         /* anything else, terminate */
  454.                   build_loop = FALSE;
  455.                   break;
  456.                }
  457.  
  458.             }
  459.  
  460.          /* assign the value to the mantissa variable */
  461.          
  462.          sscanf( exp_es[ exp_esc ].string, "%lf", 
  463.            var_finddval( &mantissa, mantissa.array_pos ));
  464.  
  465.          #if INTENSIVE_DEBUG
  466.          sprintf( bwb_ebuf, "in exp_numconst(): read mantissa, string <%s> val <%lf>",
  467.             exp_es[ exp_esc ].string, var_getdval( &mantissa ) );
  468.          bwb_debug( bwb_ebuf );
  469.          #endif
  470.  
  471.          /* test if integer bounds have been exceeded */
  472.  
  473.          if ( exp_es[ exp_esc ].type == INTEGER )
  474.             {
  475.             i = (int) var_getdval( &mantissa );
  476.             d = (double) i;
  477.             if ( d != var_getdval( &mantissa ))
  478.                {
  479.                exp_es[ exp_esc ].type = DOUBLE;
  480.                #if INTENSIVE_DEBUG
  481.                sprintf( bwb_ebuf, "in exp_numconst(): integer bounds violated, promote to DOUBLE" );
  482.                bwb_debug( bwb_ebuf );
  483.                #endif               
  484.                }
  485.             }
  486.  
  487.          /* read the exponent if there is one */
  488.  
  489.          if ( exponent == TRUE )
  490.             {
  491.  
  492.         /* allow a plus or minus once at the beginning */
  493.  
  494.         need_pm = TRUE;
  495.  
  496.         /* initialize counters */
  497.  
  498.             exp_es[ exp_esc ].string[ 0 ] = '\0';
  499.             s_pos = 0;
  500.             build_loop = TRUE;
  501.  
  502.             /* loop to build the string */
  503.  
  504.             while ( build_loop == TRUE )
  505.                {
  506.                switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  507.                   {
  508.           case '-':                        /* prefixed plus or minus */
  509.                   case '+':
  510.  
  511.              if ( need_pm == TRUE )        /* only allow once */
  512.             {
  513.             exp_es[ exp_esc ].string[ s_pos ] = expression[ exp_es[ exp_esc ].pos_adv ];
  514.             ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  515.             ++s_pos;
  516.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  517.             }
  518.              else
  519.             {
  520.             build_loop = FALSE;
  521.             }
  522.              break;
  523.  
  524.           case '0':                        /* or ordinary digit */
  525.                   case '1':
  526.                   case '2':
  527.                   case '3':
  528.                   case '4':
  529.                   case '5':
  530.                   case '6':
  531.                   case '7':
  532.                   case '8':
  533.                   case '9':
  534.  
  535.                      exp_es[ exp_esc ].string[ s_pos ] = expression[ exp_es[ exp_esc ].pos_adv ];
  536.                      ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  537.                      ++s_pos;
  538.              exp_es[ exp_esc ].string[ s_pos ] = '\0';
  539.              need_pm = FALSE;
  540.                      break;
  541.  
  542.                   default:                         /* anything else, terminate */
  543.                      build_loop = FALSE;
  544.                      break;
  545.                   }
  546.  
  547.                }                                /* end of build loop for exponent */
  548.  
  549.             /* assign the value to the user variable */
  550.  
  551.             sscanf( exp_es[ exp_esc ].string, "%d",
  552.                &( exp_es[ exp_esc ].ival ) );
  553.  
  554.         #if INTENSIVE_DEBUG
  555.         sprintf( bwb_ebuf, "in exp_numconst(): exponent is <%d>",
  556.                exp_es[ exp_esc ].ival );
  557.             bwb_debug( bwb_ebuf );
  558.             #endif
  559.  
  560.             }                           /* end of exponent search */
  561.  
  562.          if ( exp_es[ exp_esc ].ival == 0 )
  563.             {
  564.             exp_es[ exp_esc ].dval = var_getdval( &mantissa );
  565.             }
  566.          else
  567.             {
  568.             exp_es[ exp_esc ].dval = var_getdval( &mantissa )
  569.                * pow( (double) 10.0, (double) exp_es[ exp_esc ].ival );
  570.             }
  571.  
  572.          exp_es[ exp_esc ].fval = (float) exp_es[ exp_esc ].dval;
  573.          exp_es[ exp_esc ].ival = (int) exp_es[ exp_esc ].dval;
  574.  
  575.          #if INTENSIVE_DEBUG
  576.          sprintf( bwb_ebuf, "in exp_numconst(): val double <%lf> single <%f> int <%d>",
  577.             exp_es[ exp_esc ].dval, exp_es[ exp_esc ].fval, exp_es[ exp_esc ].ival );
  578.          bwb_debug( bwb_ebuf );
  579.          #endif
  580.  
  581.          break;
  582.  
  583.       case 8:                           /* octal constant */
  584.  
  585.          /* initialize counters */
  586.  
  587.          exp_es[ exp_esc ].pos_adv = man_start;
  588.          exp_es[ exp_esc ].type = INTEGER;
  589.          exp_es[ exp_esc ].string[ 0 ] = '\0';
  590.          s_pos = 0;
  591.          exponent = OP_NULL;
  592.          build_loop = TRUE;
  593.  
  594.          /* loop to build the string */
  595.  
  596.          while ( build_loop == TRUE )
  597.             {
  598.             switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  599.                {
  600.                case '0':                        /* or ordinary digit */
  601.                case '1':
  602.                case '2':
  603.                case '3':
  604.                case '4':
  605.                case '5':
  606.                case '6':
  607.                case '7':
  608.                   exp_es[ exp_esc ].string[ s_pos ] = expression[ exp_es[ exp_esc ].pos_adv ];
  609.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  610.                   ++s_pos;
  611.                   exp_es[ exp_esc ].string[ s_pos ] = '\0';
  612.                   break;
  613.  
  614.                default:                         /* anything else, terminate */
  615.                   build_loop = FALSE;
  616.                   break;
  617.                }
  618.  
  619.             }
  620.  
  621.          /* now scan the string to determine the number */
  622.  
  623.          sscanf( exp_es[ exp_esc ].string, "%o",
  624.             &( exp_es[ exp_esc ].ival ));
  625.  
  626.          break;
  627.  
  628.       case 16:                          /* hexadecimal constant */
  629.  
  630.          /* initialize counters */
  631.  
  632.          exp_es[ exp_esc ].pos_adv = man_start;
  633.          exp_es[ exp_esc ].type = INTEGER;
  634.          exp_es[ exp_esc ].string[ 0 ] = '\0';
  635.          s_pos = 0;
  636.          exponent = OP_NULL;
  637.          build_loop = TRUE;
  638.  
  639.          /* loop to build the string */
  640.  
  641.          while ( build_loop == TRUE )
  642.             {
  643.             switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  644.                {
  645.                case '0':                        /* or ordinary digit */
  646.                case '1':
  647.                case '2':
  648.                case '3':
  649.                case '4':
  650.                case '5':
  651.                case '6':
  652.                case '7':
  653.                case '8':
  654.                case '9':
  655.                case 'A':
  656.                case 'a':
  657.                case 'B':
  658.                case 'b':
  659.                case 'C':
  660.                case 'c':
  661.                case 'D':
  662.                case 'd':
  663.                case 'E':
  664.                case 'e':
  665.                   exp_es[ exp_esc ].string[ s_pos ] = expression[ exp_es[ exp_esc ].pos_adv ];
  666.  
  667.                   ++exp_es[ exp_esc ].pos_adv;  /* advance to next character */
  668.                   ++s_pos;
  669.                   exp_es[ exp_esc ].string[ s_pos ] = '\0';
  670.                   break;
  671.  
  672.                default:                         /* anything else, terminate */
  673.                   build_loop = FALSE;
  674.                   break;
  675.                }
  676.  
  677.             }
  678.  
  679.          /* now scan the string to determine the number */
  680.  
  681.          sscanf( exp_es[ exp_esc ].string, "%x",
  682.             &( exp_es[ exp_esc ].ival ));
  683.  
  684.          break;
  685.       }
  686.  
  687.    /* note that the operation at this level is now a determined NUMBER */
  688.  
  689.    exp_es[ exp_esc ].operation = NUMBER;
  690.  
  691.    #if INTENSIVE_DEBUG
  692.    sprintf( bwb_ebuf, "in exp_numconst(): exit level <%d> precision <%c> value <%lf>",
  693.       exp_esc, exp_es[ exp_esc ].type, exp_getdval( &( exp_es[ exp_esc ] ) ) );
  694.    bwb_debug( bwb_ebuf );
  695.    #endif
  696.  
  697.    #if CHECK_RECURSION
  698.    in_use = FALSE;
  699.    #endif
  700.  
  701.    return TRUE;
  702.  
  703.    }
  704.  
  705. /***************************************************************
  706.  
  707.         FUNCTION:   exp_function()
  708.  
  709.         DESCRIPTION:  This function interprets a function,
  710.         calling bwb_exp() (recursively) to resolve any
  711.         arguments to the function.
  712.  
  713. ***************************************************************/
  714.  
  715. int
  716. exp_function( char *expression )
  717.    {
  718.    struct exp_ese *e;
  719.    register int c;
  720.    int s_pos;                           /* position in build buffer */
  721.    int loop;
  722.    int paren_level;
  723.    int n_args;
  724.    struct bwb_variable *v;
  725.    struct bwb_variable argv[ MAX_FARGS ];
  726.    bstring *b;
  727.    #if INTENSIVE_DEBUG
  728.    char tbuf[ MAXSTRINGSIZE + 1 ];
  729.  
  730.    sprintf( bwb_ebuf, "in exp_function(): entered function, expression <%s>",
  731.       expression );
  732.    bwb_debug( bwb_ebuf );
  733.    #endif
  734.  
  735.    /* assign pointers to argument stack */
  736.  
  737.    /* get the function name */
  738.  
  739.    exp_getvfname( expression, exp_es[ exp_esc ].string );
  740.  
  741.    #if INTENSIVE_DEBUG
  742.    sprintf( bwb_ebuf, "in exp_function(): name is <%s>.",
  743.       exp_es[ exp_esc ].string );
  744.    bwb_debug( bwb_ebuf );
  745.    #endif
  746.  
  747.    /* now find the function itself */
  748.  
  749.    exp_es[ exp_esc ].function = fnc_find( exp_es[ exp_esc ].string );
  750.  
  751.    /* check to see if it is valid */
  752.  
  753.    if ( exp_es[ exp_esc ].function == NULL )
  754.       {
  755.       #if PROG_ERRORS
  756.       sprintf( bwb_ebuf, "Failed to find function <%s>.",
  757.          exp_es[ exp_esc ].string );
  758.       bwb_error( bwb_ebuf );
  759.       #else
  760.       bwb_error( err_uf  );
  761.       #endif
  762.       return OP_ERROR;
  763.       }
  764.  
  765.    /* note that this level is a function */
  766.  
  767.    exp_es[ exp_esc ].operation = FUNCTION;
  768.    exp_es[ exp_esc ].pos_adv = strlen( exp_es[ exp_esc ].string );
  769.  
  770.    /* check for begin parenthesis */
  771.  
  772.    loop = TRUE;
  773.    while( loop == TRUE )
  774.       {
  775.       switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  776.          {
  777.  
  778.          case ' ':                              /* whitespace */
  779.          case '\t':
  780.             ++exp_es[ exp_esc ].pos_adv;        /* advance */
  781.             break;
  782.  
  783.          case '(':                              /* begin paren */
  784.  
  785.             #if INTENSIVE_DEBUG
  786.             sprintf( bwb_ebuf, "in exp_function(): found begin parenthesis." );
  787.             bwb_debug( bwb_ebuf );
  788.             #endif
  789.  
  790.             ++exp_es[ exp_esc ].pos_adv;        /* advance beyond it */
  791.             paren_level = 1;                    /* set paren_level */
  792.             loop = FALSE;                       /* and break out */
  793.             break;
  794.  
  795.          default:                               /* anything else */
  796.             loop = FALSE;
  797.             paren_level = 0;                    /* do not look for arguments */
  798.             break;
  799.          }
  800.       }
  801.  
  802.    /* find arguments within parentheses */
  803.    /* for each argument, find a string ending with ',' or with end parenthesis */
  804.  
  805.    n_args = 0;
  806.    s_pos = 0;
  807.    exp_es[ exp_esc ].string[ 0 ] = '\0';
  808.  
  809.    while( paren_level > 0 )
  810.       {
  811.  
  812.       /* check the current character */
  813.  
  814.       switch( expression[ exp_es[ exp_esc ].pos_adv ] )
  815.          {
  816.  
  817.          case ',':                      /* end of an argument */
  818.  
  819.             if ( paren_level == 1 )     /* ignore ',' within parentheses */
  820.                {
  821.  
  822.                /* call bwb_exp() recursively to resolve the argument */
  823.  
  824.                if ( exp_validarg( exp_es[ exp_esc ].string ) == TRUE )
  825.                   {
  826.           #if INTENSIVE_DEBUG
  827.           sprintf( bwb_ebuf,
  828.              "in exp_function(): valid argument (not last)." );
  829.                   bwb_debug( bwb_ebuf );
  830.                   #endif
  831.  
  832.                   exp_es[ exp_esc ].rec_pos = 0;
  833.                   e = bwb_exp( exp_es[ exp_esc ].string, FALSE,
  834.                      &( exp_es[ exp_esc ].rec_pos ) );
  835.  
  836.                   /* assign operation and value at this level */
  837.  
  838.                   var_make( &( argv[ n_args ] ), e->type );
  839.  
  840.                   switch( argv[ n_args ].type )
  841.                      {
  842.                      case DOUBLE:
  843.                         * var_finddval( &( argv[ n_args ] ), argv[ n_args ].array_pos )
  844.                             = exp_getdval( e );
  845.                         break;
  846.                      case SINGLE:
  847.                         * var_findfval( &( argv[ n_args ] ), argv[ n_args ].array_pos )
  848.                             = exp_getfval( e );
  849.                         break;
  850.                      case INTEGER:
  851.                         * var_findival( &( argv[ n_args ] ), argv[ n_args ].array_pos )
  852.                             = exp_getival( e );
  853.                         break;
  854.                      case STRING:
  855.                         str_btob( var_findsval( &( argv[ n_args ] ),
  856.                            argv[ n_args ].array_pos ), exp_getsval( e ) );
  857.                         break;
  858.                      }
  859.  
  860.                   ++n_args;                /* increment number of arguments */
  861.  
  862.                   }
  863.  
  864.                s_pos = 0;               /* reset counter */
  865.                exp_es[ exp_esc ].string[ 0 ] = '\0';
  866.                }
  867.  
  868.             else
  869.                {
  870.                exp_es[ exp_esc ].string[ s_pos ]
  871.                   = expression[ exp_es[ exp_esc ].pos_adv ];
  872.                ++s_pos;
  873.                exp_es[ exp_esc ].string[ s_pos ] = '\0';
  874.                }
  875.             break;
  876.  
  877.          case '(':
  878.             ++paren_level;
  879.             exp_es[ exp_esc ].string[ s_pos ]
  880.                = expression[ exp_es[ exp_esc ].pos_adv ];
  881.             ++s_pos;
  882.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  883.             break;
  884.  
  885.          case ')':
  886.             --paren_level;
  887.  
  888.             #if INTENSIVE_DEBUG
  889.             sprintf( bwb_ebuf,
  890.                "in exp_function(): hit close parenthesis." );
  891.             bwb_debug( bwb_ebuf );
  892.             #endif
  893.  
  894.             if ( paren_level == 0 )
  895.                {
  896.  
  897.                #if INTENSIVE_DEBUG
  898.                sprintf( bwb_ebuf,
  899.                   "in exp_function(): paren level 0." );
  900.                bwb_debug( bwb_ebuf );
  901.                #endif
  902.  
  903.                /* call bwb_exp() recursively to resolve the argument */
  904.  
  905.                if ( exp_validarg( exp_es[ exp_esc ].string ) == TRUE )
  906.                   {
  907.           #if INTENSIVE_DEBUG
  908.           sprintf( bwb_ebuf,
  909.              "in exp_function(): valid argument (last)." );
  910.           bwb_debug( bwb_ebuf );
  911.           #endif
  912.  
  913.                   exp_es[ exp_esc ].rec_pos = 0;
  914.                   e = bwb_exp( exp_es[ exp_esc ].string, FALSE,
  915.                      &( exp_es[ exp_esc ].rec_pos ) );
  916.  
  917.           #if INTENSIVE_DEBUG
  918.           sprintf( bwb_ebuf,
  919.              "in exp_function(): return from bwb_exp(), last arg, type <%c> op <%d>",
  920.              e->type, e->operation );
  921.           bwb_debug( bwb_ebuf );
  922.           #endif
  923.  
  924.                   /* assign operation and value at this level */
  925.  
  926.                   var_make( &( argv[ n_args ] ), e->type );
  927.  
  928.                   switch( argv[ n_args ].type )
  929.                      {
  930.                      case DOUBLE:
  931.                         * var_finddval( &( argv[ n_args ] ), argv[ n_args ].array_pos )
  932.                             = exp_getdval( e );
  933.                         break;
  934.                      case SINGLE:
  935.                         * var_findfval( &( argv[ n_args ] ), argv[ n_args ].array_pos )
  936.                             = exp_getfval( e );
  937.                         break;
  938.                      case INTEGER:
  939.                         * var_findival( &( argv[ n_args ] ), argv[ n_args ].array_pos )
  940.                             = exp_getival( e );
  941.                         break;
  942.                      case STRING:
  943.                         str_btob( var_findsval( &( argv[ n_args ] ),
  944.                            argv[ n_args ].array_pos ), exp_getsval( e ) );
  945.                         break;
  946.                      }
  947.  
  948.                   ++n_args;                /* increment number of arguments */
  949.  
  950.                   }
  951.  
  952.                s_pos = 0;               /* reset counter */
  953.                exp_es[ exp_esc ].string[ 0 ] = '\0';
  954.                }
  955.  
  956.             else
  957.                {
  958.                exp_es[ exp_esc ].string[ s_pos ]
  959.                   = expression[ exp_es[ exp_esc ].pos_adv ];
  960.                ++s_pos;
  961.                exp_es[ exp_esc ].string[ s_pos ] = '\0';
  962.                }
  963.             break;
  964.  
  965.          case '\"':                             /* embedded string constant */
  966.  
  967.             /* add the initial quotation mark */
  968.  
  969.             exp_es[ exp_esc ].string[ s_pos ]
  970.                = expression[ exp_es[ exp_esc ].pos_adv ];
  971.             ++s_pos;
  972.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  973.             ++exp_es[ exp_esc ].pos_adv;
  974.  
  975.             /* add intervening characters */
  976.  
  977.             while ( ( expression[ exp_es[ exp_esc ].pos_adv ] != '\"' )
  978.                && ( expression[ exp_es[ exp_esc ].pos_adv ] != '\0' ) )
  979.                {
  980.                exp_es[ exp_esc ].string[ s_pos ]
  981.                   = expression[ exp_es[ exp_esc ].pos_adv ];
  982.                ++s_pos;
  983.                exp_es[ exp_esc ].string[ s_pos ] = '\0';
  984.                ++exp_es[ exp_esc ].pos_adv;
  985.                }
  986.  
  987.             /* add the concluding quotation mark */
  988.  
  989.             exp_es[ exp_esc ].string[ s_pos ]
  990.                = expression[ exp_es[ exp_esc ].pos_adv ];
  991.             ++s_pos;
  992.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  993.             /* the following bracketed out 14 July 1992; since this counter */
  994.             /* incremented at the end of the switch statement, this may */
  995.             /* increment it past the next character needed */
  996.             /* ++exp_es[ exp_esc ].pos_adv; */
  997.             break;
  998.  
  999.          default:
  1000.             exp_es[ exp_esc ].string[ s_pos ]
  1001.                = expression[ exp_es[ exp_esc ].pos_adv ];
  1002.             ++s_pos;
  1003.             exp_es[ exp_esc ].string[ s_pos ] = '\0';
  1004.             #if INTENSIVE_DEBUG
  1005.             sprintf( bwb_ebuf, "in exp_function(): new char <%d>=<%c>",
  1006.                expression[ exp_es[ exp_esc ].pos_adv ],
  1007.                expression[ exp_es[ exp_esc ].pos_adv ] );
  1008.             bwb_debug( bwb_ebuf );
  1009.             sprintf( bwb_ebuf, "in exp_function(): building <%s>.",
  1010.                exp_es[ exp_esc ].string );
  1011.             bwb_debug( bwb_ebuf );
  1012.             #endif
  1013.             break;
  1014.          }
  1015.  
  1016.       /* advance the counter */
  1017.  
  1018.       ++exp_es[ exp_esc ].pos_adv;
  1019.  
  1020.       }
  1021.  
  1022.    #if INTENSIVE_DEBUG
  1023.    sprintf( bwb_ebuf, "in exp_function(): ready to call function vector" );
  1024.    bwb_debug( bwb_ebuf );
  1025.    #endif
  1026.  
  1027.    /* call the function vector */
  1028.  
  1029.    if ( exp_es[ exp_esc ].function->ufnc != NULL )
  1030.       {
  1031.       #if INTENSIVE_DEBUG
  1032.       sprintf( bwb_ebuf, "in exp_function(): calling fnc_intufnc()" );
  1033.       bwb_debug( bwb_ebuf );
  1034.       #endif
  1035.       v = fnc_intufnc( n_args, &( argv[ 0 ] ), exp_es[ exp_esc ].function );
  1036.       }
  1037.    else
  1038.       {
  1039.       #if INTENSIVE_DEBUG
  1040.       sprintf( bwb_ebuf, "in exp_function(): calling preset function" );
  1041.       bwb_debug( bwb_ebuf );
  1042.       #endif
  1043.       v = exp_es[ exp_esc ].function->vector ( n_args, &( argv[ 0 ] ) );
  1044.       }
  1045.  
  1046.    #if INTENSIVE_DEBUG
  1047.    sprintf( bwb_ebuf, "in exp_function(): return from function vector, type <%c>",
  1048.       v->type );
  1049.    bwb_debug( bwb_ebuf );
  1050.    #endif
  1051.  
  1052.    /* assign the value at this level */
  1053.  
  1054.    exp_es[ exp_esc ].type = (char) v->type;
  1055.    
  1056.    switch( v->type )
  1057.       {
  1058.       case STRING:
  1059.          exp_es[ exp_esc ].operation = CONST_STRING;
  1060.  
  1061.          #if INTENSIVE_DEBUG
  1062.          sprintf( bwb_ebuf, "in exp_function(): ready to assign STRING" );
  1063.          bwb_debug( bwb_ebuf );
  1064.          #endif
  1065.  
  1066.          b = var_findsval( v, v->array_pos );
  1067.          str_btob( exp_getsval( &( exp_es[ exp_esc ] )), b );
  1068.  
  1069.          #if INTENSIVE_DEBUG
  1070.          str_btoc( tbuf, b );
  1071.          sprintf( bwb_ebuf, "in exp_function(): string assigned <%s>", tbuf );
  1072.          bwb_debug( bwb_ebuf );
  1073.          #endif
  1074.  
  1075.          break;
  1076.  
  1077.       case DOUBLE:
  1078.          exp_es[ exp_esc ].operation = NUMBER;
  1079.          exp_es[ exp_esc ].dval = var_getdval( v );
  1080.          break;
  1081.       case INTEGER:
  1082.          exp_es[ exp_esc ].operation = NUMBER;
  1083.          exp_es[ exp_esc ].ival = var_getival( v );
  1084.          break;
  1085.       default:
  1086.          exp_es[ exp_esc ].operation = NUMBER;
  1087.          exp_es[ exp_esc ].fval = var_getfval( v );
  1088.          break;
  1089.       }
  1090.  
  1091.    #if INTENSIVE_DEBUG
  1092.    sprintf( bwb_ebuf, "in exp_function(): end of function" );
  1093.    bwb_debug( bwb_ebuf );
  1094.    #endif
  1095.  
  1096.    /* return */
  1097.  
  1098.    return TRUE;
  1099.  
  1100.    }
  1101.  
  1102. /***************************************************************
  1103.  
  1104.         FUNCTION:   exp_variable()
  1105.  
  1106.         DESCRIPTION:  This function interprets a variable.
  1107.  
  1108. ***************************************************************/
  1109.  
  1110. int
  1111. exp_variable( char *expression )
  1112.    {
  1113.    int pos;
  1114.    int *pp;
  1115.    int n_params;
  1116.    register int n;
  1117.    struct bwb_variable *v;
  1118.    bstring *b;
  1119.    int p;
  1120.  
  1121.    #if INTENSIVE_DEBUG
  1122.    sprintf( bwb_ebuf, "in exp_variable(): entered function." );
  1123.    bwb_debug( bwb_ebuf );
  1124.    #endif
  1125.  
  1126.    /* get the variable name */
  1127.  
  1128.    exp_getvfname( expression, exp_es[ exp_esc ].string );
  1129.  
  1130.    /* now find the variable itself */
  1131.  
  1132.    v = exp_es[ exp_esc ].xvar = var_find( exp_es[ exp_esc ].string );
  1133.  
  1134.    #if INTENSIVE_DEBUG
  1135.    sprintf( bwb_ebuf, "in exp_variable(): level <%d>, found variable name <%s>",
  1136.       exp_esc, exp_es[ exp_esc ].xvar->name );
  1137.    bwb_debug( bwb_ebuf );
  1138.    #endif
  1139.  
  1140.    /* note that this level is a variable */
  1141.  
  1142.    exp_es[ exp_esc ].operation = VARIABLE;
  1143.  
  1144.    /* read subscripts */
  1145.  
  1146.    pos = strlen( exp_es[ exp_esc ].string );
  1147.    if ( ( v->dimensions == 1 ) && ( v->array_sizes[ 0 ] == 1 ))
  1148.       {
  1149.       #if INTENSIVE_DEBUG
  1150.       sprintf( bwb_ebuf, "in exp_variable(): variable <%s> has 1 dimension",
  1151.          exp_es[ exp_esc ].xvar->name );
  1152.       bwb_debug( bwb_ebuf );
  1153.       #endif
  1154.       pos = strlen( v->name );
  1155.       n_params = 1;
  1156.       pp = &p;
  1157.       pp[ 0 ] = dim_base;
  1158.       }
  1159.    else
  1160.       {
  1161.       #if INTENSIVE_DEBUG
  1162.       sprintf( bwb_ebuf, "in exp_variable(): variable <%s> has > 1 dimensions",
  1163.          exp_es[ exp_esc ].xvar->name );
  1164.       bwb_debug( bwb_ebuf );
  1165.       #endif
  1166.       dim_getparams( expression, &pos, &n_params, &pp );
  1167.       }
  1168.  
  1169.    exp_es[ exp_esc ].pos_adv = pos;
  1170.    for ( n = 0; n < v->dimensions; ++n )
  1171.       {
  1172.       exp_es[ exp_esc ].array_pos[ n ] = v->array_pos[ n ] = pp[ n ];
  1173.       }
  1174.  
  1175.    #if INTENSIVE_DEBUG
  1176.    for ( n = 0; n < v->dimensions; ++ n )
  1177.       {
  1178.       sprintf( bwb_ebuf, "in exp_variable(): var <%s> array_pos element <%d> is <%d>.",
  1179.          v->name, n, v->array_pos[ n ] );
  1180.       bwb_debug( bwb_ebuf );
  1181.       }
  1182.    #endif
  1183.  
  1184.    /* assign the type and value at this level */
  1185.  
  1186.    exp_es[ exp_esc ].type = (char) v->type;
  1187.    
  1188.    switch( v->type )
  1189.       {
  1190.       case STRING:
  1191.          b = var_findsval( v, v->array_pos );
  1192.          #if TEST_BSTRING
  1193.          sprintf( bwb_ebuf, "in exp_variable(): b string name is <%s>",
  1194.             b->name );
  1195.          bwb_debug( bwb_ebuf );
  1196.          #endif
  1197.          exp_es[ exp_esc ].sval.length = b->length;
  1198.          exp_es[ exp_esc ].sval.buffer = b->buffer;
  1199.          break;
  1200.       case DOUBLE:
  1201.          exp_es[ exp_esc ].dval = var_getdval( v );
  1202.          break;
  1203.       case INTEGER:
  1204.          exp_es[ exp_esc ].ival = var_getival( v );
  1205.          break;
  1206.       default:
  1207.          exp_es[ exp_esc ].fval = var_getfval( v );
  1208.          break;
  1209.       }
  1210.  
  1211.    #if INTENSIVE_DEBUG
  1212.    sprintf( bwb_ebuf, "in exp_variable(): exit, name <%s>, level <%d>, op <%d>",
  1213.       v->name, exp_esc, exp_es[ exp_esc ].operation  );
  1214.    bwb_debug( bwb_ebuf );
  1215.    #endif
  1216.  
  1217.    /* return */
  1218.  
  1219.    return TRUE;
  1220.  
  1221.    }
  1222.  
  1223.  
  1224.