
           ICALC: Infix Calculator for Un*x, VAX/VMS and PC/MS-DOS
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                       Modified and made available by:
                                  Rao Akella
                Research Assistant, Colon Cancer Control Study
                     University of Minnesota, Minneapolis

Introduction:
~~~~~~~~~~~~
Ever wanted to do a quick calculation and didn't have a calculator handy? 
ICALC is a simple, portable and quickly-accessible program for doing INFIX
computations. It is neither very sophisticated nor intended to provide enormous
flexibility. It merely provides the functionality of a simple infix pocket
calculator.

In the words of the Bard:
	"'Tis not so deep as a well, nor so wide as a church-door;
	 but 'tis enough, 'twill serve."

Features:
~~~~~~~~
    1) Addition (+), Subtraction (-), Multiplication (*), Division (/)

    2) Modulus (%), Power (^)

    3) Bitwise logical operators: bitwise AND (&), bitwise inclusive OR (|),
       unary one's complement (~)

    4) 20 Math/Trigonometric functions: sin, cos, tan, asin, acos, atan,
       sinh, cosh, tanh, exp (exponentiation), ln (natural log),
       log (base 10 log), sqrt (square root), ceil (ceiling), floor,
       int/trunc (truncation), abs (absolute value),
       degtorad (degrees->radians), radtodeg (radians->degrees).

       Two Date functions to convert between calendar dates and julian days:
       caltojul (calendar->julian date) and jultocal (julian->calendar date).

       One '?'-for-help command to display a help screen of all supported
       commands and functions.

    5) Temporary variables (as many as you want, with names as long as you
       want) to store intermediate computations.

    6) This is a "portable" calculator in the sense that it's not specific to
       any operating system.  The yacc output should be compilable by any C
       compiler; this program has been tested on Unix, VAX/VMS and PC/MS-DOS,
       and has required no changes to compile.

    7) This program uses the simplest of input and output formats, and is in
       no way hardware dependent.  So, as long as it compiles without any
       problems, there are no other requirements for it to work properly.

    8) All numbers are of the C floating-point type "double", which, according
       to the VAX C manual, has a range of 0.29*10^-38 to 1.7*10^38, and has
       values precise to 16 decimal digits.

    9) Allows any number of expressions on a line, separated by ';'

   10) icalc can now be run either interactively (when it is
       invoked without any arguments, in which case the user is
       prompted for input) or in a command-line mode (when all
       expressions to be computed are passed to icalc via
       command-line "argv" arguments, in which case icalc computes
       and prints the result of each expression -- exactly as if
       it had been entered interactively -- and then exits).
       In the latter case, the user is supposed to delimit/
       separate the expressions by ';'

Availability:
~~~~~~~~~~~~
ICALC is available via Anonymous FTP from
	cccs.umn.edu  (Internet Address 128.101.133.53)
Just get the file ICALC.TXT (in ASCII mode), read it and follow the
instructions contained therein.

If you do not have FTP access, please contact me somehow with some form of
e-mail/paper-mail address, and I'll post it to you personally.

Installation Instructions:
~~~~~~~~~~~~~~~~~~~~~~~~~
The installation instructions for ICALC are extremely simple, and remain
practically the same on Unix, VAX/VMS and PC/MS-DOS.

At the end of this file, you will find a C program (it is actually the output
from yacc; if you want the original yacc grammar, please ask me, and I'll post
it to you)...anyway, as I was saying, you'll find a C program at the end of
this file (after the "Cut here" line).  Cut it out using an editor and save it
in a separate file called "icalc.c".

All you have to do now is to compile this program using a C compiler, and then
link it (if necessary).

To be more specific:

In VMS:
------
1)	Compile this C program using the commands:
		$ DEFINE LNK$LIBRARY   SYS$LIBRARY:VAXCCURSE
		$ DEFINE LNK$LIBRARY_1 SYS$LIBRARY:VAXCRTLG
		$ DEFINE LNK$LIBRARY_2 SYS$LIBRARY:VAXCRTL
		$ CC ICALC
	This should produce an object file called ICALC.OBJ.

2)	Then link this object file using the command:
		$ LINK ICALC,SYS$INPUT/OPTIONS
		SYS$SHARE:VAXCRTL/SHAREABLE
		^Z	<-- this is a Ctrl-Z
		$

3)	Run the program using the command:
		$ RUN ICALC
	The program will then prompt you for input.

	If you want to pass the expressions you want to be computed on the
	command line, you must define a global symbol (foreign command) as
	follows:
		$ ICALC :== $dev:[dir]ICALC
	where "dev" and "dir" are your site-specific device and directory where
	ICALC.EXE resides.
	Then you can run ICALC interactively using the command:
		$ ICALC
	Alternatively, you can run ICALC in the commmand-line mode as follows:
		$ ICALC expression-1; expression-2; ...

	For example:
		$ ICALC 9+4; 9-4; 9*4; 9/4
			13
			5
			36
			2.25
		$

	To exit ICALC in the interactive mode in VMS, type:
		Ctrl-Z, Ctrl-Y or Ctrl-C.

In Unix:
-------
1) 	Compile and link the C program "icalc.c" using the command:
		% cc icalc.c -lm -o icalc
	This should produce an executable file called "icalc".

Note: On some Ultrix/4.3BSD systems, not all math functions are available in
      the regular math library; they may be in the mathV library.  On such
      systems, the compilation command is changed to:
		% cc icalc.c -lm -lmV -o icalc

So, if you have trouble compiling icalc.c, please check your system for any
non-standard math libraries.

2)	Run the program interactively using the command:
		% icalc

	To run icalc in the command-line mode, passing all the expressions
	you want to be computed on the command line:
		% icalc 'expression-1; expression-2; ... '
	Note:	You must enclose all expressions supplied on the command line
		within single quotes, because the Un*x shell interprets some
		characters (like ';', '(', ')', '*', etc.) instead of passing
		them on to icalc.

	For example:
		% icalc '9+4; 9-4; 9*4; 9/4'
			13
			5
			36
			2.25
		%

	To exit icalc in Unix, type Ctrl-D or Ctrl-C.

In PC/MS-DOS:
------------
	The installations instructions remain basically the same: compile and
	link ICALC.C.  The precise syntax for compiling and linking will depend
	on what compiler you're using, so I can't be any more specific than
	this.  I have personally been able to get ICALC to work on a PC clone
	running MS-DOS Version 4.00, using the Microsoft QuickC Compiler
	Version 2.01 and the Microsoft QuickC Linker Version 4.07.

	In PC/MS-DOS, type Ctrl-C or Ctrl-Z+Return to exit the program.

