[BACK]Return to calc.y CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / demos / calc

Annotation of OpenXM_contrib/gmp/demos/calc/calc.y, Revision 1.1.1.1

1.1       ohara       1: %{
                      2: /* A simple integer desk calculator using yacc and gmp.
                      3:
                      4: Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
                      5:
                      6: This file is part of the GNU MP Library.
                      7:
                      8: This program is free software; you can redistribute it and/or modify it under
                      9: the terms of the GNU General Public License as published by the Free Software
                     10: Foundation; either version 2 of the License, or (at your option) any later
                     11: version.
                     12:
                     13: This program is distributed in the hope that it will be useful, but WITHOUT ANY
                     14: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
                     15: PARTICULAR PURPOSE.  See the GNU General Public License for more details.
                     16:
                     17: You should have received a copy of the GNU General Public License along with
                     18: this program; if not, write to the Free Software Foundation, Inc., 59 Temple
                     19: Place - Suite 330, Boston, MA 02111-1307, USA. */
                     20:
                     21:
                     22: /* This is a simple program, meant only to show one way to use GMP for this
                     23:    sort of thing.  There's few features, and error checking is minimal.
                     24:    Standard input is read, calc_help() below shows the inputs accepted.
                     25:
                     26:    Expressions are evaluated as they're read.  If user defined functions
                     27:    were wanted it'd be necessary to build a parse tree like pexpr.c does, or
                     28:    a list of operations for a stack based evaluator.  That would also make
                     29:    it possible to detect and optimize evaluations "mod m" like pexpr.c does.
                     30:
                     31:    A stack is used for intermediate values in the expression evaluation,
                     32:    separate from the yacc parser stack.  This is simple, makes error
                     33:    recovery easy, minimizes the junk around mpz calls in the rules, and
                     34:    saves initializing or clearing "mpz_t"s during a calculation.  A
                     35:    disadvantage though is that variables must be copied to the stack to be
                     36:    worked on.  A more sophisticated calculator or language system might be
                     37:    able to avoid that when executing a compiled or semi-compiled form.
                     38:
                     39:    Avoiding repeated initializing and clearing of "mpz_t"s is important.  In
                     40:    this program the time spent parsing is obviously much greater than any
                     41:    possible saving from this, but a proper calculator or language should
                     42:    take some trouble over it.  Don't be surprised if an init/clear takes 3
                     43:    or more times as long as a 10 limb addition, depending on the system (see
                     44:    the mpz_init_realloc_clear example in tune/README).  */
                     45:
                     46:
                     47: #include <stdio.h>
                     48: #include <stdlib.h>
                     49: #include <string.h>
                     50: #include "gmp.h"
                     51: #define NO_CALC_H /* because it conflicts with normal calc.c stuff */
                     52: #include "calc-common.h"
                     53:
                     54:
                     55: #define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
                     56:
                     57:
                     58: void
                     59: calc_help (void)
                     60: {
                     61:   printf ("Examples:\n");
                     62:   printf ("    2+3*4        expressions are evaluated\n");
                     63:   printf ("    x=5^6        variables a to z can be set and used\n");
                     64:   printf ("Operators:\n");
                     65:   printf ("    + - *        arithmetic\n");
                     66:   printf ("    / %%          division and remainder (rounding towards negative infinity)\n");
                     67:   printf ("    ^            exponentiation\n");
                     68:   printf ("    !            factorial\n");
                     69:   printf ("    << >>        left and right shifts\n");
                     70:   printf ("    <= >= >      \\ comparisons, giving 1 if true, 0 if false\n");
                     71:   printf ("    == != <      /\n");
                     72:   printf ("    && ||        logical and/or, giving 1 if true, 0 if false\n");
                     73:   printf ("Functions:\n");
                     74:   printf ("    abs(n)       absolute value\n");
                     75:   printf ("    bin(n,m)     binomial coefficient\n");
                     76:   printf ("    fib(n)       fibonacci number\n");
                     77:   printf ("    gcd(a,b,..)  greatest common divisor\n");
                     78:   printf ("    kron(a,b)    kronecker symbol\n");
                     79:   printf ("    lcm(a,b,..)  least common multiple\n");
                     80:   printf ("    lucnum(n)    lucas number\n");
                     81:   printf ("    nextprime(n) next prime after n\n");
                     82:   printf ("    powm(b,e,m)  modulo powering, b^e%%m\n");
                     83:   printf ("    root(n,r)    r-th root\n");
                     84:   printf ("    sqrt(n)      square root\n");
                     85:   printf ("Other:\n");
                     86:   printf ("    hex          \\ set hex or decimal for input and output\n");
                     87:   printf ("    decimal      /   (\"0x\" can be used for hex too)\n");
                     88:   printf ("    quit         exit program (EOF works too)\n");
                     89:   printf ("    ;            statements are separated with a ; or newline\n");
                     90:   printf ("    \\            continue expressions with \\ before newline\n");
                     91:   printf ("    # xxx        comments are # though to newline\n");
                     92:   printf ("Hex numbers must be entered in upper case, to distinguish them from the\n");
                     93:   printf ("variables a to f (like in bc).\n");
                     94: }
                     95:
                     96:
                     97: int  ibase = 0;
                     98: int  obase = 10;
                     99:
                    100:
                    101: /* The stack is a fixed size, which means there's a limit on the nesting
                    102:    allowed in expressions.  A more sophisticated program could let it grow
                    103:    dynamically.  */
                    104:
                    105: mpz_t    stack[100];
                    106: mpz_ptr  sp = stack[0];
                    107:
                    108: #define CHECK_OVERFLOW()                                                  \
                    109:   if (sp >= stack[numberof(stack)])                                       \
                    110:     {                                                                     \
                    111:       fprintf (stderr,                                                    \
                    112:                "Value stack overflow, too much nesting in expression\n"); \
                    113:       YYERROR;                                                            \
                    114:     }
                    115:
                    116: #define CHECK_EMPTY()                                                   \
                    117:   if (sp != stack[0])                                                   \
                    118:     {                                                                   \
                    119:       fprintf (stderr, "Oops, expected the value stack to be empty\n"); \
                    120:       sp = stack[0];                                                    \
                    121:     }
                    122:
                    123:
                    124: mpz_t  variable[26];
                    125:
                    126: #define CHECK_VARIABLE(var)                                             \
                    127:   if ((var) < 0 || (var) >= numberof (variable))                        \
                    128:     {                                                                   \
                    129:       fprintf (stderr, "Oops, bad variable somehow: %d\n", var);        \
                    130:       YYERROR;                                                          \
                    131:     }
                    132:
                    133:
                    134: #define CHECK_UI(name,z)                        \
                    135:   if (! mpz_fits_ulong_p (z))                   \
                    136:     {                                           \
                    137:       fprintf (stderr, "%s too big\n", name);   \
                    138:       YYERROR;                                  \
                    139:     }
                    140:
                    141: %}
                    142:
                    143: %union {
                    144:   char  *str;
                    145:   int   var;
                    146: }
                    147:
                    148: %token EOS BAD
                    149: %token HELP HEX DECIMAL QUIT
                    150: %token ABS BIN FIB GCD KRON LCM LUCNUM NEXTPRIME POWM ROOT SQRT
                    151: %token <str> NUMBER
                    152: %token <var> VARIABLE
                    153:
                    154: /* operators, increasing precedence */
                    155: %left     LOR
                    156: %left     LAND
                    157: %nonassoc '<' '>' EQ NE LE GE
                    158: %left     LSHIFT RSHIFT
                    159: %left     '+' '-'
                    160: %left     '*' '/' '%'
                    161: %nonassoc UMINUS
                    162: %right    '^'
                    163: %nonassoc '!'
                    164:
                    165: %%
                    166:
                    167: top:
                    168:   statement
                    169:   | statements statement;
                    170:
                    171: statements:
                    172:   statement EOS
                    173:   | statements statement EOS
                    174:   | error EOS { sp = stack[0]; yyerrok; };
                    175:
                    176: statement:
                    177:   /* empty */
                    178:   | e {
                    179:       mpz_out_str (stdout, obase, sp); putchar ('\n');
                    180:       sp--;
                    181:       CHECK_EMPTY ();
                    182:     }
                    183:   | VARIABLE '=' e {
                    184:       CHECK_VARIABLE ($1);
                    185:       mpz_swap (variable[$1], sp);
                    186:       sp--;
                    187:       CHECK_EMPTY ();
                    188:     }
                    189:   | HELP    { calc_help (); }
                    190:   | HEX     { ibase = 16; obase = -16; }
                    191:   | DECIMAL { ibase = 0;  obase = 10; }
                    192:   | QUIT    { exit (0); };
                    193:
                    194: /* "e" leaves it's value on the top of the mpz stack.  A rule like "e '+' e"
                    195:    will have done a reduction for the first "e" first and the second "e"
                    196:    second, so the code receives the values in that order on the stack.  */
                    197: e:
                    198:     '(' e ')'     /* value on stack */
                    199:     | e '+' e     { sp--; mpz_add    (sp, sp, sp+1); }
                    200:     | e '-' e     { sp--; mpz_sub    (sp, sp, sp+1); }
                    201:     | e '*' e     { sp--; mpz_mul    (sp, sp, sp+1); }
                    202:     | e '/' e     { sp--; mpz_fdiv_q (sp, sp, sp+1); }
                    203:     | e '%' e     { sp--; mpz_fdiv_r (sp, sp, sp+1); }
                    204:     | e '^' e     { CHECK_UI ("Exponent", sp);
                    205:                     sp--; mpz_pow_ui (sp, sp, mpz_get_ui (sp+1)); }
                    206:     | e LSHIFT e  { CHECK_UI ("Shift count", sp);
                    207:                     sp--; mpz_mul_2exp (sp, sp, mpz_get_ui (sp+1)); }
                    208:     | e RSHIFT e  { CHECK_UI ("Shift count", sp);
                    209:                     sp--; mpz_fdiv_q_2exp (sp, sp, mpz_get_ui (sp+1)); }
                    210:     | e '!'       { CHECK_UI ("Factorial", sp);
                    211:                     mpz_fac_ui (sp, mpz_get_ui (sp)); }
                    212:     | '-' e %prec UMINUS   { mpz_neg (sp, sp); }
                    213:
                    214:     | e '<' e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <  0); }
                    215:     | e LE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <= 0); }
                    216:     | e EQ  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) == 0); }
                    217:     | e NE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) != 0); }
                    218:     | e GE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >= 0); }
                    219:     | e '>' e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >  0); }
                    220:
                    221:     | e LAND e    { sp--; mpz_set_ui (sp, mpz_sgn (sp) && mpz_sgn (sp+1)); }
                    222:     | e LOR e     { sp--; mpz_set_ui (sp, mpz_sgn (sp) || mpz_sgn (sp+1)); }
                    223:
                    224:     | ABS '(' e ')'              { mpz_abs (sp, sp); }
                    225:     | BIN '(' e ',' e ')'        { sp--; CHECK_UI ("Binomial base", sp+1);
                    226:                                    mpz_bin_ui (sp, sp, mpz_get_ui (sp+1)); }
                    227:     | FIB '(' e ')'              { CHECK_UI ("Fibonacci", sp);
                    228:                                    mpz_fib_ui (sp, mpz_get_ui (sp)); }
                    229:     | GCD '(' gcdlist ')'        /* value on stack */
                    230:     | KRON '(' e ',' e ')'       { sp--; mpz_set_si (sp,
                    231:                                          mpz_kronecker (sp, sp+1)); }
                    232:     | LCM '(' lcmlist ')'        /* value on stack */
                    233:     | LUCNUM '(' e ')'           { CHECK_UI ("Lucas number", sp);
                    234:                                    mpz_lucnum_ui (sp, mpz_get_ui (sp)); }
                    235:     | NEXTPRIME '(' e ')'        { mpz_nextprime (sp, sp); }
                    236:     | POWM '(' e ',' e ',' e ')' { sp -= 2; mpz_powm (sp, sp, sp+1, sp+2); }
                    237:     | ROOT '(' e ',' e ')'       { sp--; CHECK_UI ("Nth-root", sp+1);
                    238:                                    mpz_root (sp, sp, mpz_get_ui (sp+1)); }
                    239:     | SQRT '(' e ')'             { mpz_sqrt (sp, sp); }
                    240:
                    241:     | VARIABLE {
                    242:         sp++;
                    243:         CHECK_OVERFLOW ();
                    244:         CHECK_VARIABLE ($1);
                    245:         mpz_set (sp, variable[$1]);
                    246:       }
                    247:     | NUMBER {
                    248:         sp++;
                    249:         CHECK_OVERFLOW ();
                    250:         if (mpz_set_str (sp, $1, ibase) != 0)
                    251:           {
                    252:             fprintf (stderr, "Invalid number: %s\n", $1);
                    253:             YYERROR;
                    254:           }
                    255:       };
                    256:
                    257: gcdlist:
                    258:     e                /* value on stack */
                    259:     | gcdlist ',' e  { sp--; mpz_gcd (sp, sp, sp+1); };
                    260:
                    261: lcmlist:
                    262:     e                /* value on stack */
                    263:     | lcmlist ',' e  { sp--; mpz_lcm (sp, sp, sp+1); };
                    264:
                    265: %%
                    266:
                    267: yyerror (char *s)
                    268: {
                    269:   fprintf (stderr, "%s\n", s);
                    270: }
                    271:
                    272: int calc_option_readline = -1;
                    273:
                    274: int
                    275: main (int argc, char *argv[])
                    276: {
                    277:   int  i;
                    278:
                    279:   for (i = 1; i < argc; i++)
                    280:     {
                    281:       if (strcmp (argv[i], "--readline") == 0)
                    282:         calc_option_readline = 1;
                    283:       else if (strcmp (argv[i], "--noreadline") == 0)
                    284:         calc_option_readline = 0;
                    285:       else if (strcmp (argv[i], "--help") == 0)
                    286:         {
                    287:           printf ("Usage: calc [--option]...\n");
                    288:           printf ("  --readline    use readline\n");
                    289:           printf ("  --noreadline  don't use readline\n");
                    290:           printf ("  --help        this message\n");
                    291:           printf ("Readline is only available when compiled in,\n");
                    292:           printf ("and in that case it's the default on a tty.\n");
                    293:           exit (0);
                    294:         }
                    295:       else
                    296:         {
                    297:           fprintf (stderr, "Unrecognised option: %s\n", argv[i]);
                    298:           exit (1);
                    299:         }
                    300:     }
                    301:
                    302: #if WITH_READLINE
                    303:   calc_init_readline ();
                    304: #else
                    305:   if (calc_option_readline == 1)
                    306:     {
                    307:       fprintf (stderr, "Readline support not available\n");
                    308:       exit (1);
                    309:     }
                    310: #endif
                    311:
                    312:   for (i = 0; i < numberof (variable); i++)
                    313:     mpz_init (variable[i]);
                    314:
                    315:   for (i = 0; i < numberof (stack); i++)
                    316:     mpz_init (stack[i]);
                    317:
                    318:   return yyparse ();
                    319: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>