home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / gnu / dc-0.2-src.lha / src / amiga / dc-0.2 / dc.c < prev    next >
C/C++ Source or Header  |  1993-05-19  |  18KB  |  910 lines

  1. /* 
  2.  * `dc' desk calculator utility.
  3.  *
  4.  * Copyright (C) 1984, 1993 Free Software Foundation, Inc.
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, you can either send email to this
  18.  * program's author (see below) or write to: The Free Software Foundation,
  19.  * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include "decimal.h"  /* definitions for our decimal arithmetic package */
  24.  
  25. FILE *open_file;    /* input file now open */
  26. int file_count;        /* Number of input files not yet opened */
  27. char **next_file;    /* Pointer to vector of names of input files left */
  28.  
  29. struct regstack
  30.   {
  31.     decimal value;    /* Saved value of register */
  32.     struct regstack *rest;    /* Tail of list */
  33.   };
  34.  
  35. typedef struct regstack *regstack;
  36.  
  37. regstack freeregstacks;    /* Chain of free regstack structures for fast realloc */
  38.  
  39. decimal regs[128];    /* "registers", with single-character names */
  40. regstack regstacks[128]; /* For each register, a stack of previous values */
  41.  
  42. int stacktop;        /* index of last used element in stack */
  43. int stacksize;        /* Current allocates size of stack */
  44. decimal *stack;    /* Pointer to computation stack */
  45.  
  46. /* A decimal number can be regarded as a string by
  47.  treating its contents as characters and ignoring the
  48.  position of its decimal point.
  49.  Decimal numbers are marked as strings by having an `after' field of -1
  50.  One use of strings is to execute them as macros.
  51. */
  52.  
  53. #define STRING -1
  54.  
  55. int macrolevel;    /* Current macro nesting; 0 if taking keyboard input */
  56. int macrostacksize;    /* Current allocated size of macrostack and macroindex */
  57. decimal *macrostack;    /* Pointer to macro stack array */
  58. int *macroindex;    /* Pointer to index-within-macro stack array */
  59.     /* Note that an empty macro is popped from the stack
  60.        only when an trying to read a character from it
  61.        or trying to push another macro.  */
  62.  
  63. int ibase;    /* Radix for numeric input.  */
  64. int obase;    /* Radix for numeric output.  */
  65. int precision;    /* Number of digits to keep in multiply and divide.  */
  66.  
  67. char *buffer;    /* Address of buffer used for reading numbers */
  68. int bufsize;    /* Current size of buffer (made bigger when nec) */
  69.  
  70. decimal dec_read ();
  71. regstack get_regstack ();
  72. int fetch ();
  73. int fgetchar ();
  74. char *concat ();
  75. void pushsqrt ();
  76. void condop ();
  77. void setibase ();
  78. void setobase ();
  79. void setprecision ();
  80. void pushmacro ();
  81. decimal read_string ();
  82. void pushlength ();
  83. void pushscale ();
  84. void unfetch ();
  85. void popmacros ();
  86. void popmacro ();
  87. void popstack ();
  88. void print_obj ();
  89. void print_string ();
  90. void free_regstack ();
  91. void pushreg ();
  92. void execute ();
  93. void fputchar ();
  94. void push ();
  95. void incref ();
  96. void decref ();
  97. void binop ();
  98.  
  99. main (argc, argv, env)
  100.      int argc;
  101.      char **argv, **env;
  102. {
  103.  
  104.   ibase = 10;
  105.   obase = 10;
  106.   precision = 0;
  107.  
  108.   freeregstacks = 0;
  109.  
  110.   bzero (regs, sizeof regs);
  111.   bzero (regstacks, sizeof regstacks);
  112.  
  113.   bufsize = 40;
  114.   buffer = (char *) xmalloc (40);
  115.  
  116.   stacksize = 40;
  117.   stack = (decimal *) xmalloc (stacksize * sizeof (decimal));
  118.   stacktop = -1;
  119.  
  120.   macrostacksize = 40;
  121.   macrostack = (decimal *) xmalloc (macrostacksize * sizeof (decimal));
  122.   macroindex = (int *) xmalloc (macrostacksize * sizeof (int));
  123.   macrolevel = 0;
  124.   /* Initialize for reading input files if any */
  125.  
  126.   open_file = 0;
  127.  
  128.   file_count = argc - 1;
  129.   next_file = argv + 1;
  130.  
  131.  
  132.   while (1)
  133.     {
  134.       execute ();
  135.     }
  136. }
  137.  
  138. /* Read and execute one command from the current source of input */
  139.  
  140. void
  141. execute ()
  142. {
  143.   int c = fetch ();
  144.  
  145.   if (c < 0) exit (0);
  146.  
  147.     {
  148.       switch (c)
  149.     {
  150.     case '+':        /* Arithmetic operators... */
  151.       binop (decimal_add);
  152.       break;
  153.  
  154.     case '-':
  155.       binop (decimal_sub);
  156.       break;
  157.  
  158.     case '*':
  159.       binop (decimal_mul_dc);  /* Like decimal_mul but hairy
  160.                       way of deciding precision to keep */
  161.       break;
  162.  
  163.     case '/':
  164.       binop (decimal_div);
  165.       break;
  166.  
  167.     case '%':
  168.       binop (decimal_rem);
  169.       break;
  170.  
  171.     case '^':
  172.       binop (decimal_expt);
  173.       break;
  174.  
  175.     case '_':        /* Begin a negative decimal constant */
  176.       {
  177.         decimal tem = dec_read (stdin);
  178.         tem->sign = !tem->sign;
  179.         push (tem);
  180.       }
  181.       break;
  182.  
  183.     case '.':
  184.     case '0':
  185.     case '1':
  186.     case '2':
  187.     case '3':
  188.     case '4':
  189.     case '5':
  190.     case '6':
  191.     case '7':
  192.     case '8':
  193.     case '9':        /* All these begin decimal constants */
  194.       unfetch (c);
  195.       push (dec_read (stdin));
  196.       break;
  197.  
  198.     case 'A':
  199.     case 'B':
  200.     case 'C':
  201.     case 'D':
  202.     case 'E':
  203.     case 'F':
  204.       unfetch (c);
  205.       push (dec_read (stdin));
  206.       break;
  207.  
  208.     case 'c':        /* Clear the stack */
  209.       while (stacktop >= 0)
  210.         decref (stack[stacktop--]);
  211.       break;
  212.  
  213.     case 'd':        /* Duplicate top of stack */
  214.       if (stacktop < 0)
  215.         error ("stack empty", 0);
  216.       else push (stack[stacktop]);
  217.       break;
  218.  
  219.     case 'f':        /* Describe all registers and stack contents */
  220.       {
  221.         int regno;
  222.         int somereg = 0;    /* set to 1 if we print any registers */
  223.         for (regno = 0; regno < 128; regno++)
  224.           {
  225.         if (regs[regno])
  226.           {
  227.             printf ("register %c: ", regno);
  228.             print_obj (regs[regno]);
  229.             somereg = 1;
  230.             printf ("\n");
  231.           }
  232.           }
  233.         if (somereg)
  234.           printf ("\n");
  235.         if (stacktop < 0)
  236.           printf ("stack empty\n");
  237.         else
  238.           {
  239.         int i;
  240.         printf ("stack:\n");
  241.         for (i = 0; i <= stacktop; i++)
  242.           {
  243.             print_obj (stack[stacktop - i]);
  244.             printf ("\n");
  245.           }
  246.           }
  247.       }
  248.       break;
  249.  
  250.     case 'i':        /* ibase <- top of stack */
  251.       popstack (setibase);
  252.       break;
  253.  
  254.     case 'I':        /* Push current ibase */
  255.       push (decimal_from_int (ibase));
  256.       break;
  257.  
  258.     case 'k':        /* like i, I but for precision instead of ibase */
  259.       popstack (setprecision);
  260.       break;
  261.  
  262.     case 'K':
  263.       push (decimal_from_int (precision));
  264.       break;
  265.  
  266.     case 'l':        /* l<x> load register <x> onto stack */
  267.       {
  268.         char c1 = fetch ();
  269.         if (c1 < 0) exit (0);
  270.         if (!regs[c1])
  271.           error ("register %c empty", c1);
  272.         else
  273.           push (regs[c1]);
  274.       }
  275.       break;
  276.  
  277.     case 'L':        /* L<x> load register <x> to stack, pop <x>'s own stack */
  278.       {
  279.         char c1 = fetch ();
  280.         if (c1 < 0) exit (0);
  281.         if (!regstacks[c1])
  282.           error ("nothing pushed on register %c", c1);
  283.         else
  284.           {
  285.         regstack r = regstacks[c1];
  286.         if (!regs[c1])
  287.           error ("register %c empty after pop", c1);
  288.         else
  289.           push (regs[c1]);
  290.         regs[c1] = r->value;
  291.         regstacks[c1] = r->rest;
  292.         free_regstack (r);
  293.           }
  294.       }
  295.       break;
  296.  
  297.     case 'o':        /* o, O like i, I but for obase instead of ibase */
  298.       popstack (setobase);
  299.       break;
  300.  
  301.     case 'O':
  302.       push (decimal_from_int (obase));
  303.       break;
  304.  
  305.     case 'p':        /* Print tos, don't pop, do print newline afterward */
  306.       if (stacktop < 0)
  307.         error ("stack empty", 0);
  308.       else
  309.         {
  310.           print_obj (stack[stacktop]);
  311.           printf ("\n");
  312.         }
  313.       break;
  314.  
  315.     case 'P':        /* Print tos, do pop, no newline afterward */
  316.       popstack (print_obj);
  317.       break;
  318.  
  319.     case 'q':        /* Exit */
  320.       if (macrolevel)
  321.         { popmacro (); popmacro (); }  /* decrease recursion level by 2 */
  322.       else
  323.         exit (0);        /* If not in a macro, exit the program.  */
  324.  
  325.       break;
  326.  
  327.     case 'Q':        /* Tos says how many levels to exit */
  328.       popstack (popmacros);
  329.       break;
  330.  
  331.     case 's':        /* s<x> -- Pop stack and set register <x> */
  332.       if (stacktop < 0)
  333.         empty ();
  334.       else
  335.         {
  336.           int c1 = fetch ();
  337.           if (c1 < 0) exit (0);
  338.           if (regs[c1]) decref (regs[c1]);
  339.           regs[c1] = stack[stacktop--];
  340.         }
  341.       break;
  342.  
  343.     case 'S':        /* S<x> -- pop stack and push as new value of register <x> */
  344.       if (stacktop < 0)
  345.         empty ();
  346.       else
  347.         {
  348.           int c1 = fetch ();
  349.           if (c1 < 0) exit (0);
  350.           pushreg (c1);
  351.           regs[c1] = stack[stacktop--];
  352.         }
  353.       break;
  354.  
  355.     case 'v':        /* tos gets square root of tos */
  356.       popstack (pushsqrt);
  357.       break;
  358.  
  359.     case 'x':        /* pop stack , call as macro */
  360.       popstack (pushmacro);
  361.       break;
  362.  
  363.     case 'X