Examples:
~~~~~~~~
A short transcript of an ICALC session follows.  This will demonstrate the
majority of it's features.

$ ICALC
IC> 4 + 4.5 - (34/(8*3+-3))
        6.880952381
IC> -56 + 2
        -54
IC> 3 ^ 2
        9
IC> -3 ^ 2
        -9
IC> 9 % 4
        1
IC> 9.7 % 4.2
        1.3
IC> pi = 3.141592653589
        pi = 3.141592654
        3.141592654
IC> sin(PI)                  <- Note: Variable names are case-INsensitive.
        7.9326579347e-13     <- This is close enough to zero, don't you think?
IC> x = (y = (z = 4.5)*2)*3  <- Note: Multiple variable assignments
        z = 4.5
        y = 9
        x = 27
        27
IC> ln(y)
        2.197224577
IC> exp(ln(y))
        9
IC> uninitialisedvariable    <- Note: Uninitialised variables are automatically
        0                    <-       initialised to zero.
IC> 1 & 2
        0
IC> ~3
        -4
IC> 0 | 1
        1
IC> 9+4; 9-4; 9*4; 9/4
	13
	5
	36
	2.25
IC> ?	/* help screen will be displayed */
IC> sin(degtorad(90))
	1
IC> radtodeg(asin(1))
	90
IC> caltojul(1992, 3, 16)
	149538
IC> jultocal(149538)
	19920316	/* yyyymmdd format */
IC> caltojul(1582, 10,15)
	1		/* October 15, 1582 is julian day 1 */
IC> jultocal(1)
	15821015
IC> floor(56.789)
        56
IC> int(56.789)		/* trunc is an alias for int */
        56
IC> floor(-56.789)
        -57
IC> int(-56.789)
        -56
IC> ^C
$

History:
~~~~~~~
Let me make one thing perfectly clear.  I am NOT the author of this program.  I
merely copied the yacc grammar for an infix calculator verbatim out of the
"Bison" manual (the "mfcalc" example) of the "Free Software Foundation, Inc.",
made some cosmetic modifications to customize it to my particular taste, ran it
through "yacc", compiled it with a C compiler, and voila! it works.

If you would prefer to have the original yacc grammar (icalc.y; you would need
it if you were planning to make further modifications yourself to the source
code), please ask me, and I'll post it to you.

All comments/suggestions/problems/questions/criticism/flames/etc. most welcome.
If there's anything at all that you don't understand or would like futher
clarified, please ask me (e-mail, paper-mail, phone, anything goes).

Rao V. Akella
Research Assistant, Colon Cancer Control Study
University of Minnesota, Minneapolis

Address:
  E-Mail:
    Internet: rao@cccs.umn.edu
    Bitnet:   rao%moose@umnacvx
  Work:                     Home:
    212 Ontario St. S.E.      2111, 21st Ave. S.
    Suite #202                #S-20
    Minneapolis, MN 55414     Minneapolis, MN 55404
    (612) 627-4151            (612) 339-9982

/*== Cut here == Cut here == Cut here == Cut here == Cut here == Cut here ==*/

# line 1 "icalc.y"
	/*== C declarations =================================================*/

