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

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

1.1     ! maekawa     1: /* A simple integer desk calculator using yacc and gmp. */
        !             2:
        !             3: /*
        !             4: Copyright (C) 2000 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:
        !            23: /* This is a simple program, meant only to show one way to use GMP for this
        !            24:    sort of thing.  There's few features, and error checking is minimal.
        !            25:    Standard input is read, there's no command line options.
        !            26:
        !            27:    Examples:
        !            28:        2+3*4        expressions are evaluated
        !            29:        x=5^6        variables a to z can be set and used
        !            30:
        !            31:    Operators:
        !            32:        + - *        arithmetic
        !            33:        / %          division and remainder (rounding towards negative infinity)
        !            34:        ^            exponentiation
        !            35:        !            factorial
        !            36:        << >>        left and right shifts
        !            37:        <= >= >      \ comparisons, giving 1 if true, 0 if false
        !            38:        == != <      /
        !            39:        && ||        logical and/or, giving 1 if true, 0 if false
        !            40:
        !            41:    Functions:
        !            42:        abs(n)       absolute value
        !            43:        bin(n,m)     binomial coefficient
        !            44:        fib(n)       fibonacci number
        !            45:        gcd(a,b,..)  greatest common divisor
        !            46:        lcm(a,b,..)  least common multiple
        !            47:        nextprime(n) next prime after n
        !            48:        powm(b,e,m)  modulo powering, b^e%m
        !            49:        root(n,r)    r-th root (rounded down)
        !            50:        sqrt(n)      square root (rounded down)
        !            51:
        !            52:    Other:
        !            53:        hex          \ set hex or decimal for input and output
        !            54:        decimal      /   ("0x" can be used for hex too)
        !            55:        quit         exit program (EOF works too)
        !            56:        ;            statements are separated with a ; or newline
        !            57:        \            continue expressions with \ before newline
        !            58:        # xxx        comments are # though to newline
        !            59:
        !            60:    Hex numbers must be entered in upper case, to distinguish them from the
        !            61:    variables a to f (like in bc).
        !            62:
        !            63:
        !            64:    Expressions are evaluated as they're read.  If user defined functions
        !            65:    were wanted it'd be necessary to build a parse tree like pexpr.c does, or
        !            66:    a list of operations for a stack based evaluator.  That would also make
        !            67:    it possible to detect and optimize evaluations "mod m" like pexpr.c does.
        !            68:
        !            69:    A stack is used for intermediate values in the expression evaluation,
        !            70:    separate from the yacc parser stack.  This is simple, makes error
        !            71:    recovery easy, minimizes the junk around mpz calls in the rules, and
        !            72:    saves initializing or clearing "mpz_t"s during a calculation.  A
        !            73:    disadvantage though is that variables must be copied to the stack to be
        !            74:    worked on.  A more sophisticated calculator or language system might be
        !            75:    able to avoid that when executing a compiled or semi-compiled form.
        !            76:
        !            77:    Avoiding repeated initializing and clearing of "mpz_t"s is important.  In
        !            78:    this program the time spent parsing is obviously much greater than any
        !            79:    possible saving from this, but a proper calculator or language should
        !            80:    take some trouble over it.  Don't be surprised if an init/clear takes 3
        !            81:    or more times as long as a 10 limb addition, depending on the system (see
        !            82:    the mpz_init_realloc_clear example in tune/README).
        !            83:
        !            84:    In a calculator or language using dynamic memory allocation, a good idea
        !            85:    would be to keep some "mpz_t"s on a free list.  A structure like the
        !            86:    following is effectively an "mpz_t" with an extra field tacked on the end
        !            87:    for that purpose.
        !            88:
        !            89:            struct foo {
        !            90:              mpz_t       z;
        !            91:              struct foo  *next;
        !            92:            };
        !            93:
        !            94:    A pointer "struct foo *p" used as "p->z" will be just a type-safe cast.
        !            95:    With care a free list could be made thread safe, and it should never be
        !            96:    larger than the deepest nested calculation.  */
        !            97:
        !            98:
        !            99: %{
        !           100: #include <stdio.h>
        !           101: #include <stdlib.h>
        !           102:
        !           103: #include "gmp.h"
        !           104:
        !           105: #define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
        !           106:
        !           107:
        !           108: int  ibase = 0;
        !           109: int  obase = 10;
        !           110:
        !           111:
        !           112: /* The stack is a fixed size, which means there's a limit on the nesting
        !           113:    allowed in expressions.  A more sophisticated program could let it grow
        !           114:    dynamically.  */
        !           115:
        !           116: mpz_t    stack[100];
        !           117: mpz_ptr  sp = stack[0];
        !           118:
        !           119: #define CHECK_OVERFLOW()                                                  \
        !           120:   if (sp >= stack[numberof(stack)])                                       \
        !           121:     {                                                                     \
        !           122:       fprintf (stderr,                                                    \
        !           123:                "Value stack overflow, too much nesting in expression\n"); \
        !           124:       YYERROR;                                                            \
        !           125:     }
        !           126:
        !           127: #define CHECK_EMPTY()                                                   \
        !           128:   if (sp != stack[0])                                                   \
        !           129:     {                                                                   \
        !           130:       fprintf (stderr, "Oops, expected the value stack to be empty\n"); \
        !           131:       sp = stack[0];                                                    \
        !           132:     }
        !           133:
        !           134:
        !           135: mpz_t  variable[26];
        !           136:
        !           137: #define CHECK_VARIABLE(var)                                             \
        !           138:   if ((var) < 0 || (var) >= numberof (variable))                        \
        !           139:     {                                                                   \
        !           140:       fprintf (stderr, "Oops, bad variable somehow: %d\n", var);        \
        !           141:       YYERROR;                                                          \
        !           142:     }
        !           143:
        !           144:
        !           145: #define CHECK_UI(name,z)                                                   \
        !           146:   if (! mpz_fits_ulong_p (z))                                              \
        !           147:     {                                                                      \
        !           148:       fprintf (stderr,                                                     \
        !           149:                "Operand must fit in an \"unsigned long\" for %s\n", name); \
        !           150:       YYERROR;                                                             \
        !           151:     }
        !           152:
        !           153: %}
        !           154:
        !           155: %union {
        !           156:   char  *str;
        !           157:   int   var;
        !           158: }
        !           159:
        !           160: %token EOS BAD
        !           161: %token HEX DECIMAL QUIT
        !           162: %token ABS BIN FIB GCD LCM NEXTPRIME POWM ROOT SQRT
        !           163: %token <str> NUMBER
        !           164: %token <var> VARIABLE
        !           165:
        !           166: /* operators, increasing precedence */
        !           167: %left     LOR
        !           168: %left     LAND
        !           169: %nonassoc '<' '>' EQ NE LE GE
        !           170: %left     LSHIFT RSHIFT
        !           171: %left     '+' '-'
        !           172: %left     '*' '/' '%'
        !           173: %nonassoc UMINUS
        !           174: %right    '^'
        !           175: %nonassoc '!'
        !           176:
        !           177: %%
        !           178:
        !           179: top:
        !           180:   statement
        !           181:   | statements statement
        !           182:
        !           183: statements:
        !           184:   statement EOS
        !           185:   | statements statement EOS
        !           186:   | error EOS ={ sp = stack[0]; yyerrok; }
        !           187:
        !           188: statement:
        !           189:   /* empty */
        !           190:   | e ={
        !           191:       mpz_out_str (stdout, obase, sp); putchar ('\n');
        !           192:       sp--;
        !           193:       CHECK_EMPTY ();
        !           194:     }
        !           195:   | VARIABLE '=' e ={
        !           196:       CHECK_VARIABLE ($1);
        !           197:       mpz_swap (variable[$1], sp);
        !           198:       sp--;
        !           199:       CHECK_EMPTY ();
        !           200:     }
        !           201:   | HEX     ={ ibase = 16; obase = -16; }
        !           202:   | DECIMAL ={ ibase = 0;  obase = 10; }
        !           203:   | QUIT    ={ exit (0); }
        !           204:
        !           205: /* "e" leaves it's value on the top of the mpz stack.  A rule like "e '+' e"
        !           206:    will have done a reduction for the first "e" first and the second "e"
        !           207:    second, so the code receives the values in that order on the stack.  */
        !           208: e:
        !           209:     '(' e ')'     /* value on stack */
        !           210:     | e '+' e     ={ sp--; mpz_add    (sp, sp, sp+1); }
        !           211:     | e '-' e     ={ sp--; mpz_sub    (sp, sp, sp+1); }
        !           212:     | e '*' e     ={ sp--; mpz_mul    (sp, sp, sp+1); }
        !           213:     | e '/' e     ={ sp--; mpz_fdiv_q (sp, sp, sp+1); }
        !           214:     | e '%' e     ={ sp--; mpz_fdiv_r (sp, sp, sp+1); }
        !           215:     | e '^' e     ={ CHECK_UI ("exponentiation", sp);
        !           216:                      sp--; mpz_pow_ui (sp, sp, mpz_get_ui (sp+1)); }
        !           217:     | e LSHIFT e  ={ CHECK_UI ("lshift", sp);
        !           218:                      sp--; mpz_mul_2exp (sp, sp, mpz_get_ui (sp+1)); }
        !           219:     | e RSHIFT e  ={ CHECK_UI ("rshift", sp);
        !           220:                      sp--; mpz_fdiv_q_2exp (sp, sp, mpz_get_ui (sp+1)); }
        !           221:     | e '!'       ={ CHECK_UI ("factorial", sp);
        !           222:                      mpz_fac_ui (sp, mpz_get_ui (sp)); }
        !           223:     | '-' e %prec UMINUS   ={ mpz_neg (sp, sp); }
        !           224:
        !           225:     | e '<' e     ={ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <  0); }
        !           226:     | e LE  e     ={ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <= 0); }
        !           227:     | e EQ  e     ={ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) == 0); }
        !           228:     | e NE  e     ={ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) != 0); }
        !           229:     | e GE  e     ={ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >= 0); }
        !           230:     | e '>' e     ={ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >  0); }
        !           231:
        !           232:     | e LAND e    ={ sp--; mpz_set_ui (sp, mpz_sgn (sp) && mpz_sgn (sp+1)); }
        !           233:     | e LOR e     ={ sp--; mpz_set_ui (sp, mpz_sgn (sp) || mpz_sgn (sp+1)); }
        !           234:
        !           235:     | ABS '(' e ')'              ={ mpz_abs (sp, sp); }
        !           236:     | BIN '(' e ',' e ')'        ={ sp--; CHECK_UI ("binomial", sp+1);
        !           237:                                     mpz_bin_ui (sp, sp, mpz_get_ui (sp+1)); }
        !           238:     | FIB '(' e ')'              ={ CHECK_UI ("fibonacci", sp);
        !           239:                                     mpz_fib_ui (sp, mpz_get_ui (sp)); }
        !           240:     | GCD '(' gcdlist ')'        /* value on stack */
        !           241:     | LCM '(' lcmlist ')'        /* value on stack */
        !           242:     | NEXTPRIME '(' e ')'        ={ mpz_nextprime (sp, sp); }
        !           243:     | POWM '(' e ',' e ',' e ')' ={ sp -= 2; mpz_powm (sp, sp, sp+1, sp+2); }
        !           244:     | ROOT '(' e ',' e ')'       ={ sp--; CHECK_UI ("nth-root", sp+1);
        !           245:                                     mpz_root (sp, sp, mpz_get_ui (sp+1)); }
        !           246:     | SQRT '(' e ')'             ={ mpz_sqrt (sp, sp); }
        !           247:
        !           248:     | VARIABLE ={
        !           249:         sp++;
        !           250:         CHECK_OVERFLOW ();
        !           251:         CHECK_VARIABLE ($1);
        !           252:         mpz_set (sp, variable[$1]);
        !           253:       }
        !           254:     | NUMBER ={
        !           255:         sp++;
        !           256:         CHECK_OVERFLOW ();
        !           257:         if (mpz_set_str (sp, $1, ibase) != 0)
        !           258:           {
        !           259:             fprintf (stderr, "Invalid number: %s\n", $1);
        !           260:             YYERROR;
        !           261:           }
        !           262:       }
        !           263:
        !           264: gcdlist:
        !           265:     e                /* value on stack */
        !           266:     | gcdlist ',' e  ={ sp--; mpz_gcd (sp, sp, sp+1); }
        !           267:
        !           268: lcmlist:
        !           269:     e                /* value on stack */
        !           270:     | lcmlist ',' e  ={ sp--; mpz_lcm (sp, sp, sp+1); }
        !           271:
        !           272: %%
        !           273:
        !           274: yyerror (char *s)
        !           275: {
        !           276:   fprintf (stderr, "%s\n", s);
        !           277: }
        !           278:
        !           279: int
        !           280: main (void)
        !           281: {
        !           282:   int  i;
        !           283:
        !           284:   for (i = 0; i < numberof (variable); i++)
        !           285:     mpz_init (variable[i]);
        !           286:
        !           287:   for (i = 0; i < numberof (stack); i++)
        !           288:     mpz_init (stack[i]);
        !           289:
        !           290:   return yyparse ();
        !           291: }

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