home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / troff / number.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  12.6 KB  |  663 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.uucp)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 1, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file LICENSE.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21.  
  22. #include "groff.h"
  23. #include "symbol.h"
  24. #include "hvunits.h"
  25. #include "env.h"
  26. #include "token.h"
  27. #include "div.h"
  28.  
  29. vunits V0;
  30. hunits H0;
  31.  
  32. int hresolution = 1;
  33. int vresolution = 1;
  34. int units_per_inch;
  35. int sizescale;
  36.  
  37. static int parse_expr(units *v, int scale_indicator, int parenthesised);
  38. static int start_number();
  39.  
  40. int get_vunits(vunits *res, unsigned char si)
  41. {
  42.   if (!start_number())
  43.     return 0;
  44.   units x;
  45.   if (parse_expr(&x, si, 0)) {
  46.     *res = vunits(x);
  47.     return 1;
  48.   }
  49.   else
  50.     return 0;
  51. }
  52.  
  53. int get_hunits(hunits *res, unsigned char si)
  54. {
  55.   if (!start_number())
  56.     return 0;
  57.   units x;
  58.   if (parse_expr(&x, si, 0)) {
  59.     *res = hunits(x);
  60.     return 1;
  61.   }
  62.   else
  63.     return 0;
  64. }
  65.  
  66. int get_number(units *res, unsigned char si)
  67. {
  68.   if (!start_number())
  69.     return 0;
  70.   units x;
  71.   if (parse_expr(&x, si, 0)) {
  72.     *res = x;
  73.     return 1;
  74.   }
  75.   else
  76.     return 0;
  77. }
  78.  
  79. int get_integer(int *res)
  80. {
  81.   if (!start_number())
  82.     return 0;
  83.   units x;
  84.   if (parse_expr(&x, 0, 0)) {
  85.     *res = x;
  86.     return 1;
  87.   }
  88.   else
  89.     return 0;
  90. }
  91.  
  92. enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
  93.  
  94. static incr_number_result get_incr_number(units *res, unsigned char);
  95.  
  96. int get_vunits(vunits *res, unsigned char si, vunits prev_value)
  97. {
  98.   units v;
  99.   switch (get_incr_number(&v, si)) {
  100.   case BAD:
  101.     return 0;
  102.   case ABSOLUTE:
  103.     *res = v;
  104.     break;
  105.   case INCREMENT:
  106.     *res = prev_value + v;
  107.     break;
  108.   case DECREMENT:
  109.     *res = prev_value - v;
  110.     break;
  111.   default:
  112.     assert(0);
  113.   }
  114.   return 1;
  115. }
  116.  
  117. int get_hunits(hunits *res, unsigned char si, hunits prev_value)
  118. {
  119.   units v;
  120.   switch (get_incr_number(&v, si)) {
  121.   case BAD:
  122.     return 0;
  123.   case ABSOLUTE:
  124.     *res = v;
  125.     break;
  126.   case INCREMENT:
  127.     *res = prev_value + v;
  128.     break;
  129.   case DECREMENT:
  130.     *res = prev_value - v;
  131.     break;
  132.   default:
  133.     assert(0);
  134.   }
  135.   return 1;
  136. }
  137.  
  138. int get_number(units *res, unsigned char si, units prev_value)
  139. {
  140.   units v;
  141.   switch (get_incr_number(&v, si)) {
  142.   case BAD:
  143.     return 0;
  144.   case ABSOLUTE:
  145.     *res = v;
  146.     break;
  147.   case INCREMENT:
  148.     *res = prev_value + v;
  149.     break;
  150.   case DECREMENT:
  151.     *res = prev_value - v;
  152.     break;
  153.   default:
  154.     assert(0);
  155.   }
  156.   return 1;
  157. }
  158.  
  159. int get_integer(int *res, int prev_value)
  160. {
  161.   units v;
  162.   switch (get_incr_number(&v, 0)) {
  163.   case BAD:
  164.     return 0;
  165.   case ABSOLUTE:
  166.     *res = v;
  167.     break;
  168.   case INCREMENT:
  169.     *res = prev_value + int(v);
  170.     break;
  171.   case DECREMENT:
  172.     *res = prev_value - int(v);
  173.     break;
  174.   default:
  175.     assert(0);
  176.   }
  177.   return 1;
  178. }
  179.  
  180.  
  181. static incr_number_result get_incr_number(units *res, unsigned char si)
  182. {
  183.   if (!start_number())
  184.     return BAD;
  185.   incr_number_result result = ABSOLUTE;
  186.   if (tok.ch() == '+') {
  187.     tok.next();
  188.     result = INCREMENT;
  189.   }
  190.   else if (tok.ch() == '-') {
  191.     tok.next();
  192.     result = DECREMENT;
  193.   }
  194.   if (parse_expr(res, si, 0))
  195.     return result;
  196.   else
  197.     return BAD;
  198. }
  199.  
  200. static int start_number()
  201. {
  202.   while (tok.space())
  203.     tok.next();
  204.   if (tok.newline()) {
  205.     warning(WARN_MISSING, "missing number");
  206.     return 0;
  207.   }
  208.   if (tok.tab()) {
  209.     warning(WARN_TAB, "tab character where number expected");
  210.     return 0;
  211.   }
  212.   if (tok.right_brace()) {
  213.     warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
  214.     return 0;
  215.   }
  216.   return 1;
  217. }
  218.  
  219. enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
  220.  
  221. #define SCALE_INDICATOR_CHARS "icPmnpuvMsz"
  222.  
  223. static int parse_term(units *v, int scale_indicator, int parenthesised);
  224.  
  225. static int parse_expr(units *v, int scale_indicator, int parenthesised)
  226. {
  227.   int result = parse_term(v, scale_indicator, parenthesised);
  228.   while (result) {
  229.     if (parenthesised)
  230.       tok.skip();
  231.     int op = tok.ch();
  232.     switch (op) {
  233.     case '+':
  234.     case '-':
  235.     case '/':
  236.     case '*':
  237.     case '%':
  238.     case ':':
  239.     case '&':
  240.       tok.next();
  241.       break;
  242.     case '>':
  243.       tok.next();
  244.       if (tok.ch() == '=') {
  245.     tok.next();
  246.     op = OP_GEQ;
  247.       }
  248.       else if (tok.ch() == '?') {
  249.     tok.next();
  250.     op = OP_MAX;
  251.       }
  252.       break;
  253.     case '<':
  254.       tok.next();
  255.       if (tok.ch() == '=') {
  256.     tok.next();
  257.     op = OP_LEQ;
  258.       }
  259.       else if (tok.ch() == '?') {
  260.     tok.next();
  261.     op = OP_MIN;
  262.       }
  263.       break;
  264.     case '=':
  265.       tok.next();
  266.       if (tok.ch() == '=')
  267.     tok.next();
  268.       break;
  269.     default:
  270.       return result;
  271.     }
  272.     units v2;
  273.     if (!parse_term(&v2, scale_indicator, parenthesised))
  274.       return 0;
  275.     int overflow = 0;
  276.     switch (op) {
  277.     case '<':
  278.       *v = *v < v2;
  279.       break;
  280.     case '>':
  281.       *v = *v > v2;
  282.       break;
  283.     case OP_LEQ:
  284.       *v = *v <= v2;
  285.       break;
  286.     case OP_GEQ:
  287.       *v = *v >= v2;
  288.       break;
  289.     case OP_MIN:
  290.       if (*v > v2)
  291.     *v = v2;
  292.       break;
  293.     case OP_MAX:
  294.       if (*v < v2)
  295.     *v = v2;
  296.       break;
  297.     case '=':
  298.       *v = *v == v2;
  299.       break;
  300.     case '&':
  301.       *v = *v > 0 && v2 > 0;
  302.       break;
  303.     case ':':
  304.       *v = *v > 0 || v2 > 0;
  305.     case '+':
  306.       if (v2 < 0) {
  307.     if (*v < INT_MIN - v2)
  308.       overflow = 1;
  309.       }
  310.       else if (v2 > 0) {
  311.     if (*v > INT_MAX - v2)
  312.       overflow = 1;
  313.       }
  314.       if (overflow) {
  315.     error("addition overflow");
  316.     return 0;
  317.       }
  318.       *v += v2;
  319.       break;
  320.     case '-':
  321.       if (v2 < 0) {
  322.     if (*v > INT_MAX + v2)
  323.       overflow = 1;
  324.       }
  325.       else if (v2 > 0) {
  326.     if (*v < INT_MIN + v2)
  327.       overflow = 1;
  328.       }
  329.       if (overflow) {
  330.     error("subtraction overflow");
  331.     return 0;
  332.       }
  333.       *v -= v2;
  334.       break;
  335.     case '*':
  336.       if (v2 < 0) {
  337.     if (*v > 0) {
  338.       if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
  339.         overflow = 1;
  340.     }
  341.     else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
  342.       overflow = 1;
  343.       }
  344.       else if (v2 > 0) {
  345.     if (*v > 0) {
  346.       if (*v > INT_MAX / v2)
  347.         overflow = 1;
  348.     }
  349.     else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
  350.       overflow = 1;
  351.       }
  352.       if (overflow) {
  353.     error("multiplication overflow");
  354.     return 0;
  355.       }
  356.       *v *= v2;
  357.       break;
  358.     case '/':
  359.       if (v2 == 0) {
  360.     error("division by zero");
  361.     return 0;
  362.       }
  363.       *v /= v2;
  364.       break;
  365.     case '%':
  366.       if (v2 == 0) {
  367.     error("modulus by zero");
  368.     return 0;
  369.       }
  370.       *v %= v2;
  371.       break;
  372.     default:
  373.       assert(0);
  374.     }
  375.   }
  376.   return result;
  377. }
  378.  
  379. static int parse_term(units *v, int scale_indicator, int parenthesised)
  380. {
  381.   int negative = 0;
  382.   for (;;)
  383.     if (parenthesised && tok.space())
  384.       tok.next();
  385.     else if (tok.ch() == '+')
  386.       tok.next();
  387.     else if (tok.ch() == '-') {
  388.       tok.next();
  389.       negative = !negative;
  390.     }
  391.     else if (tok.is_size()) {
  392.       tok.process();
  393.       tok.next();
  394.     }
  395.     else
  396.       break;
  397.   unsigned char c = tok.ch();
  398.   switch (c) {
  399.   case '|':
  400.     // | is not restricted to the outermost level
  401.     // tbl uses this
  402.     tok.next();
  403.     if (!parse_term(v, scale_indicator, parenthesised))
  404.       return 0;
  405.     int tem = (scale_indicator == 'v'
  406.            ? curdiv->get_vertical_position().to_units()
  407.            : curenv->get_input_line_position().to_units());
  408.     if (*v < INT_MIN + tem) {
  409.       error("numeric overflow");
  410.       return 0;
  411.     }
  412.     *v -= tem;
  413.     if (negative) {
  414.       if (*v == INT_MIN) {
  415.     error("numeric overflow");
  416.     return 0;
  417.       }
  418.       *v = -*v;
  419.     }
  420.     return 1;
  421.   case '(':
  422.     tok.next();
  423.     c = tok.ch();
  424.     if (c == ')') {
  425.       warning(WARN_SYNTAX, "empty parentheses");
  426.       tok.next();
  427.       *v = 0;
  428.       return 1;
  429.     }
  430.     else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
  431.       tok.next();
  432.       if (tok.ch() == ';') {
  433.     tok.next();
  434.     scale_indicator = c;
  435.       }
  436.       else {
  437.     error("expected `;' after scale-indicator");
  438.     return 0;
  439.       }
  440.     }
  441.     else if (c == ';') {
  442.       scale_indicator = 0;
  443.       tok.next();
  444.     }
  445.     if (!parse_expr(v, scale_indicator, 1))
  446.       return 0;
  447.     tok.skip();
  448.     if (tok.ch() != ')') {
  449.       warning(WARN_SYNTAX, "missing ')'");
  450.     }
  451.     else
  452.       tok.next();
  453.     if (negative) {
  454.       if (*v == INT_MIN) {
  455.     error("numeric overflow");
  456.     return 0;
  457.       }
  458.       *v = -*v;
  459.     }
  460.     return 1;
  461.   case '.':
  462.     *v = 0;
  463.     break;
  464.   case '0':
  465.   case '1':
  466.   case '2':
  467.   case '3':
  468.   case '4':
  469.   case '5':
  470.   case '6':
  471.   case '7':
  472.   case '8':
  473.   case '9':
  474.     *v = 0;
  475.     do {
  476.       if (*v > INT_MAX/10) {
  477.     error("numeric overflow");
  478.     return 0;
  479.       }
  480.       *v *= 10;
  481.       if (*v > INT_MAX - (c - '0')) {
  482.     error("numeric overflow");
  483.     return 0;
  484.       }
  485.       *v += c - '0';
  486.       tok.next();
  487.       c = tok.ch();
  488.     } while (csdigit(c));
  489.     break;
  490.   case '/':
  491.   case '*':
  492.   case '%':
  493.   case ':':
  494.   case '&':
  495.   case '>':
  496.   case '<':
  497.   case '=':
  498.     warning(WARN_SYNTAX, "empty left operand");
  499.     *v = 0;
  500.     return 1;
  501.   default:
  502.     warning(WARN_NUMBER, "numeric expression expected (got %1)",
  503.         tok.description());
  504.     return 0;
  505.   }
  506.   int divisor = 1;
  507.   if (tok.ch() == '.') {
  508.     tok.next();
  509.     for (;;) {
  510.       c = tok.ch();
  511.       if (!csdigit(c))
  512.     break;
  513.       // we may multiply the divisor by 254 later on
  514.       if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
  515.     *v *= 10;
  516.     *v += c - '0';
  517.     divisor *= 10;
  518.       }
  519.       tok.next();
  520.     }
  521.   }
  522.   int si = scale_indicator;
  523.   if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
  524.     switch (scale_indicator) {
  525.     case 'z':
  526.       if (c != 'u' && c != 'z') {
  527.     warning(WARN_SCALE,
  528.         "only `z' and `u' scale indicators valid in this context");
  529.     break;
  530.       }
  531.       si = c;
  532.       break;
  533.     case 0:
  534.       warning(WARN_SCALE, "scale indicator invalid in this context");
  535.       break;
  536.     case 'u':
  537.       si = c;
  538.       break;
  539.     default:
  540.       if (c == 'z') {
  541.     warning(WARN_SCALE, "`z' scale indicator invalid in this context");
  542.     break;
  543.       }
  544.       si = c;
  545.       break;
  546.     }
  547.     tok.next();
  548.   }
  549.   switch (si) {
  550.   case 'i':
  551.     *v = scale(*v, units_per_inch, divisor);
  552.     break;
  553.   case 'c':
  554.     *v = scale(*v, units_per_inch*100, divisor*254);
  555.     break;
  556.   case 0:
  557.   case 'u':
  558.     if (divisor != 1)
  559.       *v /= divisor;
  560.     break;
  561.   case 'p':
  562.     *v = scale(*v, units_per_inch, divisor*72);
  563.     break;
  564.   case 'P':
  565.     *v = scale(*v, units_per_inch, divisor*6);
  566.     break;
  567.   case 'm':
  568.     {
  569.       // Convert to hunits so that with -Tascii `m' behaves as in nroff.
  570.       hunits em = curenv->get_size();
  571.       *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
  572.     }
  573.     break;
  574.   case 'M':
  575.     {
  576.       hunits em = curenv->get_size();
  577.       *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
  578.     }
  579.     break;
  580.   case 'n':
  581.     {
  582.       // Convert to hunits so that with -Tascii `n' behaves as in nroff.
  583.       hunits en = curenv->get_size()/2;
  584.       *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
  585.     }
  586.     break;
  587.   case 'v':
  588.     *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
  589.     break;
  590.   case 's':
  591.     while (divisor > INT_MAX/(sizescale*72)) {
  592.       divisor /= 10;
  593.       *v /= 10;
  594.     }
  595.     *v = scale(*v, units_per_inch, divisor*sizescale*72);
  596.     break;
  597.   case 'z':
  598.     *v = scale(*v, sizescale, divisor);
  599.     break;
  600.   default:
  601.     assert(0);
  602.   }
  603.   if (tok.is_size()) {
  604.     tok.process();
  605.     tok.next();
  606.   }
  607.   if (negative) {
  608.     if (*v == INT_MIN) {
  609.       error("numeric overflow");
  610.       return 0;
  611.     }
  612.     *v = -*v;
  613.   }
  614.   return 1;
  615. }
  616.  
  617. units scale(units n, units x, units y)
  618. {
  619.   assert(x >= 0 && y > 0);
  620.   if (x == 0)
  621.     return 0;
  622.   if (n >= 0) {
  623.     if (n <= INT_MAX/x)
  624.       return (n*x)/y;
  625.   }
  626.   else {
  627.     if (-(unsigned)n <= -(unsigned)INT_MIN/x)
  628.       return (n*x)/y;
  629.   }
  630.   double res = n*double(x)/double(y);
  631.   if (res > INT_MAX) {
  632.     error("numeric overflow");
  633.     return INT_MAX;
  634.   }
  635.   else if (res < INT_MIN) {
  636.     error("numeric overflow");
  637.     return INT_MIN;
  638.   }
  639.   return int(res);
  640. }
  641.  
  642. vunits::vunits(units x)
  643. {
  644.   // don't depend on the rounding direction for division of negative integers
  645.   if (vresolution == 1)
  646.     n = x;
  647.   else
  648.     n = (x < 0
  649.      ? -((-x + vresolution/2 - 1)/vresolution)
  650.      : (x + vresolution/2 - 1)/vresolution);
  651. }
  652.  
  653. hunits::hunits(units x)
  654. {
  655.   // don't depend on the rounding direction for division of negative integers
  656.   if (hresolution == 1)
  657.     n = x;
  658.   else
  659.     n = (x < 0
  660.      ? -((-x + hresolution/2 - 1)/hresolution)
  661.      : (x + hresolution/2 - 1)/hresolution);
  662. }
  663.