/*
 *******************************************************************************
 *
 *  yacc grammar          :  icalc.y
 *
 *  version               :
 *      2.2 of 920317
 *      2.1 of 920316
 *      2.0 of 911214
 *      1.1 of 900816
 *      1.0 of 900708
 *
 *  author                :  Rao V. Akella
 *                           Research Assistant, Colon Cancer Control Study
 *                           University of Minnesota, Minneapolis
 *
 *                           Address:
 *                             E-Mail:
 *                               Internet: rao@cccs.umn.edu
 *                               Bitnet:   rao%moose@umnacvx
 *                             Work:                     Home:
 *                               212 Ontario St. S.E.      2111, 21st Ave. S.
 *                               Suite #202                #S-20
 *                               Minneapolis, MN 55414     Minneapolis, MN 55404
 *                               (612) 627-4151            (612) 339-9982
 *
 *  written on            :  900708
 *
 *  purpose               :
 *    This program is a yacc grammar to parse an infix calculator.
 *
 *  date(s) modified      :  920317, 920316, 911214, 900816
 *
 *  modifications         :
 *  920317:  Fixed a bug in the definition of the "int" (truncation) function,
 *           and added a new alias (trunc) for it.
 *  920316:  Added 1 new command and 2 new pairs of functions.
 *    1) Added '?' command to display a help screen briefly describing all
 *       operators and functions supported.
 *    2) Added 'degtorad' and 'radtodeg' functions to convert degrees to
 *       radians and vice versa.  This should be useful because trigonometric
 *       functions usually take only radian arguments (which are difficult to
 *       specify).  Using these functions, sine of 90 degress can be easily
 *       computed using sin(degtorad(90)).
 *    3) Added a pair of date functions 'caltojul' and 'jultocal'.  This can
 *       typically be used to determine the difference (in days) between two
 *       given dates.  These functions assume the base of the Gregorian
 *       calendar is October 15, 1582 (=julian day #1).
 *       The 'caltojul' function should be invoked as caltojul(yyyy, mm, dd)
 *       where yyyy is the full 4-digit year number (eg. 1992), mm is the month
 *       number (rane 1-12) and dd is the day number (range 1-31).  caltojul
 *       returns the number of days elapsed since October 15, 1582.
 *       The 'jultocal' function takes a julian day as input and returns the
 *       corresponding calendar date as an integer (in the format yyyymmdd).
 *       So, jultocal(1) should return 15821015, which stands for Oct 15, 1582.
 *  911214:
 *    Minor change: allow any number of expressions on a line, separated by ';'
 *    Major change: icalc can now be run either interactively (when it is
 *                  invoked without any arguments, in which case the user is
 *                  prompted for input) or in a command-line mode (when all
 *                  expressions to be computed are passed to icalc via
 *                  command-line "argv" arguments, in which case icalc computes
 *                  and prints the result of each expression -- exactly as if
 *                  it had been entered interactively -- and then exits).
 *                  In the latter case, the user is supposed to delimit/
 *                  separate the expressions by ';'
 *  900816:
 *    Added a check to yylex() so that tolower() is invoked (to convert all
 *    symbol names to lower case) only if the input character is in upper case.
 *    Some systems have the isupper() check built into tolower(), and therefore
 *    work OK even without this change, but other systems return unspecified
 *    results if a lower-case character is fed to tolower().
 *
 *  invoked by            :  The user.
 *
 *  functions called      :
 *    init_table: Puts math/trig functions in symbol table.
 *    yyparse:    Grammar Parser.
 *    yyerror:    Error Handler.
 *    yylex:      Lexical Analyzer to supply tokens by parsing input.
 *    getsym:     Look-up symbol in symbol table.
 *    putsym:     Install symbol in symbol table.
 *    my_getchar: Return a single character to yylex(), either read from the
 *                keyboard (in interactive mode) or from the command-line
 *                "argv" arguments (in command-line mode).
 *   help:        Display the help screen.
 *   caltojul:    Convert calendar date to julian day.
 *   jultocal:    Convert julian day to calendar date.
 *   degtorad:    Convert degrees to radians.
 *   radtodeg:    Convert radians to degrees.
 *   trunc:       Returns its truncated argument.
 *
 *  inputs                :
 *    Math expression to be calculated, input by the user at the keyboard (in
 *    interactive mode) or supplied via command-line arguments (in command-line
 *    mode).
 *
 *  outputs               :
 *    The resultant computed value of the input expression.
 *
 *  instructions for use  :
 *    This is an "infix" calculator, so any infix expression will be computed
 *    and the result displayed.
 *    In VAX/VMS, type Ctrl-Z, Ctrl-Y or Ctrl-C to exit the program.
 *    In Unix, type Ctrl-D or Ctrl-C to exit the program.
 *    In PC/MS-DOS, type Ctrl-C or Ctrl-Z+Return to exit the program.
 *
 *  notes                 :
 *    Let me make one thing perfectly clear.  I am NOT the author of this
 *    program.  I merely copied it verbatim out of the "Bison" manual of the
 *    "Free Software Foundation, Inc.", made some cosmetic changes to customize
 *    it to my particular taste, ran it through "yacc", compiled it with a
 *    C compiler, and voila! it works.
 *
 *    Motivation: I wanted an "infix" calculator for my day-to-day work.  There
 *    is a plethora of Reverse Polish Notation calculators in Unix and the
 *    public domain, but I haven't seen many infix calculators around
 *    (presumably because they're a bit harder to program than RPN calculators?
 *    Or maybe I haven't been looking hard enough).  I remembered seeing a
 *    bison/yacc grammar example to parse an infix calculator in the Bison
 *    manual of FSF, Inc., and since the manual permits me to copy it
 *    (provided FSF is given proper copyright and credit, and this resulting
 *    code is placed in the public domain), I used it as a starting point,
 *    and simply made a FEW modifications to suit my tastes.
 *
 *   Since using the Bison manual example mandates me to include the FSF's
 *   copyright, their permission notice, the "GNU General Public License" and
 *   "Conditions for Using Bison" in the resulting derived work, here goes...

Copyright (C) 1988, 1989 Free Software Foundation, Inc.

Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the sections entitled ``GNU General Public License'' and
``Conditions for Using Bison'' are included exactly as in the
original, and provided that the entire resulting derived work is
distributed under the terms of a permission notice identical to this
one.

Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that the sections entitled ``GNU General Public
License'', ``Conditions for Using Bison'' and this permission notice
may be included in translations approved by the Free Software
Foundation instead of in the original English.

Conditions for Using Bison
**************************

Bison grammars can be used only in programs that are free software. 
This is in contrast to what happens with the GNU C compiler and the
other GNU programming tools.

The reason Bison is special is that the output of the Bison
utility--the Bison parser file--contains a verbatim copy of a sizable
piece of Bison, which is the code for the `yyparse' function.  (The
actions from your grammar are inserted into this function at one
point, but the rest of the function is not changed.)

As a result, the Bison parser file is covered by the same copying
conditions that cover Bison itself and the rest of the GNU system:
any program containing it has to be distributed under the standard
GNU copying conditions.

Occasionally people who would like to use Bison to develop
proprietary programs complain about this.

We don't particularly sympathize with their complaints.  The purpose
of the GNU project is to promote the right to share software and the
practice of sharing software; it is a means of changing society.  The
people who complain are planning to be uncooperative toward the rest
of the world; why should they deserve our help in doing so?

However, it's possible that a change in these conditions might
encourage computer companies to use and distribute the GNU system. 
If so, then we might decide to change the terms on `yyparse' as a
matter of the strategy of promoting the right to share.  Such a
change would be irrevocable.  Since we stand by the copying
permissions we have announced, we cannot withdraw them once given.

We mustn't make an irrevocable change hastily.  We have to wait until
there is a complete GNU system and there has been time to learn how
this issue affects its reception.

GNU GENERAL PUBLIC LICENSE
**************************

                        Version 1, February 1989

     Copyright (C) 1989 Free Software Foundation, Inc.
     675 Mass Ave, Cambridge, MA 02139, USA
     
     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.

 Preamble
=========

  The license agreements of most software companies try to keep users
at the mercy of those companies.  By contrast, our General Public
License is intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users. 
The General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it. 
You can use it for your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the software, or if you modify it.

  For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must tell them their rights.

  We protect your rights with two steps: (1) copyright the software,
and (2) offer you this license which gives you legal permission to
copy, distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on,
we want its recipients to know that what they have is not the
original, so that any problems introduced by others will not reflect
on the original authors' reputations.

  The precise terms and conditions for copying, distribution and
modification follow.

                          TERMS AND CONDITIONS

  1. This License Agreement applies to any program or other work
     which contains a notice placed by the copyright holder saying it
     may be distributed under the terms of this General Public
     License.  The ``Program'', below, refers to any such program or
     work, and a ``work based on the Program'' means either the
     Program or any work containing the Program or a portion of it,
     either verbatim or with modifications.  Each licensee is
     addressed as ``you''.

  2. You may copy and distribute verbatim copies of the Program's
     source code as you receive it, in any medium, provided that you
     conspicuously and appropriately publish on each copy an
     appropriate copyright notice and disclaimer of warranty; keep
     intact all the notices that refer to this General Public License
     and to the absence of any warranty; and give any other
     recipients of the Program a copy of this General Public License
     along with the Program.  You may charge a fee for the physical
     act of transferring a copy.

  3. You may modify your copy or copies of the Program or any portion
     of it, and copy and distribute such modifications under the
     terms of Paragraph 1 above, provided that you also do the
     following:

        * cause the modified files to carry prominent notices stating
          that you changed the files and the date of any change; and

        * cause the whole of any work that you distribute or publish,
          that in whole or in part contains the Program or any part
          thereof, either with or without modifications, to be
          licensed at no charge to all third parties under the terms
          of this General Public License (except that you may choose
          to grant warranty protection to some or all third parties,
          at your option).

        * If the modified program normally reads commands
          interactively when run, you must cause it, when started
          running for such interactive use in the simplest and most
          usual way, to print or display an announcement including an
          appropriate copyright notice and a notice that there is no
          warranty (or else, saying that you provide a warranty) and
          that users may redistribute the program under these
          conditions, and telling the user how to view a copy of this
          General Public License.

        * You may charge a fee for the physical act of transferring a
          copy, and you may at your option offer warranty protection
          in exchange for a fee.

     Mere aggregation of another independent work with the Program
     (or its derivative) on a volume of a storage or distribution
     medium does not bring the other work under the scope of these
     terms.

  4. You may copy and distribute the Program (or a portion or
     derivative of it, under Paragraph 2) in object code or
     executable form under the terms of Paragraphs 1 and 2 above
     provided that you also do one of the following:

        * accompany it with the complete corresponding
          machine-readable source code, which must be distributed
          under the terms of Paragraphs 1 and 2 above; or,

        * accompany it with a written offer, valid for at least three
          years, to give any third party free (except for a nominal
          charge for the cost of distribution) a complete
          machine-readable copy of the corresponding source code, to
          be distributed under the terms of Paragraphs 1 and 2 above;
          or,

        * accompany it with the information you received as to where
          the corresponding source code may be obtained.  (This
          alternative is allowed only for noncommercial distribution
          and only if you received the program in object code or
          executable form alone.)

     Source code for a work means the preferred form of the work for
     making modifications to it.  For an executable file, complete
     source code means all the source code for all modules it
     contains; but, as a special exception, it need not include
     source code for modules which are standard libraries that
     accompany the operating system on which the executable file
     runs, or for standard header files or definitions files that
     accompany that operating system.

  5. You may not copy, modify, sublicense, distribute or transfer the
     Program except as expressly provided under this General Public
     License.  Any attempt otherwise to copy, modify, sublicense,
     distribute or transfer the Program is void, and will
     automatically terminate your rights to use the Program under
     this License.  However, parties who have received copies, or
     rights to use copies, from you under this General Public License
     will not have their licenses terminated so long as such parties
     remain in full compliance.

  6. By copying, distributing or modifying the Program (or any work
     based on the Program) you indicate your acceptance of this
     license to do so, and all its terms and conditions.

  7. Each time you redistribute the Program (or any work based on the
     Program), the recipient automatically receives a license from
     the original licensor to copy, distribute or modify the Program
     subject to these terms and conditions.  You may not impose any
     further restrictions on the recipients' exercise of the rights
     granted herein.

  8. The Free Software Foundation may publish revised and/or new
     versions of the General Public License from time to time.  Such
     new versions will be similar in spirit to the present version,
     but may differ in detail to address new problems or concerns.

     Each version is given a distinguishing version number.  If the
     Program specifies a version number of the license which applies
     to it and ``any later version'', you have the option of
     following the terms and conditions either of that version or of
     any later version published by the Free Software Foundation.  If
     the Program does not specify a version number of the license,
     you may choose any version ever published by the Free Software
     Foundation.

  9. If you wish to incorporate parts of the Program into other free
     programs whose distribution conditions are different, write to
     the author to ask for permission.  For software which is
     copyrighted by the Free Software Foundation, write to the Free
     Software Foundation; we sometimes make exceptions for this.  Our
     decision will be guided by the two goals of preserving the free
     status of all derivatives of our free software and of promoting
     the sharing and reuse of software generally.

                                   NO WARRANTY

 10. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
     WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
     LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
     HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS''
     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE
     ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
     WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE
     COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

 11. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
     WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
     MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
     LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
     INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
     INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS
     OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
     YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH
     ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

                      END OF TERMS AND CONDITIONS

Appendix: How to Apply These Terms to Your New Programs
=======================================================

  If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the ``copyright'' line and a pointer to where the full notice is found.

     ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES.
     Copyright (C) 19YY  NAME OF AUTHOR
     
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 1, or (at your option)
     any later version.
     
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
     
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 Also add information on how to contact you by electronic and paper
mail.

If the program is interactive, make it output a short notice like
this when it starts in an interactive mode:

     Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.

 The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License.  Of course, the
commands you use may be called something other than `show w' and
`show c'; they could even be mouse-clicks or menu items--whatever
suits your program.

You should also get your employer (if you work as a programmer) or
your school, if any, to sign a ``copyright disclaimer'' for the
program, if necessary.  Here a sample; alter the names:

     Yoyodyne, Inc., hereby disclaims all copyright interest in the
     program `Gnomovision' (a program to direct compilers to make passes
     at assemblers) written by James Hacker.
     
     SIGNATURE OF TY COON, 1 April 1989
     Ty Coon, President of Vice

That's all there is to it!
 *
 *  There!  I've done it, and now my conscience is clear!
 *
 *  As the good license above says, folks, this code is in the public domain,
 *  and is to be distributed under the terms of a permission notice identical
 *  to the GNU license.  So, here goes...
 *     
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 1, or (at your option)
 *      any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Now that that's done, let us on, let us on...
 *
 *  features              :
 *     1) Addition (+), Subtraction (-), Multiplication (*), Division (/)
 *     2) Modulus (%), Power (^)
 *     3) Bitwise logical operators: bitwise AND (&), bitwise inclusive OR (|),
 *        unary one's complement (~)
 *     4) 20 Math/Trigonometric functions: sin, cos, tan, asin, acos, atan,
 *        sinh, cosh, tanh, exp (exponential), ln (natural log),
 *        log (base 10 log), sqrt (square root), ceil (ceiling), floor,
 *        int/trunc (truncation), abs (absolute value),
 *        degtorad (degrees->radians), radtodeg (radians->degrees).
 *        Two Date functions to convert between calendar dates and julian days:
 *        caltojul (calendar->julian) and jultocal (julian->calendar).
 *        One '?'-for-help command to display a help screen.
 *     5) Temporary variables (as many as you want, with names as long as you
 *        want) to store intermediate computations.
 *     6) This is a "portable" calculator in the sense that it's not specific to
 *        any operating system.  The yacc output should be compilable by any C
 *        compiler; this program has been tested on Unix, VAX/VMS and PC/MS-DOS,
 *        and has required no changes to compile.
 *     7) This program uses the simplest of input and output formats, and is in
 *        no way hardware dependent.  So, as long as it compiles and executes
 *        without any problems, there are no other requirements for it to work
 *        as advertised.
 *     8) All numbers are of the C floating-point type "double", which,
 *        according to the VAX C manual, has a range of 0.29*10^-38 to
 *        1.7*10^38, and has values precise to 16 decimal digits.
 *     9) Allows any number of expressions on a line, separated by ';'
 *    10) icalc can now be run either interactively (when it is
 *        invoked without any arguments, in which case the user is
 *        prompted for input) or in a command-line mode (when all
 *        expressions to be computed are passed to icalc via
 *        command-line "argv" arguments, in which case icalc computes
 *        and prints the result of each expression -- exactly as if
 *        it had been entered interactively -- and then exits).
 *        In the latter case, the user is supposed to delimit/
 *        separate the expressions by ';'
 *
 *  limitations           :
 *     1) This is a simple calculator that works only in character mode.
 *        No jazzy graphics, no explanatory error messages, nothin' fancy.
 *     2) This calculator is only double precision and NOT infinite precision.
 *
 *  references            :
 *    The "Bison" manual of the "Free Software Foundation, Inc."
 *
 *************************************************************************
 */

