home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / m4v05as.zip / EVAL.C < prev    next >
C/C++ Source or Header  |  1992-02-22  |  12KB  |  627 lines

  1. /*
  2.  * GNU m4 -- A simple macro processor
  3.  * Copyright (C) 1989, 1990 Free Software Foundation, Inc. 
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 1, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. /*
  21.  * MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  22.  * This port is also distributed under the terms of the
  23.  * GNU General Public License as published by the
  24.  * Free Software Foundation.
  25.  *
  26.  * Please note that this file is not identical to the
  27.  * original GNU release, you should have received this
  28.  * code as patch to the official release.
  29.  *
  30.  * $Header: e:/gnu/m4/RCS/eval.c 0.5.1.0 90/09/28 18:34:58 tho Exp $
  31.  */
  32.  
  33. /* 
  34.  * This file contains teh functions to evaluate integer expressions for
  35.  * the "eval" macro.  It is a little, fairly self contained module, with
  36.  * its own scanner, and a recursive descent parser.  The only entry
  37.  * point is evaluate().
  38.  */
  39.  
  40. #include "m4.h"
  41.  
  42. /* 
  43.  * Evaluates token types.
  44.  */
  45. typedef enum eval_token {
  46.     ERROR,
  47.     PLUS, MINUS,
  48.     EXPONENT,
  49.     TIMES, DIVIDE, MODULO,
  50.     EQ, NOTEQ, GT, GTEQ, LS, LSEQ,
  51.     NOT,
  52.     LAND, LOR,
  53.     AND, OR,
  54.     LEFTP, RIGHTP,
  55.     NUMBER, EOTEXT,
  56. } eval_token;
  57.  
  58. /* 
  59.  * Error types.
  60.  */
  61. typedef enum eval_error {
  62.     NO_ERROR,
  63.     MISSING_RIGHT,
  64.     SYNTAX_ERROR,
  65.     UNKNOWN_INPUT,
  66.     DIVIDE_ZERO,
  67.     MODULO_ZERO,
  68. } eval_error;
  69.  
  70. #ifdef MSDOS
  71.  
  72. static enum eval_error add_term (enum eval_token et, eval_t *v1);
  73. static enum eval_error and_term (enum eval_token et, eval_t *v1);
  74. static enum eval_error cmp_term (enum eval_token et, eval_t *v1);
  75. static enum eval_error exp_term (enum eval_token et, eval_t *v1);
  76. static enum eval_error logical_and_term (enum eval_token et, eval_t *v1);
  77. static enum eval_error logical_or_term (enum eval_token et, eval_t *v1);
  78. static enum eval_error mult_term (enum eval_token et, eval_t *v1);
  79. static enum eval_error not_term (enum eval_token et, eval_t *v1);
  80. static enum eval_error or_term (enum eval_token et, eval_t *v1);
  81. static enum eval_error simple_term (enum eval_token et, eval_t *v1);
  82. static enum eval_error unary_term (enum eval_token et, eval_t *v1);
  83. static enum eval_token eval_lex (eval_t *val);
  84. static void eval_init_lex (char *text);
  85. static void eval_undo (void);
  86.  
  87. #else /* not MSDOS */
  88.  
  89. static eval_error logical_or_term();
  90. static eval_error logical_and_term();
  91. static eval_error or_term();
  92. static eval_error and_term();
  93. static eval_error not_term();
  94. static eval_error cmp_term();
  95. static eval_error add_term();
  96. static eval_error mult_term();
  97. static eval_error exp_term();
  98. static eval_error unary_term();
  99. static eval_error simple_term();
  100.  
  101. #endif /* not MSDOS */
  102.  
  103. /* 
  104.  * Lexical functions.
  105.  */
  106.  
  107. /* Pointer to next character of input text */
  108. static char *eval_text;
  109.  
  110. /* Value of eval_text, from before last call of eval_lex().  This is so we
  111.    can back up, if we have read too much */
  112. static char *last_text;
  113.  
  114. static void 
  115. eval_init_lex(text)
  116.     char *text;
  117. {
  118.     eval_text = text;
  119.     last_text = nil;
  120. }
  121.  
  122. static void 
  123. eval_undo()
  124. {
  125.     eval_text = last_text;
  126. }
  127.  
  128. static eval_token 
  129. eval_lex(val)
  130.     eval_t *val;                /* numerical value, if any */
  131. {
  132.     while (isspace(*eval_text))
  133.     eval_text++;
  134.  
  135.     last_text = eval_text;
  136.  
  137.     if (*eval_text == '\0')
  138.     return EOTEXT;
  139.  
  140.     if (isdigit(*eval_text)) {
  141.     char *digits, *tmp;
  142.     int base;
  143.  
  144.     if (*eval_text == '0') {
  145.         if (*++eval_text == 'x' || *eval_text == 'X') {
  146.         base = 16;
  147.         digits = "0123456789abcdef";
  148.         eval_text++;
  149.         } else {
  150.         base = 8;
  151.         digits = "01234567";
  152.         }
  153.     } else {
  154.         base = 10;
  155.         digits = "0123456789";
  156.     }
  157.     (*val) = 0;
  158.     while (*eval_text && (tmp = index(digits, *eval_text)) != nil) {
  159.         (*val) = (*val) * base + (tmp - digits);
  160.         eval_text++;
  161.     }
  162.     return NUMBER;
  163.     }
  164.     
  165.     switch (*eval_text++) {
  166.     case '+':
  167.     return PLUS;
  168.     case '-':
  169.     return MINUS;
  170.     case '*':
  171.     if (*eval_text == '*') {
  172.         eval_text++;
  173.         return EXPONENT;
  174.     } else
  175.         return TIMES;
  176.     case '^':
  177.     return EXPONENT;
  178.     case '/':
  179.     return DIVIDE;
  180.     case '%':
  181.     return MODULO;
  182.     case '=':
  183.     if (*eval_text == '=')
  184.         eval_text++;
  185.     return EQ;
  186.     case '!':
  187.     if (*eval_text == '=') {
  188.         eval_text++;
  189.         return NOTEQ;
  190.     } else
  191.         return NOT;
  192.     case '>':
  193.     if (*eval_text == '=') {
  194.         eval_text++;
  195.         return GTEQ;
  196.     } else
  197.         return GT;
  198.     case '<':
  199.     if (*eval_text == '=') {
  200.         eval_text++;
  201.         return LSEQ;
  202.     } else
  203.         return LS;
  204.     case '&':
  205.     if (*eval_text == '&') {
  206.         eval_text++;
  207.         return LAND;
  208.     } else
  209.         return AND;
  210.     case '|':
  211.     if (*eval_text == '|') {
  212.         eval_text++;
  213.         return LOR;
  214.     } else
  215.         return OR;
  216.     case '(':
  217.     return LEFTP;
  218.     case ')':
  219.     return RIGHTP;
  220.     default:
  221.     return ERROR;
  222.     }
  223. }
  224.  
  225. /* 
  226.  * Main entry point, called from "eval".
  227.  */
  228. boolean 
  229. evaluate(expr, val)
  230.     char *expr;
  231.     eval_t *val;
  232. {
  233.     eval_token et;
  234.     eval_error err;
  235.  
  236.     eval_init_lex(expr);
  237.     et = eval_lex(val);
  238.     err = logical_or_term(et, val);
  239.  
  240.     switch (err) {
  241.     case NO_ERROR:
  242.     break;
  243.     case MISSING_RIGHT:
  244.     error("bad expression in eval (missing right paren): %s", expr);
  245.     break;
  246.     case SYNTAX_ERROR:
  247.     error("bad expression in eval: %s", expr);
  248.     break;
  249.     case UNKNOWN_INPUT:
  250.     error("bad expression in eval (bad input): %s", expr);
  251.     break;
  252.     case DIVIDE_ZERO:
  253.     error("divide by zero in eval: %s", expr);
  254.     break;
  255.     case MODULO_ZERO:
  256.     error("modulo by zero in eval: %s", expr);
  257.     break;
  258.     default:
  259.     internal_error("Bad error code in evaluate()");
  260.     break;
  261.     }
  262.  
  263.     return (boolean)(err != NO_ERROR);
  264. }
  265.  
  266. /* 
  267.  * Recursive descent parser.
  268.  */
  269. static eval_error 
  270. logical_or_term(et, v1)
  271.     eval_token et;
  272.     eval_t *v1;
  273. {
  274.     eval_t v2;
  275.     eval_error er;
  276.  
  277.     if (er = logical_and_term(et, v1))
  278.     return er;
  279.  
  280.     while ((et = eval_lex(&v2)) == LOR) {
  281.     et = eval_lex(&v2);
  282.     if (et == ERROR)
  283.         return UNKNOWN_INPUT;
  284.  
  285.     if (er = logical_and_term(et, &v2))
  286.         return er;
  287.  
  288.     *v1 = *v1 || v2;
  289.     }
  290.     if (et == ERROR)
  291.     return UNKNOWN_INPUT;
  292.  
  293.     eval_undo();
  294.     return NO_ERROR;
  295. }
  296.  
  297. static eval_error 
  298. logical_and_term(et, v1)
  299.     eval_token et;
  300.     eval_t *v1;
  301. {
  302.     eval_t v2;
  303.     eval_error er;
  304.    
  305.     if (er = or_term(et, v1))
  306.     return er;
  307.  
  308.     while ((et = eval_lex(&v2)) == LAND) {
  309.     et = eval_lex(&v2);
  310.     if (et == ERROR)
  311.         return UNKNOWN_INPUT;
  312.  
  313.     if (er = or_term(et, &v2))
  314.         return er;
  315.  
  316.     *v1 = *v1 && v2;
  317.     }
  318.     if (et == ERROR)
  319.     return UNKNOWN_INPUT;
  320.  
  321.     eval_undo();
  322.     return NO_ERROR;
  323. }
  324.  
  325. static eval_error 
  326. or_term(et, v1)
  327.     eval_token et;
  328.     eval_t *v1;
  329. {
  330.     eval_t v2;
  331.     eval_error er;
  332.  
  333.     if (er = and_term(et, v1))
  334.     return er;
  335.  
  336.     while ((et = eval_lex(&v2)) == OR) {
  337.     et = eval_lex(&v2);
  338.     if (et == ERROR)
  339.         return UNKNOWN_INPUT;
  340.  
  341.     if (er = and_term(et, &v2))
  342.         return er;
  343.  
  344.     *v1 = *v1 | v2;
  345.     }
  346.     if (et == ERROR)
  347.     return UNKNOWN_INPUT;
  348.  
  349.     eval_undo();
  350.     return NO_ERROR;
  351. }
  352.  
  353. static eval_error 
  354. and_term(et, v1)
  355.     eval_token et;
  356.     eval_t *v1;
  357. {
  358.     eval_t v2;
  359.     eval_error er;
  360.  
  361.     if (er = not_term(et, v1))
  362.     return er;
  363.  
  364.     while ((et = eval_lex(&v2)) == AND) {
  365.     et = eval_lex(&v2);
  366.     if (et == ERROR)
  367.         return UNKNOWN_INPUT;
  368.  
  369.     if (er = not_term(et, &v2))
  370.         return er;
  371.  
  372.     *v1 = *v1 & v2;
  373.     }
  374.     if (et == ERROR)
  375.     return UNKNOWN_INPUT;
  376.  
  377.     eval_undo();
  378.     return NO_ERROR;
  379. }
  380.  
  381. static eval_error 
  382. not_term(et, v1)
  383.     eval_token et;
  384.     eval_t *v1;
  385. {
  386.     eval_error er;
  387.  
  388.     if (et == NOT) {
  389.     et = eval_lex(v1);
  390.     if (et == ERROR)
  391.         return UNKNOWN_INPUT;
  392.  
  393.     if (er = not_term(et, v1))
  394.         return er;
  395.     *v1 = !*v1;
  396.     } else
  397.     if (er = cmp_term(et, v1))
  398.         return er;
  399.  
  400.     return NO_ERROR;
  401. }
  402.  
  403. static eval_error 
  404. cmp_term(et, v1)
  405.     eval_token et;
  406.     eval_t *v1;
  407. {
  408.     eval_token op;
  409.     eval_t v2;
  410.     eval_error er;
  411.  
  412.     if (er = add_term(et, v1))
  413.     return er;
  414.  
  415.     while ((op = eval_lex(&v2)) == EQ || op == NOTEQ
  416.        || op == GT || op == GTEQ
  417.        || op == LS || op == LSEQ) {
  418.  
  419.     et = eval_lex(&v2);
  420.     if (et == ERROR)
  421.         return UNKNOWN_INPUT;
  422.  
  423.     if (er = add_term(et, &v2))
  424.         return er;
  425.  
  426.     switch (op) {
  427.     case EQ:
  428.         *v1 = *v1 == v2;
  429.         break;
  430.     case NOTEQ:
  431.         *v1 = *v1 != v2;
  432.         break;
  433.     case GT:
  434.         *v1 = *v1 > v2;
  435.         break;
  436.     case GTEQ:
  437.         *v1 = *v1 >= v2;
  438.         break;
  439.     case LS:
  440.         *v1 = *v1 < v2;
  441.         break;
  442.     case LSEQ:
  443.         *v1 = *v1 <= v2;
  444.         break;
  445.     default:
  446.         internal_error("Bad comparison operator in cmp_term()");
  447.         break;
  448.     }
  449.     }
  450.     if (op == ERROR)
  451.     return UNKNOWN_INPUT;
  452.  
  453.     eval_undo();
  454.     return NO_ERROR;
  455. }
  456.  
  457. static eval_error 
  458. add_term(et, v1)
  459.     eval_token et;
  460.     eval_t *v1;
  461. {
  462.     eval_token op;
  463.     eval_t v2;
  464.     eval_error er;
  465.  
  466.     if (er = mult_term(et, v1))
  467.     return er;
  468.  
  469.     while ((op = eval_lex(&v2)) == PLUS || op == MINUS) {
  470.     et = eval_lex(&v2);
  471.     if (et == ERROR)
  472.         return UNKNOWN_INPUT;
  473.  
  474.     if (er = mult_term(et, &v2))
  475.         return er;
  476.  
  477.     if (op == PLUS)
  478.         *v1 = *v1 + v2;
  479.     else
  480.         *v1 = *v1 - v2;
  481.     }
  482.     if (op == ERROR)
  483.     return UNKNOWN_INPUT;
  484.  
  485.     eval_undo();
  486.     return NO_ERROR;
  487. }
  488.  
  489. static eval_error 
  490. mult_term(et, v1)
  491.     eval_token et;
  492.     eval_t *v1;
  493. {
  494.     eval_token op;
  495.     eval_t v2;
  496.     eval_error er;
  497.  
  498.     if (er = exp_term(et, v1))
  499.     return er;
  500.  
  501.     while ((op = eval_lex(&v2)) == TIMES || op == DIVIDE || op == MODULO) {
  502.     et = eval_lex(&v2);
  503.     if (et == ERROR)
  504.         return UNKNOWN_INPUT;
  505.  
  506.     if (er = exp_term(et, &v2))
  507.         return er;
  508.  
  509.     switch (op) {
  510.     case TIMES:
  511.         *v1 = *v1 * v2;
  512.         break;
  513.     case DIVIDE:
  514.         if (v2 == 0)
  515.         return DIVIDE_ZERO;
  516.         else
  517.         *v1 = *v1 / v2;
  518.         break;
  519.     case MODULO:
  520.         if (v2 == 0)
  521.         return MODULO_ZERO;
  522.         else
  523.         *v1 = *v1 % v2;
  524.         break;
  525.     default:
  526.         internal_error("Bad operator in mult_term()");
  527.         break;
  528.     }
  529.     }
  530.     if (op == ERROR)
  531.     return UNKNOWN_INPUT;
  532.  
  533.     eval_undo();
  534.     return NO_ERROR;
  535. }
  536.  
  537. static eval_error 
  538. exp_term(et, v1)
  539.     eval_token et;
  540.     eval_t *v1;
  541. {
  542.     register eval_t result;
  543.     eval_t v2;
  544.     eval_error er;
  545.  
  546.     if (er = unary_term(et, v1))
  547.     return er;
  548.     result = *v1;
  549.     
  550.     while ((et = eval_lex(&v2)) == EXPONENT) {
  551.     et = eval_lex(&v2);
  552.     if (et == ERROR)
  553.         return UNKNOWN_INPUT;
  554.  
  555.     if (er = exp_term(et, &v2))
  556.         return er;
  557.  
  558.     result = *v1;
  559.     while (--v2 > 0)
  560.         result *= *v1;
  561.     *v1 = result;
  562.     }
  563.     if (et == ERROR)
  564.     return UNKNOWN_INPUT;
  565.  
  566.     eval_undo();
  567.     return NO_ERROR;
  568. }
  569.  
  570. static eval_error 
  571. unary_term(et, v1)
  572.     eval_token et;
  573.     eval_t *v1;
  574. {
  575.     eval_token et2 = et;
  576.     eval_error er;
  577.  
  578.     if (et == PLUS || et == MINUS) {
  579.     et2 = eval_lex(v1);
  580.     if (et2 == ERROR)
  581.         return UNKNOWN_INPUT;
  582.  
  583.     if (er = simple_term(et2, v1))
  584.         return er;
  585.  
  586.     if (et == MINUS)
  587.         *v1 = -*v1;
  588.     } else
  589.     if (er = simple_term(et, v1))
  590.         return er;
  591.  
  592.     return NO_ERROR;
  593. }
  594.  
  595. static eval_error 
  596. simple_term(et, v1)
  597.     eval_token et;
  598.     eval_t *v1;
  599. {
  600.     eval_t v2;
  601.     eval_error er;
  602.  
  603.     switch (et) {
  604.     case LEFTP:
  605.     et = eval_lex(v1);
  606.     if (et == ERROR)
  607.         return UNKNOWN_INPUT;
  608.  
  609.     if (er = logical_or_term(et, v1))
  610.         return er;
  611.  
  612.     et = eval_lex(&v2);
  613.     if (et == ERROR)
  614.         return UNKNOWN_INPUT;
  615.  
  616.     if (et != RIGHTP)
  617.         return MISSING_RIGHT;
  618.  
  619.     break;
  620.     case NUMBER:
  621.     break;
  622.     default:
  623.     return SYNTAX_ERROR;
  624.     }
  625.     return NO_ERROR;
  626. }
  627.