home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / troff / number.cc < prev    next >
C/C++ Source or Header  |  1995-06-22  |  13KB  |  670 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  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 2, 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 COPYING.  If not, write to the Free Software
  19. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  20.  
  21.  
  22. #include "troff.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
  392.       break;
  393.   unsigned char c = tok.ch();
  394.   switch (c) {
  395.   case '|':
  396.     // | is not restricted to the outermost level
  397.     // tbl uses this
  398.     tok.next();
  399.     if (!parse_term(v, scale_indicator, parenthesised))
  400.       return 0;
  401.     int tem;
  402.     tem = (scale_indicator == 'v'
  403.        ? curdiv->get_vertical_position().to_units()
  404.        : curenv->get_input_line_position().to_units());
  405.     if (tem >= 0) {
  406.       if (*v < INT_MIN + tem) {
  407.     error("numeric overflow");
  408.     return 0;
  409.       }
  410.     }
  411.     else {
  412.       if (*v > INT_MAX + tem) {
  413.     error("numeric overflow");
  414.     return 0;
  415.       }
  416.     }
  417.     *v -= tem;
  418.     if (negative) {
  419.       if (*v == INT_MIN) {
  420.     error("numeric overflow");
  421.     return 0;
  422.       }
  423.       *v = -*v;
  424.     }
  425.     return 1;
  426.   case '(':
  427.     tok.next();
  428.     c = tok.ch();
  429.     if (c == ')') {
  430.       warning(WARN_SYNTAX, "empty parentheses");
  431.       tok.next();
  432.       *v = 0;
  433.       return 1;
  434.     }
  435.     else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
  436.       tok.next();
  437.       if (tok.ch() == ';') {
  438.     tok.next();
  439.     scale_indicator = c;
  440.       }
  441.       else {
  442.     error("expected `;' after scale-indicator (got %1)",
  443.           tok.description());
  444.     return 0;
  445.       }
  446.     }
  447.     else if (c == ';') {
  448.       scale_indicator = 0;
  449.       tok.next();
  450.     }
  451.     if (!parse_expr(v, scale_indicator, 1))
  452.       return 0;
  453.     tok.skip();
  454.     if (tok.ch() != ')') {
  455.       warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
  456.     }
  457.     else
  458.       tok.next();
  459.     if (negative) {
  460.       if (*v == INT_MIN) {
  461.     error("numeric overflow");
  462.     return 0;
  463.       }
  464.       *v = -*v;
  465.     }
  466.     return 1;
  467.   case '.':
  468.     *v = 0;
  469.     break;
  470.   case '0':
  471.   case '1':
  472.   case '2':
  473.   case '3':
  474.   case '4':
  475.   case '5':
  476.   case '6':
  477.   case '7':
  478.   case '8':
  479.   case '9':
  480.     *v = 0;
  481.     do {
  482.       if (*v > INT_MAX/10) {
  483.     error("numeric overflow");
  484.     return 0;
  485.       }
  486.       *v *= 10;
  487.       if (*v > INT_MAX - (int(c) - '0')) {
  488.     error("numeric overflow");
  489.     return 0;
  490.       }
  491.       *v += c - '0';
  492.       tok.next();
  493.       c = tok.ch();
  494.     } while (csdigit(c));
  495.     break;
  496.   case '/':
  497.   case '*':
  498.   case '%':
  499.   case ':':
  500.   case '&':
  501.   case '>':
  502.   case '<':
  503.   case '=':
  504.     warning(WARN_SYNTAX, "empty left operand");
  505.     *v = 0;
  506.     return 1;
  507.   default:
  508.     warning(WARN_NUMBER, "numeric expression expected (got %1)",
  509.         tok.description());
  510.     return 0;
  511.   }
  512.   int divisor = 1;
  513.   if (tok.ch() == '.') {
  514.     tok.next();
  515.     for (;;) {
  516.       c = tok.ch();
  517.       if (!csdigit(c))
  518.     break;
  519.       // we may multiply the divisor by 254 later on
  520.       if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
  521.     *v *= 10;
  522.     *v += c - '0';
  523.     divisor *= 10;
  524.       }
  525.       tok.next();
  526.     }
  527.   }
  528.   int si = scale_indicator;
  529.   int do_next = 0;
  530.   if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
  531.     switch (scale_indicator) {
  532.     case 'z':
  533.       if (c != 'u' && c != 'z') {
  534.     warning(WARN_SCALE,
  535.         "only `z' and `u' scale indicators valid in this context");
  536.     break;
  537.       }
  538.       si = c;
  539.       break;
  540.     case 0:
  541.       warning(WARN_SCALE, "scale indicator invalid in this context");
  542.       break;
  543.     case 'u':
  544.       si = c;
  545.       break;
  546.     default:
  547.       if (c == 'z') {
  548.     warning(WARN_SCALE, "`z' scale indicator invalid in this context");
  549.     break;
  550.       }
  551.       si = c;
  552.       break;
  553.     }
  554.     // Don't do tok.next() here because the next token might be \s, which
  555.     // would affect the interpretation of m.
  556.     do_next = 1;
  557.   }
  558.   switch (si) {
  559.   case 'i':
  560.     *v = scale(*v, units_per_inch, divisor);
  561.     break;
  562.   case 'c':
  563.     *v = scale(*v, units_per_inch*100, divisor*254);
  564.     break;
  565.   case 0:
  566.   case 'u':
  567.     if (divisor != 1)
  568.       *v /= divisor;
  569.     break;
  570.   case 'p':
  571.     *v = scale(*v, units_per_inch, divisor*72);
  572.     break;
  573.   case 'P':
  574.     *v = scale(*v, units_per_inch, divisor*6);
  575.     break;
  576.   case 'm':
  577.     {
  578.       // Convert to hunits so that with -Tascii `m' behaves as in nroff.
  579.       hunits em = curenv->get_size();
  580.       *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
  581.     }
  582.     break;
  583.   case 'M':
  584.     {
  585.       hunits em = curenv->get_size();
  586.       *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
  587.     }
  588.     break;
  589.   case 'n':
  590.     {
  591.       // Convert to hunits so that with -Tascii `n' behaves as in nroff.
  592.       hunits en = curenv->get_size()/2;
  593.       *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
  594.     }
  595.     break;
  596.   case 'v':
  597.     *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
  598.     break;
  599.   case 's':
  600.     while (divisor > INT_MAX/(sizescale*72)) {
  601.       divisor /= 10;
  602.       *v /= 10;
  603.     }
  604.     *v = scale(*v, units_per_inch, divisor*sizescale*72);
  605.     break;
  606.   case 'z':
  607.     *v = scale(*v, sizescale, divisor);
  608.     break;
  609.   default:
  610.     assert(0);
  611.   }
  612.   if (do_next)
  613.     tok.next();
  614.   if (negative) {
  615.     if (*v == INT_MIN) {
  616.       error("numeric overflow");
  617.       return 0;
  618.     }
  619.     *v = -*v;
  620.   }
  621.   return 1;
  622. }
  623.  
  624. units scale(units n, units x, units y)
  625. {
  626.   assert(x >= 0 && y > 0);
  627.   if (x == 0)
  628.     return 0;
  629.   if (n >= 0) {
  630.     if (n <= INT_MAX/x)
  631.       return (n*x)/y;
  632.   }
  633.   else {
  634.     if (-(unsigned)n <= -(unsigned)INT_MIN/x)
  635.       return (n*x)/y;
  636.   }
  637.   double res = n*double(x)/double(y);
  638.   if (res > INT_MAX) {
  639.     error("numeric overflow");
  640.     return INT_MAX;
  641.   }
  642.   else if (res < INT_MIN) {
  643.     error("numeric overflow");
  644.     return INT_MIN;
  645.   }
  646.   return int(res);
  647. }
  648.  
  649. vunits::vunits(units x)
  650. {
  651.   // don't depend on the rounding direction for division of negative integers
  652.   if (vresolution == 1)
  653.     n = x;
  654.   else
  655.     n = (x < 0
  656.      ? -((-x + vresolution/2 - 1)/vresolution)
  657.      : (x + vresolution/2 - 1)/vresolution);
  658. }
  659.  
  660. hunits::hunits(units x)
  661. {
  662.   // don't depend on the rounding direction for division of negative integers
  663.   if (hresolution == 1)
  664.     n = x;
  665.   else
  666.     n = (x < 0
  667.      ? -((-x + hresolution/2 - 1)/hresolution)
  668.      : (x + hresolution/2 - 1)/hresolution);
  669. }
  670.