#include <math.h>  /* For math functions, cos(), sin(), etc.     */

/* #include "calc.h" */  /* Contains definition of `symrec'            */
/* ^^^^^^^^^^^^^^^^^ instead of having another one-time-only include file,
 *                   the file itself has been physically included here       */

/*-- calc.h -----------------------------------------------------------------*/

/* Data type for links in the chain of symbols.                  */
struct symrec
{
  char *name;  /* name of symbol                     */
  int type;    /* type of symbol: either VAR or FNCT */
  union {
    double var;           /* value of a VAR          */
    double (*fnctptr)();  /* value of a FNCT         */
  } value;
  struct symrec *next;    /* link field              */
};

typedef struct symrec symrec;

/* The symbol table: a chain of `struct symrec'.     */
extern symrec *sym_table;

symrec *putsym ();
symrec *getsym ();

/*-- end of calc.h ----------------------------------------------------------*/


# line 565 "icalc.y"
typedef union  {
double     val;  /* For returning numbers.                  */
symrec  *tptr;   /* For returning symbol-table pointers     */
} YYSTYPE;
# define NUM 257
# define VAR 258
# define FNCT 259
# define NEG 260
#define yyclearin yychar = -1
#define yyerrok yyerrflag = 0
extern int yychar;
extern short yyerrflag;
#ifndef YYMAXDEPTH
#define YYMAXDEPTH 150
#endif
YYSTYPE yylval, yyval;
# define YYERRCODE 256

# line 628 "icalc.y"


/*== additional C code ======================================================*/

#include <stdio.h>

int interactive;
char *sargs;

double caltojul();	/* calendar date -> julian day */
double jultocal();	/* julian day -> calendar date */

double degtorad();	/* degrees -> radians */
double radtodeg();	/* radians -> degrees */

double trunc();		/* truncate */

main(argc, argv)
	int argc;
	char **argv;
{
    char *version = "2.2 of 17-MAR-1992";
/*  char *version = "2.1 of 16-MAR-1992";  */
/*  char *version = "2.0 of 14-DEC-1991";  */
/*  char *version = "1.1 of 16-AUG-1990";  */
/*  char *version = "1.0 of  8-JUL-1990";  */

  init_table ();
  if (argc == 1) {
    interactive = 1;
    printf("IC> ");
  } else {
    interactive = 0;
    /*
     * contruct a single string "sargs" comprising all argv strings in order,
     * with a single space separating each argv element (this is not strictly
     * necessary since the user is supposed to separate all expressions passed
     * through argv with ';' already, but it may be useful in the future to
     * know this).
     * signal the end of the string with '\n' followed by NULL (the '\n' is
     * required for the way ICALC works, and the NULL will act as the
     * equivalent of an EOF in an interactive session).
     */
    sargs = (char *) malloc(strlen(argv[1]) + 2);
    strcpy(sargs, argv[1]);
    argc--;
    argv++;
    while (--argc) {
        sargs = (char *) realloc(sargs, strlen(sargs)+1 + strlen(*++argv)+2);
        strcat(sargs, " ");	/* argv separator -- not strictly necessary */
        strcat(sargs, *argv);
    }
    sargs[strlen(sargs) + 1] = (char) NULL;
    sargs[strlen(sargs)]     = '\n';
  }

  yyparse ();
}

/*---------------------------------------------------------------------------*/

#define BEL	0x7

yyerror (s)  /* Called by yyparse on error */
     char *s;
{
  printf ("%c%s\n", BEL, s);	/* Beep! */
}

/*---------------------------------------------------------------------------*/

struct init
{
  char *fname;
  double (*fnct)();
};

struct init arith_fncts[]
  = {
      "sin",		sin,
      "sinh",		sinh,
      "asin",		asin,
      "cos",		cos,
      "cosh",		cosh,
      "acos",		acos,
      "tan",		tan,
      "tanh",		tanh,
      "atan",		atan,
      "exp",		exp,
      "ln",		log,
      "log",		log10,
      "sqrt",		sqrt,
      "ceil",		ceil,
      "floor",		floor,
      "int",		trunc,
      "trunc",		trunc,
      "abs",		fabs,
      "caltojul",	caltojul,
      "jultocal",	jultocal,
      "degtorad",	degtorad,
      "radtodeg",	radtodeg,
      0,		0
    };

/* The symbol table: a chain of `struct symrec'.      */
symrec *sym_table = (symrec *)0;

/*---------------------------------------------------------------------------*/

init_table ()  /* puts arithmetic functions in table. */
{
  int i;
  symrec *ptr;
  for (i = 0; arith_fncts[i].fname != 0; i++)
    {
      ptr = putsym (arith_fncts[i].fname, FNCT);
      ptr->value.fnctptr = arith_fncts[i].fnct;
    }
}

/*---------------------------------------------------------------------------*/

symrec *
putsym (sym_name,sym_type)
     char *sym_name;
     int sym_type;
{
  symrec *ptr;
  ptr = (symrec *) malloc (sizeof(symrec));
  ptr->name = (char *) malloc (strlen(sym_name)+1);
  strcpy (ptr->name,sym_name);
  ptr->type = sym_type;
  ptr->value.var = 0; /* set value to 0 even if fctn.  */
  ptr->next = (struct symrec *)sym_table;
  sym_table = ptr;
  return ptr;
}

/*---------------------------------------------------------------------------*/

symrec *
getsym (sym_name)
     char *sym_name;
{
  symrec *ptr;
  for (ptr = sym_table; ptr != (symrec *) 0;
       ptr = (symrec *)ptr->next)
    if (strcmp (ptr->name,sym_name) == 0)
      return ptr;
  return 0;
}

/*---------------------------------------------------------------------------*/

#include <ctype.h>

/*
 * This lexical analyzer has been hand-coded, but in return for its simplicity,
 * it has the restriction that only single-character tokens are allowed.
 * For multiple-character tokens, you might consider replacing the following
 * 'yylex' with REAL lex-generated source.
 */

yylex()
{
  int c;

  /* Ignore whitespace, get first nonwhite character.  */
  while ((c = my_getchar ()) == ' ' || c == '\t');

  if (c == EOF)
    return 0;

  /* Char starts a number => parse the number.         */
  if (c == '.' || isdigit (c))
    {
      if (interactive) {
        ungetc (c, stdin);
        scanf ("%lf", &yylval.val);
      } else {
        sargs--;
        sscanf (sargs, "%lf", &yylval.val);
        /*
         * move the sargs pointer to the spot where sscanf() left off scanning
         */
        move_sargs();
      }
      return NUM;
    }

  /* Char starts an identifier => read the name.       */
  if (isalpha (c))
    {
      symrec *s;
      static char *symbuf = 0;
      static int length = 0;
      int i;

      /* Initially make the buffer long enough
         for a 40-character symbol name.  */
      if (length == 0)
        length = 40, symbuf = (char *)malloc (length + 1);

      i = 0;
      do
        {
          /* If buffer is full, make it bigger.  */
          if (i == length)
            {
              length *= 2;
              symbuf = (char *)realloc (symbuf, length + 1);
            }
          /* Add this character to the buffer.   */
          symbuf[i++] = isupper(c) ? tolower(c) : c;	/*
							 * "tolower" makes
							 * variable names
							 * case-INsensitive
							 * by converting them
							 * ALL to lower-case.
							 */
          /* Get another character.              */
          c = my_getchar ();
        }
      while (c != EOF && isalnum (c));

      if (interactive)
        ungetc (c, stdin);
      else
        sargs--;
      symbuf[i] = '\0';

      s = getsym (symbuf);
      if (s == 0)
        s = putsym (symbuf, VAR);
      yylval.tptr = s;
      return s->type;
    }

  /* Any other character is a token by itself.   */
  return c;
}

/*---------------------------------------------------------------------------*/

my_getchar()
{
	int c;

	if (interactive)
		return getchar();
	else {
		c = *sargs;
                if (c) {
                  sargs++;
                  return c;
                } else
                  return EOF;
	}
}

/*---------------------------------------------------------------------------*/

move_sargs()
{
	/*
	 * At the point when this routine is called, the sargs pointer is
	 * sitting at the beginning of a floating-point number (we also know
	 * that the character at the head of this number is either a '.' or a
	 * digit.
	 * This routine should move the sargs pointer to the spot/point/char
	 * on the string where the preceding sscanf() call should have stopped
	 * scanning.
         */

	/*
	 * Floating-point number format:
	 *	[ + | - ] nnn [ . [ ddd ] ] [ { E | e } [ + | - ] nn ]
	 */

	/*
	 * I'm starting with the assumption that *sargs is either a digit or
	 * the character '.'
	 */

	while (isdigit(*sargs))
		sargs++;

	switch (*sargs) {
		case '.':
			switch (*++sargs) {
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					while (isdigit(*sargs))
						sargs++;

					switch (*sargs) {
						case 'E':
						case 'e':
							break;
						default:
							return;
					}
				case 'E':
				case 'e':
					break;
				default:
					return;
			}
		case 'E':
		case 'e':
			break;
		default:
			return;
	}

	/* If control has dropped to this point, *sargs is 'E' or 'e' */
	switch (*++sargs) {
		case '+':
		case '-':
			switch (*++sargs) {
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					break;
				default:
					return;
			}
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			while (isdigit(*sargs))
				sargs++;
			return;
		default:
			return;
	}
}

/*---------------------------------------------------------------------------*/

help()
{
	/* display a help screen of all supported commands and functions */

	printf("Arithmetic Operators:                   Trig Functions (take radian arguments):\n");
	printf("+          Addition (plus)                        sin       sine\n");
	printf("-          Subtraction (minus)                    sinh      hyperbolic sine\n");
	printf("*          Multiplication (times)                 asin      arc sine\n");
	printf("/          Division (divided by)                  cos       cosine\n");
	printf("%%          Modulus (remainder)                    cosh      hyperbolic cosine\n");
	printf("^          Power (raised to)                      acos      arc cosine\n");
	printf("Bitwise Logical Operators:                        tan       tangent\n");
	printf("&          bitwise AND                            tanh      hyperbolic tangent\n");
	printf("|          bitwise inclusive OR                   atan      arc tangent\n");
	printf("~          unary one's complement       Math Functions:\n");
	printf("Date Functions:                                   exp       exponentiation\n");
	printf("caltojul   calendar to julian date                ln        natural log\n");
	printf("  Usage:   caltojul(yyyy, mm, dd)                 log       base 10 log\n");
	printf("  Returns: #days elapsed since October 15, 1582   sqrt      square root\n");
	printf("jultocal   julian to calendar date                ceil      ceiling\n");
	printf("  Usage:   jultocal(julian_date)                  floor     floor\n");
	printf("  Returns: date in yyyymmdd format                int,trunc truncation\n");
	printf("  Eg:  caltojul(1989,12,31) <=> jultocal(148732)  abs       absolute value\n");
	printf("Help Functions:                                   degtorad  degrees -> radians\n");
	printf("?          Help (print this screen)               radtodeg  radians -> degrees\n");
}

/*---------------------------------------------------------------------------*/

/*
 * function to convert calender dates to julian dates.
 * (originally adapted from ACM, Oct '68, page 657).
 * This function assumes dayzero=yrmoda/julian/spss/sir =>
 * assumes idayzer=2299160 (Oct 15, 1582).
 */

double caltojul(yyyy, mm, dd)
	double yyyy, mm, dd;
{
	long idayzer, i, j, k, ci2j;	/* DON'T use "unsigned"!
					 * ci2j calculation will blow up */

	idayzer = 2299160;
	i = yyyy;
	j = mm;
	k = dd;

	ci2j = k-32075+1461*(i+4800+(j-14)/12)/4+367*(j-2-(j-14)/12*12)
		/12-3*((i+4900+(j-14)/12)/100)/4 - idayzer;

	return( (double) ci2j );
}

/*---------------------------------------------------------------------------*/

#ifndef abs
#define abs(x) ((x) < 0 ? (-(x)) : (x)) 		  /* absolute val */
#endif

/*---------------------------------------------------------------------------*/

double jultocal(jd)
	double jd;
{
	/*
	 * function to convert julian days to calendar dates
	 * (converse of caltojul)

	 * idayzer    -- julian day-one offset
	 * i,j,k,l,n  -- integer ease transcription of algorithm 
	 * dd,mm,yyyy -- day,month,year digits respectively
	 * jd         -- incoming integer julian date
	 * jdz        -- local integer julian date  has dayzero addedon

	 * converts julian date 'jd' with specifiable first day to
	 * gregorian date with output format 'yyyymmdd'.
	 * uses acm algorithm by hf fliegel, and tc van flandern acm vol 11,
	 * #10,oct68.

	 * dayone is a string indicating first julian day of calendar.
	 * algorithm uses prehistoric day-one, so 2299161 is oct 15, 1582
	 * used by spss/sir for base date
	 */

	long idayzer, jdz, i, j, k, l, n, yyyy, mm, dd;

	idayzer = 2299160;

	jdz = abs((long) jd) + idayzer;

	/* i is julian year, j is month, k is day */

	l = jdz + 68569;
	n = 4*l/146097;
	l = l - (146097*n + 3)/4;
	i = 4000*(l+1)/1461001;
	l = l - 1461*i/4 + 31;
	j = 80*l/2447;
	k = l - 2447*j/80;
	l = j/11;
	j = j + 2 - 12*l;
	i = 100*(n - 49) + i + l;

	yyyy = i;
	mm   = j;
	dd   = k;

	return( (double) (yyyy * 10000 + mm * 100 + dd) );
}

/*---------------------------------------------------------------------------*/

#define PI 3.14159265358979323846

/*---------------------------------------------------------------------------*/

double degtorad(x)
	double x;
{
	return( x * (PI / 180.0) );	/* deg->rad */
}

/*---------------------------------------------------------------------------*/

double radtodeg(x)
	double x;
{
	return( x * (180.0 / PI) );	/* rad->deg */
}

/*---------------------------------------------------------------------------*/

double trunc(x)
	double x;
{
	return( (long) x );		/* truncate */
}

/*== end of additional C code ===============================================*/
short yyexca[] ={
-1, 1,
	0, -1,
	-2, 0,
	};
# define YYNPROD 26
# define YYLAST 250
short yyact[]={

   3,  13,  25,  22,  23,  26,  11,  46,  20,  18,
  47,  19,  27,  21,  22,  23,  14,  17,  43,  20,
  18,  44,  19,  16,  21,   4,   2,   1,  22,  23,
  13,   0,  49,  20,  18,  11,  19,   0,  21,  22,
  23,   0,   0,  42,  20,  18,   0,  19,   0,  21,
   0,  22,  23,   6,   0,   0,  20,  18,   0,  19,
  25,  21,  22,  23,  22,  15,   0,  20,  18,  20,
  19,  25,  21,  22,  21,   0,   0,   0,  20,  18,
   0,  19,   0,  21,   0,  25,   0,  12,   0,   0,
  24,   0,   0,   0,   0,   0,  25,   0,   0,   0,
   0,  24,   0,   0,   0,   0,   0,   0,  25,   0,
   0,   0,   0,   0,   0,  24,  12,   0,   0,  25,
   7,  25,   0,   0,   0,   0,  24,   0,   0,   0,
  25,   0,  28,  29,  30,   0,  31,   0,  24,  32,
  33,  34,  35,  36,  37,  38,  39,  40,  41,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,  45,   0,   0,  48,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   8,   9,
  10,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
   0,   0,   0,   0,   0,   0,   5,   8,   9,  10 };
short yypact[]={

-1000, -10,-1000,-1000,   6,  13,   7,  14,-1000, -56,
 -28, -39, -39, -39,-1000, -39,-1000,-1000, -39, -39,
 -39, -39, -39, -39, -39, -39, -39, -39, -92, -92,
   2,  14,  27,  27, -92, -92, -92,  36,  25, -92,
  14, -23,-1000,-1000, -39, -34,-1000, -39,  -9,-1000 };
short yypgo[]={

   0, 120,  27,  26,  25 };
short yyr1[]={

   0,   2,   2,   3,   3,   3,   3,   4,   4,   1,
   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
   1,   1,   1,   1,   1,   1 };
short yyr2[]={

   0,   0,   2,   1,   2,   2,   2,   1,   3,   1,
   1,   3,   4,   6,   8,   3,   3,   3,   3,   3,
   3,   3,   2,   2,   3,   3 };
short yychk[]={

-1000,  -2,  -3,  10,  -4, 256,  63,  -1, 257, 258,
 259,  45, 126,  40,  10,  59,  10,  10,  43,  45,
  42,  47,  37,  38, 124,  94,  61,  40,  -1,  -1,
  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
  -1,  -1,  41,  41,  44,  -1,  41,  44,  -1,  41 };
short yydef[]={

   1,  -2,   2,   3,   0,   0,   0,   7,   9,  10,
   0,   0,   0,   0,   4,   0,   5,   6,   0,   0,
   0,   0,   0,   0,   0,   0,   0,   0,  22,  23,
   0,   8,  15,  16,  17,  18,  19,  20,  21,  24,
  11,   0,  25,  12,   0,   0,  13,   0,   0,  14 };

#ifndef lint
static char yaccpar_sccsid[] = "@(#)yaccpar	4.1	(Berkeley)	2/11/83";
#endif not lint

#
# define YYFLAG -1000
# define YYERROR goto yyerrlab
# define YYACCEPT return(0)
# define YYABORT return(1)

/*	parser for yacc output	*/

#ifdef YYDEBUG
int yydebug = 0; /* 1 for debugging */
#endif
YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */
int yychar = -1; /* current input token number */
int yynerrs = 0;  /* number of errors */
short yyerrflag = 0;  /* error recovery flag */

yyparse() {

	short yys[YYMAXDEPTH];
	short yyj, yym;
	register YYSTYPE *yypvt;
	register short yystate, *yyps, yyn;
	register YYSTYPE *yypv;
	register short *yyxi;

	yystate = 0;
	yychar = -1;
	yynerrs = 0;
	yyerrflag = 0;
	yyps= &yys[-1];
	yypv= &yyv[-1];

 yystack:    /* put a state and value onto the stack */

#ifdef YYDEBUG
	if( yydebug  ) printf( "state %d, char 0%o\n", yystate, yychar );
#endif
		if( ++yyps> &yys[YYMAXDEPTH] ) { yyerror( "yacc stack overflow" ); return(1); }
		*yyps = yystate;
		++yypv;
		*yypv = yyval;

 yynewstate:

	yyn = yypact[yystate];

	if( yyn<= YYFLAG ) goto yydefault; /* simple state */

	if( yychar<0 ) if( (yychar=yylex())<0 ) yychar=0;
	if( (yyn += yychar)<0 || yyn >= YYLAST ) goto yydefault;

	if( yychk[ yyn=yyact[ yyn ] ] == yychar ){ /* valid shift */
		yychar = -1;
		yyval = yylval;
		yystate = yyn;
		if( yyerrflag > 0 ) --yyerrflag;
		goto yystack;
		}

 yydefault:
	/* default state action */

	if( (yyn=yydef[yystate]) == -2 ) {
		if( yychar<0 ) if( (yychar=yylex())<0 ) yychar = 0;
		/* look through exception table */

		for( yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=yystate) ; yyxi += 2 ) ; /* VOID */

		while( *(yyxi+=2) >= 0 ){
			if( *yyxi == yychar ) break;
			}
		if( (yyn = yyxi[1]) < 0 ) return(0);   /* accept */
		}

	if( yyn == 0 ){ /* error */
		/* error ... attempt to resume parsing */

		switch( yyerrflag ){

		case 0:   /* brand new error */

			yyerror( "syntax error" );
		yyerrlab:
			++yynerrs;

		case 1:
		case 2: /* incompletely recovered error ... try again */

			yyerrflag = 3;

			/* find a state where "error" is a legal shift action */

			while ( yyps >= yys ) {
			   yyn = yypact[*yyps] + YYERRCODE;
			   if( yyn>= 0 && yyn < YYLAST && yychk[yyact[yyn]] == YYERRCODE ){
			      yystate = yyact[yyn];  /* simulate a shift of "error" */
			      goto yystack;
			      }
			   yyn = yypact[*yyps];

			   /* the current yyps has no shift onn "error", pop stack */

#ifdef YYDEBUG
			   if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] );
#endif
			   --yyps;
			   --yypv;
			   }

			/* there is no state on the stack with an error shift ... abort */

	yyabort:
			return(1);


		case 3:  /* no shift yet; clobber input char */

#ifdef YYDEBUG
			if( yydebug ) printf( "error recovery discards char %d\n", yychar );
#endif

			if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */
			yychar = -1;
			goto yynewstate;   /* try again in the same state */

			}

		}

	/* reduction by production yyn */

#ifdef YYDEBUG
		if( yydebug ) printf("reduce %d\n",yyn);
#endif
		yyps -= yyr2[yyn];
		yypvt = yypv;
		yypv -= yyr2[yyn];
		yyval = yypv[1];
		yym=yyn;
			/* consult goto table to find next state */
		yyn = yyr1[yyn];
		yyj = yypgo[yyn] + *yyps + 1;
		if( yyj>=YYLAST || yychk[ yystate = yyact[yyj] ] != -yyn ) yystate = yyact[yypgo[yyn]];
		switch(yym){
			
case 3:
# line 592 "icalc.y"
{ if (interactive) printf("IC> ");         } break;
case 4:
# line 593 "icalc.y"
{ if (interactive) printf("IC> ");         } break;
case 5:
# line 594 "icalc.y"
{ yyerrok;
                       if (interactive) printf("IC> ");         } break;
case 6:
# line 596 "icalc.y"
{ help();	/* display a help screen */
                       if (interactive) printf("IC> ");         } break;
case 7:
# line 601 "icalc.y"
{ printf("        %.10g\n", yypvt[-0].val);   } break;
case 8:
# line 602 "icalc.y"
{ printf("        %.10g\n", yypvt[-0].val);   } break;
case 9:
# line 605 "icalc.y"
{ yyval.val = yypvt[-0].val;                         } break;
case 10:
# line 606 "icalc.y"
{ yyval.val = yypvt[-0].tptr->value.var;              } break;
case 11:
# line 607 "icalc.y"
{ yyval.val = yypvt[-0].val; yypvt[-2].tptr->value.var = yypvt[-0].val;
                               printf("        %s = %.10g\n",
                                 yypvt[-2].tptr->name, yypvt[-0].val);                 } break;
case 12:
# line 610 "icalc.y"
{ yyval.val = (*(yypvt[-3].tptr->value.fnctptr))(yypvt[-1].val); } break;
case 13:
# line 611 "icalc.y"
{ yyval.val = (*(yypvt[-5].tptr->value.fnctptr))(yypvt[-3].val, yypvt[-1].val); } break;
case 14:
# line 612 "icalc.y"
{ yyval.val = (*(yypvt[-7].tptr->value.fnctptr))(yypvt[-5].val, yypvt[-3].val, yypvt[-1].val); } break;
case 15:
# line 613 "icalc.y"
{ yyval.val = yypvt[-2].val + yypvt[-0].val;                    } break;
case 16:
# line 614 "icalc.y"
{ yyval.val = yypvt[-2].val - yypvt[-0].val;                    } break;
case 17:
# line 615 "icalc.y"
{ yyval.val = yypvt[-2].val * yypvt[-0].val;                    } break;
case 18:
# line 616 "icalc.y"
{ yyval.val = yypvt[-2].val / yypvt[-0].val;                    } break;
case 19:
# line 617 "icalc.y"
{ yyval.val = fmod(yypvt[-2].val, yypvt[-0].val);               } break;
case 20:
# line 618 "icalc.y"
{ yyval.val = ((int) yypvt[-2].val) & ((int) yypvt[-0].val);    } break;
case 21:
# line 619 "icalc.y"
{ yyval.val = ((int) yypvt[-2].val) | ((int) yypvt[-0].val);    } break;
case 22:
# line 620 "icalc.y"
{ yyval.val = -yypvt[-0].val;                        } break;
case 23:
# line 621 "icalc.y"
{ yyval.val = ~((int) yypvt[-0].val);                } break;
case 24:
# line 622 "icalc.y"
{ yyval.val = pow (yypvt[-2].val, yypvt[-0].val);               } break;
case 25:
# line 623 "icalc.y"
{ yyval.val = yypvt[-1].val;                         } break;
		}
		goto yystack;  /* stack new state and value */

	}
/*== End of ICALC.C == End of ICALC.C == End of ICALC.C == End of ICALC.C ==*/
