Import GNU bc 1.04

PR:		4183
This commit is contained in:
Andreas Klemm 1998-04-29 21:53:01 +00:00
commit 17f33912d7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/bc/dist/; revision=35516
svn path=/vendor/bc/1.0.4/; revision=35518; tag=vendor/misc-GNU/bc/1.0.4
90 changed files with 27534 additions and 0 deletions

4
contrib/bc/AUTHORS Normal file
View File

@ -0,0 +1,4 @@
Phil Nelson <phil@cs.wwu.edu> wrote bc, including the number.c
source in the "lib" directory.
Ken Pizzini wrote dc.

341
contrib/bc/COPYING Normal file
View File

@ -0,0 +1,341 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU 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. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), 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 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 show them these terms so they know 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.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License 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 derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. 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 License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
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.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary 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
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing 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 for copying, distributing or modifying
the Program or works based on it.
6. 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.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. 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 this 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
this License, you may choose any version ever published by the Free Software
Foundation.
10. 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
11. 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.
12. 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 the public, 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 2 of the License, 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 is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

694
contrib/bc/ChangeLog Normal file
View File

@ -0,0 +1,694 @@
Mon Apr 21 14:57:14 1997 Phil Nelson <phil@cs.wwu.edu>
* bc/scan.l: Changed rules for single line comment to work
with lex as well as flex. Also, do not include \n in the
comment.
* doc/bc.1: Clarified the single line comment and that \n
is processed outside of the comment.
Sun Apr 20 22:21:30 1997 Phil Nelson <phil@cs.wwu.edu>
* bc/scan.l: Added rules for a single line comment starting
with the # character.
* doc/bc.1: Documented the single line comment.
* bc/Makefile.am: Added DISTCLEANFILES for proper clean up.
Sat Apr 19 22:08:05 1997 Phil Nelson <phil@cs.wwu.edu>
* dc/Makefile.am: Removed file from distribution list.
* h/version.h: Updated dc version to 1.1.
Fri Apr 18 16:43:04 1997 Phil Nelson <phil@cs.wwu.edu>
* lib/number.c (bc_add, bc_sub) Added 1 to the length
of the memset call to make sure it zeroed all the
storage.
Fri Apr 18 13:58:56 1997 Phil Nelson <phil@cs.wwu.edu>
* configure.in: Tweeks to get things right. Not sure if things
changed much. Still working with autoconf/automake to do
the right thing.
Wed Apr 16 16:49:17 1997 Phil Nelson <phil@cs.wwu.edu>
* bc/main.c (main): Changed processing of BC_ENV_ARGS.
* bc/main.c (parse_args): Removed "start" parameter.
Tue Apr 15 13:21:28 1997 Phil Nelson <phil@cs.wwu.edu>
* acconfig.h: Included support for PACKAGE and VERSION.
* configure.in: More tweeks for automake support.
* h/number.h: Improve definition of MIN and MAX.
* doc/bc.1: Changed copyright, tweeked other text, added
e-mail address for bugs.
* doc/dc.1: Added copyright and GPL license information,
Changed a few .SH formats.
Fri Apr 11 16:14:42 1997 Phil Nelson <phil@cs.wwu.edu>
* Makefile.am configure.in doc/Makefile.am lib/Makefile.am
bc/Makefile.am bc/bc.y dc/Makefile.am: Changes to accomodate
automake-1.1n (pre-release version of automake 1.2).
* bc/bc.y bc/sbc.y: Changes to make sure tokens are numbered the
same in bc/bc.h and bc/sbc.h.
* bc/scan.l: Changes for automake's naming convention.
* NEWS: Fixed a typo.
Thu Apr 10 14:42:55 1997 Phil Nelson <phil@cs.wwu.edu>
* bc/{execute.c, global.c, libmath.b, load.c, main.c, sbc.y
scan.l, storage.c, util.c}: Changed copyright comment and
added 1997 to copyright years.
* h/{bcdefs.h, const.h, global.h, number.h proto.h, version.h}:
Changed copyright comment and added 1997 to copyright years.
* h/version.h: Changed bc version to 1.04.
* lib/number.c: Changed copyright comment and added 1997 to
copyright years.
* lib/vfprintf.c: Noted that this was only for minix.
* NEWS, README: README is now comp.sources.reviewed readme only.
NEWS now lists changes from version to version.
Thu Apr 10 13:41:56 1997 Phil Nelson <phil@fawn.cs.wwu.edu>
* Makefile.am: Removed FIXME stuff.
Thu Apr 8 13:39:53 1997 Phil Nelson <phil@cs.wwu.edu>
* bc/Makefile.am: Remove files that should not be distributed.
Mon Apr 7 17:14:28 1997 Phil Nelson <phil@cs.wwu.edu>
* Makefile.am: Removed Misc directory from distribution.
Mon Apr 7 16:16:01 1997 Phil Nelson <phil@cs.wwu.edu>
* bc/sbc.y: Corrected use of nextarg().
Tue Mar 25 19:32:28 1997 Ken Pizzini <ken@halcyon.com>
* dc/eval.c, dc/misc.c, dc/stack.c, dc/string.c,
dc/dc.h, dc/dc-proto.h, dc/dc.c, dc/numeric.c,
doc/dc.texi: updated years in copyright
notices.
* dc/dc.1: updated last-revision date.
Tue Mar 25 16:35:46 1997 Ken Pizzini <ken@halcyon.com>
* lib/number.c: give a run-time warning in bc_raisemod()
if the modulus does not appear to be an integer.
* doc/dc.texi, doc/dc.1: documented a warning against
the use of the new | command in conjunction with a
non-integral modulus.
Tue Mar 25 15:36:04 1997 Ken Pizzini <ken@halcyon.com>
* dc/string.c: dc_out_str() updated to use fwrite()
instead of printf(), to allow for the existence of
a NUL character in the string.
Tue Mar 25 13:42:51 1997 Ken Pizzini <ken@halcyon.com>
* doc/dc.texi, doc/dc.1: added documentation for new | command.
Tue Mar 25 13:19:55 1997 Ken Pizzini <ken@halcyon.com>
* dc/dc-proto.h: added prototype for dc_triop().
Tue Mar 25 12:00:38 1997 Ken Pizzini <ken@halcyon.com>
* lib/number.c: add bc_modexp() modular-exponentiation function.
* h/proto.h: add prototypes for bc_modexp() and bc_divmod().
Tue Mar 25 09:07:13 1997 Ken Pizzini <ken@halcyon.com>
* doc/dc.texi, doc/dc.1: updated documentation with the
new command-line options.
* doc/dc.texi, doc/dc.1: updated documentation with the
new '~', 'r', and 'a' commands.
* dc/dc.c: added bug reporting information to --version text.
Mon Mar 24 19:37:30 1997 Ken Pizzini <ken@halcyon.com>
* lib/number.c: added new "bc_divmod" function.
* dc/numeric.c: added new "dc_divrem" glue function to bc_divmod.
* dc/stack.c: added new "dc_binop2" function.
* dc/dc-proto.h: added new prototypes for dc_divrem() and dc_binop2().
* dc/eval.c, dc/numeric.c: add new '~' command which
returns both the quotient and remainder from division.
Mon Mar 24 18:13:42 1997 Ken Pizzini <ken@halcyon.com>
* dc/eval.c: Add new 'r' (reverse top two stack elements) command.
Mon Mar 24 17:47:02 1997 Ken Pizzini <ken@halcyon.com>
* dc/misc.c: split out the main() related functions into
a seperate dc/dc.c file.
* dc/Makefile.am: updated to reflect this split.
Sat Mar 1 04:57:54 1997 Ken Pizzini <ken@halcyon.com>
* dc/misc.c: added "--file" option.
Sat Mar 1 02:13:06 1997 Ken Pizzini <ken@halcyon.com>
* dc/eval.c: fixed bug of an excess increment in
dc_evalstr()'s DC_COMMENT case. (Probably would
never show up in practice, but did violate the
letter of the C Standard.)
* renamed dc/number.c to dc/numeric.c, to avoid
confusion with lib/number.c.
Thu Feb 27 19:45:45 1997 Ken Pizzini <ken@halcyon.com>
* dc/string.c, dc/dc.h: changed implementation of dc_str
type from a void * to a type which is only completed
in dc/string.c. No functional change, just prettier code.
Thu Feb 27 18:25:19 1997 Ken Pizzini <ken@halcyon.com>
* Cleaned up Makefile.am files.
Thu Feb 6 00:41:02 1997 Ken Pizzini <ken@halcyon.com>
* Noticed pre-autoconf vestages (NO_XXX configuration options);
fixed to refer to autoconf HAVE_XXX definitions.
* The definition of BC_XXX values in h/const.h might
conflict with values of the same name from <limits.h>;
fixed to override without spewing warnings.
* Added check for ptrdiff_t to configure.in; removed
special ptrdiff_t definition from dc/string.c .
Wed Feb 5 22:28:37 1997 Ken Pizzini <ken@halcyon.com>
* Only compile (guts of) lib/vfprintf.c if system does
not have its own version.
Wed Feb 5 22:26:16 1997 Ken Pizzini <ken@halcyon.com>
* Changed dc/misc.c source to use standard GNU option
parsing routine (instead of special-case code).
* Added "-e" option to dc.
* Bumped dc version number to 1.0.4.
Wed Feb 5 22:08:06 1997 Ken Pizzini <ken@halcyon.com>
* rearranged source layout (added subdirectory structure);
removed "dc-" prefix from dc C source in its new home.
* merged bc's "version.h" and dc's "dc-version.h" files
into h/version.h; patched dc/misc.c to refer to new
DC_VERSION macro name.
* Tweaked configure.in in anticipation of using automake.
Wed Jul 24 16:27:20 1996 Phil Nelson <phil@cs.wwu.edu>
* number.c (out_num): Move free of t_num to proper place.
Mon Jun 3 00:31:10 1996 Phil Nelson <phil@cs.wwu.edu>
* number.c: (bc_sqrt, is_near_zero) Was hanging in an infinite
loop on sqrt(.9999). Rewrote to take difference. New routine
is_near_zero to check for one digit off.
Thu Feb 22 12:14:38 1996 Phil Nelson <phil@cs.wwu.edu>
* dc-eval.c (dc_func): Added the 'a' (number to ascii character)
command.
Thu Feb 22 11:55:15 1996 Phil Nelson <phil@cs.wwu.edu>
* dc-eval.c: (Changes from Ken) Changes dealing with stdin_lookahead
and peekc.
* dc-misc.c: (Changes from Ken) Changes in option processing.
* dc-version.c: (Change from Ken) Version is 1.0.2.
Mon Oct 9 15:40:06 1995 Phil Nelson <phil@cs.wwu.edu>
* execute.c (execute): Add a pop to 'W' and 'P' codes. Otherwise,
the stack continues to grow.
* number.c (out_num): Free all bc_nums used.
Thu Jun 29 00:35:57 1995 Phil Nelson <phil@cs.wwu.edu>
* bc.1: Added information about long options and use of the
readline library.
Wed Jun 28 21:03:45 1995 Phil Nelson <phil@cs.wwu.edu>
* scan.l: rl_input: detect EOF.
Wed Jun 28 19:03:51 1995 Phil Nelson <phil@cs.wwu.edu>
* Makefile.in: fbc target, changed $(LEXLIB) => $(LIBS)
Wed Jun 28 01:33:07 1995 Phil Nelson <phil@cs.wwu.edu>
* acconfig.h, bc.y, scan.l, storage.c, util.c, configure.in:
Improved readline support with a new pseudo variable "history"
that controls the number of history lines available.
Also removed "optional" history.
Wed Jun 28 01:03:52 1995 Phil Nelson <phil@cs.wwu.edu>
* getopt.h, getopt.c, getopt1.c: Imported from glibc-1.09
to allow long option processing.
* main.c (parse_args): Make it use long arguments.
* global.h: Change option flag variables from "char" to "int"
to allow long_arguments easy access to the variables.
* Makefile.in: Add getopt.h, getopt.c, and getopt1.c in the
proper places in the Makefile.
Fri Jun 23 12:00:16 1995 Phil Nelson <phil@cs.wwu.edu>
* scan.l, main.c (main), acconfig.h, configure.in:
Added support for readline input on stdin.
Thu Jun 22 20:08:57 1995 Phil Nelson <phil@cs.wwu.edu>
* bc.1: Change documentation on POSIX array parameter support.
Fri Apr 7 12:29:28 1995 Phil Nelson <phil@cs.wwu.edu>
* main.c (parse_args): change "char ch" to "int optch" with
related changes.
Thu Mar 23 04:11:00 1995 Phil Nelson <phil@cs.wwu.edu>
* bc.1: Update documentation to include new -q
option and the environment variables.
Thu Mar 23 03:30:38 1995 Phil Nelson <phil@cs.wwu.edu>
* bcdefs.h, global.h, main.c, util.c, bc.y: Reworked
argument processing to allow for getting arguments
from the environment and the command line. Added
a new mechanism to access file names for opening
and for error messages. Also added a "quiet"
option to turn off the welcome banner.
Thu Mar 23 03:12:11 1995 Phil Nelson <phil@cs.wwu.edu>
* util.c: Corrected a comment.
Tue Mar 21 13:36:24 1995 Phil Nelson <phil@cs.wwu.edu>
* bc.y: Added "opt_newline" to allow more newlines
in non-POSIX mode.
Tue Mar 21 09:38:28 1995 Phil Nelson <phil@cs.wwu.edu>
* execute.c, main.c, util.c: Add support for user
defined line length, "correct POSIX line length",
no breaking of strings in std_only mode. This
included adding a new function "out_schar" to
util.c. Also removed "if (interactive)" before
all fflushes.
Tue Mar 21 09:12:16 1995 Phil Nelson <phil@cs.wwu.edu>
* global.h: Added new variable "line_size". Cleaned up
some definitions by adding comments.
Mon Mar 20 23:33:01 1995 Phil Nelson <phil@cs.wwu.edu>
* proto.h: Define getopt only if no unistd.h file.
Mon Mar 20 23:23:34 1995 Phil Nelson <phil@cs.wwu.edu>
* number.c, proto.h, execute.c, storage.c, dc-number.c:
Changes to bc_add and bc_sub parameters to allow for
different scale results than were possible. This is
for correct implementation of modulo. All calls were
updated.
Mon Mar 20 19:26:06 1995 Phil Nelson <phil@cs.wwu.edu>
* sbc.y: Removed second parameter on calls to arg_str to match
real function.
Tue Feb 28 14:30:18 1995 Phil Nelson <phil@cs.wwu.edu>
* Makefile.in: Change realclean to maintainer-clean. Added warning.
Mon Feb 27 17:08:24 1995 Phil Nelson <phil@cs.wwu.edu>
* number.c: Change output to conform with POSIX standard for zero
only when the -s flag is given. Otherwise it does the tradational
thing.
* dc-misc.c: Add the "std_only" flag, always set to zero. This is
needed due to the above change.
Tue Nov 29 15:18:20 1994 Phil Nelson <phil@cs.wwu.edu>
* bc.1: Remove the "then" keyword in the if statement documentation.
Mon Nov 28 16:50:25 1994 Phil Nelson <phil@cs.wwu.edu>
* bc.1: Fixed a font change error.
* Makefile.in: Added missing \ in two targets.
Tue Nov 22 11:09:08 1994 Phil Nelson <phil@cs.wwu.edu>
* bc.1: clarified ibase and math routines.
Thu Nov 3 14:09:31 1994 Phil Nelson (phil@cs.wwu.edu)
* Makefile.in: added targets uninstall, installdirs and modified
other targets to get makes in a directory other than srcdir to
work.
* configure.in: added shell commands to get configure to work
correctly in directories other than srcdir.
Wed Nov 2 10:18:19 1994 Phil Nelson (phil@cs.wwu.edu)
* bc.1 bc.y bcdefs.h const.h execute.c global.c global.h load.c
main.c number.c number.h proto.h sbc.y scan.l storage.c util.c:
updated copyright to 1994.
* version.h: updated version number and copyright date.
* Makefile.in, configure.in, Install: updated for use with
autoconf-2.0 and install-sh. Changed target install a bit.
* install-sh: Included this file from the autoconf-2.0
distribution to have configure run without errors.
* README: updated to version 1.03.
Mon Oct 31 10:26:28 1994 Phil Nelson (phil@cs.wwu.edu)
* Added Ken Pizzini's dc implementation that uses bc numeric
routines. The following files have been added:
dc-Concerns dc-array.c dc-eval.c dc-misc.c dc-number.c
dc-proto.h dc-regdef.h dc-stack.c dc-string.c dc-version.h
dc.1 dc.h dc.texinfo
* dc-array.c: Added a conditional include of stdlib.h to get
size_t defined on my SunOS 4.1.3 system.
* configure.in: Added support for dc.
* Makefile.in: Added support for dc. Added rule to make
config.h.in.
Sun Aug 7 15:09:19 1994 Phil Nelson (phil@cs.wwu.edu)
* configure.in, Makefile.in, acconfig.h: Add support for autoconf.
Removed old Makefile.
Wed Jul 20 22:46:32 1994 Phil Nelson (phil@cs.wwu.edu)
* bc.y: change definition of next_label in function definition.
Previous value of 0 caused break to not work. It is now 1.
Fri Apr 8 14:16:37 1994 Phil Nelson (phil@cs.wwu.edu)
* Makefile: Change the distribution to include libmath.h.dist
which is a copy of libmath.h that has the compiled libmath.b.
Sun Feb 13 01:08:14 1994 Phil Nelson (phil@cs.wwu.edu)
* execute.c: Change the string quote characters to be more like
C. \a => alert (bell) \b => backspace and added \q => ".
* bc.1: Updated information on above changes.
Wed Oct 27 23:34:40 1993 Phil Nelson (phil@cs.wwu.edu)
* Makefile: Changed compress to gzip. Changed the
comment and definition of the DOT_IS_LAST compile option.
* scan.l: Changed DOT_IS_LAST to NO_DOT_LAST and changed
the test so "." is the last variable is standard.
Wed May 19 15:15:12 1993 Phil Nelson (phil at cs.wwu.edu)
* number.c: Fixed output of negative numbers in bases other than
base 10.
Wed Apr 21 11:56:31 1993 Phil Nelson (phil at cs.wwu.edu)
* bc.1: Changed Steve Sommars e-mail address.
Wed Apr 14 12:13:39 1993 Phil Nelson (phil at cs.wwu.edu)
* sbc.y: removed leading , on first line.
Wed Mar 31 16:12:39 1993 Phil Nelson (phil at cs.wwu.edu)
* bc.1: Updated segment number for function bodies.
Thu Mar 11 15:34:34 1993 Phil Nelson (phil at cs.wwu.edu)
* Makefile: added version.h to bc.o's dependency list.
Mon Mar 1 14:00:46 1993 Phil Nelson (phil at cs.wwu.edu)
* util.c: (nextarg) changed parameter "val" to be an int.
Tue Feb 16 10:06:45 1993 Phil Nelson (phil at cs.wwu.edu)
* util.c: (call_str, arg_str) added a function call_str that
correctly produces the string of argmuent types for a function
call. arg_str produced them in the reverse order. This
eliminated the need for the "comma" argument to arg_str, which
was removed.
* bc.y: changed the calls to arg_str to have only one parameter
in the function definition rule and replaced the call to arg_str
with call_str in the function call rule.
Tue Nov 24 17:38:40 1992 Phil Nelson (phil at cs.wwu.edu)
* Makefile: Added LEXLIB definitions for use with lex.
Thu Oct 22 13:43:16 1992 Phil Nelson (phil at cs.wwu.edu)
* number.c (bc_raise): Rearranged and added code to speed up
the computation by not doing unneeded multiplications.
Wed Sep 30 10:43:52 1992 Phil Nelson (phil at cs.wwu.edu)
* global.h: Fixed documentation.
Tue Sep 29 15:27:50 1992 Phil Nelson (phil at cs.wwu.edu)
* storage.c (process_params): Changed processing of more arguments
than in a function definition to just a return.
* Makefile: Made changes to make it more in conformance with the
GNU coding standards.
Tue Jul 7 21:09:07 1992 Phil Nelson (phil at cs.wwu.edu)
* (const.h, bc.y, util.c) Added code so that when the math
library is loaded, redefinition of any math library function
will not cause the other functions to quit working correctly.
Before this change, redefining a(x) would cause s(x) and c(x)
to quit working and redefining s(x) would cause c(x) to quit
working.
Wed Jul 1 14:35:29 1992 Phil Nelson (phil at cs.wwu.edu)
* (libmath.b) Changed the calculation of scale for computing
e(x) and l(x). This provides a little more accuracy in the
last digit at the expense of a little speed.
* (Test/checklib.b) Changed tests to be parameterized and test
more values.
Thu Jun 25 09:22:59 1992 Phil Nelson (phil at cs.wwu.edu)
* (configure) changed the script from looking in the
include directory for a .h file to asking cc (gcc) to
find the .h file. This will allow better detection
of include files available to the C compiler.
Wed Jun 24 22:11:37 1992 Phil Nelson (phil at cs.wwu.edu)
* (bc.y) Added a warning for the "last" variable.
* (scan.l) Added code to allow for a single dot (.) to be the
same as the variable "last". This is not a "standard" feature,
but is provided for those who want it.
* (Install) Documented the new define for dot (.).
* (bc.1) Documented the use of dot (.) for "last".
* (Makefile) Added an easy method for adding extra defines for
use during the compile. Set DOT_IS_LAST as a standard
extra define.
* (number.c) Changed the code for sqrt for better speed.
Mon Jun 22 21:47:05 1992 Phil Nelson (phil at cs.wwu.edu)
* Changed the name of math.h to libmath.h to avoid conflict
with /usr/include/math.h. Changed all references to math.h
to libmath.h in all files.
* (configure) Changed the test for long strings accepted by
cc to not include libmath.h and thus not need to distribute
a file that is generated by the system.
* (Makefile) Changed PREFIX, BINDIR, LIBDIR, and MANDIR to
lower case.
Tue Mar 3 10:16:07 1992 Phil Nelson (phil at cs.wwu.edu)
* (main.c) Added missing } at line 140.
* (version.h) Changed date of version 1.02 to March 3, 1992.
Mon Feb 3 16:07:57 1992 Phil Nelson (phil at cs.wwu.edu)
* (version.h) Updated version number and date.
* (bc.1) Added a new "VERSION" section.
Wed Jan 29 14:13:55 1992 Phil Nelson (phil at cs.wwu.edu)
* (execute.c) Removed the setjmp and longjmp calls that may have
caused some problems with interrupted programs.
Thu Jan 16 17:08:16 1992 Phil Nelson (phil at cs.wwu.edu)
* (Makefile) Changed install to install the manual.
Wed Jan 8 13:23:42 1992 Phil Nelson (phil at cs.wwu.edu)
* Change all copyright notices to include 1992.
* (load.c) Added termination to "load_code" to ignore code
after an error has been found.
* (scan.l) Changed the check for NUL characters in STRING tokens
(before the close quote) to work correctly. Also added code to
report illegal characters in a more readable output format.
* (bc.1) Added the exclusion of NUL characters from strings in
the "differences" section and updated date of last change.
* (const.h) Changed BC_MAX_SEGS to 16.
Mon Jan 6 14:20:02 1992 Phil Nelson (phil at cs.wwu.edu)
* (number.c) Changed the out_num routine to use a correct field
size for bases greater than 16. e.g. For base 1000, each
"digit" is a three digit number.
* (Makefile) Added the "8" flag to get an 8 bit scanner.
* (scan.l) Changed "char *" to "unsigned char *" to match the
declaration of yytext for the 8 bit scanner. Also added code
to detect the null character in strings and generate an error.
Sat Jan 4 20:32:20 1992 Phil Nelson (phil at cs.wwu.edu)
* (const.h) Changed BC_BASE_MAX to INT_MAX to allow more bases!
Mon Dec 30 21:47:28 1991 Phil Nelson (phil at cs.wwu.edu)
* (main.c) Fixed the bug that loaded the math library before
every file.
* (bc.y) Removed some type declarations that duplicated token
definitions so it could be run through bison.
* (load.c) Added a check for maximum code size.
* (Makefile) Added a prefix for LIBDIR and BINDIR so it can be
changed easily.
Mon Nov 25 13:11:17 1991 Phil Nelson (phil at cs.wwu.edu)
* Changed version number in version.h to 1.01 with current date.
* Changed LIBFILE definition in Makefile.
* Added a recursive function example to bc.1.
Sun Nov 24 21:24:01 1991 Phil Nelson (phil at cs.wwu.edu)
* Changed the Makefile to make sure configure is run first.
Added the $(CC) the configure call. Moved some defines
toward the front of the Makefile to make sure they are
read by installers. Also added SUBDIRS variable and updated
the GNU distribution to include the subdirectories. Included
math.h in the distribution for use by configure. Included
ChangeLog in the distribution.
* Split the README into README and Install. Changed Install
to have current information. Documented the STRINGS_H define.
Updated the version number in README.
* Added a check for <strings.h> in configure.
Fri Nov 22 15:06:32 1991 Phil Nelson (phil at cs.wwu.edu)
* Changed configure to check for varargs.h first. Also, added
checks to see if long strings (math.h) are accepted by the
C compiler. Also added parameters to configure.
* Deleted #include <sys/types.h> from proto.h. Also made only
ANSI C compilers include <stdlib.h>.
* Changed the Makefile to have the install bin directory be
/usr/local/bin and the install lib directory be /usr/local/lib.
* Changed some files in the Test directory to eliminate the
<op>= form that some older bcs don't like.
* Made some small corrections in bc.1.
Tue Oct 29 10:06:32 1991 Phil Nelson (phil at cs.wwu.edu)
* Called current version 1.00.
* Submitted GNU bc-1.00 to comp.sources.reviewed

View File

@ -0,0 +1,16 @@
scale=2
print "\nCheck book program!\n"
print " Remember, deposits are negative transactions.\n"
print " Exit by a 0 transaction.\n\n"
print "Initial balance? "; bal = read()
bal /= 1
print "\n"
while (1) {
"current balance = "; bal
"transaction? "; trans = read()
if (trans == 0) break;
bal -= trans
bal /= 1
}
quit

53
contrib/bc/Examples/pi.b Normal file
View File

@ -0,0 +1,53 @@
/*
This is a program to determine the distribution of digits in the
fraction part of PI. It will look at the first scale digits.
The results are left in the global variable digits.
digits[0] is the number of 0's in PI.
This program requires the math library.
*/
define pi () {
auto ix, pi, save_scale, work;
save_scale = scale;
scale += 5;
print "\n\nCalculating PI to ",scale," digits. Please wait . . .";
pi = 4*a(1);
scale -= 5;
work = pi;
print "\nCounting digits. . .";
for (ix = 0; ix < 10; ix++) digits[ix] = 0;
/* Extract the One's digit from pi. */
scale = 0;
one_digit = work / 1;
for (ix = save_scale; ix > 0; ix--) {
/* Remove the One's digit and multiply by 10. */
scale = ix;
work = (work - one_digit) / 1 * 10;
/* Extract the One's digit. */
scale = 0;
one_digit = work / 1;
digits[one_digit] += 1;
}
/* Restore the scale. */
scale = save_scale;
/* Report. */
print "\n\n"
print "PI to ", scale, " digits is:\n", pi/1, "\n\n"
print "The frequency of the digits are:\n"
for (ix = 0; ix < 10; ix++) {
print " ", ix, " - ", digits[ix], " times\n"
}
print "\n\n"
}

View File

@ -0,0 +1,32 @@
/* An example that finds all primes between 2 and limit. */
define primes (limit) {
auto num, p, root, i
prime[1] = 2;
prime[2] = 3;
num = 2;
if (limit >= 2) print "prime 1 = 2\n"
if (limit >= 3) print "prime 2 = 3\n";
scale = 0;
for ( p=5; p <= limit; p += 2) {
root = sqrt(p);
isprime = 1;
for ( i = 1; i < num && prime[i] <= root; i++ ) {
if ( p % prime[i] == 0 ) {
isprime = 0;
break;
}
}
if (isprime) {
num += 1;
prime [num] = p;
print "prime ", num, " = ", p, "\n"
}
}
}
print "\ntyping 'primes (10)' will print all primes less than 10.\n"

View File

@ -0,0 +1,40 @@
/* An example that finds all primes between 2 and limit. */
define primes (limit) {
auto num, p, root, i
prime[1] = 2;
prime[2] = 3;
num = 2;
scale = 0;
for ( p=5; p <= limit; p += 2) {
root = sqrt(p);
isprime = 1;
for ( i = 1; i < num && prime[i] <= root; i++ ) {
if ( p % prime[i] == 0 ) {
isprime = 0;
break;
}
}
if (isprime) {
num += 1;
prime [num] = p;
}
}
}
print "\ntyping 'twins (10)' will print all twin primes less than 10.\n"
define twins (limit) {
auto i;
i = primes(limit+2);
for (i=1; prime[i] > 0; i++) {
if ((prime[i]+2) == prime[i+1]) \
print "twins are ", prime[i], " and ", prime[i+1], "\n"
}
}

176
contrib/bc/INSTALL Normal file
View File

@ -0,0 +1,176 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes a while. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made.
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

9
contrib/bc/Makefile.am Normal file
View File

@ -0,0 +1,9 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = lib bc dc doc
dist-hook:
mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test
cp -p $(srcdir)/h/*.h $(distdir)/h
cp -p $(srcdir)/Examples/*.b $(distdir)/Examples
cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test
cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test

296
contrib/bc/Makefile.in Normal file
View File

@ -0,0 +1,296 @@
# Makefile.in generated automatically by automake 1.1n from Makefile.am
# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
SHELL = /bin/sh
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = .
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = true
PRE_INSTALL = true
POST_INSTALL = true
NORMAL_UNINSTALL = true
PRE_UNINSTALL = true
POST_UNINSTALL = true
CC = @CC@
LEX = @LEX@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
VERSION = @VERSION@
YACC = @YACC@
SUBDIRS = lib bc dc doc
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
CONFIG_HEADER_IN = config.h.in
CONFIG_HEADER_FULL = config.h
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
Makefile.in NEWS acconfig.h aclocal.m4 config.h.in configure \
configure.in install-sh missing mkinstalldirs stamp-h.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP = --best
default: all
.SUFFIXES:
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
$(srcdir)/aclocal.m4: configure.in
cd $(srcdir) && $(ACLOCAL)
config.status: configure
$(SHELL) ./config.status --recheck
$(srcdir)/configure: configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
cd $(srcdir) && $(AUTOCONF)
$(CONFIG_HEADER): stamp-h
stamp-h: $(CONFIG_HEADER_IN) $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES= CONFIG_HEADERS=$(CONFIG_HEADER_FULL) \
$(SHELL) ./config.status
@echo timestamp > stamp-h
$(srcdir)/$(CONFIG_HEADER_IN): stamp-h.in
$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
cd $(top_srcdir) && $(AUTOHEADER)
echo timestamp > $(srcdir)/stamp-h.in
mostlyclean-hdr:
clean-hdr:
distclean-hdr:
rm -f $(CONFIG_HEADER)
maintainer-clean-hdr:
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
# (1) if the variable is set in `config.status', edit `config.status'
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
@SET_MAKE@
all-recursive install-data-recursive install-exec-recursive \
installdirs-recursive install-recursive uninstall-recursive \
check-recursive installcheck-recursive info-recursive dvi-recursive \
mostlyclean-recursive clean-recursive distclean-recursive \
maintainer-clean-recursive:
@for subdir in $(SUBDIRS); do \
target=`echo $@ | sed s/-recursive//`; \
echo "Making $$target in $$subdir"; \
(cd $$subdir && $(MAKE) $$target) \
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
done && test -z "$$fail"
tags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
(cd $$subdir && $(MAKE) tags); \
done
tags: TAGS
ID: $(HEADERS) $(SOURCES)
here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
done; \
test -z "$(ETAGS_ARGS)config.h.in$(SOURCES)$(HEADERS)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $(SOURCES) $(HEADERS) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
rm -f TAGS ID
maintainer-clean-tags:
distdir = $(PACKAGE)-$(VERSION)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
rm -rf $(distdir)
GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz
mkdir $(distdir)/=build
mkdir $(distdir)/=inst
dc_install_base=`cd $(distdir)/=inst && pwd`; \
cd $(distdir)/=build \
&& ../configure --srcdir=.. --prefix=$$dc_install_base \
&& $(MAKE) \
&& $(MAKE) dvi \
&& $(MAKE) check \
&& $(MAKE) install \
&& $(MAKE) installcheck \
&& $(MAKE) dist
rm -rf $(distdir)
@echo "========================"; \
echo "$(distdir).tar.gz is ready for distribution"; \
echo "========================"
dist: distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
rm -rf $(distdir)
dist-all: distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
rm -rf $(distdir)
distdir: $(DISTFILES)
rm -rf $(distdir)
mkdir $(distdir)
-chmod 755 $(distdir)
@for file in $(DISTFILES); do \
d=$(srcdir); \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done
for subdir in $(SUBDIRS); do \
test -d $(distdir)/$$subdir \
|| mkdir $(distdir)/$$subdir \
|| exit 1; \
chmod 755 $(distdir)/$$subdir; \
(cd $$subdir && $(MAKE) distdir=../$(distdir)/$$subdir distdir) \
|| exit 1; \
done
$(MAKE) distdir="$(distdir)" dist-hook
info: info-recursive
dvi: dvi-recursive
check: all-am
$(MAKE) check-recursive
installcheck: installcheck-recursive
all-recursive-am: $(CONFIG_HEADER)
$(MAKE) all-recursive
all-am: Makefile config.h
install-exec: install-exec-recursive
@$(NORMAL_INSTALL)
install-data: install-data-recursive
@$(NORMAL_INSTALL)
install: install-recursive
@:
uninstall: uninstall-recursive
all: all-recursive-am all-am
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
installdirs: installdirs-recursive
mostlyclean-generic:
test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
rm -f Makefile $(DISTCLEANFILES)
rm -f config.cache config.log stamp-h
test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
maintainer-clean-generic distclean-am
mostlyclean: mostlyclean-recursive mostlyclean-am
clean: clean-recursive clean-am
distclean: distclean-recursive distclean-am
rm -f config.status
maintainer-clean: maintainer-clean-recursive maintainer-clean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
rm -f config.status
.PHONY: default mostlyclean-hdr distclean-hdr clean-hdr \
maintainer-clean-hdr install-data-recursive uninstall-data-recursive \
install-exec-recursive uninstall-exec-recursive installdirs-recursive \
uninstalldirs-recursive all-recursive check-recursive \
installcheck-recursive info-recursive dvi-recursive \
mostlyclean-recursive distclean-recursive clean-recursive \
maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
distclean-tags clean-tags maintainer-clean-tags distdir info dvi \
installcheck all-recursive-am all-am install-exec install-data install \
uninstall all installdirs mostlyclean-generic distclean-generic \
clean-generic maintainer-clean-generic clean mostlyclean distclean \
maintainer-clean
dist-hook:
mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test
cp -p $(srcdir)/h/*.h $(distdir)/h
cp -p $(srcdir)/Examples/*.b $(distdir)/Examples
cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test
cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

31
contrib/bc/NEWS Normal file
View File

@ -0,0 +1,31 @@
This is GNU bc version 1.04. (And dc version 1.0.4)
Changes from 1.03
reorganization of source tree
use of automake
new commands for dc (|, ~, r, a)
new command line options for dc
fixed infinite loop in sqrt in bc
fixed an I/O bug in bc
made bc conform to POSIX for array parameters
added long option support for bc
new commandline options for bc (-q)
added support for readline to bc (use configure --with-readline)
command line argumens can now be taken from an environment variable
Changes from 1.02
minor bug fixes in bc.
addition of Ken Pizzini's dc program that uses the GNU bc
arbitrary precision arithmetic routines.
Changes from 1.01
minor bug fixes.

57
contrib/bc/README Normal file
View File

@ -0,0 +1,57 @@
-------- Original comp.sources.reviewed README --------
Program: GNU bc
Author: Philip A. Nelson
E-mail: phil@cs.wwu.edu
OS: UNIX (BSD, System V, MINIX, POSIX)
Copying: GNU GPL version 2
Copyright holder: Free Software Foundation, Inc.
Version: bc version 1.01
Required: vsprintf and vfprintf routines.
Machines: It has been compiled and run on the following environments:
BSD4.3 (VAX 11)
MINIX 1.5 (IBM PC, both K&R and ANSI compilers)
MINIX 1.5 (pc532)
SUN-OS 4.1 (SUN 3 and SUN 4)
SVR3V5 (Motorola 68K)
SVR3.2 (3B2)
SVR4.0.2 (a 386 box)
ULTRIX 4.1 (DEC 5000)
UTS (Amdahl)
bc is an arbitrary precision numeric processing language. Syntax is
similar to C, but differs in many substantial areas. It supports
interactive execution of statements. bc is a utility included in the
POSIX P1003.2/D11 draft standard.
This version was written to be a POSIX compliant bc processor with
several extensions to the draft standard. Option flags are available
to cause warning or rejection of the extensions to the POSIX standard.
For those who want only POSIX bc with no extensions, a grammar is
provided for exactly the language described in the POSIX document.
The grammar (sbc.y) comes from the POSIX document. The Makefile
contains rules to make sbc. (for Standard BC)
Since the POSIX document does not specify how bc must be implemented,
this version does not use the historical method of having bc be a
compiler for the dc calculator. This version has a single executable
that both compiles the language and runs the a resulting "byte code".
The "byte code" is NOT the dc language.
Also, included in the initial distribution is the library file
vfprintf.c for MINIX systems. My minix 1.5 did not have this file.
Also, you should verify that vsprintf.c works correctly on your
system.
The extensions add some features I think are missing. The major
changes and additions for bc are (a) names are allowed to be full
identifiers ([a-z][a-z0-9_]*), (b) addition of the &&, ||, and !
operators, (c) allowing comparison and boolean operations in any
expression, (d) addition of an else clause to the if statement, (e)
addition of a new standard function "read()" that reads a number from
the standard input under program control, (f) passing of arrays as
parameters by variable, (g) addition of the "halt" statement that is
an executable statement unlike the quit (i.e. "if (1 == 0) quit" will
halt bc but "if (1 == 0) halt" will not halt bc.), and (h) the
addition of the special variable "last" that is assigned the value of
each print as the number is printed.

40
contrib/bc/Test/BUG.bc Normal file
View File

@ -0,0 +1,40 @@
/* <--- bug.bc ---><--- bug.bc ---><--- bug.bc ---><--- bug.bc ---> */
/*
* See the file "signum" for a description and reference for this
* program.
*
* THIS BUG IS *NOT* IN GNU BC!!!
*
*/
obase=16
ibase=16
x=1A8F5C99605AE52 /* dividend */
y=BB0B404 /* divisor */
q=245A07AD /* (correct) quotient */
r=147EB9E /* (correct) remainder */
"Base 16
"
"x = "; x /* output numbers just to be sure... */
"y = "; y
"quo = "; q
"rem = "; r
"x/y = "; x/y /* watch this result! */
"x%y = "; x%y /* watch this result! */
"y*q+r= "; y*q+r /* check quotient & remainder */
/*
* Do the same thing in base 10:
*/
"
Base 10
"
ibase=A
obase=10
"x = "; x /* output numbers just to be sure... */
"y = "; y
"q = "; q
"r = "; r
"x/y = "; x/y /* watch this result! */
"x%y = "; x%y /* watch this result! */
"y*q+r= "; y*q+r /* check quotient & remainder */

565
contrib/bc/Test/TESTS.bc Normal file
View File

@ -0,0 +1,565 @@
From phil@cs.wwu.edu Mon Mar 20 23:13:22 1995
Date: Mon, 20 Mar 1995 23:12:17 -0800
From: Phil Nelson <phil@cs.wwu.edu>
To: phil@steelhead.cs.wwu.edu
Subject: [jhn@ironwood.cray.com: XPG4 bc(1) failures]
From: jhn@ironwood.cray.com (James Nordby)
Subject: XPG4 bc(1) failures
To: phil@cs.wwu.edu
Date: Fri, 17 Mar 1995 12:14:13 -0600 (CST)
X-Mailer: ELM [version 2.4 PL24-CRI-b]
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Length: 14277
Phil,
Here are the test results I'm getting from the XPG4 test suite,
with some explanation and fixes so far. Let me know what you
think...
Thanks much,
Jim Nordby (jhn@cray.com)
-------- bc 08:38:34 --------
Assertion #20 (A): bc reads text files
Expected exit code = 0; Received 139
Standard output isn't the same as file 'bc_eso_20_1'
diff of "out.stdout" and "bc_eso_20_1":
*** out.stdout Fri Mar 17 08:39:22 1995
--- bc_eso_20_1 Fri Mar 17 08:39:22 1995
***************
*** 0 ****
--- 1,31 ----
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 11111111111111111111111111111111111111111111111111111111111111111111
+ 1111111
Assertion Result: FAIL
I couldn't reproduce this problem; when I rebuilt your bc and
ran it, I got a different problem with printing out a large
number. The XPG4 tests expected lines to be 70 characters
long, INCLUDING the newline (this comes from the POSIX definition
of a line). To fix it, I changed util.c like so:
*** util.c Thu Mar 16 10:47:36 1995
--- util.c.old Thu Mar 16 10:50:10 1995
***************
*** 309,323 ****
else
{
out_col++;
- #ifdef _CRAY
- /*
- * XPG4 considers a line to include the <newline>;
- * therefore we want 68 numerals, <backslash>, <newline>
- */
- if (out_col == 69)
- #else
if (out_col == 70)
- #endif
{
putchar ('\\');
putchar ('\n');
--- 309,315 ----
Assertion #42 (A): check reserved words
Standard error isn't empty
Contents of out.stderr:
(standard_in) 6: syntax error
(standard_in) 15: syntax error
Standard output isn't the same as file 'bc_eso_42_1'
diff of "out.stdout" and "bc_eso_42_1":
*** out.stdout Fri Mar 17 08:39:43 1995
--- bc_eso_42_1 Fri Mar 17 08:39:43 1995
***************
*** 1,2 ****
--- 1,3 ----
2
1
+ 0
Assertion Result: FAIL
This one is debatable, based on the grammar in the POSIX manual.
Here's the input file:
cat << \VSC-EOF > input
define a() {
auto b;
for ( b = 0; b < 10; b++ ) {
b;
if ( b == 1 )
break;
}
return ( 5 ) ;
}
ibase = 10;
length ( obase );
scale = 0;
sqrt(1);
while ( a() != 5 )
VSC-EOF
They want these constructs to be accepted:
if (b == 1)
whatever;
for (x = 0; x < 10; x++)
whatever;
while (x < 10)
whatever;
rather than just
if (b == 1) {
whatever
}
etc.
The grammar as it's currently worded requires a '{' before hitting
a NEWLINE for these constructs. It's easy enough to change in bc.y
(see below), but if I do change it, it still barfs on the last
line of the file ( 'while (a() != 5)' ). Since the while lacks
a body, it gives a syntax error; they're expecting a '0' to be
returned. The grammar could be changed to support this, but is
it a good idea?
*** bc.y Thu Mar 16 10:47:20 1995
--- bc.y.old Thu Mar 16 10:50:11 1995
***************
*** 142,150 ****
| error statement
{ $$ = $2; }
;
- allow_newlines : /* empty */
- | NEWLINE allow_newlines
- ;
statement : Warranty
{ warranty (""); }
| Limits
--- 142,147 ----
***************
*** 231,237 ****
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
generate (genstr);
}
! allow_newlines statement
{
sprintf (genstr, "J%1d:N%1d:",
continue_label, break_label);
--- 228,234 ----
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
generate (genstr);
}
! statement
{
sprintf (genstr, "J%1d:N%1d:",
continue_label, break_label);
***************
*** 246,252 ****
sprintf (genstr, "Z%1d:", if_label);
generate (genstr);
}
! allow_newlines statement opt_else
{
sprintf (genstr, "N%1d:", if_label);
generate (genstr);
--- 243,249 ----
sprintf (genstr, "Z%1d:", if_label);
generate (genstr);
}
! statement opt_else
{
sprintf (genstr, "N%1d:", if_label);
generate (genstr);
***************
*** 265,271 ****
sprintf (genstr, "Z%1d:", break_label);
generate (genstr);
}
! ')' allow_newlines statement
{
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
generate (genstr);
--- 262,268 ----
sprintf (genstr, "Z%1d:", break_label);
generate (genstr);
}
! ')' statement
{
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
generate (genstr);
Assertion #49 (A): check strings
Expected exit code = 0; Received 1
Standard error isn't empty
Contents of out.stderr:
File (NULL) is unavailable.
Standard output isn't the same as file 'bc_eso_49_1'
diff of "out.stdout" and "bc_eso_49_1":
cmd-1794 diff: Missing newline at end of file 'bc_eso_49_1'.
*** out.stdout Fri Mar 17 08:40:01 1995
--- bc_eso_49_1 Fri Mar 17 08:40:01 1995
***************
*** 0 ****
--- 1 ----
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
*LINE CONTINUATION -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
*LINE CONTINUATION -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Assertion Result: FAIL
This gist of this is that the standard expects numbers to
be truncated to 70 characters, but STRINGS should not.
My changes to fix this are:
*** execute.c Thu Mar 16 13:06:39 1995
--- execute.c.old Thu Mar 16 10:50:09 1995
***************
*** 208,218 ****
case 'O' : /* Write a string to the output with processing. */
while ((ch = byte(&pc)) != '"')
if (ch != '\\')
- #ifdef _CRAY
- putchar (ch);
- #else
out_char (ch);
- #endif
else
{
ch = byte(&pc);
--- 207,213 ----
***************
*** 219,234 ****
if (ch == '"') break;
switch (ch)
{
- #ifdef _CRAY
- case 'a': putchar (007); break;
- case 'b': putchar ('\b'); break;
- case 'f': putchar ('\f'); break;
- case 'n': putchar ('\n'); break;
- case 'q': putchar ('"'); break;
- case 'r': putchar ('\r'); break;
- case 't': putchar ('\t'); break;
- case '\\': putchar ('\\'); break;
- #else
case 'a': out_char (007); break;
case 'b': out_char ('\b'); break;
case 'f': out_char ('\f'); break;
--- 214,219 ----
***************
*** 237,243 ****
case 'r': out_char ('\r'); break;
case 't': out_char ('\t'); break;
case '\\': out_char ('\\'); break;
- #endif
default: break;
}
}
--- 222,227 ----
***************
*** 350,360 ****
break;
case 'w' : /* Write a string to the output. */
- #ifdef _CRAY
- while ((ch = byte(&pc)) != '"') putchar (ch);
- #else
while ((ch = byte(&pc)) != '"') out_char (ch);
- #endif
if (interactive) fflush (stdout);
break;
Assertion #77 (C): output longer than 70 characters
Standard output isn't the same as file 'bc_eso_77_1'
diff of "out.stdout" and "bc_eso_77_1":
*** out.stdout Fri Mar 17 08:41:13 1995
--- bc_eso_77_1 Fri Mar 17 08:41:13 1995
***************
*** 1,2 ****
! 3.3333333333333333333333333333333333333333333333333333333333333333333
! 33333333333333333333333333333333
--- 1,2 ----
! 3.333333333333333333333333333333333333333333333333333333333333333333
! 333333333333333333333333333333333
Assertion Result: FAIL
Same as assertion #20 above...
Assertion #92 (A): check %
Standard output isn't the same as file 'bc_eso_92_1'
diff of "out.stdout" and "bc_eso_92_1":
*** out.stdout Fri Mar 17 08:41:33 1995
--- bc_eso_92_1 Fri Mar 17 08:41:33 1995
***************
*** 4,8 ****
4
15
1
! 0
! 0
--- 4,8 ----
4
15
1
! 6
! 5
Assertion Result: FAIL
This one is a pain. The failing code looks like this:
scale = 4
scale ( 5.000000 % 2.0 )
scale ( 5.00 % 2.0 )
They expect '6' and '5' for output, instead of '0', based on
the explanation of the modulus operator ("scale of the result
shall be 'max(scale + scale(b), scale(a)'"), even though the
result is a 0. I was able to fix this problem by the change
below:
*** number.c Thu Mar 16 13:15:43 1995
--- number.c.old Thu Mar 16 10:50:09 1995
***************
*** 614,623 ****
case 0:
/* They are equal! return zero! */
diff = copy_num (_zero_);
- #ifdef _CRAY
- /* correct the scale here */
- diff->n_scale = MAX (n1->n_scale, n2->n_scale);
- #endif
break;
case 1:
/* n2 is less than n1, subtract n2 from n1. */
but this causes another test failure that I haven't looked at.
Assertion #130 (A): functions are call by value
Standard output isn't the same as file 'bc_eso_130_1'
diff of "out.stdout" and "bc_eso_130_1":
*** out.stdout Fri Mar 17 08:42:24 1995
--- bc_eso_130_1 Fri Mar 17 08:42:24 1995
***************
*** 4,10 ****
5
4
0
! 4
3
3
5
--- 4,10 ----
5
4
0
! 5
3
3
5
Assertion Result: FAIL
Assertion #131 (A): functions are call by value
Standard output isn't the same as file 'bc_eso_131_1'
diff of "out.stdout" and "bc_eso_131_1":
*** out.stdout Fri Mar 17 08:42:28 1995
--- bc_eso_131_1 Fri Mar 17 08:42:28 1995
***************
*** 4,10 ****
5
4
0
! 4
3
3
5
--- 4,10 ----
5
4
0
! 5
3
3
5
Assertion Result: FAIL
Both of these are the 'arrays are passed by value' problem.
One of the test cases is below:
cat << \VSC-EOF > bc_in_130_1
a[0] = 3
a[0]
define b(a[]) {
a[0]
a[0] = 4
a[0]
}
a[0]
a[0] = 5
a[0]
b(a[])
a[0]
VSC-EOF
They expect the assignment of a[0] inside the b() function
to not affect a[0] outside of the function.
Assertion #139 (A): check sin
Standard output isn't the same as file 'bc_eso_139_1'
diff of "out.stdout" and "bc_eso_139_1":
*** out.stdout Fri Mar 17 08:42:40 1995
--- bc_eso_139_1 Fri Mar 17 08:42:39 1995
***************
*** 1,5 ****
0
! 20
1.68294196961579301330
20
1.6829419696
--- 1,5 ----
0
! 0
1.68294196961579301330
20
1.6829419696
Assertion Result: FAIL
Assertion #141 (A): check arctanngent
Standard output isn't the same as file 'bc_eso_141_1'
diff of "out.stdout" and "bc_eso_141_1":
*** out.stdout Fri Mar 17 08:42:44 1995
--- bc_eso_141_1 Fri Mar 17 08:42:44 1995
***************
*** 1,5 ****
0
! 20
3.14159265358979323844
20
3.1415926532
--- 1,5 ----
0
! 0
3.14159265358979323844
20
3.1415926532
Assertion Result: FAIL
Assertion #142 (A): check log
Standard output isn't the same as file 'bc_eso_142_1'
diff of "out.stdout" and "bc_eso_142_1":
*** out.stdout Fri Mar 17 08:42:47 1995
--- bc_eso_142_1 Fri Mar 17 08:42:47 1995
***************
*** 1,5 ****
0
! 20
2.30258509299404568401
20
2.3025850929
--- 1,5 ----
0
! 0
2.30258509299404568401
20
2.3025850929
Assertion Result: FAIL
Assertion #144 (A): check bessel
Standard output isn't the same as file 'bc_eso_144_1'
diff of "out.stdout" and "bc_eso_144_1":
*** out.stdout Fri Mar 17 08:42:51 1995
--- bc_eso_144_1 Fri Mar 17 08:42:51 1995
***************
*** 1,5 ****
0
! 20
.57672480775687338720
20
.5767248077
--- 1,5 ----
0
! 0
.57672480775687338720
20
.5767248077
Assertion Result: FAIL
All of these are the same. I'll give you the test case
for 'sin'; what they're expecting is 0:
scale(s(0))
bc outputs '20' (which is the scale at the time), but the
interpretation of the standard says that it should be '0',
since s(0) is 0, and the scale of 0 is 0. I think that
this interpretation disagrees with one of the previous
assertions (assertion #92).
/* end of test results */
--
Phil Nelson
e-mail: phil@cs.wwu.edu
http://www.cs.wwu.edu/~phil

14
contrib/bc/Test/array.b Normal file
View File

@ -0,0 +1,14 @@
"This tests arrays!
"
define p(x,y) {
auto i;
for (i=x; i<y; i++) a[i];
}
for (i=0; i<10; i++) a[i] = i;
j = p(0,10);
for (i=1000; i<1030; i++) a[i] = i;
j = p(1000,1030);
j = p(0,10);

30
contrib/bc/Test/arrayp.b Normal file
View File

@ -0,0 +1,30 @@
"This tests arrays!
"
define p(a[],x,y) {
auto i;
for (i=x; i<y; i++) a[i];
}
define m(a[],x,y) {
auto i;
for (i=x; i<y; i++) a[i] = i;
}
define m1(*a[],x,y) {
auto i;
print "m1\n"
for (i=x; i<y; i++) a[i] = i;
}
for (i=0; i<10; i++) a[i] = i;
j = p(a[],0,10);
j = m(b[],0,10);
j = p(b[],0,10);
print "---\n";
j = m1(b[],0,10);
j = p(b[],0,10);
quit

16
contrib/bc/Test/aryprm.b Normal file
View File

@ -0,0 +1,16 @@
define p ( x[] ) {
auto i;
for (i=0; i<10; i++) x[i];
}
define m ( x[] ) {
auto i;
for (i=0; i<10; i++) x[i] *= 2;
}
scale = 20;
for (i=0; i<10; i++) a[i] = sqrt(i);
p(a[]);
m(a[]);
p(a[]);

5
contrib/bc/Test/atan.b Normal file
View File

@ -0,0 +1,5 @@
for (a=0; a<1000; a+=2) x=a(a)
x
for (a=0; a<2; a+=.01) x=a(a)
x
quit

109
contrib/bc/Test/checklib.b Normal file
View File

@ -0,0 +1,109 @@
define t (x,y,d,s,t) {
auto u, v, w, i, b, c;
if (s >= t) {
"Bad Scales. Try again.
"; return;
}
for (i = x; i < y; i += d) {
scale = s;
u = f(i);
scale = t;
v = f(i);
scale = s;
w = v / 1;
b += 1;
if (u != w) {
c += 1;
"
Failed:
"
" index = "; i;
" val1 = "; u;
" val2 = "; v;
"
"
}
}
"
Total tests: "; b;
"
Total failures: "; c;
"
Percent failed: "; scale = 2; c*100/b;
}
/*
b = begining scale value,
l = limit scale value,
i = increment scale value.
if b is set to a non-zero value before this file is executed,
b, l and i are not reset.
*/
if (b == 0) { b = 10; l = 61; i = 10; }
"
Checking e(x)"
define f(x) {
return (e(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(0,200,1,s,s+4)
}
"
Checking l(x)"
define f(x) {
return (l(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(1,10000,25,s,s+4)
}
"
Checking s(x)"
define f(x) {
return (s(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(0,8*a(1),.01,s,s+4)
}
"
Checking a(x)"
define f(x) {
return (a(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(-1000,1000,10,s,s+4)
}
"
Checking j(n,x)"
define f(x) {
return (j(n,x))
}
for (s=10; s<l; s=s+i) {
"
n=0, scale = "; s
n=0
j = t(0,30,.1,s,s+4)
"
n=1, scale = "; s
n=1
j = t(0,30,.1,s,s+4)
}

8
contrib/bc/Test/div.b Normal file
View File

@ -0,0 +1,8 @@
scale = 20
a=2/3
for (i=0; i<1000; i++) {
for (j=1; j<100; j++) b=a/j
}
b
quit

3
contrib/bc/Test/exp.b Normal file
View File

@ -0,0 +1,3 @@
for (a=0; a<150; a++) x=e(a)
x
quit

13
contrib/bc/Test/fact.b Normal file
View File

@ -0,0 +1,13 @@
define f (x) {
if (x<=1) return(1)
return (f(x-1)*x)
}
"Here we go"
for (a=1; a<100; a++) b+=f(a)/a
"
"
"b=";b
quit

6
contrib/bc/Test/jn.b Normal file
View File

@ -0,0 +1,6 @@
scale = 30
for (a=0; a<5; a=a+2) {
for (b=0; b<100; b=b+10) x=j(a,b)
}
x
quit

3
contrib/bc/Test/ln.b Normal file
View File

@ -0,0 +1,3 @@
for (a=1; a<10000000000000000000000000000; a = a*2) x=l(a)
x
quit

7
contrib/bc/Test/mul.b Normal file
View File

@ -0,0 +1,7 @@
scale = 20
for (i=0; i<1000; i++) {
for (j=1; j<100; j++) b=i*j
}
b
quit

3
contrib/bc/Test/raise.b Normal file
View File

@ -0,0 +1,3 @@
for (i=0; i<1000; i++) a = 2^i;
a
quit

87
contrib/bc/Test/signum Normal file
View File

@ -0,0 +1,87 @@
/* From gnu@cygnus.com Wed Jul 14 13:46:44 1993
Return-Path: <gnu@cygnus.com>
To: phil@cs.wwu.edu, gnu@cygnus.com
Subject: bc/dc - no rest for the wicked
Date: Tue, 06 Jul 93 19:12:40 -0700
From: gnu@cygnus.com
GNU bc 1.02 passes all these tests. Can you add the test to the distribution?
Putting it into a DejaGnu test case for GNU bc would be a great thing, too.
(I haven't seen the Signum paper, maybe you can dig it out.)
John Gilmore
Cygnus Support
------- Forwarded Message
Date: Tue, 6 Jul 93 08:45:48 PDT
From: uunet!Eng.Sun.COM!David.Hough@uunet.UU.NET (David Hough)
Message-Id: <9307061545.AA14477@dgh.Eng.Sun.COM>
To: numeric-interest@validgh.com
Subject: bc/dc - no rest for the wicked
Steve Sommars sent me a bc script which reproduces ALL the test cases from
Dittmer's paper. Neither SunOS 5.2 on SPARC nor 5.1 on x86 come out clean.
Anybody else who has fixed all the bugs would be justified in
bragging about it here. */
/*Ingo Dittmer, ACM Signum, April 1993, page 8-11*/
define g(x,y,z){
auto a
a=x%y
if(a!=z){
"
x=";x
"y=";y
"Should be ";z
"was ";a
}
}
/*Table 1*/
g=g(53894380494284,9980035577,2188378484)
g=g(47907874973121,9980035577,3704203521)
g=g(76850276401922,9980035577,4002459022)
g=g(85830854846664,9980035577,2548884464)
g=g(43915353970066,9980035577,3197431266)
g=g(35930746212825,9980035577,2618135625)
g=g(51900604524715,9980035577,4419524315)
g=g(87827018005068,9980035577,2704927468)
g=g(57887902441764,9980035577,3696095164)
g=g(96810941031110,9980035577,4595934210)
/*Table 2*/
g=g(86833646827370,9980035577,7337307470)
g=g(77850880592435,9980035577,6603091835)
g=g(84836601050323,9980035577,6298645823)
g=g(85835110016211,9980035577,6804054011)
g=g(94817143459192,9980035577,6805477692)
g=g(94818870293481,9980035577,8532311981)
g=g(91823235571154,9980035577,6908262754)
g=g(59885451951796,9980035577,5238489796)
g=g(80844460893239,9980035577,6172719539)
g=g(67869195894693,9980035577,4953971093)
g=g(95813990985202,9980035577,5649446002)
/*Skip Table 3, duplicate of line 1, table 1*/
/*Table 4*/
g=g(28420950579078013018256253301,17987947258,16619542243)
g=g(12015118977201790601658257234,16687885701,8697335297)
g=g(14349070374946789715188912007,13712994561,3605141129)
g=g(61984050238512905451986475027,13337935089,5296182558)
g=g(86189707791214681859449918641,17837971389,14435206830)
g=g(66747908181102582528134773954,19462997965,8615839889)
/*Table 6*/
g=g(4999253,9998,253)
g=g(8996373,9995,873)
/* Added by Phil Nelson..... */
"end of tests
"

5
contrib/bc/Test/sine.b Normal file
View File

@ -0,0 +1,5 @@
for (i=0; i<8*a(1); i=i+.01) x=s(i)
x
for (i=i; i<16*a(1); i=i+.01) x=s(i+.1234123412341234)
x
quit

13
contrib/bc/Test/sqrt.b Normal file
View File

@ -0,0 +1,13 @@
scale = 5
for (a=1; a<500; a++) r=sqrt(a)
r
scale = 10
for (a=1; a<500; a++) r=sqrt(a)
r
scale = 25
for (a=1; a<500; a++) r=sqrt(a)
r
scale = 40
for (a=1; a<500; a++) r=sqrt(a)
r
quit

13
contrib/bc/Test/sqrt1.b Normal file
View File

@ -0,0 +1,13 @@
for (j=0; j<10; j++) {
a = .9;
b = .9+j;
scale = 2;
for (i=0; i<90; i++) {
scale += 1;
a /= 10;
b += a;
x = sqrt(b);
}
x;
}
quit

10
contrib/bc/Test/sqrt2.b Normal file
View File

@ -0,0 +1,10 @@
scale = 20
for (a=1; a<5000; a += 1) r=sqrt(a)
r
for (a=1; a<50000; a += 100) r=sqrt(a)
r
for (a=1; a<500000; a+=1000) r=sqrt(a)
r
for (a=1; a<5000000; a+=10000) r=sqrt(a)
r
quit

47
contrib/bc/Test/testfn.b Normal file
View File

@ -0,0 +1,47 @@
/* This function "t" tests the function "f" to see if computing at
two different scales has much effect on the accuracy.
test from f(x) to f(y) incrementing the index by d. f(i) is
computed at two scales, scale s and then scale t, where t>s.
the result from scale t is divided by 1 at scale s and the
results are compared. If they are different, the function is
said to have failed. It will then print out the value of i
(called index) and the two original values val1 (scale s) and
val2 (scale t) */
define t (x,y,d,s,t) {
auto u, v, w, i, b, c;
if (s >= t) {
"Bad Scales. Try again.
"; return;
}
for (i = x; i < y; i += d) {
scale = s;
u = f(i);
scale = t;
v = f(i);
scale = s;
w = v / 1;
b += 1;
if (u != w) {
c += 1;
"
Failed:
"
" index = "; i;
" val1 = "; u;
" val2 = "; v;
"
"
}
}
"
Total tests: "; b;
"
Total failures: "; c;
"
Percent failed: "; scale = 2; c*100/b;
}

14
contrib/bc/Test/timetest Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
#
# Time the functions.
#
BC=../bc
SYSBC=/usr/bin/bc
for file in exp.b ln.b sine.b atan.b jn.b mul.b div.b raise.b sqrt.b
do
for prog in $BC $SYSBC
do
echo Timing $file with $prog
time $prog -l $file
done
done

15
contrib/bc/acconfig.h Normal file
View File

@ -0,0 +1,15 @@
/* PACKAGE name */
#undef PACKAGE
/* Package VERSION number */
#undef VERSION
/* define if the math lib is to be loaded from a file. */
#undef BC_MATH_FILE
/* Define to use the readline library. */
#undef READLINE
/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
#undef ptrdiff_t

100
contrib/bc/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,100 @@
dnl aclocal.m4 generated automatically by aclocal 1.1n
# Do all the work for Automake. This macro actually does too much --
# some checks are only needed if your package does certain things.
# But this isn't really a big deal.
# serial 1
dnl Usage:
dnl AM_INIT_AUTOMAKE(package,version, [no-define])
AC_DEFUN(AM_INIT_AUTOMAKE,
[AC_REQUIRE([AM_PROG_INSTALL])
PACKAGE=[$1]
AC_SUBST(PACKAGE)
VERSION=[$2]
AC_SUBST(VERSION)
ifelse([$3],,
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
AC_DEFINE_UNQUOTED(VERSION, "$VERSION"))
AM_SANITY_CHECK
AC_ARG_PROGRAM
dnl FIXME This is truly gross.
missing_dir=`cd $ac_aux_dir && pwd`
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
AC_PROG_MAKE_SET])
# serial 1
AC_DEFUN(AM_PROG_INSTALL,
[AC_REQUIRE([AC_PROG_INSTALL])
test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
AC_SUBST(INSTALL_SCRIPT)dnl
])
#
# Check to make sure that the build environment is sane.
#
AC_DEFUN(AM_SANITY_CHECK,
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftestfile
# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
if test "$@" = "X"; then
# -L didn't work.
set X `ls -t $srcdir/configure conftestfile`
fi
test "[$]2" = conftestfile
)
then
# Ok.
:
else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
rm -f conftest*
AC_MSG_RESULT(yes)])
dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
dnl The program must properly implement --version.
AC_DEFUN(AM_MISSING_PROG,
[AC_MSG_CHECKING(for working $2)
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
if ($2 --version) > /dev/null 2>&1; then
$1=$2
AC_MSG_RESULT(found)
else
$1="$3/missing $2"
AC_MSG_RESULT(missing)
fi
AC_SUBST($1)])
# Like AC_CONFIG_HEADER, but automatically create stamp file.
AC_DEFUN(AM_CONFIG_HEADER,
[AC_PREREQ([2.12])
AC_CONFIG_HEADER([$1])
dnl When config.status generates a header, we must update the stamp-h file.
dnl This file resides in the same directory as the config header
dnl that is generated. We must strip everything past the first ":",
dnl and everything past the last "/".
AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl
changequote([,]))])

46
contrib/bc/bc/Makefile.am Normal file
View File

@ -0,0 +1,46 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = bc
bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c
EXTRA_DIST = bc.h fix-libmath_h libmath.b sbc.y
noinst_HEADERS = libmath.h
DISTCLEANFILES = sbc sbc.c sbc.h
MAINTAINERCLEANFILES = libmath.h bc.c bc.h
datadir = $(prefix)/@DATADIRNAME@
INCLUDES = -I$(srcdir) -I$(srcdir)/../h
LDADD = ../lib/libbc.a @LEXLIB@
$(PROGRAMS): $(LDADD)
scan.o: bc.h
global.o: libmath.h
libmath.h: libmath.b
echo \"\" > libmath.h
$(MAKE) fbc
./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h
$(srcdir)/fix-libmath_h
rm -f ./fbc
install-data-local:
if grep -s "define BC_MATH_FILE" ../config.h; \
then $(mkinstalldirs) $(libdir); \
rm -f $(libdir)/libmath.b; \
$(INSTALL_DATA) $(srcdir)/libmath.b $(libdir); \
chmod 444 $(libdir)/libmath.b; \
else true; \
fi
fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o
fbc: $(fbcOBJ)
$(LINK) $(fbcOBJ) $(LDADD) $(LIBS)
sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o
sbc.o: sbc.c
sbc: $(sbcOBJ)
$(LINK) $(sbcOBJ) $(LDADD) $(LIBS)

294
contrib/bc/bc/Makefile.in Normal file
View File

@ -0,0 +1,294 @@
# Makefile.in generated automatically by automake 1.1n from Makefile.am
# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
SHELL = /bin/sh
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = true
PRE_INSTALL = true
POST_INSTALL = true
NORMAL_UNINSTALL = true
PRE_UNINSTALL = true
POST_UNINSTALL = true
CC = @CC@
LEX = @LEX@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
VERSION = @VERSION@
YACC = @YACC@
bin_PROGRAMS = bc
bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c
EXTRA_DIST = bc.h fix-libmath_h libmath.b sbc.y
noinst_HEADERS = libmath.h
DISTCLEANFILES = sbc sbc.c sbc.h
MAINTAINERCLEANFILES = libmath.h bc.c bc.h
datadir = $(prefix)/@DATADIRNAME@
INCLUDES = -I$(srcdir) -I$(srcdir)/../h
LDADD = ../lib/libbc.a @LEXLIB@
fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o
sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(bin_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
bc_OBJECTS = main.o bc.o scan.o execute.o load.o storage.o util.o \
global.o
bc_LDADD = $(LDADD)
bc_DEPENDENCIES = ../lib/libbc.a
bc_LDFLAGS =
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LEXLIB = @LEXLIB@
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LINK = $(CC) $(LDFLAGS) -o $@
HEADERS = $(noinst_HEADERS)
DIST_COMMON = Makefile.am Makefile.in bc.c scan.c
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP = --best
SOURCES = $(bc_SOURCES)
OBJECTS = $(bc_OBJECTS)
default: all
.SUFFIXES:
.SUFFIXES: .c .o .y .l
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu bc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-binPROGRAMS:
clean-binPROGRAMS:
test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
distclean-binPROGRAMS:
maintainer-clean-binPROGRAMS:
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`"; \
$(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
else :; fi; \
done
uninstall-binPROGRAMS:
$(NORMAL_UNINSTALL)
list='$(bin_PROGRAMS)'; for p in $$list; do \
rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
done
.c.o:
$(COMPILE) -c $<
mostlyclean-compile:
rm -f *.o core
clean-compile:
distclean-compile:
rm -f *.tab.c
maintainer-clean-compile:
bc: $(bc_OBJECTS) $(bc_DEPENDENCIES)
@rm -f bc
$(LINK) $(bc_LDFLAGS) $(bc_OBJECTS) $(bc_LDADD) $(LIBS)
.y.c:
$(YACC) $(YFLAGS) $< && mv y.tab.c $@
if test -f y.tab.h; then \
if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
else :; fi
.l.c:
$(LEX) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
tags: TAGS
ID: $(HEADERS) $(SOURCES)
here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
done; \
test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = bc
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done
info:
dvi:
check: all
$(MAKE)
installcheck:
install-exec: install-binPROGRAMS
@$(NORMAL_INSTALL)
install-data: install-data-local
@$(NORMAL_INSTALL)
install: install-exec install-data all
@:
uninstall: uninstall-binPROGRAMS
all: $(PROGRAMS) $(HEADERS) Makefile
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
installdirs:
$(mkinstalldirs) $(bindir)
mostlyclean-generic:
test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
rm -f Makefile $(DISTCLEANFILES)
rm -f config.cache config.log stamp-h
test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \
mostlyclean
distclean: distclean-binPROGRAMS distclean-compile distclean-tags \
distclean-generic clean
rm -f config.status
maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \
maintainer-clean-tags maintainer-clean-generic \
distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \
clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info dvi installcheck \
install-exec install-data install uninstall all installdirs \
mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
$(PROGRAMS): $(LDADD)
scan.o: bc.h
global.o: libmath.h
libmath.h: libmath.b
echo \"\" > libmath.h
$(MAKE) fbc
./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h
$(srcdir)/fix-libmath_h
rm -f ./fbc
install-data-local:
if grep -s "define BC_MATH_FILE" ../config.h; \
then $(mkinstalldirs) $(libdir); \
rm -f $(libdir)/libmath.b; \
$(INSTALL_DATA) $(srcdir)/libmath.b $(libdir); \
chmod 444 $(libdir)/libmath.b; \
else true; \
fi
fbc: $(fbcOBJ)
$(LINK) $(fbcOBJ) $(LDADD) $(LIBS)
sbc.o: sbc.c
sbc: $(sbcOBJ)
$(LINK) $(sbcOBJ) $(LDADD) $(LIBS)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

1808
contrib/bc/bc/bc.c Normal file

File diff suppressed because it is too large Load Diff

42
contrib/bc/bc/bc.h Normal file
View File

@ -0,0 +1,42 @@
typedef union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
} YYSTYPE;
#define NEWLINE 258
#define AND 259
#define OR 260
#define NOT 261
#define STRING 262
#define NAME 263
#define NUMBER 264
#define ASSIGN_OP 265
#define REL_OP 266
#define INCR_DECR 267
#define Define 268
#define Break 269
#define Quit 270
#define Length 271
#define Return 272
#define For 273
#define If 274
#define While 275
#define Sqrt 276
#define Else 277
#define Scale 278
#define Ibase 279
#define Obase 280
#define Auto 281
#define Read 282
#define Warranty 283
#define Halt 284
#define Last 285
#define Continue 286
#define Print 287
#define Limits 288
#define UNARY_MINUS 289
#define History 290
extern YYSTYPE yylval;

637
contrib/bc/bc/bc.y Normal file
View File

@ -0,0 +1,637 @@
%{
/* bc.y: The grammar for a POSIX compatable bc processor with some
extensions to the language. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
%}
%start program
%union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
}
/* Extensions over POSIX bc.
a) NAME was LETTER. This grammer allows longer names.
Single letter names will still work.
b) Relational_expression allowed only one comparison.
This grammar has added boolean expressions with
&& (and) || (or) and ! (not) and allowed all of them in
full expressions.
c) Added an else to the if.
d) Call by variable array parameters
e) read() procedure that reads a number under program control from stdin.
f) halt statement that halts the the program under program control. It
is an executed statement.
g) continue statement for for loops.
h) optional expressions in the for loop.
i) print statement to print multiple numbers per line.
j) warranty statement to print an extended warranty notice.
j) limits statement to print the processor's limits.
*/
%token <i_value> NEWLINE AND OR NOT
%token <s_value> STRING NAME NUMBER
/* '-', '+' are tokens themselves */
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
%token <c_value> ASSIGN_OP
/* '==', '<=', '>=', '!=', '<', '>' */
%token <s_value> REL_OP
/* '++', '--' */
%token <c_value> INCR_DECR
/* 'define', 'break', 'quit', 'length' */
%token <i_value> Define Break Quit Length
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
%token <i_value> Return For If While Sqrt Else
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
%token <i_value> Scale Ibase Obase Auto Read
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
/* 'history' */
%token <i_value> UNARY_MINUS History
/* Types of all other things. */
%type <i_value> expression return_expression named_expression opt_expression
%type <c_value> '+' '-' '*' '/' '%'
%type <a_value> opt_parameter_list opt_auto_define_list define_list
%type <a_value> opt_argument_list argument_list
%type <i_value> program input_item semicolon_list statement_list
%type <i_value> statement function statement_or_error
/* precedence */
%left OR
%left AND
%nonassoc NOT
%left REL_OP
%right ASSIGN_OP
%left '+' '-'
%left '*' '/' '%'
%right '^'
%nonassoc UNARY_MINUS
%nonassoc INCR_DECR
%%
program : /* empty */
{
$$ = 0;
if (interactive && !quiet)
{
printf ("%s\n", BC_VERSION);
welcome ();
}
}
| program input_item
;
input_item : semicolon_list NEWLINE
{ run_code (); }
| function
{ run_code (); }
| error NEWLINE
{
yyerrok;
init_gen ();
}
;
opt_newline : /* empty */
| NEWLINE
{ warn ("newline not allowed"); }
;
semicolon_list : /* empty */
{ $$ = 0; }
| statement_or_error
| semicolon_list ';' statement_or_error
| semicolon_list ';'
;
statement_list : /* empty */
{ $$ = 0; }
| statement_or_error
| statement_list NEWLINE
| statement_list NEWLINE statement_or_error
| statement_list ';'
| statement_list ';' statement
;
statement_or_error : statement
| error statement
{ $$ = $2; }
;
statement : Warranty
{ warranty (""); }
| Limits
{ limits (); }
| expression
{
if ($1 & 2)
warn ("comparison in expression");
if ($1 & 1)
generate ("W");
else
generate ("p");
}
| STRING
{
$$ = 0;
generate ("w");
generate ($1);
free ($1);
}
| Break
{
if (break_label == 0)
yyerror ("Break outside a for/while");
else
{
sprintf (genstr, "J%1d:", break_label);
generate (genstr);
}
}
| Continue
{
warn ("Continue statement");
if (continue_label == 0)
yyerror ("Continue outside a for");
else
{
sprintf (genstr, "J%1d:", continue_label);
generate (genstr);
}
}
| Quit
{ exit (0); }
| Halt
{ generate ("h"); }
| Return
{ generate ("0R"); }
| Return '(' return_expression ')'
{ generate ("R"); }
| For
{
$1 = break_label;
break_label = next_label++;
}
'(' opt_expression ';'
{
if ($4 > 1)
warn ("Comparison in first for expression");
$4 = next_label++;
if ($4 < 0)
sprintf (genstr, "N%1d:", $4);
else
sprintf (genstr, "pN%1d:", $4);
generate (genstr);
}
opt_expression ';'
{
if ($7 < 0) generate ("1");
$7 = next_label++;
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
generate (genstr);
$<i_value>$ = continue_label;
continue_label = next_label++;
sprintf (genstr, "N%1d:", continue_label);
generate (genstr);
}
opt_expression ')'
{
if ($10 > 1)
warn ("Comparison in third for expression");
if ($10 < 0)
sprintf (genstr, "J%1d:N%1d:", $4, $7);
else
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
generate (genstr);
}
opt_newline statement
{
sprintf (genstr, "J%1d:N%1d:",
continue_label, break_label);
generate (genstr);
break_label = $1;
continue_label = $<i_value>9;
}
| If '(' expression ')'
{
$3 = if_label;
if_label = next_label++;
sprintf (genstr, "Z%1d:", if_label);
generate (genstr);
}
opt_newline statement opt_else
{
sprintf (genstr, "N%1d:", if_label);
generate (genstr);
if_label = $3;
}
| While
{
$1 = next_label++;
sprintf (genstr, "N%1d:", $1);
generate (genstr);
}
'(' expression
{
$4 = break_label;
break_label = next_label++;
sprintf (genstr, "Z%1d:", break_label);
generate (genstr);
}
')' opt_newline statement
{
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
generate (genstr);
break_label = $4;
}
| '{' statement_list '}'
{ $$ = 0; }
| Print
{ warn ("print statement"); }
print_list
;
print_list : print_element
| print_element ',' print_list
;
print_element : STRING
{
generate ("O");
generate ($1);
free ($1);
}
| expression
{ generate ("P"); }
;
opt_else : /* nothing */
| Else
{
warn ("else clause in if statement");
$1 = next_label++;
sprintf (genstr, "J%d:N%1d:", $1, if_label);
generate (genstr);
if_label = $1;
}
opt_newline statement
function : Define NAME '(' opt_parameter_list ')' opt_newline
'{' NEWLINE opt_auto_define_list
{
/* Check auto list against parameter list? */
check_params ($4,$9);
sprintf (genstr, "F%d,%s.%s[",
lookup($2,FUNCTDEF),
arg_str ($4), arg_str ($9));
generate (genstr);
free_args ($4);
free_args ($9);
$1 = next_label;
next_label = 1;
}
statement_list /* NEWLINE */ '}'
{
generate ("0R]");
next_label = $1;
}
;
opt_parameter_list : /* empty */
{ $$ = NULL; }
| define_list
;
opt_auto_define_list : /* empty */
{ $$ = NULL; }
| Auto define_list NEWLINE
{ $$ = $2; }
| Auto define_list ';'
{ $$ = $2; }
;
define_list : NAME
{ $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
| NAME '[' ']'
{ $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
| '*' NAME '[' ']'
{ $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
| define_list ',' NAME '[' ']'
{ $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
| define_list ',' '*' NAME '[' ']'
{ $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); }
;
opt_argument_list : /* empty */
{ $$ = NULL; }
| argument_list
;
argument_list : expression
{
if ($1 > 1) warn ("comparison in argument");
$$ = nextarg (NULL,0,FALSE);
}
| NAME '[' ']'
{
sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
generate (genstr);
$$ = nextarg (NULL,1,FALSE);
}
| argument_list ',' expression
{
if ($3 > 1) warn ("comparison in argument");
$$ = nextarg ($1,0,FALSE);
}
| argument_list ',' NAME '[' ']'
{
sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
generate (genstr);
$$ = nextarg ($1,1,FALSE);
}
;
opt_expression : /* empty */
{
$$ = -1;
warn ("Missing expression in for statement");
}
| expression
;
return_expression : /* empty */
{
$$ = 0;
generate ("0");
}
| expression
{
if ($1 > 1)
warn ("comparison in return expresion");
}
;
expression : named_expression ASSIGN_OP
{
if ($2 != '=')
{
if ($1 < 0)
sprintf (genstr, "DL%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
}
expression
{
if ($4 > 1) warn("comparison in assignment");
if ($2 != '=')
{
sprintf (genstr, "%c", $2);
generate (genstr);
}
if ($1 < 0)
sprintf (genstr, "S%d:", -$1);
else
sprintf (genstr, "s%d:", $1);
generate (genstr);
$$ = 0;
}
;
| expression AND
{
warn("&& operator");
$2 = next_label++;
sprintf (genstr, "DZ%d:p", $2);
generate (genstr);
}
expression
{
sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
generate (genstr);
$$ = $1 | $4;
}
| expression OR
{
warn("|| operator");
$2 = next_label++;
sprintf (genstr, "B%d:", $2);
generate (genstr);
}
expression
{
int tmplab;
tmplab = next_label++;
sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
$2, tmplab, $2, tmplab);
generate (genstr);
$$ = $1 | $4;
}
| NOT expression
{
$$ = $2;
warn("! operator");
generate ("!");
}
| expression REL_OP expression
{
$$ = 3;
switch (*($2))
{
case '=':
generate ("=");
break;
case '!':
generate ("#");
break;
case '<':
if ($2[1] == '=')
generate ("{");
else
generate ("<");
break;
case '>':
if ($2[1] == '=')
generate ("}");
else
generate (">");
break;
}
}
| expression '+' expression
{
generate ("+");
$$ = $1 | $3;
}
| expression '-' expression
{
generate ("-");
$$ = $1 | $3;
}
| expression '*' expression
{
generate ("*");
$$ = $1 | $3;
}
| expression '/' expression
{
generate ("/");
$$ = $1 | $3;
}
| expression '%' expression
{
generate ("%");
$$ = $1 | $3;
}
| expression '^' expression
{
generate ("^");
$$ = $1 | $3;
}
| '-' expression %prec UNARY_MINUS
{
generate ("n");
$$ = $2;
}
| named_expression
{
$$ = 1;
if ($1 < 0)
sprintf (genstr, "L%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
| NUMBER
{
int len = strlen($1);
$$ = 1;
if (len == 1 && *$1 == '0')
generate ("0");
else if (len == 1 && *$1 == '1')
generate ("1");
else
{
generate ("K");
generate ($1);
generate (":");
}
free ($1);
}
| '(' expression ')'
{ $$ = $2 | 1; }
| NAME '(' opt_argument_list ')'
{
$$ = 1;
if ($3 != NULL)
{
sprintf (genstr, "C%d,%s:",
lookup ($1,FUNCT),
call_str ($3));
free_args ($3);
}
else
{
sprintf (genstr, "C%d:", lookup ($1,FUNCT));
}
generate (genstr);
}
| INCR_DECR named_expression
{
$$ = 1;
if ($2 < 0)
{
if ($1 == '+')
sprintf (genstr, "DA%d:L%d:", -$2, -$2);
else
sprintf (genstr, "DM%d:L%d:", -$2, -$2);
}
else
{
if ($1 == '+')
sprintf (genstr, "i%d:l%d:", $2, $2);
else
sprintf (genstr, "d%d:l%d:", $2, $2);
}
generate (genstr);
}
| named_expression INCR_DECR
{
$$ = 1;
if ($1 < 0)
{
sprintf (genstr, "DL%d:x", -$1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "A%d:", -$1);
else
sprintf (genstr, "M%d:", -$1);
}
else
{
sprintf (genstr, "l%d:", $1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "i%d:", $1);
else
sprintf (genstr, "d%d:", $1);
}
generate (genstr);
}
| Length '(' expression ')'
{ generate ("cL"); $$ = 1;}
| Sqrt '(' expression ')'
{ generate ("cR"); $$ = 1;}
| Scale '(' expression ')'
{ generate ("cS"); $$ = 1;}
| Read '(' ')'
{
warn ("read function");
generate ("cI"); $$ = 1;
}
;
named_expression : NAME
{ $$ = lookup($1,SIMPLE); }
| NAME '[' expression ']'
{
if ($3 > 1) warn("comparison in subscript");
$$ = lookup($1,ARRAY);
}
| Ibase
{ $$ = 0; }
| Obase
{ $$ = 1; }
| Scale
{ $$ = 2; }
| History
{ $$ = 3;
warn ("History variable");
}
| Last
{ $$ = 4;
warn ("Last variable");
}
;
%%

786
contrib/bc/bc/execute.c Normal file
View File

@ -0,0 +1,786 @@
/* execute.c - run a bc program. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include <signal.h>
#include "global.h"
#include "proto.h"
/* The SIGINT interrupt handling routine. */
int had_sigint;
void
stop_execution (sig)
int sig;
{
had_sigint = TRUE;
printf ("\n");
rt_error ("interrupted execution");
}
/* Get the current byte and advance the PC counter. */
unsigned char
byte (pc)
program_counter *pc;
{
int seg, offset;
seg = pc->pc_addr >> BC_SEG_LOG;
offset = pc->pc_addr++ % BC_SEG_SIZE;
return (functions[pc->pc_func].f_body[seg][offset]);
}
/* The routine that actually runs the machine. */
void
execute ()
{
int label_num, l_gp, l_off;
bc_label_group *gp;
char inst, ch;
int new_func;
int var_name;
int const_base;
bc_num temp_num;
arg_list *auto_list;
/* Initialize this run... */
pc.pc_func = 0;
pc.pc_addr = 0;
runtime_error = FALSE;
init_num (&temp_num);
/* Set up the interrupt mechanism for an interactive session. */
if (interactive)
{
signal (SIGINT, stop_execution);
had_sigint = FALSE;
}
while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error)
{
inst = byte(&pc);
#if DEBUG > 3
{ /* Print out address and the stack before each instruction.*/
int depth; estack_rec *temp = ex_stack;
printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst);
if (temp == NULL) printf ("empty stack.\n", inst);
else
{
depth = 1;
while (temp != NULL)
{
printf (" %d = ", depth);
out_num (temp->s_num, 10, out_char);
depth++;
temp = temp->s_next;
}
}
}
#endif
switch ( inst )
{
case 'A' : /* increment array variable (Add one). */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
incr_array (var_name);
break;
case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */
case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */
c_code = !is_zero (ex_stack->s_num);
pop ();
case 'J' : /* Jump to a label. */
label_num = byte(&pc); /* Low order bits first. */
label_num += byte(&pc) << 8;
if (inst == 'J' || (inst == 'B' && c_code)
|| (inst == 'Z' && !c_code)) {
gp = functions[pc.pc_func].f_label;
l_gp = label_num >> BC_LABEL_LOG;
l_off = label_num % BC_LABEL_GROUP;
while (l_gp-- > 0) gp = gp->l_next;
pc.pc_addr = gp->l_adrs[l_off];
}
break;
case 'C' : /* Call a function. */
/* Get the function number. */
new_func = byte(&pc);
if ((new_func & 0x80) != 0)
new_func = ((new_func << 8) & 0x7f) + byte(&pc);
/* Check to make sure it is defined. */
if (!functions[new_func].f_defined)
{
rt_error ("Function %s not defined.", f_names[new_func]);
break;
}
/* Check and push parameters. */
process_params (&pc, new_func);
/* Push auto variables. */
for (auto_list = functions[new_func].f_autos;
auto_list != NULL;
auto_list = auto_list->next)
auto_var (auto_list->av_name);
/* Push pc and ibase. */
fpush (pc.pc_func);
fpush (pc.pc_addr);
fpush (i_base);
/* Reset pc to start of function. */
pc.pc_func = new_func;
pc.pc_addr = 0;
break;
case 'D' : /* Duplicate top of stack */
push_copy (ex_stack->s_num);
break;
case 'K' : /* Push a constant */
/* Get the input base and convert it to a bc number. */
if (pc.pc_func == 0)
const_base = i_base;
else
const_base = fn_stack->s_val;
if (const_base == 10)
push_b10_const (&pc);
else
push_constant (prog_char, const_base);
break;
case 'L' : /* load array variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
load_array (var_name);
break;
case 'M' : /* decrement array variable (Minus!) */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
decr_array (var_name);
break;
case 'O' : /* Write a string to the output with processing. */
while ((ch = byte(&pc)) != '"')
if (ch != '\\')
out_schar (ch);
else
{
ch = byte(&pc);
if (ch == '"') break;
switch (ch)
{
case 'a': out_schar (007); break;
case 'b': out_schar ('\b'); break;
case 'f': out_schar ('\f'); break;
case 'n': out_schar ('\n'); break;
case 'q': out_schar ('"'); break;
case 'r': out_schar ('\r'); break;
case 't': out_schar ('\t'); break;
case '\\': out_schar ('\\'); break;
default: break;
}
}
fflush (stdout);
break;
case 'R' : /* Return from function */
if (pc.pc_func != 0)
{
/* "Pop" autos and parameters. */
pop_vars(functions[pc.pc_func].f_autos);
pop_vars(functions[pc.pc_func].f_params);
/* reset the pc. */
fpop ();
pc.pc_addr = fpop ();
pc.pc_func = fpop ();
}
else
rt_error ("Return from main program.");
break;
case 'S' : /* store array variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
store_array (var_name);
break;
case 'T' : /* Test tos for zero */
c_code = is_zero (ex_stack->s_num);
assign (c_code);
break;
case 'W' : /* Write the value on the top of the stack. */
case 'P' : /* Write the value on the top of the stack. No newline. */
out_num (ex_stack->s_num, o_base, out_char);
if (inst == 'W') out_char ('\n');
store_var (4); /* Special variable "last". */
fflush (stdout);
pop ();
break;
case 'c' : /* Call special function. */
new_func = byte(&pc);
switch (new_func)
{
case 'L': /* Length function. */
/* For the number 0.xxxx, 0 is not significant. */
if (ex_stack->s_num->n_len == 1 &&
ex_stack->s_num->n_scale != 0 &&
ex_stack->s_num->n_value[0] == 0 )
int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
else
int2num (&ex_stack->s_num, ex_stack->s_num->n_len
+ ex_stack->s_num->n_scale);
break;
case 'S': /* Scale function. */
int2num (&ex_stack->s_num, ex_stack->s_num->n_scale);
break;
case 'R': /* Square Root function. */
if (!bc_sqrt (&ex_stack->s_num, scale))
rt_error ("Square root of a negative number");
break;
case 'I': /* Read function. */
push_constant (input_char, i_base);
break;
}
break;
case 'd' : /* Decrement number */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
decr_var (var_name);
break;
case 'h' : /* Halt the machine. */
exit (0);
case 'i' : /* increment number */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
incr_var (var_name);
break;
case 'l' : /* load variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
load_var (var_name);
break;
case 'n' : /* Negate top of stack. */
bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0);
break;
case 'p' : /* Pop the execution stack. */
pop ();
break;
case 's' : /* store variable */
var_name = byte(&pc);
if ((var_name & 0x80) != 0)
var_name = ((var_name << 8) & 0x7f) + byte(&pc);
store_var (var_name);
break;
case 'w' : /* Write a string to the output. */
while ((ch = byte(&pc)) != '"') out_schar (ch);
fflush (stdout);
break;
case 'x' : /* Exchange Top of Stack with the one under the tos. */
if (check_stack(2)) {
bc_num temp = ex_stack->s_num;
ex_stack->s_num = ex_stack->s_next->s_num;
ex_stack->s_next->s_num = temp;
}
break;
case '0' : /* Load Constant 0. */
push_copy (_zero_);
break;
case '1' : /* Load Constant 0. */
push_copy (_one_);
break;
case '!' : /* Negate the boolean value on top of the stack. */
c_code = is_zero (ex_stack->s_num);
assign (c_code);
break;
case '&' : /* compare greater than */
if (check_stack(2))
{
c_code = !is_zero (ex_stack->s_next->s_num)
&& !is_zero (ex_stack->s_num);
pop ();
assign (c_code);
}
break;
case '|' : /* compare greater than */
if (check_stack(2))
{
c_code = !is_zero (ex_stack->s_next->s_num)
|| !is_zero (ex_stack->s_num);
pop ();
assign (c_code);
}
break;
case '+' : /* add */
if (check_stack(2))
{
bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '-' : /* subtract */
if (check_stack(2))
{
bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '*' : /* multiply */
if (check_stack(2))
{
bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num,
&temp_num, scale);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '/' : /* divide */
if (check_stack(2))
{
if (bc_divide (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale) == 0)
{
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
else
rt_error ("Divide by zero");
}
break;
case '%' : /* remainder */
if (check_stack(2))
{
if (is_zero (ex_stack->s_num))
rt_error ("Modulo by zero");
else
{
bc_modulo (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale);
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
}
break;
case '^' : /* raise */
if (check_stack(2))
{
bc_raise (ex_stack->s_next->s_num,
ex_stack->s_num, &temp_num, scale);
if (is_zero (ex_stack->s_next->s_num) && is_neg (ex_stack->s_num))
rt_error ("divide by zero");
pop();
pop();
push_num (temp_num);
init_num (&temp_num);
}
break;
case '=' : /* compare equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == 0;
pop ();
assign (c_code);
}
break;
case '#' : /* compare not equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) != 0;
pop ();
assign (c_code);
}
break;
case '<' : /* compare less than */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == -1;
pop ();
assign (c_code);
}
break;
case '{' : /* compare less than or equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) <= 0;
pop ();
assign (c_code);
}
break;
case '>' : /* compare greater than */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) == 1;
pop ();
assign (c_code);
}
break;
case '}' : /* compare greater than or equal */
if (check_stack(2))
{
c_code = bc_compare (ex_stack->s_next->s_num,
ex_stack->s_num) >= 0;
pop ();
assign (c_code);
}
break;
default : /* error! */
rt_error ("bad instruction: inst=%c", inst);
}
}
/* Clean up the function stack and pop all autos/parameters. */
while (pc.pc_func != 0)
{
pop_vars(functions[pc.pc_func].f_autos);
pop_vars(functions[pc.pc_func].f_params);
fpop ();
pc.pc_addr = fpop ();
pc.pc_func = fpop ();
}
/* Clean up the execution stack. */
while (ex_stack != NULL) pop();
/* Clean up the interrupt stuff. */
if (interactive)
{
signal (SIGINT, use_quit);
if (had_sigint)
printf ("Interruption completed.\n");
}
}
/* Prog_char gets another byte from the program. It is used for
conversion of text constants in the code to numbers. */
char
prog_char ()
{
return byte(&pc);
}
/* Read a character from the standard input. This function is used
by the "read" function. */
char
input_char ()
{
char in_ch;
/* Get a character from the standard input for the read function. */
in_ch = getchar();
/* Check for a \ quoted newline. */
if (in_ch == '\\')
{
in_ch = getchar();
if (in_ch == '\n')
in_ch = getchar();
}
/* Classify and preprocess the input character. */
if (isdigit(in_ch))
return (in_ch - '0');
if (in_ch >= 'A' && in_ch <= 'F')
return (in_ch + 10 - 'A');
if (in_ch >= 'a' && in_ch <= 'f')
return (in_ch + 10 - 'a');
if (in_ch == '.' || in_ch == '+' || in_ch == '-')
return (in_ch);
if (in_ch <= ' ')
return (' ');
return (':');
}
/* Push_constant converts a sequence of input characters as returned
by IN_CHAR into a number. The number is pushed onto the execution
stack. The number is converted as a number in base CONV_BASE. */
void
push_constant (in_char, conv_base)
char (*in_char)(VOID);
int conv_base;
{
int digits;
bc_num build, temp, result, mult, divisor;
char in_ch, first_ch;
char negative;
/* Initialize all bc numbers */
init_num (&temp);
init_num (&result);
init_num (&mult);
build = copy_num (_zero_);
negative = FALSE;
/* The conversion base. */
int2num (&mult, conv_base);
/* Get things ready. */
in_ch = in_char();
while (in_ch == ' ')
in_ch = in_char();
if (in_ch == '+')
in_ch = in_char();
else
if (in_ch == '-')
{
negative = TRUE;
in_ch = in_char();
}
/* Check for the special case of a single digit. */
if (in_ch < 16)
{
first_ch = in_ch;
in_ch = in_char();
if (in_ch < 16 && first_ch >= conv_base)
first_ch = conv_base - 1;
int2num (&build, (int) first_ch);
}
/* Convert the integer part. */
while (in_ch < 16)
{
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
bc_multiply (build, mult, &result, 0);
int2num (&temp, (int) in_ch);
bc_add (result, temp, &build, 0);
in_ch = in_char();
}
if (in_ch == '.')
{
in_ch = in_char();
if (in_ch >= conv_base) in_ch = conv_base-1;
free_num (&result);
free_num (&temp);
divisor = copy_num (_one_);
result = copy_num (_zero_);
digits = 0;
while (in_ch < 16)
{
bc_multiply (result, mult, &result, 0);
int2num (&temp, (int) in_ch);
bc_add (result, temp, &result, 0);
bc_multiply (divisor, mult, &divisor, 0);
digits++;
in_ch = in_char();
if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1;
}
bc_divide (result, divisor, &result, digits);
bc_add (build, result, &build, 0);
}
/* Final work. */
if (negative)
bc_sub (_zero_, build, &build, 0);
push_num (build);
free_num (&temp);
free_num (&result);
free_num (&mult);
}
/* When converting base 10 constants from the program, we use this
more efficient way to convert them to numbers. PC tells where
the constant starts and is expected to be advanced to after
the constant. */
void
push_b10_const (pc)
program_counter *pc;
{
bc_num build;
program_counter look_pc;
int kdigits, kscale;
char inchar;
char *ptr;
/* Count the digits and get things ready. */
look_pc = *pc;
kdigits = 0;
kscale = 0;
inchar = byte (&look_pc);
while (inchar != '.' && inchar != ':')
{
kdigits++;
inchar = byte(&look_pc);
}
if (inchar == '.' )
{
inchar = byte(&look_pc);
while (inchar != ':')
{
kscale++;
inchar = byte(&look_pc);
}
}
/* Get the first character again and move the pc. */
inchar = byte(pc);
/* Secial cases of 0, 1, and A-F single inputs. */
if (kdigits == 1 && kscale == 0)
{
if (inchar == 0)
{
push_copy (_zero_);
inchar = byte(pc);
return;
}
if (inchar == 1) {
push_copy (_one_);
inchar = byte(pc);
return;
}
if (inchar > 9)
{
init_num (&build);
int2num (&build, inchar);
push_num (build);
inchar = byte(pc);
return;
}
}
/* Build the new number. */
if (kdigits == 0)
{
build = new_num (1,kscale);
ptr = build->n_value;
*ptr++ = 0;
}
else
{
build = new_num (kdigits,kscale);
ptr = build->n_value;
}
while (inchar != ':')
{
if (inchar != '.')
if (inchar > 9)
*ptr++ = 9;
else
*ptr++ = inchar;
inchar = byte(pc);
}
push_num (build);
}
/* Put the correct value on the stack for C_CODE. Frees TOS num. */
void
assign (c_code)
char c_code;
{
free_num (&ex_stack->s_num);
if (c_code)
ex_stack->s_num = copy_num (_one_);
else
ex_stack->s_num = copy_num (_zero_);
}

8
contrib/bc/bc/fix-libmath_h Executable file
View File

@ -0,0 +1,8 @@
ed libmath.h <<EOS-EOS
1,1s/^/"/
1,\$s/\$/\\\\/
\$,\$d
\$,\$s/\\\\\$/"/
w
q
EOS-EOS

42
contrib/bc/bc/global.c Normal file
View File

@ -0,0 +1,42 @@
/* global.c: This defines the global variables. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
/* Since we want to define them here, we use the following define. */
#undef EXTERN
#define EXTERN
/* Define all the global variables for bc. */
#include "global.h"
#ifndef BC_MATH_FILE
CONST char libmath[] =
#include "libmath.h"
;
#endif

279
contrib/bc/bc/libmath.b Normal file
View File

@ -0,0 +1,279 @@
/* libmath.b for GNU bc. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
scale = 20
/* Uses the fact that e^x = (e^(x/2))^2
When x is small enough, we use the series:
e^x = 1 + x + x^2/2! + x^3/3! + ...
*/
define e(x) {
auto a, d, e, f, i, m, n, v, z
/* a - holds x^y of x^y/y! */
/* d - holds y! */
/* e - is the value x^y/y! */
/* v - is the sum of the e's */
/* f - number of times x was divided by 2. */
/* m - is 1 if x was minus. */
/* i - iteration count. */
/* n - the scale to compute the sum. */
/* z - orignal scale. */
/* Check the sign of x. */
if (x<0) {
m = 1
x = -x
}
/* Precondition x. */
z = scale;
n = 6 + z + .44*x;
scale = scale(x)+1;
while (x > 1) {
f += 1;
x /= 2;
scale += 1;
}
/* Initialize the variables. */
scale = n;
v = 1+x
a = x
d = 1
for (i=2; 1; i++) {
e = (a *= x) / (d *= i)
if (e == 0) {
if (f>0) while (f--) v = v*v;
scale = z
if (m) return (1/v);
return (v/1);
}
v += e
}
}
/* Natural log. Uses the fact that ln(x^2) = 2*ln(x)
The series used is:
ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1)
*/
define l(x) {
auto e, f, i, m, n, v, z
/* return something for the special case. */
if (x <= 0) return ((1 - 10^scale)/1)
/* Precondition x to make .5 < x < 2.0. */
z = scale;
scale = 6 + scale;
f = 2;
i=0
while (x >= 2) { /* for large numbers */
f *= 2;
x = sqrt(x);
}
while (x <= .5) { /* for small numbers */
f *= 2;
x = sqrt(x);
}
/* Set up the loop. */
v = n = (x-1)/(x+1)
m = n*n
/* Sum the series. */
for (i=3; 1; i+=2) {
e = (n *= m) / i
if (e == 0) {
v = f*v
scale = z
return (v/1)
}
v += e
}
}
/* Sin(x) uses the standard series:
sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */
define s(x) {
auto e, i, m, n, s, v, z
/* precondition x. */
z = scale
scale = 1.1*z + 2;
v = a(1)
if (x < 0) {
m = 1;
x = -x;
}
scale = 0
n = (x / v + 2 )/4
x = x - 4*n*v
if (n%2) x = -x
/* Do the loop. */
scale = z + 2;
v = e = x
s = -x*x
for (i=3; 1; i+=2) {
e *= s/(i*(i-1))
if (e == 0) {
scale = z
if (m) return (-v/1);
return (v/1);
}
v += e
}
}
/* Cosine : cos(x) = sin(x+pi/2) */
define c(x) {
auto v;
scale += 1;
v = s(x+a(1)*2);
scale -= 1;
return (v/1);
}
/* Arctan: Using the formula:
atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here)
For under .2, use the series:
atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */
define a(x) {
auto a, e, f, i, m, n, s, v, z
/* a is the value of a(.2) if it is needed. */
/* f is the value to multiply by a in the return. */
/* e is the value of the current term in the series. */
/* v is the accumulated value of the series. */
/* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */
/* i is the denominator value for series element. */
/* n is the numerator value for the series element. */
/* s is -x*x. */
/* z is the saved user's scale. */
/* Negative x? */
m = 1;
if (x<0) {
m = -1;
x = -x;
}
/* Special case and for fast answers */
if (x==1) {
if (scale <= 25) return (.7853981633974483096156608/m)
if (scale <= 40) return (.7853981633974483096156608458198757210492/m)
if (scale <= 60) \
return (.785398163397448309615660845819875721049292349843776455243736/m)
}
if (x==.2) {
if (scale <= 25) return (.1973955598498807583700497/m)
if (scale <= 40) return (.1973955598498807583700497651947902934475/m)
if (scale <= 60) \
return (.197395559849880758370049765194790293447585103787852101517688/m)
}
/* Save the scale. */
z = scale;
/* Note: a and f are known to be zero due to being auto vars. */
/* Calculate atan of a known number. */
if (x > .2) {
scale = z+5;
a = a(.2);
}
/* Precondition x. */
scale = z+3;
while (x > .2) {
f += 1;
x = (x-.2) / (1+x*.2);
}
/* Initialize the series. */
v = n = x;
s = -x*x;
/* Calculate the series. */
for (i=3; 1; i+=2) {
e = (n *= s) / i;
if (e == 0) {
scale = z;
return ((f*a+v)/m);
}
v += e
}
}
/* Bessel function of integer order. Uses the following:
j(-n,x) = (-1)^n*j(n,x)
j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2))
- x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... )
*/
define j(n,x) {
auto a, d, e, f, i, m, s, v, z
/* Make n an integer and check for negative n. */
z = scale;
scale = 0;
n = n/1;
if (n<0) {
n = -n;
if (n%2 == 1) m = 1;
}
/* Compute the factor of x^n/(2^n*n!) */
f = 1;
for (i=2; i<=n; i++) f = f*i;
scale = 1.5*z;
f = x^n / 2^n / f;
/* Initialize the loop .*/
v = e = 1;
s = -x*x/4
scale = 1.5*z
/* The Loop.... */
for (i=1; 1; i++) {
e = e * s / i / (n+i);
if (e == 0) {
scale = z
if (m) return (-f*v/1);
return (f*v/1);
}
v += e;
}
}

40
contrib/bc/bc/libmath.h Normal file
View File

@ -0,0 +1,40 @@
"@iK20:s2:p@r\
@iF1,5.6,7,8,9,10,11,12,13,14[l5:0<Z1:1s11:pl5:ns5:pN1:l2:s14:\
pK6:l14:+K.44:l5:*+s12:pl5:cS1+s2:pN2:l5:1>Z3:l9:1+s9:pl5:K2:\
/s5:pl2:1+s2:pJ2:N3:l12:s2:p1l5:+s13:pl5:s6:p1s7:pK2:s10:pN5:\
1B6:J4:N7:l10:i10:pJ5:N6:l6:l5:*s6:l7:l10:*s7:/s8:pl8:0=Z8:l9:\
0>Z9:N10:l9:d9:Z11:l13:l13:*s13:pJ10:N11:N9:l14:s2:pl11:Z12:1\
l13:/RN12:l13:1/RN8:l13:l8:+s13:pJ7:N4:0R]@r\
@iF2,5.8,9,10,11,12,13,14[l5:0{Z1:1K10:l2:^-1/RN1:l2:s14:pK6:\
l2:+s2:pK2:s9:p0s10:pN2:l5:K2:}Z3:l9:K2:*s9:pl5:cRs5:pJ2:N3:N4:\
l5:K.5:{Z5:l9:K2:*s9:pl5:cRs5:pJ4:N5:l5:1-l5:1+/s12:s13:pl12:\
l12:*s11:pK3:s10:pN7:1B8:J6:N9:l10:K2:+s10:pJ7:N8:l12:l11:*s12:\
l10:/s8:pl8:0=Z10:l9:l13:*s13:pl14:s2:pl13:1/RN10:l13:l8:+s13:\
pJ9:N6:0R]@r\
@iF3,5.8,10,11,12,15,13,14[l2:s14:pK1.1:l14:*K2:+s2:p1C4,0:s13:\
pl5:0<Z1:1s11:pl5:ns5:pN1:0s2:pl5:l13:/K2:+K4:/s12:pl5:K4:l12:\
*l13:*-s5:pl12:K2:%Z2:l5:ns5:pN2:l14:K2:+s2:pl5:s8:s13:pl5:nl5:\
*s15:pK3:s10:pN4:1B5:J3:N6:l10:K2:+s10:pJ4:N5:l8:l15:l10:l10:\
1-*/*s8:pl8:0=Z7:l14:s2:pl11:Z8:l13:n1/RN8:l13:1/RN7:l13:l8:+\
s13:pJ6:N3:0R]@r\
@iF5,5.13[l2:1+s2:pl5:1C4,0:K2:*+C3,0:s13:pl2:1-s2:pl13:1/R0R]\
@r\
@iF4,5.6,8,9,10,11,12,15,13,14[1s11:pl5:0<Z1:1ns11:pl5:ns5:pN1:\
l5:1=Z2:l2:K25:{Z3:K.7853981633974483096156608:l11:/RN3:l2:K40\
:{Z4:K.7853981633974483096156608458198757210492:l11:/RN4:l2:K\
60:{Z5:K.785398163397448309615660845819875721049292349843776455243736\
:l11:/RN5:N2:l5:K.2:=Z6:l2:K25:{Z7:K.1973955598498807583700497\
:l11:/RN7:l2:K40:{Z8:K.1973955598498807583700497651947902934475\
:l11:/RN8:l2:K60:{Z9:K.197395559849880758370049765194790293447585103787852101517688\
:l11:/RN9:N6:l2:s14:pl5:K.2:>Z10:l14:K5:+s2:pK.2:C4,0:s6:pN10:\
l14:K3:+s2:pN11:l5:K.2:>Z12:l9:1+s9:pl5:K.2:-1l5:K.2:*+/s5:pJ11:N12:\
l5:s12:s13:pl5:nl5:*s15:pK3:s10:pN14:1B15:J13:N16:l10:K2:+s10:\
pJ14:N15:l12:l15:*s12:l10:/s8:pl8:0=Z17:l14:s2:pl9:l6:*l13:+l11:\
/RN17:l13:l8:+s13:pJ16:N13:0R]@r\
@iF6,12,5.6,7,8,9,10,11,15,13,14[l2:s14:p0s2:pl12:1/s12:pl12:\
0<Z1:l12:ns12:pl12:K2:%1=Z2:1s11:pN2:N1:1s9:pK2:s10:pN4:l10:l12:\
{B5:J3:N6:l10:i10:pJ4:N5:l9:l10:*s9:pJ6:N3:K1.5:l14:*s2:pl5:l12:\
^K2:l12:^/l9:/s9:p1s8:s13:pl5:nl5:*K4:/s15:pK1.5:l14:*s2:p1s10:\
pN8:1B9:J7:N10:l10:i10:pJ8:N9:l8:l15:*l10:/l12:l10:+/s8:pl8:0\
=Z11:l14:s2:pl11:Z12:l9:nl13:*1/RN12:l9:l13:*1/RN11:l13:l8:+s13:\
pJ10:N7:0R]@r"

348
contrib/bc/bc/load.c Normal file
View File

@ -0,0 +1,348 @@
/* load.c: This code "loads" code into the code segments. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
/* Load variables. */
program_counter load_adr;
char load_str;
char load_const;
/* Initialize the load sequence. */
void
init_load ()
{
clear_func(0);
load_adr.pc_func = 0;
load_adr.pc_addr = 0;
load_str = FALSE;
load_const = FALSE;
}
/* addbyte adds one BYTE to the current code segment. */
void
addbyte (byte)
char byte;
{
int seg, offset, func;
/* If there was an error, don't continue. */
if (had_error) return;
/* Calculate the segment and offset. */
seg = load_adr.pc_addr >> BC_SEG_LOG;
offset = load_adr.pc_addr++ % BC_SEG_SIZE;
func = load_adr.pc_func;
if (seg >= BC_MAX_SEGS)
{
yyerror ("Function too big.");
return;
}
if (functions[func].f_body[seg] == NULL)
functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE);
/* Store the byte. */
functions[func].f_body[seg][offset] = byte;
functions[func].f_code_size++;
}
/* Define a label LAB to be the current program counter. */
void
def_label (lab)
long lab;
{
bc_label_group *temp;
int group, offset, func;
/* Get things ready. */
group = lab >> BC_LABEL_LOG;
offset = lab % BC_LABEL_GROUP;
func = load_adr.pc_func;
/* Make sure there is at least one label group. */
if (functions[func].f_label == NULL)
{
functions[func].f_label =
(bc_label_group *) bc_malloc (sizeof(bc_label_group));
functions[func].f_label->l_next = NULL;
}
/* Add the label group. */
temp = functions[func].f_label;
while (group > 0)
{
if (temp->l_next == NULL)
{
temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
temp->l_next->l_next = NULL;
}
temp = temp->l_next;
group --;
}
/* Define it! */
temp->l_adrs [offset] = load_adr.pc_addr;
}
/* Several instructions have integers in the code. They
are all known to be legal longs. So, no error code
is added. STR is the pointer to the load string and
must be moved to the last non-digit character. */
long
long_val (str)
char **str;
{ int val = 0;
char neg = FALSE;
if (**str == '-')
{
neg = TRUE;
(*str)++;
}
while (isdigit(**str))
val = val*10 + *(*str)++ - '0';
if (neg)
return -val;
else
return val;
}
/* load_code loads the CODE into the machine. */
void
load_code (code)
char *code;
{
char *str;
long ap_name; /* auto or parameter name. */
long label_no;
long vaf_name; /* variable, array or function number. */
long func;
program_counter save_adr;
/* Initialize. */
str = code;
/* Scan the code. */
while (*str != 0)
{
/* If there was an error, don't continue. */
if (had_error) return;
if (load_str)
{
if (*str == '"') load_str = FALSE;
addbyte (*str++);
}
else
if (load_const)
{
if (*str == '\n')
str++;
else
{
if (*str == ':')
{
load_const = FALSE;
addbyte (*str++);
}
else
if (*str == '.')
addbyte (*str++);
else
if (*str >= 'A')
addbyte (*str++ + 10 - 'A');
else
addbyte (*str++ - '0');
}
}
else
{
switch (*str)
{
case '"': /* Starts a string. */
load_str = TRUE;
break;
case 'N': /* A label */
str++;
label_no = long_val (&str);
def_label (label_no);
break;
case 'B': /* Branch to label. */
case 'J': /* Jump to label. */
case 'Z': /* Branch Zero to label. */
addbyte(*str++);
label_no = long_val (&str);
if (label_no > 65535L)
{ /* Better message? */
fprintf (stderr,"Program too big.\n");
exit(1);
}
addbyte ( (char) label_no & 0xFF);
addbyte ( (char) label_no >> 8);
break;
case 'F': /* A function, get the name and initialize it. */
str++;
func = long_val (&str);
clear_func (func);
#if DEBUG > 2
printf ("Loading function number %d\n", func);
#endif
/* get the parameters */
while (*str++ != '.')
{
if (*str == '.')
{
str++;
break;
}
if (*str == '*')
{
str++;
ap_name = long_val (&str);
#if DEBUG > 2
printf ("var parameter number %d\n", ap_name);
#endif
functions[(int)func].f_params =
nextarg (functions[(int)func].f_params, ap_name,
TRUE);
}
else
{
ap_name = long_val (&str);
#if DEBUG > 2
printf ("parameter number %d\n", ap_name);
#endif
functions[(int)func].f_params =
nextarg (functions[(int)func].f_params, ap_name,
FALSE);
}
}
/* get the auto vars */
while (*str != '[')
{
if (*str == ',') str++;
ap_name = long_val (&str);
#if DEBUG > 2
printf ("auto number %d\n", ap_name);
#endif
functions[(int)func].f_autos =
nextarg (functions[(int)func].f_autos, ap_name, FALSE);
}
save_adr = load_adr;
load_adr.pc_func = func;
load_adr.pc_addr = 0;
break;
case ']': /* A function end */
functions[load_adr.pc_func].f_defined = TRUE;
load_adr = save_adr;
break;
case 'C': /* Call a function. */
addbyte (*str++);
func = long_val (&str);
if (func < 128)
addbyte ( (char) func);
else
{
addbyte ((func >> 8) & 0xff | 0x80);
addbyte (func & 0xff);
}
if (*str == ',') str++;
while (*str != ':')
addbyte (*str++);
addbyte (':');
break;
case 'c': /* Call a special function. */
addbyte (*str++);
addbyte (*str);
break;
case 'K': /* A constant.... may have an "F" in it. */
addbyte (*str);
load_const = TRUE;
break;
case 'd': /* Decrement. */
case 'i': /* Increment. */
case 'l': /* Load. */
case 's': /* Store. */
case 'A': /* Array Increment */
case 'M': /* Array Decrement */
case 'L': /* Array Load */
case 'S': /* Array Store */
addbyte (*str++);
vaf_name = long_val (&str);
if (vaf_name < 128)
addbyte (vaf_name);
else
{
addbyte ((vaf_name >> 8) & 0xff | 0x80);
addbyte (vaf_name & 0xff);
}
break;
case '@': /* A command! */
switch (*(++str))
{
case 'i':
init_load ();
break;
case 'r':
execute ();
break;
}
break;
case '\n': /* Ignore the newlines */
break;
default: /* Anything else */
addbyte (*str);
}
str++;
}
}
}

323
contrib/bc/bc/main.c Normal file
View File

@ -0,0 +1,323 @@
/* main.c: The main program for bc. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include <signal.h>
#include "global.h"
#include "proto.h"
#include "getopt.h"
/* Variables for processing multiple files. */
char first_file;
extern FILE *yyin;
/* Points to the last node in the file name list for easy adding. */
static file_node *last = NULL;
#ifdef READLINE
/* Readline support. */
extern char *rl_readline_name;
extern FILE *rl_instream;
#endif
/* long option support */
static struct option long_options[] =
{
{"compile", 0, &compile_only, TRUE},
{"mathlib", 0, &use_math, TRUE},
{"quiet", 0, &quiet, TRUE},
{"standard", 0, &std_only, TRUE},
{"version", 0, 0, 'v'},
{"warn", 0, &warn_not_std, TRUE},
{0, 0, 0, 0}
};
void
parse_args (argc, argv)
int argc;
char **argv;
{
int optch;
int long_index;
file_node *temp;
/* Force getopt to initialize. Depends on GNU getopt. */
optind = 0;
/* Parse the command line */
while (1)
{
optch = getopt_long (argc, argv, "lciqsvw", long_options, &long_index);
if (optch == EOF) /* End of arguments. */
break;
switch (optch)
{
case 'c': /* compile only */
compile_only = TRUE;
break;
case 'l': /* math lib */
use_math = TRUE;
break;
case 'i': /* force interactive */
interactive = TRUE;
break;
case 'q': /* quiet mode */
quiet = TRUE;
break;
case 's': /* Non standard features give errors. */
std_only = TRUE;
break;
case 'v': /* Print the version. */
printf ("%s\n", BC_VERSION);
exit (0);
break;
case 'w': /* Non standard features give warnings. */
warn_not_std = TRUE;
break;
}
}
/* Add file names to a list of files to process. */
while (optind < argc)
{
temp = (file_node *) bc_malloc(sizeof(file_node));
temp->name = argv[optind];
temp->next = NULL;
if (last == NULL)
file_names = temp;
else
last->next = temp;
last = temp;
optind++;
}
}
/* The main program for bc. */
int
main (argc, argv)
int argc;
char *argv[];
{
char *env_value;
char *env_argv[30];
int env_argc;
/* Initialize many variables. */
compile_only = FALSE;
use_math = FALSE;
warn_not_std = FALSE;
std_only = FALSE;
if (isatty(0) && isatty(1))
interactive = TRUE;
else
interactive = FALSE;
quiet = FALSE;
file_names = NULL;
/* Environment arguments. */
env_value = getenv ("BC_ENV_ARGS");
if (env_value != NULL)
{
env_argc = 1;
env_argv[0] = "BC_ENV_ARGS";
while (*env_value != 0)
{
if (*env_value != ' ')
{
env_argv[env_argc++] = env_value;
while (*env_value != ' ' && *env_value != 0)
env_value++;
if (*env_value != 0)
{
*env_value = 0;
env_value++;
}
}
else
env_value++;
}
parse_args (env_argc, env_argv);
}
/* Command line arguments. */
parse_args (argc, argv);
/* Other environment processing. */
if (getenv ("POSIXLY_CORRECT") != NULL)
std_only = TRUE;
env_value = getenv ("BC_LINE_LENGTH");
if (env_value != NULL)
{
line_size = atoi (env_value);
if (line_size < 2)
line_size = 70;
}
else
line_size = 70;
/* Initialize the machine. */
init_storage();
init_load();
/* Set up interrupts to print a message. */
if (interactive)
signal (SIGINT, use_quit);
/* Initialize the front end. */
init_tree();
init_gen ();
is_std_in = FALSE;
first_file = TRUE;
if (!open_new_file ())
exit (1);
#ifdef READLINE
/* Readline support. Set both application name and input file. */
rl_readline_name = "bc";
rl_instream = stdin;
using_history ();
#endif
/* Do the parse. */
yyparse ();
/* End the compile only output with a newline. */
if (compile_only)
printf ("\n");
exit (0);
}
/* This is the function that opens all the files.
It returns TRUE if the file was opened, otherwise
it returns FALSE. */
int
open_new_file ()
{
FILE *new_file;
file_node *temp;
/* Set the line number. */
line_no = 1;
/* Check to see if we are done. */
if (is_std_in) return (FALSE);
/* Open the other files. */
if (use_math && first_file)
{
#ifdef BC_MATH_FILE
/* Make the first file be the math library. */
new_file = fopen (BC_MATH_FILE, "r");
use_math = FALSE;
if (new_file != NULL)
{
new_yy_file (new_file);
return TRUE;
}
else
{
fprintf (stderr, "Math Library unavailable.\n");
exit (1);
}
#else
/* Load the code from a precompiled version of the math libarary. */
extern char libmath[];
char tmp;
/* These MUST be in the order of first mention of each function.
That is why "a" comes before "c" even though "a" is defined after
after "c". "a" is used in "s"! */
tmp = lookup ("e", FUNCT);
tmp = lookup ("l", FUNCT);
tmp = lookup ("s", FUNCT);
tmp = lookup ("a", FUNCT);
tmp = lookup ("c", FUNCT);
tmp = lookup ("j", FUNCT);
load_code (libmath);
#endif
}
/* One of the argv values. */
if (file_names != NULL)
{
new_file = fopen (file_names->name, "r");
if (new_file != NULL)
{
new_yy_file (new_file);
temp = file_names;
file_name = temp->name;
file_names = temp->next;
free (temp);
return TRUE;
}
fprintf (stderr, "File %s is unavailable.\n", file_names->name);
exit (1);
}
/* If we fall through to here, we should return stdin. */
new_yy_file (stdin);
is_std_in = TRUE;
return TRUE;
}
/* Set yyin to the new file. */
void
new_yy_file (file)
FILE *file;
{
if (!first_file) fclose (yyin);
yyin = file;
first_file = FALSE;
}
/* Message to use quit. */
void
use_quit (sig)
int sig;
{
printf ("\n(interrupt) use quit to exit.\n");
signal (SIGINT, use_quit);
}

446
contrib/bc/bc/sbc.y Normal file
View File

@ -0,0 +1,446 @@
%{
/* sbc.y: A POSIX bc processor written for minix with no extensions. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h" /* To get the global variables. */
#include "proto.h"
%}
%start program
%union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
}
%token <i_value> NEWLINE AND OR NOT
%token <s_value> STRING NAME NUMBER
/* '-', '+' are tokens themselves */
%token <c_value> ASSIGN_OP
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
%token <s_value> REL_OP
/* '==', '<=', '>=', '!=', '<', '>' */
%token <c_value> INCR_DECR
/* '++', '--' */
%token <i_value> Define Break Quit Length
/* 'define', 'break', 'quit', 'length' */
%token <i_value> Return For If While Sqrt Else
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
%token <i_value> Scale Ibase Obase Auto Read
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
/* The types of all other non-terminals. */
%type <i_value> expression named_expression return_expression
%type <a_value> opt_parameter_list parameter_list opt_auto_define_list
%type <a_value> define_list opt_argument_list argument_list
%type <i_value> program input_item semicolon_list statement_list
%type <i_value> statement_or_error statement function relational_expression
/* precedence */
%nonassoc REL_OP
%right ASSIGN_OP
%left '+' '-'
%left '*' '/' '%'
%right '^'
%nonassoc UNARY_MINUS
%nonassoc INCR_DECR
%%
program : /* empty */
{
$$ = 0;
std_only = TRUE;
if (interactive)
{
printf ("s%s\n", BC_VERSION);
welcome();
}
}
| program input_item
;
input_item : semicolon_list NEWLINE
{ run_code(); }
| function
{ run_code(); }
| error NEWLINE
{
yyerrok;
init_gen() ;
}
;
semicolon_list : /* empty */
{ $$ = 0; }
| statement_or_error
| semicolon_list ';' statement_or_error
| semicolon_list ';'
;
statement_list : /* empty */
{ $$ = 0; }
| statement
| statement_list NEWLINE
| statement_list NEWLINE statement
| statement_list ';'
| statement_list ';' statement
;
statement_or_error : statement
| error statement
{ $$ = $2; }
;
statement : Warranty
{ warranty("s"); }
| expression
{
if ($1 & 1)
generate ("W");
else
generate ("p");
}
| STRING
{
$$ = 0;
generate ("w");
generate ($1);
free ($1);
}
| Break
{
if (break_label == 0)
yyerror ("Break outside a for/while");
else
{
sprintf (genstr, "J%1d:", break_label);
generate (genstr);
}
}
| Quit
{ exit(0); }
| Return
{ generate ("0R"); }
| Return '(' return_expression ')'
{ generate ("R"); }
| For
{
$1 = break_label;
break_label = next_label++;
}
'(' expression ';'
{
$4 = next_label++;
sprintf (genstr, "pN%1d:", $4);
generate (genstr);
}
relational_expression ';'
{
$7 = next_label++;
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
generate (genstr);
$<i_value>$ = next_label++;
sprintf (genstr, "N%1d:", $<i_value>$);
generate (genstr);
}
expression ')'
{
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
generate (genstr);
}
statement
{
sprintf (genstr, "J%1d:N%1d:", $<i_value>9,
break_label);
generate (genstr);
break_label = $1;
}
| If '(' relational_expression ')'
{
$3 = next_label++;
sprintf (genstr, "Z%1d:", $3);
generate (genstr);
}
statement
{
sprintf (genstr, "N%1d:", $3);
generate (genstr);
}
| While
{
$1 = next_label++;
sprintf (genstr, "N%1d:", $1);
generate (genstr);
}
'(' relational_expression
{
$4 = break_label;
break_label = next_label++;
sprintf (genstr, "Z%1d:", break_label);
generate (genstr);
}
')' statement
{
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
generate (genstr);
break_label = $4;
}
| '{' statement_list '}'
{ $$ = 0; }
;
function : Define NAME '(' opt_parameter_list ')' '{'
NEWLINE opt_auto_define_list
{
check_params ($4,$8);
sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
arg_str ($4), arg_str ($8));
generate (genstr);
free_args ($4);
free_args ($8);
$1 = next_label;
next_label = 0;
}
statement_list NEWLINE '}'
{
generate ("0R]");
next_label = $1;
}
;
opt_parameter_list : /* empty */
{ $$ = NULL; }
| parameter_list
;
parameter_list : NAME
{ $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); }
;
opt_auto_define_list : /* empty */
{ $$ = NULL; }
| Auto define_list NEWLINE
{ $$ = $2; }
| Auto define_list ';'
{ $$ = $2; }
;
define_list : NAME
{ $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); }
| NAME '[' ']'
{ $$ = nextarg (NULL, lookup($1,ARRAY), FALSE); }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); }
| define_list ',' NAME '[' ']'
{ $$ = nextarg ($1, lookup($3,ARRAY), FALSE); }
;
opt_argument_list : /* empty */
{ $$ = NULL; }
| argument_list
;
argument_list : expression
{ $$ = nextarg (NULL,0, FALSE); }
| argument_list ',' expression
{ $$ = nextarg ($1,0, FALSE); }
;
relational_expression : expression
{ $$ = 0; }
| expression REL_OP expression
{
$$ = 0;
switch (*($2))
{
case '=':
generate ("=");
break;
case '!':
generate ("#");
break;
case '<':
if ($2[1] == '=')
generate ("{");
else
generate ("<");
break;
case '>':
if ($2[1] == '=')
generate ("}");
else
generate (">");
break;
}
}
;
return_expression : /* empty */
{
$$ = 0;
generate ("0");
}
| expression
;
expression : named_expression ASSIGN_OP
{
if ($2 != '=')
{
if ($1 < 0)
sprintf (genstr, "DL%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
}
expression
{
$$ = 0;
if ($2 != '=')
{
sprintf (genstr, "%c", $2);
generate (genstr);
}
if ($1 < 0)
sprintf (genstr, "S%d:", -$1);
else
sprintf (genstr, "s%d:", $1);
generate (genstr);
}
| expression '+' expression
{ generate ("+"); }
| expression '-' expression
{ generate ("-"); }
| expression '*' expression
{ generate ("*"); }
| expression '/' expression
{ generate ("/"); }
| expression '%' expression
{ generate ("%"); }
| expression '^' expression
{ generate ("^"); }
| '-' expression %prec UNARY_MINUS
{ generate ("n"); $$ = 1;}
| named_expression
{
$$ = 1;
if ($1 < 0)
sprintf (genstr, "L%d:", -$1);
else
sprintf (genstr, "l%d:", $1);
generate (genstr);
}
| NUMBER
{
int len = strlen($1);
$$ = 1;
if (len == 1 && *$1 == '0')
generate ("0");
else
{
if (len == 1 && *$1 == '1')
generate ("1");
else
{
generate ("K");
generate ($1);
generate (":");
}
free ($1);
}
}
| '(' expression ')'
{ $$ = 1; }
| NAME '(' opt_argument_list ')'
{
$$ = 1;
if ($3 != NULL)
{
sprintf (genstr, "C%d,%s:", lookup($1,FUNCT),
arg_str ($3));
free_args ($3);
}
else
sprintf (genstr, "C%d:", lookup($1,FUNCT));
generate (genstr);
}
| INCR_DECR named_expression
{
$$ = 1;
if ($2 < 0)
{
if ($1 == '+')
sprintf (genstr, "DA%d:L%d:", -$2, -$2);
else
sprintf (genstr, "DM%d:L%d:", -$2, -$2);
}
else
{
if ($1 == '+')
sprintf (genstr, "i%d:l%d:", $2, $2);
else
sprintf (genstr, "d%d:l%d:", $2, $2);
}
generate (genstr);
}
| named_expression INCR_DECR
{
$$ = 1;
if ($1 < 0)
{
sprintf (genstr, "DL%d:x", -$1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "A%d:", -$1);
else
sprintf (genstr, "M%d:", -$1);
}
else
{
sprintf (genstr, "l%d:", $1);
generate (genstr);
if ($2 == '+')
sprintf (genstr, "i%d:", $1);
else
sprintf (genstr, "d%d:", $1);
}
generate (genstr);
}
| Length '(' expression ')'
{ generate ("cL"); $$ = 1;}
| Sqrt '(' expression ')'
{ generate ("cR"); $$ = 1;}
| Scale '(' expression ')'
{ generate ("cS"); $$ = 1;}
;
named_expression : NAME
{ $$ = lookup($1,SIMPLE); }
| NAME '[' expression ']'
{ $$ = lookup($1,ARRAY); }
| Ibase
{ $$ = 0; }
| Obase
{ $$ = 1; }
| Scale
{ $$ = 2; }
;
%%

1612
contrib/bc/bc/scan.c Normal file

File diff suppressed because it is too large Load Diff

293
contrib/bc/bc/scan.l Normal file
View File

@ -0,0 +1,293 @@
%{
/* scan.l: the (f)lex description file for the scanner. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "bc.h"
#include "global.h"
#include "proto.h"
#include <errno.h>
/* Using flex, we can ask for a smaller input buffer. With lex, this
does nothing! */
#ifdef SMALL_BUF
#undef YY_READ_BUF_SIZE
#define YY_READ_BUF_SIZE 512
#endif
/* Force . as last for now. */
#define DOT_IS_LAST
/* We want to define our own yywrap. */
#undef yywrap
_PROTOTYPE(int yywrap, (void));
#ifdef READLINE
/* Support for the readline and history libraries. This allows
nicer input on the interactive part of input. */
/* Have input call the following function. */
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
rl_input((char *)buf, &result, max_size)
/* Variables to help interface readline with bc. */
static char *rl_line = (char *)NULL;
static char *rl_start = (char *)NULL;
static char rl_len = 0;
/* Definitions for readline access. */
extern FILE *rl_instream;
_PROTOTYPE(char *readline, (char *));
/* Needed here? */
extern FILE *yyin;
/* rl_input puts upto MAX characters into BUF with the number put in
BUF placed in *RESULT. If the yy input file is the same as
rl_instream (stdin), use readline. Otherwise, just read it.
*/
static void
rl_input (buf, result, max)
char *buf;
int *result;
int max;
{
if (yyin != rl_instream)
{
while ( (*result = read( fileno(yyin), buf, max )) < 0 )
if (errno != EINTR)
{
yyerror( "read() in flex scanner failed" );
exit (1);
}
return;
}
/* Do we need a new string? */
if (rl_len == 0)
{
if (rl_line)
free(rl_line);
rl_line = readline ("");
if (rl_line == NULL) {
/* end of file */
*result = 0;
rl_len = 0;
return;
}
rl_len = strlen (rl_line)+1;
if (rl_len != 1)
add_history (rl_line);
rl_line[rl_len-1] = '\n';
printf ("\r");
fflush (stdout);
}
if (rl_len <= max)
{
strncpy (buf, rl_line, rl_len);
*result = rl_len;
rl_len = 0;
}
else
{
strncpy (buf, rl_line, max);
*result = max;
rl_len -= max;
}
}
#else
/* MINIX returns from read with < 0 if SIGINT is encountered.
In flex, we can redefine YY_INPUT to the following. In lex, this
does nothing! */
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
if (errno != EINTR) \
YY_FATAL_ERROR( "read() in flex scanner failed" );
#endif
%}
DIGIT [0-9A-F]
LETTER [a-z]
%s slcomment
%%
"#" {
if (!std_only)
BEGIN(slcomment);
else
yyerror ("illegal character: #");
}
<slcomment>[^\n]* { BEGIN(INITIAL); }
<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(NEWLINE); }
define return(Define);
break return(Break);
quit return(Quit);
length return(Length);
return return(Return);
for return(For);
if return(If);
while return(While);
sqrt return(Sqrt);
scale return(Scale);
ibase return(Ibase);
obase return(Obase);
auto return(Auto);
else return(Else);
read return(Read);
halt return(Halt);
last return(Last);
history {
#ifdef READLINE
return(History);
#else
yylval.s_value = strcopyof(yytext); return(NAME);
#endif
}
warranty return(Warranty);
continue return(Continue);
print return(Print);
limits return(Limits);
"." {
#ifdef DOT_IS_LAST
return(Last);
#else
yyerror ("illegal character: %s",yytext);
#endif
}
"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0];
return((int)yytext[0]); }
&& { return(AND); }
\|\| { return(OR); }
"!" { return(NOT); }
"*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
=\+|=-|=\*|=\/|=%|=\^ {
#ifdef OLD_EQ_OP
char warn_save;
warn_save = warn_not_std;
warn_not_std = TRUE;
warn ("Old fashioned =<op>");
warn_not_std = warn_save;
yylval.c_value = yytext[1];
#else
yylval.c_value = '=';
yyless (1);
#endif
return(ASSIGN_OP);
}
==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
"\n" { line_no++; return(NEWLINE); }
\\\n { line_no++; /* ignore a "quoted" newline */ }
[ \t]+ { /* ignore spaces and tabs */ }
"/*" {
int c;
for (;;)
{
while ( ((c=input()) != '*') && (c != EOF))
/* eat it */
if (c == '\n') line_no++;
if (c == '*')
{
while ( (c=input()) == '*') /* eat it*/;
if (c == '/') break; /* at end of comment */
if (c == '\n') line_no++;
}
if (c == EOF)
{
fprintf (stderr,"EOF encountered in a comment.\n");
break;
}
}
}
[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
\"[^\"]*\" {
unsigned char *look;
int count = 0;
yylval.s_value = strcopyof(yytext);
for (look = yytext; *look != 0; look++)
{
if (*look == '\n') line_no++;
if (*look == '"') count++;
}
if (count != 2) yyerror ("NUL character in string.");
return(STRING);
}
{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
unsigned char *src, *dst;
int len;
/* remove a trailing decimal point. */
len = strlen(yytext);
if (yytext[len-1] == '.')
yytext[len-1] = 0;
/* remove leading zeros. */
src = yytext;
dst = yytext;
while (*src == '0') src++;
if (*src == 0) src--;
/* Copy strings removing the newlines. */
while (*src != 0)
{
if (*src == '\\')
{
src++; src++;
line_no++;
}
else
*dst++ = *src++;
}
*dst = 0;
yylval.s_value = strcopyof(yytext);
return(NUMBER);
}
. {
if (yytext[0] < ' ')
yyerror ("illegal character: ^%c",yytext[0] + '@');
else
if (yytext[0] > '~')
yyerror ("illegal character: \\%3d", (int) yytext[0]);
else
yyerror ("illegal character: %s",yytext);
}
%%
/* This is the way to get multiple files input into lex. */
int
yywrap()
{
if (!open_new_file ()) return (1); /* EOF on standard in. */
return (0); /* We have more input. */
}

1070
contrib/bc/bc/storage.c Normal file

File diff suppressed because it is too large Load Diff

859
contrib/bc/bc/util.c Normal file
View File

@ -0,0 +1,859 @@
/* util.c: Utility routines for bc. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#ifndef VARARGS
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "global.h"
#include "proto.h"
/* strcopyof mallocs new memory and copies a string to to the new
memory. */
char *
strcopyof (str)
char *str;
{
char *temp;
temp = (char *) bc_malloc (strlen (str)+1);
return (strcpy (temp,str));
}
/* nextarg adds another value to the list of arguments. */
arg_list *
nextarg (args, val, is_var)
arg_list *args;
int val;
int is_var;
{ arg_list *temp;
temp = (arg_list *) bc_malloc (sizeof (arg_list));
temp->av_name = val;
temp->arg_is_var = is_var;
temp->next = args;
return (temp);
}
/* For generate, we must produce a string in the form
"val,val,...,val". We also need a couple of static variables
for retaining old generated strings. It also uses a recursive
function that builds the string. */
static char *arglist1 = NULL, *arglist2 = NULL;
/* make_arg_str does the actual construction of the argument string.
ARGS is the pointer to the list and LEN is the maximum number of
characters needed. 1 char is the minimum needed.
*/
_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len));
static char *
make_arg_str (args, len)
arg_list *args;
int len;
{
char *temp;
char sval[20];
/* Recursive call. */
if (args != NULL)
temp = make_arg_str (args->next, len+12);
else
{
temp = (char *) bc_malloc (len);
*temp = 0;
return temp;
}
/* Add the current number to the end of the string. */
if (args->arg_is_var)
if (len != 1)
sprintf (sval, "*%d,", args->av_name);
else
sprintf (sval, "*%d", args->av_name);
else
if (len != 1)
sprintf (sval, "%d,", args->av_name);
else
sprintf (sval, "%d", args->av_name);
temp = strcat (temp, sval);
return (temp);
}
char *
arg_str (args)
arg_list *args;
{
if (arglist2 != NULL)
free (arglist2);
arglist2 = arglist1;
arglist1 = make_arg_str (args, 1);
return (arglist1);
}
char *
call_str (args)
arg_list *args;
{
arg_list *temp;
int arg_count;
int ix;
if (arglist2 != NULL)
free (arglist2);
arglist2 = arglist1;
/* Count the number of args and add the 0's and 1's. */
for (temp = args, arg_count = 0; temp != NULL; temp = temp->next)
arg_count++;
arglist1 = (char *) bc_malloc(arg_count+1);
for (temp = args, ix=0; temp != NULL; temp = temp->next)
arglist1[ix++] = ( temp->av_name ? '1' : '0');
arglist1[ix] = 0;
return (arglist1);
}
/* free_args frees an argument list ARGS. */
void
free_args (args)
arg_list *args;
{
arg_list *temp;
temp = args;
while (temp != NULL)
{
args = args->next;
free (temp);
temp = args;
}
}
/* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
There must be no duplicates any where. Also, this is where
warnings are generated for array parameters. */
void
check_params ( params, autos )
arg_list *params, *autos;
{
arg_list *tmp1, *tmp2;
/* Check for duplicate parameters. */
if (params != NULL)
{
tmp1 = params;
while (tmp1 != NULL)
{
tmp2 = tmp1->next;
while (tmp2 != NULL)
{
if (tmp2->av_name == tmp1->av_name)
yyerror ("duplicate parameter names");
tmp2 = tmp2->next;
}
if (tmp1->arg_is_var)
warn ("Variable array parameter");
tmp1 = tmp1->next;
}
}
/* Check for duplicate autos. */
if (autos != NULL)
{
tmp1 = autos;
while (tmp1 != NULL)
{
tmp2 = tmp1->next;
while (tmp2 != NULL)
{
if (tmp2->av_name == tmp1->av_name)
yyerror ("duplicate auto variable names");
tmp2 = tmp2->next;
}
if (tmp1->arg_is_var)
yyerror ("* not allowed here");
tmp1 = tmp1->next;
}
}
/* Check for duplicate between parameters and autos. */
if ((params != NULL) && (autos != NULL))
{
tmp1 = params;
while (tmp1 != NULL)
{
tmp2 = autos;
while (tmp2 != NULL)
{
if (tmp2->av_name == tmp1->av_name)
yyerror ("variable in both parameter and auto lists");
tmp2 = tmp2->next;
}
tmp1 = tmp1->next;
}
}
}
/* Initialize the code generator the parser. */
void
init_gen ()
{
/* Get things ready. */
break_label = 0;
continue_label = 0;
next_label = 1;
out_count = 2;
if (compile_only)
printf ("@i");
else
init_load ();
had_error = FALSE;
did_gen = FALSE;
}
/* generate code STR for the machine. */
void
generate (str)
char *str;
{
did_gen = TRUE;
if (compile_only)
{
printf ("%s",str);
out_count += strlen(str);
if (out_count > 60)
{
printf ("\n");
out_count = 0;
}
}
else
load_code (str);
}
/* Execute the current code as loaded. */
void
run_code()
{
/* If no compile errors run the current code. */
if (!had_error && did_gen)
{
if (compile_only)
{
printf ("@r\n");
out_count = 0;
}
else
execute ();
}
/* Reinitialize the code generation and machine. */
if (did_gen)
init_gen();
else
had_error = FALSE;
}
/* Output routines: Write a character CH to the standard output.
It keeps track of the number of characters output and may
break the output with a "\<cr>". Always used for numbers. */
void
out_char (ch)
char ch;
{
if (ch == '\n')
{
out_col = 0;
putchar ('\n');
}
else
{
out_col++;
if (out_col == line_size-1)
{
putchar ('\\');
putchar ('\n');
out_col = 1;
}
putchar (ch);
}
}
/* Output routines: Write a character CH to the standard output.
It keeps track of the number of characters output and may
break the output with a "\<cr>". This one is for strings.
In POSIX bc, strings are not broken across lines. */
void
out_schar (ch)
char ch;
{
if (ch == '\n')
{
out_col = 0;
putchar ('\n');
}
else
{
if (!std_only)
{
out_col++;
if (out_col == line_size-1)
{
putchar ('\\');
putchar ('\n');
out_col = 1;
}
}
putchar (ch);
}
}
/* The following are "Symbol Table" routines for the parser. */
/* find_id returns a pointer to node in TREE that has the correct
ID. If there is no node in TREE with ID, NULL is returned. */
id_rec *
find_id (tree, id)
id_rec *tree;
char *id;
{
int cmp_result;
/* Check for an empty tree. */
if (tree == NULL)
return NULL;
/* Recursively search the tree. */
cmp_result = strcmp (id, tree->id);
if (cmp_result == 0)
return tree; /* This is the item. */
else if (cmp_result < 0)
return find_id (tree->left, id);
else
return find_id (tree->right, id);
}
/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
provided. insert_id_rec returns TRUE if the tree height from
ROOT down is increased otherwise it returns FALSE. This is a
recursive balanced binary tree insertion algorithm. */
int insert_id_rec (root, new_id)
id_rec **root;
id_rec *new_id;
{
id_rec *A, *B;
/* If root is NULL, this where it is to be inserted. */
if (*root == NULL)
{
*root = new_id;
new_id->left = NULL;
new_id->right = NULL;
new_id->balance = 0;
return (TRUE);
}
/* We need to search for a leaf. */
if (strcmp (new_id->id, (*root)->id) < 0)
{
/* Insert it on the left. */
if (insert_id_rec (&((*root)->left), new_id))
{
/* The height increased. */
(*root)->balance --;
switch ((*root)->balance)
{
case 0: /* no height increase. */
return (FALSE);
case -1: /* height increase. */
return (FALSE);
case -2: /* we need to do a rebalancing act. */
A = *root;
B = (*root)->left;
if (B->balance <= 0)
{
/* Single Rotate. */
A->left = B->right;
B->right = A;
*root = B;
A->balance = 0;
B->balance = 0;
}
else
{
/* Double Rotate. */
*root = B->right;
B->right = (*root)->left;
A->left = (*root)->right;
(*root)->left = B;
(*root)->right = A;
switch ((*root)->balance)
{
case -1:
A->balance = 1;
B->balance = 0;
break;
case 0:
A->balance = 0;
B->balance = 0;
break;
case 1:
A->balance = 0;
B->balance = -1;
break;
}
(*root)->balance = 0;
}
}
}
}
else
{
/* Insert it on the right. */
if (insert_id_rec (&((*root)->right), new_id))
{
/* The height increased. */
(*root)->balance ++;
switch ((*root)->balance)
{
case 0: /* no height increase. */
return (FALSE);
case 1: /* height increase. */
return (FALSE);
case 2: /* we need to do a rebalancing act. */
A = *root;
B = (*root)->right;
if (B->balance >= 0)
{
/* Single Rotate. */
A->right = B->left;
B->left = A;
*root = B;
A->balance = 0;
B->balance = 0;
}
else
{
/* Double Rotate. */
*root = B->left;
B->left = (*root)->right;
A->right = (*root)->left;
(*root)->left = A;
(*root)->right = B;
switch ((*root)->balance)
{
case -1:
A->balance = 0;
B->balance = 1;
break;
case 0:
A->balance = 0;
B->balance = 0;
break;
case 1:
A->balance = -1;
B->balance = 0;
break;
}
(*root)->balance = 0;
}
}
}
}
/* If we fall through to here, the tree did not grow in height. */
return (FALSE);
}
/* Initialize variables for the symbol table tree. */
void
init_tree()
{
name_tree = NULL;
next_array = 1;
next_func = 1;
/* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
next_var = 5;
}
/* Lookup routines for symbol table names. */
int
lookup (name, namekind)
char *name;
int namekind;
{
id_rec *id;
/* Warn about non-standard name. */
if (strlen(name) != 1)
warn ("multiple letter name - %s", name);
/* Look for the id. */
id = find_id (name_tree, name);
if (id == NULL)
{
/* We need to make a new item. */
id = (id_rec *) bc_malloc (sizeof (id_rec));
id->id = strcopyof (name);
id->a_name = 0;
id->f_name = 0;
id->v_name = 0;
insert_id_rec (&name_tree, id);
}
/* Return the correct value. */
switch (namekind)
{
case ARRAY:
/* ARRAY variable numbers are returned as negative numbers. */
if (id->a_name != 0)
{
free (name);
return (-id->a_name);
}
id->a_name = next_array++;
a_names[id->a_name] = name;
if (id->a_name < MAX_STORE)
{
if (id->a_name >= a_count)
more_arrays ();
return (-id->a_name);
}
yyerror ("Too many array variables");
exit (1);
case FUNCT:
case FUNCTDEF:
if (id->f_name != 0)
{
free(name);
/* Check to see if we are redefining a math lib function. */
if (use_math && namekind == FUNCTDEF && id->f_name <= 6)
id->f_name = next_func++;
return (id->f_name);
}
id->f_name = next_func++;
f_names[id->f_name] = name;
if (id->f_name < MAX_STORE)
{
if (id->f_name >= f_count)
more_functions ();
return (id->f_name);
}
yyerror ("Too many functions");
exit (1);
case SIMPLE:
if (id->v_name != 0)
{
free(name);
return (id->v_name);
}
id->v_name = next_var++;
v_names[id->v_name - 1] = name;
if (id->v_name <= MAX_STORE)
{
if (id->v_name >= v_count)
more_variables ();
return (id->v_name);
}
yyerror ("Too many variables");
exit (1);
}
}
/* Print the welcome banner. */
void
welcome()
{
printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
printf ("For details type `warranty'. \n");
}
/* Print out the warranty information. */
void
warranty(prefix)
char *prefix;
{
printf ("\n%s%s\n\n", prefix, BC_VERSION);
printf ("%s%s%s%s%s%s%s%s%s%s%s",
" This program is free software; you can redistribute it and/or modify\n",
" it under the terms of the GNU General Public License as published by\n",
" the Free Software Foundation; either version 2 of the License , or\n",
" (at your option) any later version.\n\n",
" This program is distributed in the hope that it will be useful,\n",
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
" GNU General Public License for more details.\n\n",
" You should have received a copy of the GNU General Public License\n",
" along with this program. If not, write to the Free Software\n",
" Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
}
/* Print out the limits of this program. */
void
limits()
{
printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX);
printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX);
printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX);
printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX);
printf ("MAX Exponent = %ld\n", (long) LONG_MAX);
printf ("MAX code = %ld\n", (long) BC_MAX_SEGS * (long) BC_SEG_SIZE);
printf ("multiply digits = %ld\n", (long) LONG_MAX / (long) 90);
printf ("Number of vars = %ld\n", (long) MAX_STORE);
#ifdef OLD_EQ_OP
printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
#endif
}
/* bc_malloc will check the return value so all other places do not
have to do it! SIZE is the number of bytes to allocate. */
char *
bc_malloc (size)
int size;
{
char *ptr;
ptr = (char *) malloc (size);
if (ptr == NULL)
out_of_memory ();
return ptr;
}
/* The following routines are error routines for various problems. */
/* Malloc could not get enought memory. */
void
out_of_memory()
{
fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
exit (1);
}
/* The standard yyerror routine. Built with variable number of argumnets. */
#ifndef VARARGS
#ifdef __STDC__
void
yyerror (char *str, ...)
#else
void
yyerror (str)
char *str;
#endif
#else
void
yyerror (str, va_alist)
char *str;
#endif
{
char *name;
va_list args;
#ifndef VARARGS
va_start (args, str);
#else
va_start (args);
#endif
if (is_std_in)
name = "(standard_in)";
else
name = file_name;
fprintf (stderr,"%s %d: ",name,line_no);
vfprintf (stderr, str, args);
fprintf (stderr, "\n");
had_error = TRUE;
va_end (args);
}
/* The routine to produce warnings about non-standard features
found during parsing. */
#ifndef VARARGS
#ifdef __STDC__
void
warn (char *mesg, ...)
#else
void
warn (mesg)
char *mesg;
#endif
#else
void
warn (mesg, va_alist)
char *mesg;
#endif
{
char *name;
va_list args;
#ifndef VARARGS
va_start (args, mesg);
#else
va_start (args);
#endif
if (std_only)
{
if (is_std_in)
name = "(standard_in)";
else
name = file_name;
fprintf (stderr,"%s %d: ",name,line_no);
vfprintf (stderr, mesg, args);
fprintf (stderr, "\n");
had_error = TRUE;
}
else
if (warn_not_std)
{
if (is_std_in)
name = "(standard_in)";
else
name = file_name;
fprintf (stderr,"%s %d: (Warning) ",name,line_no);
vfprintf (stderr, mesg, args);
fprintf (stderr, "\n");
}
va_end (args);
}
/* Runtime error will print a message and stop the machine. */
#ifndef VARARGS
#ifdef __STDC__
void
rt_error (char *mesg, ...)
#else
void
rt_error (mesg)
char *mesg;
#endif
#else
void
rt_error (mesg, va_alist)
char *mesg;
#endif
{
va_list args;
char error_mesg [255];
#ifndef VARARGS
va_start (args, mesg);
#else
va_start (args);
#endif
vsprintf (error_mesg, mesg, args);
va_end (args);
fprintf (stderr, "Runtime error (func=%s, adr=%d): %s\n",
f_names[pc.pc_func], pc.pc_addr, error_mesg);
runtime_error = TRUE;
}
/* A runtime warning tells of some action taken by the processor that
may change the program execution but was not enough of a problem
to stop the execution. */
#ifndef VARARGS
#ifdef __STDC__
void
rt_warn (char *mesg, ...)
#else
void
rt_warn (mesg)
char *mesg;
#endif
#else
void
rt_warn (mesg, va_alist)
char *mesg;
#endif
{
va_list args;
char error_mesg [255];
#ifndef VARARGS
va_start (args, mesg);
#else
va_start (args);
#endif
vsprintf (error_mesg, mesg, args);
va_end (args);
fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n",
f_names[pc.pc_func], pc.pc_addr, error_mesg);
}

68
contrib/bc/config.h.in Normal file
View File

@ -0,0 +1,68 @@
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define to empty if the keyword does not work. */
#undef const
/* Define if you don't have vprintf but do have _doprnt. */
#undef HAVE_DOPRNT
/* Define if you have the vprintf function. */
#undef HAVE_VPRINTF
/* Define if on MINIX. */
#undef _MINIX
/* Define if the system does not provide POSIX.1 features except
with this defined. */
#undef _POSIX_1_SOURCE
/* Define if you need to in order for stat and other things to work. */
#undef _POSIX_SOURCE
/* Define to `unsigned' if <sys/types.h> doesn't define. */
#undef size_t
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if lex declares yytext as a char * by default, not a char[]. */
#undef YYTEXT_POINTER
/* PACKAGE name */
#undef PACKAGE
/* Package VERSION number */
#undef VERSION
/* define if the math lib is to be loaded from a file. */
#undef BC_MATH_FILE
/* Define to use the readline library. */
#undef READLINE
/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
#undef ptrdiff_t
/* Define if you have the isgraph function. */
#undef HAVE_ISGRAPH
/* Define if you have the <lib.h> header file. */
#undef HAVE_LIB_H
/* Define if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H

2315
contrib/bc/configure vendored Executable file

File diff suppressed because it is too large Load Diff

69
contrib/bc/configure.in Normal file
View File

@ -0,0 +1,69 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(doc/bc.1)
AM_INIT_AUTOMAKE(bc, 1.04)
AM_CONFIG_HEADER(config.h)
AC_PROG_CC
AC_MINIX
dnl AC_ISC_POSIX
AC_PROG_YACC
AC_DECL_YYTEXT
AC_PROG_LEX
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_PROG_MAKE_SET
AC_CHECK_HEADERS(stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h)
AC_C_CONST
AC_TYPE_SIZE_T
AC_CHECK_TYPE(ptrdiff_t, size_t)
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(isgraph)
AC_ARG_WITH(readline,[ --with-readline support fancy command input editing], [
if test "$with_readline" = "yes" ; then
echo Using the readline library.
AC_DEFINE(READLINE,1)
LIBS="$LIBS -lreadline -ltermcap"
bcrl=y
else
bcrl=n
fi
], [
bcrl=n
])
if test "$LEX" = "flex" ; then
LEX="flex -I8"
else
if test "$bcrl" = "y" ; then
AC_MSG_WARN(readline works only with flex.)
fi
fi
SaveCFLAGS="$CFLAGS"
CFLAGS="-g -O -I. -I$srcdir"
AC_MSG_CHECKING(if long strings are accepted by the C compiler)
AC_TRY_COMPILE([
char libmath[] =
#include "bc/libmath.h"
;
],[],AC_MSG_RESULT(yes),
AC_MSG_RESULT(no)
AC_MSG_WARN(libmath.b will not be preloaded into the executable)
if test "${prefix}" = "NONE" ; then
AC_DEFINE_UNQUOTED(BC_MATH_FILE,"/usr/local/lib/libmath.b")
else
AC_DEFINE_UNQUOTED(BC_MATH_FILE,"${prefix}/lib/libmath.b")
fi)
CFLAGS="$SaveCFLAGS"
AC_ARG_PROGRAM
AC_OUTPUT(Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile)

10
contrib/bc/dc/Makefile.am Normal file
View File

@ -0,0 +1,10 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = dc
dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c
noinst_HEADERS = dc.h dc-proto.h dc-regdef.h
INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h
LDADD = ../lib/libbc.a
$(PROGRAMS): $(LDADD)

250
contrib/bc/dc/Makefile.in Normal file
View File

@ -0,0 +1,250 @@
# Makefile.in generated automatically by automake 1.1n from Makefile.am
# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
SHELL = /bin/sh
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = true
PRE_INSTALL = true
POST_INSTALL = true
NORMAL_UNINSTALL = true
PRE_UNINSTALL = true
POST_UNINSTALL = true
CC = @CC@
LEX = @LEX@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
VERSION = @VERSION@
YACC = @YACC@
bin_PROGRAMS = dc
dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c
noinst_HEADERS = dc.h dc-proto.h dc-regdef.h
INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h
LDADD = ../lib/libbc.a
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(bin_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
dc_OBJECTS = dc.o misc.o eval.o stack.o array.o numeric.o string.o
dc_LDADD = $(LDADD)
dc_DEPENDENCIES = ../lib/libbc.a
dc_LDFLAGS =
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LINK = $(CC) $(LDFLAGS) -o $@
HEADERS = $(noinst_HEADERS)
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP = --best
SOURCES = $(dc_SOURCES)
OBJECTS = $(dc_OBJECTS)
default: all
.SUFFIXES:
.SUFFIXES: .c .o
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu dc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-binPROGRAMS:
clean-binPROGRAMS:
test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
distclean-binPROGRAMS:
maintainer-clean-binPROGRAMS:
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`"; \
$(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
else :; fi; \
done
uninstall-binPROGRAMS:
$(NORMAL_UNINSTALL)
list='$(bin_PROGRAMS)'; for p in $$list; do \
rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
done
.c.o:
$(COMPILE) -c $<
mostlyclean-compile:
rm -f *.o core
clean-compile:
distclean-compile:
rm -f *.tab.c
maintainer-clean-compile:
dc: $(dc_OBJECTS) $(dc_DEPENDENCIES)
@rm -f dc
$(LINK) $(dc_LDFLAGS) $(dc_OBJECTS) $(dc_LDADD) $(LIBS)
tags: TAGS
ID: $(HEADERS) $(SOURCES)
here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
done; \
test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = dc
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done
info:
dvi:
check: all
$(MAKE)
installcheck:
install-exec: install-binPROGRAMS
@$(NORMAL_INSTALL)
install-data:
@$(NORMAL_INSTALL)
install: install-exec install-data all
@:
uninstall: uninstall-binPROGRAMS
all: $(PROGRAMS) $(HEADERS) Makefile
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
installdirs:
$(mkinstalldirs) $(bindir)
mostlyclean-generic:
test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
rm -f Makefile $(DISTCLEANFILES)
rm -f config.cache config.log stamp-h
test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \
mostlyclean
distclean: distclean-binPROGRAMS distclean-compile distclean-tags \
distclean-generic clean
rm -f config.status
maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \
maintainer-clean-tags maintainer-clean-generic \
distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \
clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info dvi installcheck \
install-exec install-data install uninstall all installdirs \
mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
$(PROGRAMS): $(LDADD)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

108
contrib/bc/dc/array.c Normal file
View File

@ -0,0 +1,108 @@
/*
* implement arrays for dc
*
* Copyright (C) 1994 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* This module is the only one that knows what arrays look like. */
#include "config.h"
#include <stdio.h> /* "dc-proto.h" wants this */
#ifdef HAVE_STDLIB_H
/* get size_t definition from "almost ANSI" compiling environments. */
#include <stdlib.h>
#endif
#include "dc.h"
#include "dc-proto.h"
#include "dc-regdef.h"
/* what's most useful: quick access or sparse arrays? */
/* I'll go with sparse arrays for now */
struct dc_array {
int Index;
dc_data value;
struct dc_array *next;
};
typedef struct dc_array dc_array;
/* I can find no reason not to place arrays in their own namespace... */
static dc_array *dc_array_register[DC_REGCOUNT];
/* initialize the arrays to their initial values */
void
dc_array_init DC_DECLVOID()
{
int i;
for (i=0; i<DC_REGCOUNT; ++i)
dc_array_register[i] = NULL;
}
/* store value into array_id[Index] */
void
dc_array_set DC_DECLARG((array_id, Index, value))
int array_id DC_DECLSEP
int Index DC_DECLSEP
dc_data value DC_DECLEND
{
dc_array *cur;
dc_array *prev=NULL;
dc_array *newentry;
array_id = regmap(array_id);
cur = dc_array_register[array_id];
while (cur && cur->Index < Index){
prev = cur;
cur = cur->next;
}
if (cur && cur->Index == Index){
if (cur->value.dc_type == DC_NUMBER)
dc_free_num(&cur->value.v.number);
else if (cur->value.dc_type == DC_STRING)
dc_free_str(&cur->value.v.string);
else
dc_garbage(" in array", array_id);
cur->value = value;
}else{
newentry = dc_malloc(sizeof *newentry);
newentry->Index = Index;
newentry->value = value;
newentry->next = cur;
if (prev)
prev->next = newentry;
else
dc_array_register[array_id] = newentry;
}
}
/* retrieve a dup of a value from array_id[Index] */
/* A zero value is returned if the specified value is unintialized. */
dc_data
dc_array_get DC_DECLARG((array_id, Index))
int array_id DC_DECLSEP
int Index DC_DECLEND
{
dc_array *cur;
for (cur=dc_array_register[regmap(array_id)]; cur; cur=cur->next)
if (cur->Index == Index)
return dc_dup(cur->value);
return dc_int2data(0);
}

83
contrib/bc/dc/dc-proto.h Normal file
View File

@ -0,0 +1,83 @@
/*
* prototypes of all externally visible dc functions
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
extern const char *dc_str2charp DC_PROTO((dc_str));
extern const char *dc_system DC_PROTO((const char *));
extern void *dc_malloc DC_PROTO((size_t));
extern void dc_array_set DC_PROTO((int, int, dc_data));
extern void dc_array_init DC_PROTO((void));
extern void dc_binop DC_PROTO((int (*)(dc_num, dc_num, int, dc_num *), int));
extern void dc_binop2 DC_PROTO((int (*)(dc_num, dc_num, int,
dc_num *, dc_num *), int));
extern void dc_triop DC_PROTO((int (*)(dc_num, dc_num, dc_num, int,
dc_num *), int));
extern void dc_clear_stack DC_PROTO((void));
extern void dc_free_num DC_PROTO((dc_num *));
extern void dc_free_str DC_PROTO((dc_str *));
extern void dc_garbage DC_PROTO((const char *, int));
extern void dc_math_init DC_PROTO((void));
extern void dc_memfail DC_PROTO((void));
extern void dc_out_num DC_PROTO((dc_num, int, dc_boolean, dc_boolean));
extern void dc_out_str DC_PROTO((dc_str, dc_boolean, dc_boolean));
extern void dc_print DC_PROTO((dc_data, int));
extern void dc_printall DC_PROTO((int));
extern void dc_push DC_PROTO((dc_data));
extern void dc_register_init DC_PROTO((void));
extern void dc_register_push DC_PROTO((int, dc_data));
extern void dc_register_set DC_PROTO((int, dc_data));
extern void dc_show_id DC_PROTO((FILE *, int, const char *));
extern void dc_string_init DC_PROTO((void));
extern int dc_cmpop DC_PROTO((void));
extern int dc_compare DC_PROTO((dc_num, dc_num));
extern int dc_evalfile DC_PROTO((FILE *));
extern int dc_evalstr DC_PROTO((dc_data));
extern int dc_num2int DC_PROTO((dc_num, dc_boolean));
extern int dc_numlen DC_PROTO((dc_num));
extern int dc_pop DC_PROTO((dc_data *));
extern int dc_register_get DC_PROTO((int, dc_data *));
extern int dc_register_pop DC_PROTO((int, dc_data *));
extern int dc_tell_length DC_PROTO((dc_data, dc_boolean));
extern int dc_tell_scale DC_PROTO((dc_num, dc_boolean));
extern int dc_tell_stackdepth DC_PROTO((void));
extern int dc_top_of_stack DC_PROTO((dc_data *));
extern size_t dc_strlen DC_PROTO((dc_str));
extern dc_data dc_array_get DC_PROTO((int, int));
extern dc_data dc_dup DC_PROTO((dc_data));
extern dc_data dc_dup_num DC_PROTO((dc_num));
extern dc_data dc_dup_str DC_PROTO((dc_str));
extern dc_data dc_getnum DC_PROTO((int (*)(void), int, int *));
extern dc_data dc_int2data DC_PROTO((int));
extern dc_data dc_makestring DC_PROTO((const char *, size_t));
extern dc_data dc_readstring DC_PROTO((FILE *, int , int));
extern int dc_add DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_div DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_divrem DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *));
extern int dc_exp DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_modexp DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *));
extern int dc_mul DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_rem DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_sub DC_PROTO((dc_num, dc_num, int, dc_num *));
extern int dc_sqrt DC_PROTO((dc_num, int, dc_num *));

40
contrib/bc/dc/dc-regdef.h Normal file
View File

@ -0,0 +1,40 @@
/*
* definitions for dc's "register" declarations
*
* Copyright (C) 1994 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
#ifdef HAVE_LIMITS_H
# include <limits.h> /* UCHAR_MAX */
#endif
/* determine how many register stacks there are */
#ifndef DC_REGCOUNT
# ifndef UCHAR_MAX
# define DC_REGCOUNT 256
# else
# define DC_REGCOUNT (UCHAR_MAX+1)
# endif
#endif /* not DC_REGCOUNT */
/* efficiency hack for masking arbritrary integers to 0..(DC_REGCOUNT-1) */
#if (DC_REGCOUNT & (DC_REGCOUNT-1)) == 0 /* DC_REGCOUNT is power of 2 */
# define regmap(r) ((r) & (DC_REGCOUNT-1))
#else
# define regmap(r) ((r) % DC_REGCOUNT)
#endif

173
contrib/bc/dc/dc.c Normal file
View File

@ -0,0 +1,173 @@
/*
* implement the "dc" Desk Calculator language.
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* Written with strong hiding of implementation details
* in their own specialized modules.
*/
/* This module contains the argument processing/main functions.
*/
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif
#include <getopt.h>
#include "dc.h"
#include "dc-proto.h"
#include "version.h"
#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */
# define EXIT_SUCCESS 0
#endif
#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
# define EXIT_FAILURE 1
#endif
const char *progname; /* basename of program invocation */
/* your generic usage function */
static void
usage DC_DECLARG((f))
FILE *f DC_DECLEND
{
fprintf(f, "\
Usage: %s [OPTION] [file ...]\n\
-e, --expression=EXPR evaluate expression\n\
-f, --file=FILE evaluate contents of file\n\
-h, --help display this help and exit\n\
-V, --version output version information and exit\n\
\n\
Report bugs to @\n\
", progname);
}
static void
show_version DC_DECLVOID()
{
printf("%s\n\n", DC_VERSION);
printf("Email bug reports to: bug-gnu-utils@prep.ai.mit.edu .\n");
printf("Be sure to include the word ``dc'' \
somewhere in the ``Subject:'' field.\n");
}
/* returns a pointer to one past the last occurance of c in s,
* or s if c does not occur in s.
*/
static char *
r1bindex DC_DECLARG((s, c))
char *s DC_DECLSEP
int c DC_DECLEND
{
char *p = strrchr(s, c);
if (!p)
return s;
return p + 1;
}
static void
try_file(const char *filename) {
FILE *input;
if ( !(input=fopen(filename, "r")) ) {
fprintf(stderr, "Could not open file ");
perror(filename);
exit(EXIT_FAILURE);
}
if (dc_evalfile(input))
exit(EXIT_FAILURE);
fclose(input);
}
int
main DC_DECLARG((argc, argv))
int argc DC_DECLSEP
char **argv DC_DECLEND
{
static struct option const long_opts[] = {
{"expression", required_argument, NULL, 'e'},
{"file", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
int did_eval = 0;
int c;
progname = r1bindex(*argv, '/');
dc_math_init();
dc_string_init();
dc_register_init();
dc_array_init();
while ((c = getopt_long(argc, argv, "hVe:", long_opts, (int *)0)) != EOF) {
switch (c) {
case 'e':
{ dc_data string = dc_makestring(optarg, strlen(optarg));
if (dc_evalstr(string))
return EXIT_SUCCESS;
dc_free_str(&string.v.string);
did_eval = 1;
}
break;
case 'f':
try_file(optarg);
did_eval = 1;
break;
case 'h':
usage(stdout);
return EXIT_SUCCESS;
case 'V':
show_version();
return EXIT_SUCCESS;
default:
usage(stderr);
return EXIT_FAILURE;
}
}
for (; optind < argc; ++optind) {
if (strcmp(argv[optind], "-") == 0) {
if (dc_evalfile(stdin))
return EXIT_FAILURE;
} else {
try_file(argv[optind]);
}
did_eval = 1;
}
if (!did_eval) {
/* if no -e commands and no command files, then eval stdin */
if (dc_evalfile(stdin))
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

78
contrib/bc/dc/dc.h Normal file
View File

@ -0,0 +1,78 @@
/*
* Header file for dc routines
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
#ifndef DC_DEFS_H
#define DC_DEFS_H
/* 'I' is a command, and bases 17 and 18 are quite
* unusual, so we limit ourselves to bases 2 to 16
*/
#define DC_IBASE_MAX 16
#define DC_SUCCESS 0
#define DC_DOMAIN_ERROR 1
#define DC_FAIL 2 /* generic failure */
#ifndef __STDC__
# define DC_PROTO(x) ()
# define DC_DECLVOID() ()
# define DC_DECLARG(arglist) arglist
# define DC_DECLSEP ;
# define DC_DECLEND ;
#else /* __STDC__ */
# define DC_PROTO(x) x
# define DC_DECLVOID() (void)
# define DC_DECLARG(arglist) (
# define DC_DECLSEP ,
# define DC_DECLEND )
#endif /* __STDC__ */
typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
/* type discriminant for dc_data */
typedef enum {DC_UNINITIALIZED, DC_NUMBER, DC_STRING} dc_value_type;
/* only numeric.c knows what dc_num's *really* look like */
typedef struct dc_number *dc_num;
/* only string.c knows what dc_str's *really* look like */
typedef struct dc_string *dc_str;
/* except for the two implementation-specific modules, all
* dc functions only know of this one generic type of object
*/
typedef struct {
dc_value_type dc_type; /* discriminant for union */
union {
dc_num number;
dc_str string;
} v;
} dc_data;
/* This is dc's only global variable: */
extern const char *progname; /* basename of program invocation */
#endif /* not DC_DEFS_H */

646
contrib/bc/dc/eval.c Normal file
View File

@ -0,0 +1,646 @@
/*
* evaluate the dc language, from a FILE* or a string
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* This is the only module which knows about the dc input language */
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
# include <string.h> /* memchr */
#else
# ifdef HAVE_MEMORY_H
# include <memory.h> /* memchr, maybe */
# else
# ifdef HAVE_STRINGS_H
# include <strings.h> /* memchr, maybe */
# endif
#endif
#endif
#include "dc.h"
#include "dc-proto.h"
typedef enum {
DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
DC_EATONE, /* caller needs to eat the lookahead char */
DC_QUIT, /* quit out of unwind_depth levels of evaluation */
/* with the following return values, the caller does not have to
* fret about stdin_lookahead's value
*/
DC_INT, /* caller needs to parse a dc_num from input stream */
DC_STR, /* caller needs to parse a dc_str from input stream */
DC_SYSTEM, /* caller needs to run a system() on next input line */
DC_COMMENT, /* caller needs to skip to the next input line */
DC_EOF_ERROR /* unexpected end of input; abort current eval */
} dc_status;
static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */
static int dc_obase=10; /* output base, 2 <= dc_obase */
static int dc_scale=0; /* scale (see user documentaton) */
/* for Quitting evaluations */
static int unwind_depth=0;
/* if true, active Quit will not exit program */
static dc_boolean unwind_noexit=DC_FALSE;
/*
* Used to synchronize lookahead on stdin for '?' command.
* If set to EOF then lookahead is used up.
*/
static int stdin_lookahead=EOF;
/* input_fil and input_str are passed as arguments to dc_getnum */
/* used by the input_* functions: */
static FILE *input_fil_fp;
static const char *input_str_string;
/* Since we have a need for two characters of pushback, and
* ungetc() only guarantees one, we place the second pushback here
*/
static int input_pushback;
/* passed as an argument to dc_getnum */
static int
input_fil DC_DECLVOID()
{
if (input_pushback != EOF){
int c = input_pushback;
input_pushback = EOF;
return c;
}
return getc(input_fil_fp);
}
/* passed as an argument to dc_getnum */
static int
input_str DC_DECLVOID()
{
if (!*input_str_string)
return EOF;
return *input_str_string++;
}
/* takes a string and evals it; frees the string when done */
/* Wrapper around dc_evalstr to avoid duplicating the free call
* at all possible return points.
*/
static int
dc_eval_and_free_str DC_DECLARG((string))
dc_data string DC_DECLEND
{
dc_status status;
status = dc_evalstr(string);
if (string.dc_type == DC_STRING)
dc_free_str(&string.v.string);
return status;
}
/* dc_func does the grunt work of figuring out what each input
* character means; used by both dc_evalstr and dc_evalfile
*
* c -> the "current" input character under consideration
* peekc -> the lookahead input character
*/
static dc_status
dc_func DC_DECLARG((c, peekc))
int c DC_DECLSEP
int peekc DC_DECLEND
{
/* we occasionally need these for temporary data */
/* Despite the GNU coding standards, it is much easier
* to have these declared once here, since this function
* is just one big switch statement.
*/
dc_data datum;
int tmpint;
switch (c){
case '_': case '.':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case 'A': case 'B':
case 'C': case 'D': case 'E': case 'F':
return DC_INT;
case ' ':
case '\t':
case '\n':
/* standard command separators */
break;
case '+': /* add top two stack elements */
dc_binop(dc_add, dc_scale);
break;
case '-': /* subtract top two stack elements */
dc_binop(dc_sub, dc_scale);
break;
case '*': /* multiply top two stack elements */
dc_binop(dc_mul, dc_scale);
break;
case '/': /* divide top two stack elements */
dc_binop(dc_div, dc_scale);
break;
case '%':
/* take the remainder from division of the top two stack elements */
dc_binop(dc_rem, dc_scale);
break;
case '~':
/* Do division on the top two stack elements. Return the
* quotient as next-to-top of stack and the remainder as
* top-of-stack.
*/
dc_binop2(dc_divrem, dc_scale);
break;
case '|':
/* Consider the top three elements of the stack as (base, exp, mod),
* where mod is top-of-stack, exp is next-to-top, and base is
* second-from-top. Mod must be non-zero and exp must be a
* non-negative integer. Push the result of raising base to the exp
* power, reduced modulo mod. If we had base in register b, exp in
* register e, and mod in register m then this is conceptually
* equivalent to "lble^lm%", but it is implemented in a more efficient
* manner, and can handle arbritrarily large values for exp.
*/
dc_triop(dc_modexp, dc_scale);
break;
case '^': /* exponientiation of the top two stack elements */
dc_binop(dc_exp, dc_scale);
break;
case '<':
/* eval register named by peekc if
* less-than holds for top two stack elements
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_cmpop() < 0)
if (dc_register_get(peekc, &datum) == DC_SUCCESS)
if (dc_eval_and_free_str(datum) == DC_QUIT)
return DC_QUIT;
return DC_EATONE;
case '=':
/* eval register named by peekc if
* equal-to holds for top two stack elements
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_cmpop() == 0)
if (dc_register_get(peekc, &datum) == DC_SUCCESS)
if (dc_eval_and_free_str(datum) == DC_QUIT)
return DC_QUIT;
return DC_EATONE;
case '>':
/* eval register named by peekc if
* greater-than holds for top two stack elements
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_cmpop() > 0)
if (dc_register_get(peekc, &datum) == DC_SUCCESS)
if (dc_eval_and_free_str(datum) == DC_QUIT)
return DC_QUIT;
return DC_EATONE;
case '?': /* read a line from standard-input and eval it */
if (stdin_lookahead != EOF){
ungetc(stdin_lookahead, stdin);
stdin_lookahead = EOF;
}
if (dc_eval_and_free_str(dc_readstring(stdin, '\n', '\n')) == DC_QUIT)
return DC_QUIT;
return DC_OKAY;
case '[': /* read to balancing ']' into a dc_str */
return DC_STR;
case '!': /* read to newline and call system() on resulting string */
return DC_SYSTEM;
case '#': /* comment; skip remainder of current line */
return DC_COMMENT;
case 'a': /* Convert top of stack to an ascii character. */
if (dc_pop(&datum) == DC_SUCCESS){
char tmps;
if (datum.dc_type == DC_NUMBER){
tmps = (char) dc_num2int(datum.v.number, DC_TRUE);
dc_free_num(&datum.v.number);
}else if (datum.dc_type == DC_STRING){
tmps = *dc_str2charp(datum.v.string);
dc_free_str(&datum.v.string);
}else{
dc_garbage("at top of stack", -1);
}
dc_push(dc_makestring(&tmps, 1));
}
break;
case 'c': /* clear whole stack */
dc_clear_stack();
break;
case 'd': /* duplicate the datum on the top of stack */
if (dc_top_of_stack(&datum) == DC_SUCCESS)
dc_push(dc_dup(datum));
break;
case 'f': /* print list of all stack items */
dc_printall(dc_obase);
break;
case 'i': /* set input base to value on top of stack */
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = 0;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_num2int(datum.v.number, DC_TRUE);
if ( ! (2 <= tmpint && tmpint <= DC_IBASE_MAX) )
fprintf(stderr,
"%s: input base must be a number \
between 2 and %d (inclusive)\n",
progname, DC_IBASE_MAX);
else
dc_ibase = tmpint;
}
break;
case 'k': /* set scale to value on top of stack */
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = -1;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_num2int(datum.v.number, DC_TRUE);
if ( ! (tmpint >= 0) )
fprintf(stderr,
"%s: scale must be a nonnegative number\n",
progname);
else
dc_scale = tmpint;
}
break;
case 'l': /* "load" -- push value on top of register stack named
* by peekc onto top of evaluation stack; does not
* modify the register stack
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_register_get(peekc, &datum) == DC_SUCCESS)
dc_push(datum);
return DC_EATONE;
case 'o': /* set output base to value on top of stack */
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = 0;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_num2int(datum.v.number, DC_TRUE);
if ( ! (tmpint > 1) )
fprintf(stderr,
"%s: output base must be a number greater than 1\n",
progname);
else
dc_obase = tmpint;
}
break;
case 'p': /* print the datum on the top of stack */
if (dc_top_of_stack(&datum) == DC_SUCCESS)
dc_print(datum, dc_obase);
break;
case 'q': /* quit two levels of evaluation, posibly exiting program */
unwind_depth = 2;
unwind_noexit = DC_FALSE;
return DC_QUIT;
case 'r': /* rotate (swap) the top two elements on the stack
*/
if (dc_pop(&datum) == DC_SUCCESS) {
dc_data datum2;
int two_status;
two_status = dc_pop(&datum2);
dc_push(datum);
if (two_status == DC_SUCCESS)
dc_push(datum2);
}
break;
case 's': /* "store" -- replace top of register stack named
* by peekc with the value popped from the top
* of the evaluation stack
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_pop(&datum) == DC_SUCCESS)
dc_register_set(peekc, datum);
return DC_EATONE;
case 'v': /* replace top of stack with its square root */
if (dc_pop(&datum) == DC_SUCCESS){
dc_num tmpnum;
if (datum.dc_type != DC_NUMBER){
fprintf(stderr,
"%s: square root of nonnumeric attempted\n",
progname);
}else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
dc_free_num(&datum.v.number);
datum.v.number = tmpnum;
dc_push(datum);
}
}
break;
case 'x': /* eval the datum popped from top of stack */
if (dc_pop(&datum) == DC_SUCCESS){
if (datum.dc_type == DC_STRING){
if (dc_eval_and_free_str(datum) == DC_QUIT)
return DC_QUIT;
}else if (datum.dc_type == DC_NUMBER){
dc_push(datum);
}else{
dc_garbage("at top of stack", -1);
}
}
break;
case 'z': /* push the current stack depth onto the top of stack */
dc_push(dc_int2data(dc_tell_stackdepth()));
break;
case 'I': /* push the current input base onto the stack */
dc_push(dc_int2data(dc_ibase));
break;
case 'K': /* push the current scale onto the stack */
dc_push(dc_int2data(dc_scale));
break;
case 'L': /* pop a value off of register stack named by peekc
* and push it onto the evaluation stack
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_register_pop(peekc, &datum) == DC_SUCCESS)
dc_push(datum);
return DC_EATONE;
case 'O': /* push the current output base onto the stack */
dc_push(dc_int2data(dc_obase));
break;
case 'P': /* print the value popped off of top-of-stack;
* do not add a trailing newline
*/
if (dc_pop(&datum) == DC_SUCCESS){
if (datum.dc_type == DC_STRING)
dc_out_str(datum.v.string, DC_FALSE, DC_TRUE);
else if (datum.dc_type == DC_NUMBER)
dc_out_num(datum.v.number, dc_obase, DC_FALSE, DC_TRUE);
else
dc_garbage("at top of stack", -1);
}
break;
case 'Q': /* quit out of top-of-stack nested evals;
* pops value from stack;
* does not exit program (stops short if necessary)
*/
if (dc_pop(&datum) == DC_SUCCESS){
unwind_depth = 0;
unwind_noexit = DC_TRUE;
if (datum.dc_type == DC_NUMBER)
unwind_depth = dc_num2int(datum.v.number, DC_TRUE);
if (unwind_depth > 0)
return DC_QUIT;
fprintf(stderr,
"%s: Q command requires a number >= 1\n",
progname);
}
break;
#if 0
case 'R': /* pop a value off of the evaluation stack,;
* rotate the top
remaining stack elements that many
* places forward (negative numbers mean rotate
* backward).
*/
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = 0;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_num2int(datum.v.number, DC_TRUE);
dc_stack_rotate(tmpint);
}
break;
#endif
case 'S': /* pop a value off of the evaluation stack
* and push it onto the register stack named by peekc
*/
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_pop(&datum) == DC_SUCCESS)
dc_register_push(peekc, datum);
return DC_EATONE;
case 'X': /* replace the number on top-of-stack with its scale factor */
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = 0;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_tell_scale(datum.v.number, DC_TRUE);
dc_push(dc_int2data(tmpint));
}
break;
case 'Z': /* replace the datum on the top-of-stack with its length */
if (dc_pop(&datum) == DC_SUCCESS)
dc_push(dc_int2data(dc_tell_length(datum, DC_TRUE)));
break;
case ':': /* store into array */
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = -1;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_num2int(datum.v.number, DC_TRUE);
if (dc_pop(&datum) == DC_SUCCESS){
if (tmpint < 0)
fprintf(stderr,
"%s: array index must be a nonnegative integer\n",
progname);
else
dc_array_set(peekc, tmpint, datum);
}
}
return DC_EATONE;
case ';': /* retreive from array */
if (peekc == EOF)
return DC_EOF_ERROR;
if (dc_pop(&datum) == DC_SUCCESS){
tmpint = -1;
if (datum.dc_type == DC_NUMBER)
tmpint = dc_num2int(datum.v.number, DC_TRUE);
if (tmpint < 0)
fprintf(stderr,
"%s: array index must be a nonnegative integer\n",
progname);
else
dc_push(dc_array_get(peekc, tmpint));
}
return DC_EATONE;
default: /* What did that user mean? */
fprintf(stderr, "%s: ", progname);
dc_show_id(stdout, c, " unimplemented\n");
break;
}
return DC_OKAY;
}
/* takes a string and evals it */
int
dc_evalstr DC_DECLARG((string))
dc_data string DC_DECLEND
{
const char *s;
const char *end;
const char *p;
size_t len;
int c;
int peekc;
int count;
if (string.dc_type != DC_STRING){
fprintf(stderr,
"%s: eval called with non-string argument\n",
progname);
return DC_OKAY;
}
s = dc_str2charp(string.v.string);
end = s + dc_strlen(string.v.string);
while (s < end){
c = *(const unsigned char *)s++;
peekc = EOF;
if (s < end)
peekc = *(const unsigned char *)s;
switch (dc_func(c, peekc)){
case DC_OKAY:
break;
case DC_EATONE:
if (peekc != EOF)
++s;
break;
case DC_QUIT:
if (unwind_depth > 0){
--unwind_depth;
return DC_QUIT;
}
return DC_OKAY;
case DC_INT:
input_str_string = s - 1;
dc_push(dc_getnum(input_str, dc_ibase, &peekc));
s = input_str_string;
if (peekc != EOF)
--s;
break;
case DC_STR:
count = 1;
for (p=s; p<end && count>0; ++p)
if (*p == ']')
--count;
else if (*p == '[')
++count;
len = p - s;
dc_push(dc_makestring(s, len-1));
s = p;
break;
case DC_SYSTEM:
s = dc_system(s);
case DC_COMMENT:
s = memchr(s, '\n', (size_t)(end-s));
if (!s)
s = end;
else
++s;
break;
case DC_EOF_ERROR:
fprintf(stderr, "%s: unexpected EOS\n", progname);
return DC_OKAY;
}
}
return DC_OKAY;
}
/* This is the main function of the whole DC program.
* Reads the file described by fp, calls dc_func to do
* the dirty work, and takes care of dc_func's shortcomings.
*/
int
dc_evalfile DC_DECLARG((fp))
FILE *fp DC_DECLEND
{
int c;
int peekc;
dc_data datum;
stdin_lookahead = EOF;
for (c=getc(fp); c!=EOF; c=peekc){
peekc = getc(fp);
/*
* The following if() is the only place where ``stdin_lookahead''
* might be set to other than EOF:
*/
if (fp == stdin)
stdin_lookahead = peekc;
switch (dc_func(c, peekc)){
case DC_OKAY:
if (stdin_lookahead != peekc && fp == stdin)
peekc = getc(fp);
break;
case DC_EATONE:
peekc = getc(fp);
break;
case DC_QUIT:
if (unwind_noexit != DC_TRUE)
return DC_FAIL;
fprintf(stderr,
"%s: Q command argument exceeded string execution depth\n",
progname);
if (stdin_lookahead != peekc && fp == stdin)
peekc = getc(fp);
break;
case DC_INT:
input_fil_fp = fp;
input_pushback = c;
ungetc(peekc, fp);
dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
break;
case DC_STR:
ungetc(peekc, fp);
datum = dc_readstring(fp, '[', ']');
dc_push(datum);
peekc = getc(fp);
break;
case DC_SYSTEM:
ungetc(peekc, fp);
datum = dc_readstring(stdin, '\n', '\n');
(void)dc_system(dc_str2charp(datum.v.string));
dc_free_str(&datum.v.string);
peekc = getc(fp);
break;
case DC_COMMENT:
while (peekc!=EOF && peekc!='\n')
peekc = getc(fp);
if (peekc != EOF)
peekc = getc(fp);
break;
case DC_EOF_ERROR:
fprintf(stderr, "%s: unexpected EOF\n", progname);
return DC_FAIL;
}
}
return DC_SUCCESS;
}

177
contrib/bc/dc/misc.c Normal file
View File

@ -0,0 +1,177 @@
/*
* misc. functions for the "dc" Desk Calculator language.
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* This module contains miscelaneous functions that have no
* special knowledge of any private data structures.
* They could all be moved to their own separate modules, but
* are agglomerated here for convenience.
*/
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif
#include <ctype.h>
#ifndef isgraph
# ifndef HAVE_ISGRAPH
# define isgraph isprint
# endif
#endif
#include <getopt.h>
#include "dc.h"
#include "dc-proto.h"
#include "version.h"
#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
# define EXIT_FAILURE 1
#endif
/* print an "out of memory" diagnostic and exit program */
void
dc_memfail DC_DECLVOID()
{
fprintf(stderr, "%s: out of memory\n", progname);
exit(EXIT_FAILURE);
}
/* malloc or die */
void *
dc_malloc DC_DECLARG((len))
size_t len DC_DECLEND
{
void *result = malloc(len);
if (!result)
dc_memfail();
return result;
}
/* print the id in a human-understandable form
* fp is the output stream to place the output on
* id is the name of the register (or command) to be printed
* suffix is a modifier (such as "stack") to be printed
*/
void
dc_show_id DC_DECLARG((fp, id, suffix))
FILE *fp DC_DECLSEP
int id DC_DECLSEP
const char *suffix DC_DECLEND
{
if (isgraph(id))
fprintf(fp, "'%c' (%#o)%s", id, id, suffix);
else
fprintf(fp, "%#o%s", id, suffix);
}
/* report that corrupt data has been detected;
* use the msg and regid (if nonnegative) to give information
* about where the garbage was found,
*
* will abort() so that a debugger might be used to help find
* the bug
*/
/* If this routine is called, then there is a bug in the code;
* i.e. it is _not_ a data or user error
*/
void
dc_garbage DC_DECLARG((msg, regid))
const char *msg DC_DECLSEP
int regid DC_DECLEND
{
if (regid < 0) {
fprintf(stderr, "%s: garbage %s\n", progname, msg);
} else {
fprintf(stderr, "%s:%s register ", progname, msg);
dc_show_id(stderr, regid, " is garbage\n");
}
abort();
}
/* call system() with the passed string;
* if the string contains a newline, terminate the string
* there before calling system.
* Return a pointer to the first unused character in the string
* (i.e. past the '\n' if there was one, to the '\0' otherwise).
*/
const char *
dc_system DC_DECLARG((s))
const char *s DC_DECLEND
{
const char *p;
char *tmpstr;
size_t len;
p = strchr(s, '\n');
if (p) {
len = p - s;
tmpstr = dc_malloc(len + 1);
strncpy(tmpstr, s, len);
tmpstr[len] = '\0';
system(tmpstr);
free(tmpstr);
return p + 1;
}
system(s);
return s + strlen(s);
}
/* print out the indicated value */
void
dc_print DC_DECLARG((value, obase))
dc_data value DC_DECLSEP
int obase DC_DECLEND
{
if (value.dc_type == DC_NUMBER) {
dc_out_num(value.v.number, obase, DC_TRUE, DC_FALSE);
} else if (value.dc_type == DC_STRING) {
dc_out_str(value.v.string, DC_TRUE, DC_FALSE);
} else {
dc_garbage("in data being printed", -1);
}
}
/* return a duplicate of the passed value, regardless of type */
dc_data
dc_dup DC_DECLARG((value))
dc_data value DC_DECLEND
{
if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
dc_garbage("in value being duplicated", -1);
if (value.dc_type == DC_NUMBER)
return dc_dup_num(value.v.number);
/*else*/
return dc_dup_str(value.v.string);
}

536
contrib/bc/dc/numeric.c Normal file
View File

@ -0,0 +1,536 @@
/*
* interface dc to the bc numeric routines
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* This should be the only module that knows the internals of type dc_num */
/* In this particular implementation we just slather out some glue and
* make use of bc's numeric routines.
*/
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include "bcdefs.h"
#include "proto.h"
#include "global.h"
#include "dc.h"
#include "dc-proto.h"
/* there is no POSIX standard for dc, so we'll take the GNU definitions */
int std_only = FALSE;
/* convert an opaque dc_num into a real bc_num */
#define CastNum(x) ((bc_num)(x))
/* add two dc_nums, place into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_add DC_DECLARG((a, b, kscale, result))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0);
return DC_SUCCESS;
}
/* subtract two dc_nums, place into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_sub DC_DECLARG((a, b, kscale, result))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0);
return DC_SUCCESS;
}
/* multiply two dc_nums, place into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_mul DC_DECLARG((a, b, kscale, result))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale);
return DC_SUCCESS;
}
/* divide two dc_nums, place into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_div DC_DECLARG((a, b, kscale, result))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
fprintf(stderr, "%s: divide by zero\n", progname);
return DC_DOMAIN_ERROR;
}
return DC_SUCCESS;
}
/* divide two dc_nums, place quotient into *quotient and remainder
* into *remainder;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *quotient DC_DECLSEP
dc_num *remainder DC_DECLEND
{
init_num((bc_num *)quotient);
init_num((bc_num *)remainder);
if (bc_divmod(CastNum(a), CastNum(b),
(bc_num *)quotient, (bc_num *)remainder, kscale)){
fprintf(stderr, "%s: divide by zero\n", progname);
return DC_DOMAIN_ERROR;
}
return DC_SUCCESS;
}
/* place the reminder of dividing a by b into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_rem DC_DECLARG((a, b, kscale, result))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
fprintf(stderr, "%s: remainder by zero\n", progname);
return DC_DOMAIN_ERROR;
}
return DC_SUCCESS;
}
int
dc_modexp DC_DECLARG((base, expo, mod, kscale, result))
dc_num base DC_DECLSEP
dc_num expo DC_DECLSEP
dc_num mod DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod),
(bc_num *)result, kscale)){
if (is_zero(CastNum(mod)))
fprintf(stderr, "%s: remainder by zero\n", progname);
return DC_DOMAIN_ERROR;
}
return DC_SUCCESS;
}
/* place the result of exponentiationg a by b into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_exp DC_DECLARG((a, b, kscale, result))
dc_num a DC_DECLSEP
dc_num b DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
init_num((bc_num *)result);
bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale);
return DC_SUCCESS;
}
/* take the square root of the value, place into *result;
* return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
*/
int
dc_sqrt DC_DECLARG((value, kscale, result))
dc_num value DC_DECLSEP
int kscale DC_DECLSEP
dc_num *result DC_DECLEND
{
bc_num tmp;
tmp = copy_num(CastNum(value));
if (!bc_sqrt(&tmp, kscale)){
fprintf(stderr, "%s: square root of negative number\n", progname);
free_num(&tmp);
return DC_DOMAIN_ERROR;
}
*((bc_num *)result) = tmp;
return DC_SUCCESS;
}
/* compare dc_nums a and b;
* return a negative value if a < b;
* return a positive value if a > b;
* return zero value if a == b
*/
int
dc_compare DC_DECLARG((a, b))
dc_num a DC_DECLSEP
dc_num b DC_DECLEND
{
return bc_compare(CastNum(a), CastNum(b));
}
/* attempt to convert a dc_num to its corresponding int value
* If discard_flag is true then deallocate the value after use.
*/
int
dc_num2int DC_DECLARG((value, discard_flag))
dc_num value DC_DECLSEP
dc_boolean discard_flag DC_DECLEND
{
long result;
result = num2long(CastNum(value));
if (discard_flag)
dc_free_num(&value);
return (int)result;
}
/* convert a C integer value into a dc_num */
/* For convenience of the caller, package the dc_num
* into a dc_data result.
*/
dc_data
dc_int2data DC_DECLARG((value))
int value DC_DECLEND
{
dc_data result;
init_num((bc_num *)&result.v.number);
int2num((bc_num *)&result.v.number, value);
result.dc_type = DC_NUMBER;
return result;
}
/* get a dc_num from some input stream;
* input is a function which knows how to read the desired input stream
* ibase is the input base (2<=ibase<=DC_IBASE_MAX)
* *readahead will be set to the readahead character consumed while
* looking for the end-of-number
*/
/* For convenience of the caller, package the dc_num
* into a dc_data result.
*/
dc_data
dc_getnum DC_DECLARG((input, ibase, readahead))
int (*input) DC_PROTO((void)) DC_DECLSEP
int ibase DC_DECLSEP
int *readahead DC_DECLEND
{
bc_num base;
bc_num result;
bc_num build;
bc_num tmp;
bc_num divisor;
dc_data full_result;
int negative = 0;
int digit;
int decimal;
int c;
init_num(&tmp);
init_num(&build);
init_num(&base);
result = copy_num(_zero_);
int2num(&base, ibase);
c = (*input)();
while (isspace(c))
c = (*input)();
if (c == '_' || c == '-'){
negative = c;
c = (*input)();
}else if (c == '+'){
c = (*input)();
}
while (isspace(c))
c = (*input)();
for (;;){
if (isdigit(c))
digit = c - '0';
else if ('A' <= c && c <= 'F')
digit = 10 + c - 'A';
else
break;
c = (*input)();
int2num(&tmp, digit);
bc_multiply(result, base, &result, 0);
bc_add(result, tmp, &result, 0);
}
if (c == '.'){
free_num(&build);
free_num(&tmp);
divisor = copy_num(_one_);
build = copy_num(_zero_);
decimal = 0;
for (;;){
c = (*input)();
if (isdigit(c))
digit = c - '0';
else if ('A' <= c && c <= 'F')
digit = 10 + c - 'A';
else
break;
int2num(&tmp, digit);
bc_multiply(build, base, &build, 0);
bc_add(build, tmp, &build, 0);
bc_multiply(divisor, base, &divisor, 0);
++decimal;
}
bc_divide(build, divisor, &build, decimal);
bc_add(result, build, &result, 0);
}
/* Final work. */
if (negative)
bc_sub(_zero_, result, &result, 0);
free_num(&tmp);
free_num(&build);
free_num(&base);
if (readahead)
*readahead = c;
full_result.v.number = (dc_num)result;
full_result.dc_type = DC_NUMBER;
return full_result;
}
/* return the "length" of the number */
int
dc_numlen DC_DECLARG((value))
dc_num value DC_DECLEND
{
bc_num num = CastNum(value);
/* is this right??? */
return num->n_len + num->n_scale;
}
/* return the scale factor of the passed dc_num
* If discard_flag is true then deallocate the value after use.
*/
int
dc_tell_scale DC_DECLARG((value, discard_flag))
dc_num value DC_DECLSEP
dc_boolean discard_flag DC_DECLEND
{
int kscale;
kscale = CastNum(value)->n_scale;
if (discard_flag)
dc_free_num(&value);
return kscale;
}
/* initialize the math subsystem */
void
dc_math_init DC_DECLVOID()
{
init_numbers();
}
/* print out a dc_num in output base obase to stdout;
* if newline is true, terminate output with a '\n';
* if discard_flag is true then deallocate the value after use
*/
void
dc_out_num DC_DECLARG((value, obase, newline, discard_flag))
dc_num value DC_DECLSEP
int obase DC_DECLSEP
dc_boolean newline DC_DECLSEP
dc_boolean discard_flag DC_DECLEND
{
out_num(CastNum(value), obase, out_char);
if (newline)
out_char('\n');
if (discard_flag)
dc_free_num(&value);
}
/* deallocate an instance of a dc_num */
void
dc_free_num DC_DECLARG((value))
dc_num *value DC_DECLEND
{
free_num((bc_num *)value);
}
/* return a duplicate of the number in the passed value */
/* The mismatched data types forces the caller to deal with
* bad dc_type'd dc_data values, and makes it more convenient
* for the caller to not have to do the grunge work of setting
* up a dc_type result.
*/
dc_data
dc_dup_num DC_DECLARG((value))
dc_num value DC_DECLEND
{
dc_data result;
++CastNum(value)->n_refs;
result.v.number = value;
result.dc_type = DC_NUMBER;
return result;
}
/*---------------------------------------------------------------------------\
| The rest of this file consists of stubs for bc routines called by numeric.c|
| so as to minimize the amount of bc code needed to build dc. |
| The bulk of the code was just lifted straight out of the bc source. |
\---------------------------------------------------------------------------*/
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STDARG_H
# include <stdarg.h>
#else
# include <varargs.h>
#endif
int out_col = 0;
/* Output routines: Write a character CH to the standard output.
It keeps track of the number of characters output and may
break the output with a "\<cr>". */
void
out_char (ch)
char ch;
{
if (ch == '\n')
{
out_col = 0;
putchar ('\n');
}
else
{
out_col++;
if (out_col == 70)
{
putchar ('\\');
putchar ('\n');
out_col = 1;
}
putchar (ch);
}
}
/* Malloc could not get enough memory. */
void
out_of_memory()
{
dc_memfail();
}
/* Runtime error will print a message and stop the machine. */
#ifdef HAVE_STDARG_H
#ifdef __STDC__
void
rt_error (char *mesg, ...)
#else
void
rt_error (mesg)
char *mesg;
#endif
#else
void
rt_error (mesg, va_alist)
char *mesg;
#endif
{
va_list args;
char error_mesg [255];
#ifdef HAVE_STDARG_H
va_start (args, mesg);
#else
va_start (args);
#endif
vsprintf (error_mesg, mesg, args);
va_end (args);
fprintf (stderr, "Runtime error: %s\n", error_mesg);
}
/* A runtime warning tells of some action taken by the processor that
may change the program execution but was not enough of a problem
to stop the execution. */
#ifdef HAVE_STDARG_H
#ifdef __STDC__
void
rt_warn (char *mesg, ...)
#else
void
rt_warn (mesg)
char *mesg;
#endif
#else
void
rt_warn (mesg, va_alist)
char *mesg;
#endif
{
va_list args;
char error_mesg [255];
#ifdef HAVE_STDARG_H
va_start (args, mesg);
#else
va_start (args);
#endif
vsprintf (error_mesg, mesg, args);
va_end (args);
fprintf (stderr, "Runtime warning: %s\n", error_mesg);
}

457
contrib/bc/dc/stack.c Normal file
View File

@ -0,0 +1,457 @@
/*
* implement stack functions for dc
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* This module is the only one that knows what stacks (both the
* regular evaluation stack and the named register stacks)
* look like.
*/
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include "dc.h"
#include "dc-proto.h"
#include "dc-regdef.h"
/* an oft-used error message: */
#define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname)
/* simple linked-list implementaion suffices: */
struct dc_list {
dc_data value;
struct dc_list *link;
};
typedef struct dc_list dc_list;
/* the anonymous evaluation stack */
static dc_list *dc_stack=NULL;
/* the named register stacks */
static dc_list *dc_register[DC_REGCOUNT];
/* allocate a new dc_list item */
static dc_list *
dc_alloc DC_DECLVOID()
{
dc_list *result;
result = dc_malloc(sizeof *result);
result->value.dc_type = DC_UNINITIALIZED;
result->link = NULL;
return result;
}
/* check that there are two numbers on top of the stack,
* then call op with the popped numbers. Construct a dc_data
* value from the dc_num returned by op and push it
* on the stack.
* If the op call doesn't return DC_SUCCESS, then leave the stack
* unmodified.
*/
void
dc_binop DC_DECLARG((op, kscale))
int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP
int kscale DC_DECLEND
{
dc_data a;
dc_data b;
dc_data r;
if (!dc_stack || !dc_stack->link){
Empty_Stack;
return;
}
if (dc_stack->value.dc_type!=DC_NUMBER
|| dc_stack->link->value.dc_type!=DC_NUMBER){
fprintf(stderr, "%s: non-numeric value\n", progname);
return;
}
(void)dc_pop(&b);
(void)dc_pop(&a);
if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){
r.dc_type = DC_NUMBER;
dc_push(r);
dc_free_num(&a.v.number);
dc_free_num(&b.v.number);
}else{
/* op failed; restore the stack */
dc_push(a);
dc_push(b);
}
}
/* check that there are two numbers on top of the stack,
* then call op with the popped numbers. Construct two dc_data
* values from the dc_num's returned by op and push them
* on the stack.
* If the op call doesn't return DC_SUCCESS, then leave the stack
* unmodified.
*/
void
dc_binop2 DC_DECLARG((op, kscale))
int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP
int kscale DC_DECLEND
{
dc_data a;
dc_data b;
dc_data r1;
dc_data r2;
if (!dc_stack || !dc_stack->link){
Empty_Stack;
return;
}
if (dc_stack->value.dc_type!=DC_NUMBER
|| dc_stack->link->value.dc_type!=DC_NUMBER){
fprintf(stderr, "%s: non-numeric value\n", progname);
return;
}
(void)dc_pop(&b);
(void)dc_pop(&a);
if ((*op)(a.v.number, b.v.number, kscale,
&r1.v.number, &r2.v.number) == DC_SUCCESS){
r1.dc_type = DC_NUMBER;
dc_push(r1);
r2.dc_type = DC_NUMBER;
dc_push(r2);
dc_free_num(&a.v.number);
dc_free_num(&b.v.number);
}else{
/* op failed; restore the stack */
dc_push(a);
dc_push(b);
}
}
/* check that there are two numbers on top of the stack,
* then call dc_compare with the popped numbers.
* Return negative, zero, or positive based on the ordering
* of the two numbers.
*/
int
dc_cmpop DC_DECLVOID()
{
int result;
dc_data a;
dc_data b;
if (!dc_stack || !dc_stack->link){
Empty_Stack;
return 0;
}
if (dc_stack->value.dc_type!=DC_NUMBER
|| dc_stack->link->value.dc_type!=DC_NUMBER){
fprintf(stderr, "%s: non-numeric value\n", progname);
return 0;
}
(void)dc_pop(&b);
(void)dc_pop(&a);
result = dc_compare(b.v.number, a.v.number);
dc_free_num(&a.v.number);
dc_free_num(&b.v.number);
return result;
}
/* check that there are three numbers on top of the stack,
* then call op with the popped numbers. Construct a dc_data
* value from the dc_num returned by op and push it
* on the stack.
* If the op call doesn't return DC_SUCCESS, then leave the stack
* unmodified.
*/
void
dc_triop DC_DECLARG((op, kscale))
int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP
int kscale DC_DECLEND
{
dc_data a;
dc_data b;
dc_data c;
dc_data r;
if (!dc_stack || !dc_stack->link || !dc_stack->link->link){
Empty_Stack;
return;
}
if (dc_stack->value.dc_type!=DC_NUMBER
|| dc_stack->link->value.dc_type!=DC_NUMBER
|| dc_stack->link->link->value.dc_type!=DC_NUMBER){
fprintf(stderr, "%s: non-numeric value\n", progname);
return;
}
(void)dc_pop(&c);
(void)dc_pop(&b);
(void)dc_pop(&a);
if ((*op)(a.v.number, b.v.number, c.v.number,
kscale, &r.v.number) == DC_SUCCESS){
r.dc_type = DC_NUMBER;
dc_push(r);
dc_free_num(&a.v.number);
dc_free_num(&b.v.number);
dc_free_num(&c.v.number);
}else{
/* op failed; restore the stack */
dc_push(a);
dc_push(b);
dc_push(c);
}
}
/* initialize the register stacks to their initial values */
void
dc_register_init DC_DECLVOID()
{
int i;
for (i=0; i<DC_REGCOUNT; ++i)
dc_register[i] = NULL;
}
/* clear the evaluation stack */
void
dc_clear_stack DC_DECLVOID()
{
dc_list *n;
dc_list *t;
for (n=dc_stack; n; n=t){
t = n->link;
if (n->value.dc_type == DC_NUMBER)
dc_free_num(&n->value.v.number);
else if (n->value.dc_type == DC_STRING)
dc_free_str(&n->value.v.string);
else
dc_garbage("in stack", -1);
free(n);
}
dc_stack = NULL;
}
/* push a value onto the evaluation stack */
void
dc_push DC_DECLARG((value))
dc_data value DC_DECLEND
{
dc_list *n = dc_alloc();
if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
dc_garbage("in data being pushed", -1);
n->value = value;
n->link = dc_stack;
dc_stack = n;
}
/* push a value onto the named register stack */
void
dc_register_push DC_DECLARG((stackid, value))
int stackid DC_DECLSEP
dc_data value DC_DECLEND
{
dc_list *n = dc_alloc();
stackid = regmap(stackid);
n->value = value;
n->link = dc_register[stackid];
dc_register[stackid] = n;
}
/* set *result to the value on the top of the evaluation stack */
/* The caller is responsible for duplicating the value if it
* is to be maintained as anything more than a transient identity.
*
* DC_FAIL is returned if the stack is empty (and *result unchanged),
* DC_SUCCESS is returned otherwise
*/
int
dc_top_of_stack DC_DECLARG((result))
dc_data *result DC_DECLEND
{
if (!dc_stack){
Empty_Stack;
return DC_FAIL;
}
if (dc_stack->value.dc_type!=DC_NUMBER
&& dc_stack->value.dc_type!=DC_STRING)
dc_garbage("at top of stack", -1);
*result = dc_stack->value;
return DC_SUCCESS;
}
/* set *result to a dup of the value on the top of the named register stack */
/*
* DC_FAIL is returned if the named stack is empty (and *result unchanged),
* DC_SUCCESS is returned otherwise
*/
int
dc_register_get DC_DECLARG((regid, result))
int regid DC_DECLSEP
dc_data *result DC_DECLEND
{
dc_list *r;
regid = regmap(regid);
r = dc_register[regid];
if ( ! r ){
fprintf(stderr, "%s: register ", progname);
dc_show_id(stderr, regid, " is empty\n");
return DC_FAIL;
}
*result = dc_dup(r->value);
return DC_SUCCESS;
}
/* set the top of the named register stack to the indicated value */
/* If the named stack is empty, craft a stack entry to enter the
* value into.
*/
void
dc_register_set DC_DECLARG((regid, value))
int regid DC_DECLSEP
dc_data value DC_DECLEND
{
dc_list *r;
regid = regmap(regid);
r = dc_register[regid];
if ( ! r )
dc_register[regid] = dc_alloc();
else if (r->value.dc_type == DC_NUMBER)
dc_free_num(&r->value.v.number);
else if (r->value.dc_type == DC_STRING)
dc_free_str(&r->value.v.string);
else
dc_garbage("", regid);
dc_register[regid]->value = value;
}
/* pop from the evaluation stack
*
* DC_FAIL is returned if the stack is empty (and *result unchanged),
* DC_SUCCESS is returned otherwise
*/
int
dc_pop DC_DECLARG((result))
dc_data *result DC_DECLEND
{
dc_list *r;
r = dc_stack;
if (!r){
Empty_Stack;
return DC_FAIL;
}
if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
dc_garbage("at top of stack", -1);
*result = r->value;
dc_stack = r->link;
free(r);
return DC_SUCCESS;
}
/* pop from the named register stack
*
* DC_FAIL is returned if the named stack is empty (and *result unchanged),
* DC_SUCCESS is returned otherwise
*/
int
dc_register_pop DC_DECLARG((stackid, result))
int stackid DC_DECLSEP
dc_data *result DC_DECLEND
{
dc_list *r;
stackid = regmap(stackid);
r = dc_register[stackid];
if (!r){
fprintf(stderr, "%s: stack register ", progname);
dc_show_id(stderr, stackid, " is empty\n");
return DC_FAIL;
}
if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING)
dc_garbage(" stack", stackid);
*result = r->value;
dc_register[stackid] = r->link;
free(r);
return DC_SUCCESS;
}
/* tell how many entries are currently on the evaluation stack */
int
dc_tell_stackdepth DC_DECLVOID()
{
dc_list *n;
int depth=0;
for (n=dc_stack; n; n=n->link)
++depth;
return depth;
}
/* return the length of the indicated data value;
* if discard_flag is true, the deallocate the value when done
*
* The definition of a datum's length is deligated to the
* appropriate module.
*/
int
dc_tell_length DC_DECLARG((value, discard_flag))
dc_data value DC_DECLSEP
dc_boolean discard_flag DC_DECLEND
{
int length;
if (value.dc_type == DC_NUMBER){
length = dc_numlen(value.v.number);
if (discard_flag == DC_TRUE)
dc_free_num(&value.v.number);
} else if (value.dc_type == DC_STRING) {
length = dc_strlen(value.v.string);
if (discard_flag == DC_TRUE)
dc_free_str(&value.v.string);
} else {
dc_garbage("in tell_length", -1);
/*NOTREACHED*/
length = 0; /*just to suppress spurious compiler warnings*/
}
return length;
}
/* print out all of the values on the evaluation stack */
void
dc_printall DC_DECLARG((obase))
int obase DC_DECLEND
{
dc_list *n;
for (n=dc_stack; n; n=n->link)
dc_print(n->value, obase);
}

208
contrib/bc/dc/string.c Normal file
View File

@ -0,0 +1,208 @@
/*
* implement string functions for dc
*
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
/* This should be the only module that knows the internals of type dc_string */
#include "config.h"
#include <stdio.h>
#ifdef HAVE_STDDEF_H
# include <stddef.h> /* ptrdiff_t */
#else
# define ptrdiff_t size_t
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h> /* memcpy */
#else
# ifdef HAVE_MEMORY_H
# include <memory.h> /* memcpy, maybe */
# else
# ifdef HAVE_STRINGS_H
# include <strings.h> /* memcpy, maybe */
# endif
# endif
#endif
#include "dc.h"
#include "dc-proto.h"
/* here is the completion of the dc_string type: */
struct dc_string {
char *s_ptr; /* pointer to base of string */
size_t s_len; /* length of counted string */
int s_refs; /* reference count to cut down on memory use by duplicates */
};
/* return a duplicate of the string in the passed value */
/* The mismatched data types forces the caller to deal with
* bad dc_type'd dc_data values, and makes it more convenient
* for the caller to not have to do the grunge work of setting
* up a dc_type result.
*/
dc_data
dc_dup_str DC_DECLARG((value))
dc_str value DC_DECLEND
{
dc_data result;
++value->s_refs;
result.v.string = value;
result.dc_type = DC_STRING;
return result;
}
/* free an instance of a dc_str value */
void
dc_free_str DC_DECLARG((value))
dc_str *value DC_DECLEND
{
struct dc_string *string = *value;
if (--string->s_refs < 1){
free(string->s_ptr);
free(string);
}
}
/* Output a dc_str value.
* Add a trailing newline if "newline" is set.
* Free the value after use if discard_flag is set.
*/
void
dc_out_str DC_DECLARG((value, newline, discard_flag))
dc_str value DC_DECLSEP
dc_boolean newline DC_DECLSEP
dc_boolean discard_flag DC_DECLEND
{
fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout);
if (newline == DC_TRUE)
printf("\n");
if (discard_flag == DC_TRUE)
dc_free_str(&value);
}
/* make a copy of a string (base s, length len)
* into a dc_str value; return a dc_data result
* with this value
*/
dc_data
dc_makestring DC_DECLARG((s, len))
const char *s DC_DECLSEP
size_t len DC_DECLEND
{
dc_data result;
struct dc_string *string;
string = dc_malloc(sizeof *string);
string->s_ptr = dc_malloc(len+1);
memcpy(string->s_ptr, s, len);
string->s_ptr[len] = '\0'; /* nul terminated for those who need it */
string->s_len = len;
string->s_refs = 1;
result.v.string = string;
result.dc_type = DC_STRING;
return result;
}
/* read a dc_str value from FILE *fp;
* if ldelim == rdelim, then read until a ldelim char or EOF is reached;
* if ldelim != rdelim, then read until a matching rdelim for the
* (already eaten) first ldelim is read.
* Return a dc_data result with the dc_str value as its contents.
*/
dc_data
dc_readstring DC_DECLARG((fp, ldelim, rdelim))
FILE *fp DC_DECLSEP
int ldelim DC_DECLSEP
int rdelim DC_DECLEND
{
static char *line_buf = NULL; /* a buffer to build the string in */
static size_t buflen = 0; /* the current size of line_buf */
int depth=1;
int c;
char *p;
const char *end;
if (!line_buf){
/* initial buflen should be large enough to handle most cases */
buflen = 2016;
line_buf = dc_malloc(buflen);
}
p = line_buf;
end = line_buf + buflen;
for (;;){
c = getc(fp);
if (c == EOF)
break;
else if (c == rdelim && --depth < 1)
break;
else if (c == ldelim)
++depth;
if (p >= end){
ptrdiff_t offset = p - line_buf;
/* buflen increment should be big enough
* to avoid execessive reallocs:
*/
buflen += 2048;
line_buf = realloc(line_buf, buflen);
if (!line_buf)
dc_memfail();
p = line_buf + offset;
end = line_buf + buflen;
}
*p++ = c;
}
return dc_makestring(line_buf, (size_t)(p-line_buf));
}
/* return the base pointer of the dc_str value;
* This function is needed because no one else knows what dc_str
* looks like.
*/
const char *
dc_str2charp DC_DECLARG((value))
dc_str value DC_DECLEND
{
return value->s_ptr;
}
/* return the length of the dc_str value;
* This function is needed because no one else knows what dc_str
* looks like, and strlen(dc_str2charp(value)) won't work
* if there's an embedded '\0'.
*/
size_t
dc_strlen DC_DECLARG((value))
dc_str value DC_DECLEND
{
return value->s_len;
}
/* initialize the strings subsystem */
void
dc_string_init DC_DECLVOID()
{
/* nothing to do for this implementation */
}

View File

@ -0,0 +1,10 @@
## Process this file with automake to produce Makefile.in
info_TEXINFOS = dc.texi
MAKEINFO = makeinfo --no-split
# FIXME: remove this when automake has been fixed to include these
# files automatically
EXTRA_DIST = bc.1 dc.1
man_MANS = bc.1 dc.1

280
contrib/bc/doc/Makefile.in Normal file
View File

@ -0,0 +1,280 @@
# Makefile.in generated automatically by automake 1.1n from Makefile.am
# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
SHELL = /bin/sh
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = true
PRE_INSTALL = true
POST_INSTALL = true
NORMAL_UNINSTALL = true
PRE_UNINSTALL = true
POST_UNINSTALL = true
CC = @CC@
LEX = @LEX@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
VERSION = @VERSION@
YACC = @YACC@
info_TEXINFOS = dc.texi
MAKEINFO = makeinfo --no-split
# FIXME: remove this when automake has been fixed to include these
# files automatically
EXTRA_DIST = bc.1 dc.1
man_MANS = bc.1 dc.1
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
TEXI2DVI = texi2dvi
TEXINFO_TEX = $(srcdir)/texinfo.tex
INFO_DEPS = dc.info
DVIS = dc.dvi
TEXINFOS = dc.texi
MANS = bc.1 dc.1
NROFF = nroff
DIST_COMMON = Makefile.am Makefile.in texinfo.tex
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP = --best
default: all
.SUFFIXES:
.SUFFIXES: .texi .texinfo .info .dvi .ps
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
dc.info: dc.texi
dc.dvi: dc.texi
DVIPS = dvips
.texi.info:
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texi.dvi:
TEXINPUTS=$(srcdir):$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
.texi:
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texinfo.info:
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texinfo:
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texinfo.dvi:
TEXINPUTS=$(srcdir):$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
.dvi.ps:
$(DVIPS) $< -o $@
install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(infodir)
@for file in $(INFO_DEPS); do \
d=$(srcdir); \
for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \
if test -f $$d/$$ifile; then \
echo " $(INSTALL_DATA) $$d/$$ifile $(infodir)/$$ifile"; \
$(INSTALL_DATA) $$d/$$ifile $(infodir)/$$ifile; \
else : ; fi; \
done; \
done
@$(POST_INSTALL)
@if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \
for file in $(INFO_DEPS); do \
echo " install-info --info-dir=$(infodir) $(infodir)/$$file";\
install-info --info-dir=$(infodir) $(infodir)/$$file; :;\
done; \
else : ; fi
uninstall-info:
$(PRE_UNINSTALL)
if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \
ii=yes; \
else ii=; fi; \
for file in $(INFO_DEPS); do \
test -z $ii || install-info --info-dir=$(infodir) --remove $$file; \
done
$(NORMAL_UNINSTALL)
for file in $(INFO_DEPS); do \
(cd $(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \
done
dist-info: $(INFO_DEPS)
for base in $(INFO_DEPS); do \
d=$(srcdir); \
for file in `cd $$d && eval echo $$base*`; do \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done; \
done
mostlyclean-info:
rm -f dc.aux dc.cp dc.cps dc.dvi dc.fn dc.fns dc.ky dc.log dc.pg dc.toc \
dc.tp dc.tps dc.vr dc.vrs dc.op dc.tr dc.cv
clean-info:
distclean-info:
maintainer-clean-info:
for i in $(INFO_DEPS); do rm -f `eval echo $$i*`; done
install-man: $(MANS)
$(NORMAL_INSTALL)
$(mkinstalldirs) $(mandir)/man1
@sect=1; \
inst=`echo "bc" | sed '$(transform)'`.1; \
if test -f $(srcdir)/bc.1; then file=$(srcdir)/bc.1; \
else file=bc.1; fi; \
echo " $(INSTALL_DATA) $$file $(mandir)/man$$sect/$$inst"; \
$(INSTALL_DATA) $$file $(mandir)/man$$sect/$$inst
@sect=1; \
inst=`echo "dc" | sed '$(transform)'`.1; \
if test -f $(srcdir)/dc.1; then file=$(srcdir)/dc.1; \
else file=dc.1; fi; \
echo " $(INSTALL_DATA) $$file $(mandir)/man$$sect/$$inst"; \
$(INSTALL_DATA) $$file $(mandir)/man$$sect/$$inst
uninstall-man:
$(NORMAL_UNINSTALL)
inst=`echo "bc" | sed '$(transform)'`.1; \
rm -f $(mandir)/man1/$$inst
inst=`echo "dc" | sed '$(transform)'`.1; \
rm -f $(mandir)/man1/$$inst
tags: TAGS
TAGS:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = doc
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done
$(MAKE) distdir="$(distdir)" dist-info
info: $(INFO_DEPS)
dvi: $(DVIS)
check: all
$(MAKE)
installcheck:
install-exec:
@$(NORMAL_INSTALL)
install-data: install-info-am install-man
@$(NORMAL_INSTALL)
install: install-exec install-data all
@:
uninstall: uninstall-info uninstall-man
all: $(INFO_DEPS) $(MANS) Makefile
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
installdirs:
$(mkinstalldirs) $(infodir) $(mandir)/man1
mostlyclean-generic:
test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
rm -f Makefile $(DISTCLEANFILES)
rm -f config.cache config.log stamp-h
test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean: mostlyclean-info mostlyclean-generic
clean: clean-info clean-generic mostlyclean
distclean: distclean-info distclean-generic clean
rm -f config.status
maintainer-clean: maintainer-clean-info maintainer-clean-generic \
distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
.PHONY: default install-info-am uninstall-info mostlyclean-info \
distclean-info clean-info maintainer-clean-info install-man \
uninstall-man tags distdir info dvi installcheck install-exec \
install-data install uninstall all installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

787
contrib/bc/doc/bc.1 Normal file
View File

@ -0,0 +1,787 @@
.\"
.\" bc.1 - the *roff document processor source for the bc manual
.\"
.\" This file is part of GNU bc.
.\" Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
.\"
.\" 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 2 of the License , 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; see the file COPYING. If not, write to
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
.\"
.\" You may contact the author by:
.\" e-mail: phil@cs.wwu.edu
.\" us-mail: Philip A. Nelson
.\" Computer Science Department, 9062
.\" Western Washington University
.\" Bellingham, WA 98226-9062
.\"
.\"
.TH bc 1 .\" "Command Manual" v1.04 "June 22, 1995"
.SH NAME
bc - An arbitrary precision calculator language
.SH SYNTAX
\fBbc\fR [ \fB-lwsqv\fR ] [long-options] [ \fI file ...\fR ]
.SH VERSION
This man page documents GNU bc version 1.04.
.SH DESCRIPTION
\fBbc\fR is a language that supports arbitrary precision numbers
with interactive execution of statements. There are some similarities
in the syntax to the C programming language.
A standard math library is available by command line option.
If requested, the math library is defined before processing any files.
\fBbc\fR starts by processing code from all the files listed
on the command line in the order listed. After all files have been
processed, \fBbc\fR reads from the standard input. All code is
executed as it is read. (If a file contains a command to halt the
processor, \fBbc\fR will never read from the standard input.)
.PP
This version of \fBbc\fR contains several extensions beyond
traditional \fBbc\fR implementations and the POSIX draft standard.
Command line options can cause these extensions to print a warning
or to be rejected. This
document describes the language accepted by this processor.
Extensions will be identified as such.
.SS OPTIONS
.IP -l
Define the standard math library.
.IP -w
Give warnings for extensions to POSIX \fBbc\fR.
.IP -s
Process exactly the POSIX \fBbc\fR language.
.IP -q
Do not print the normal GNU bc welcome.
.IP -v
Print the version number and copyright and quit.
.IP --mathlib
Define the standard math library.
.IP --warn
Give warnings for extensions to POSIX \fBbc\fR.
.IP --standard
Process exactly the POSIX \fBbc\fR language.
.IP --quiet
Do not print the normal GNU bc welcome.
.IP --version
Print the version number and copyright and quit.
.SS NUMBERS
The most basic element in \fBbc\fR is the number. Numbers are
arbitrary precision numbers. This precision is both in the integer
part and the fractional part. All numbers are represented internally
in decimal and all computation is done in decimal. (This version
truncates results from divide and multiply operations.) There are two
attributes of numbers, the length and the scale. The length is the
total number of significant decimal digits in a number and the scale
is the total number of decimal digits after the decimal point. For
example:
.nf
.RS
.000001 has a length of 6 and scale of 6.
1935.000 has a length of 7 and a scale of 3.
.RE
.fi
.SS VARIABLES
Numbers are stored in two types of variables, simple variables and
arrays. Both simple variables and array variables are named. Names
begin with a letter followed by any number of letters, digits and
underscores. All letters must be lower case. (Full alpha-numeric
names are an extension. In POSIX \fBbc\fR all names are a single
lower case letter.) The type of variable is clear by the context
because all array variable names will be followed by brackets ([]).
.PP
There are four special variables, \fBscale, ibase, obase,\fR and
\fBlast\fR. \fBscale\fR defines how some operations use digits after the
decimal point. The default value of \fBscale\fR is 0. \fBibase\fR
and \fBobase\fR define the conversion base for input and output
numbers. The default for both input and output is base 10.
\fBlast\fR (an extension) is a variable that has the value of the last
printed number. These will be discussed in further detail where
appropriate. All of these variables may have values assigned to them
as well as used in expressions.
.SS COMMENTS
Comments in \fBbc\fR start with the characters \fB/*\fR and end with
the characters \fB*/\fR. Comments may start anywhere and appear as a
single space in the input. (This causes comments to delimit other
input items. For example, a comment can not be found in the middle of
a variable name.) Comments include any newlines (end of line) between
the start and the end of the comment.
.PP
To support the use of scripts for \fBbc\fR, a single line comment has been
added as an extension. A single line comment starts at a \fB#\fR
character and continues to the next end of the line. The end of line
character is not part of the comment and is processed normally.
.SS EXPRESSIONS
The numbers are manipulated by expressions and statements. Since
the language was designed to be interactive, statements and expressions
are executed as soon as possible. There is no "main" program. Instead,
code is executed as it is encountered. (Functions, discussed in
detail later, are defined when encountered.)
.PP
A simple expression is just a constant. \fBbc\fR converts constants
into internal decimal numbers using the current input base, specified
by the variable \fBibase\fR. (There is an exception in functions.)
The legal values of \fBibase\fR are 2 through 16. Assigning a
value outside this range to \fBibase\fR will result in a value of 2
or 16. Input numbers may contain the characters 0-9 and A-F. (Note:
They must be capitals. Lower case letters are variable names.)
Single digit numbers always have the value of the digit regardless of
the value of \fBibase\fR. (i.e. A = 10.) For multi-digit numbers,
\fBbc\fR changes all input digits greater or equal to ibase to the
value of \fBibase\fR-1. This makes the number \fBFFF\fR always be
the largest 3 digit number of the input base.
.PP
Full expressions are similar to many other high level languages.
Since there is only one kind of number, there are no rules for mixing
types. Instead, there are rules on the scale of expressions. Every
expression has a scale. This is derived from the scale of original
numbers, the operation performed and in many cases, the value of the
variable \fBscale\fR. Legal values of the variable \fBscale\fR are
0 to the maximum number representable by a C integer.
.PP
In the following descriptions of legal expressions, "expr" refers to a
complete expression and "var" refers to a simple or an array variable.
A simple variable is just a
.RS
\fIname\fR
.RE
and an array variable is specified as
.RS
\fIname\fR[\fIexpr\fR]
.RE
Unless specifically
mentioned the scale of the result is the maximum scale of the
expressions involved.
.IP "- expr"
The result is the negation of the expression.
.IP "++ var"
The variable is incremented by one and the new value is the result of
the expression.
.IP "-- var"
The variable
is decremented by one and the new value is the result of the
expression.
.IP "var ++"
The result of the expression is the value of
the variable and then the variable is incremented by one.
.IP "var --"
The result of the expression is the value of the variable and then
the variable is decremented by one.
.IP "expr + expr"
The result of the expression is the sum of the two expressions.
.IP "expr - expr"
The result of the expression is the difference of the two expressions.
.IP "expr * expr"
The result of the expression is the product of the two expressions.
.IP "expr / expr"
The result of the expression is the quotient of the two expressions.
The scale of the result is the value of the variable \fBscale\fR.
.IP "expr % expr"
The result of the expression is the "remainder" and it is computed in the
following way. To compute a%b, first a/b is computed to \fBscale\fR
digits. That result is used to compute a-(a/b)*b to the scale of the
maximum of \fBscale\fR+scale(b) and scale(a). If \fBscale\fR is set
to zero and both expressions are integers this expression is the
integer remainder function.
.IP "expr ^ expr"
The result of the expression is the value of the first raised to the
second. The second expression must be an integer. (If the second
expression is not an integer, a warning is generated and the
expression is truncated to get an integer value.) The scale of the
result is \fBscale\fR if the exponent is negative. If the exponent
is positive the scale of the result is the minimum of the scale of the
first expression times the value of the exponent and the maximum of
\fBscale\fR and the scale of the first expression. (e.g. scale(a^b)
= min(scale(a)*b, max( \fBscale,\fR scale(a))).) It should be noted
that expr^0 will always return the value of 1.
.IP "( expr )"
This alters the standard precedence to force the evaluation of the
expression.
.IP "var = expr"
The variable is assigned the value of the expression.
.IP "var <op>= expr"
This is equivalent to "var = var <op> expr" with the exception that
the "var" part is evaluated only once. This can make a difference if
"var" is an array.
.PP
Relational expressions are a special kind of expression
that always evaluate to 0 or 1, 0 if the relation is false and 1 if
the relation is true. These may appear in any legal expression.
(POSIX bc requires that relational expressions are used only in if,
while, and for statements and that only one relational test may be
done in them.) The relational operators are
.IP "expr1 < expr2"
The result is 1 if expr1 is strictly less than expr2.
.IP "expr1 <= expr2"
The result is 1 if expr1 is less than or equal to expr2.
.IP "expr1 > expr2"
The result is 1 if expr1 is strictly greater than expr2.
.IP "expr1 >= expr2"
The result is 1 if expr1 is greater than or equal to expr2.
.IP "expr1 == expr2"
The result is 1 if expr1 is equal to expr2.
.IP "expr1 != expr2"
The result is 1 if expr1 is not equal to expr2.
.PP
Boolean operations are also legal. (POSIX \fBbc\fR does NOT have
boolean operations). The result of all boolean operations are 0 and 1
(for false and true) as in relational expressions. The boolean
operators are:
.IP "!expr"
The result is 1 if expr is 0.
.IP "expr && expr"
The result is 1 if both expressions are non-zero.
.IP "expr || expr"
The result is 1 if either expression is non-zero.
.PP
The expression precedence is as follows: (lowest to highest)
.nf
.RS
|| operator, left associative
&& operator, left associative
! operator, nonassociative
Relational operators, left associative
Assignment operator, right associative
+ and - operators, left associative
*, / and % operators, left associative
^ operator, right associative
unary - operator, nonassociative
++ and -- operators, nonassociative
.RE
.fi
.PP
This precedence was chosen so that POSIX compliant \fBbc\fR programs
will run correctly. This will cause the use of the relational and
logical operators to have some unusual behavior when used with
assignment expressions. Consider the expression:
.RS
a = 3 < 5
.RE
.PP
Most C programmers would assume this would assign the result of "3 <
5" (the value 1) to the variable "a". What this does in \fBbc\fR is
assign the value 3 to the variable "a" and then compare 3 to 5. It is
best to use parenthesis when using relational and logical operators
with the assignment operators.
.PP
There are a few more special expressions that are provided in \fBbc\fR.
These have to do with user defined functions and standard
functions. They all appear as "\fIname\fB(\fIparameters\fB)\fR".
See the section on functions for user defined functions. The standard
functions are:
.IP "length ( expression )"
The value of the length function is the number of significant digits in the
expression.
.IP "read ( )"
The read function (an extension) will read a number from the standard
input, regardless of where the function occurs. Beware, this can
cause problems with the mixing of data and program in the standard input.
The best use for this function is in a previously written program that
needs input from the user, but never allows program code to be input
from the user. The value of the read function is the number read from
the standard input using the current value of the variable
\fBibase\fR for the conversion base.
.IP "scale ( expression )"
The value of the scale function is the number of digits after the decimal
point in the expression.
.IP "sqrt ( expression )"
The value of the sqrt function is the square root of the expression. If
the expression is negative, a run time error is generated.
.SS STATEMENTS
Statements (as in most algebraic languages) provide the sequencing of
expression evaluation. In \fBbc\fR statements are executed "as soon
as possible." Execution happens when a newline in encountered and
there is one or more complete statements. Due to this immediate
execution, newlines are very important in \fBbc\fR. In fact, both a
semicolon and a newline are used as statement separators. An
improperly placed newline will cause a syntax error. Because newlines
are statement separators, it is possible to hide a newline by using
the backslash character. The sequence "\e<nl>", where <nl> is the
newline appears to \fBbc\fR as whitespace instead of a newline. A
statement list is a series of statements separated by semicolons and
newlines. The following is a list of \fBbc\fR statements and what
they do: (Things enclosed in brackets ([]) are optional parts of the
statement.)
.IP "expression"
This statement does one of two things. If the expression starts with
"<variable> <assignment> ...", it is considered to be an assignment
statement. If the expression is not an assignment statement, the
expression is evaluated and printed to the output. After the number
is printed, a newline is printed. For example, "a=1" is an assignment
statement and "(a=1)" is an expression that has an embedded
assignment. All numbers that are printed are printed in the base
specified by the variable \fBobase\fR. The legal values for \fB
obase\fR are 2 through BC_BASE_MAX. (See the section LIMITS.) For
bases 2 through 16, the usual method of writing numbers is used. For
bases greater than 16, \fBbc\fR uses a multi-character digit method
of printing the numbers where each higher base digit is printed as a
base 10 number. The multi-character digits are separated by spaces.
Each digit contains the number of characters required to represent the
base ten value of "obase-1". Since numbers are of arbitrary
precision, some numbers may not be printable on a single output line.
These long numbers will be split across lines using the "\e" as the
last character on a line. The maximum number of characters printed
per line is 70. Due to the interactive nature of \fBbc\fR printing
a number cause the side effect of assigning the printed value the the
special variable \fBlast\fR. This allows the user to recover the
last value printed without having to retype the expression that
printed the number. Assigning to \fBlast\fR is legal and will
overwrite the last printed value with the assigned value. The newly
assigned value will remain until the next number is printed or another
value is assigned to \fBlast\fR. (Some installations may allow the
use of a single period (.) which is not part of a number as a short
hand notation for for \fBlast\fR.)
.IP "string"
The string is printed to the output. Strings start with a double quote
character and contain all characters until the next double quote character.
All characters are take literally, including any newline. No newline
character is printed after the string.
.IP "\fBprint\fR list"
The print statement (an extension) provides another method of output.
The "list" is a list of strings and expressions separated by commas.
Each string or expression is printed in the order of the list. No
terminating newline is printed. Expressions are evaluated and their
value is printed and assigned the the variable \fBlast\fR. Strings
in the print statement are printed to the output and may contain
special characters. Special characters start with the backslash
character (\e). The special characters recognized by \fBbc\fR are
"a" (alert or bell), "b" (backspace), "f" (form feed), "n" (newline),
"r" (carriage return), "q" (double quote), "t" (tab), and "\e" (backslash).
Any other character following the backslash will be ignored.
.IP "{ statement_list }"
This is the compound statement. It allows multiple statements to be
grouped together for execution.
.IP "\fBif\fR ( expression ) statement1 [\fBelse\fR statement2]"
The if statement evaluates the expression and executes statement1 or
statement2 depending on the value of the expression. If the expression
is non-zero, statement1 is executed. If statement2 is present and
the value of the expression is 0, then statement2 is executed. (The
else clause is an extension.)
.IP "\fBwhile\fR ( expression ) statement"
The while statement will execute the statement while the expression
is non-zero. It evaluates the expression before each execution of
the statement. Termination of the loop is caused by a zero
expression value or the execution of a break statement.
.IP "\fBfor\fR ( [expression1] ; [expression2] ; [expression3] ) statement"
The for statement controls repeated execution of the statement.
Expression1 is evaluated before the loop. Expression2 is evaluated
before each execution of the statement. If it is non-zero, the statement
is evaluated. If it is zero, the loop is terminated. After each
execution of the statement, expression3 is evaluated before the reevaluation
of expression2. If expression1 or expression3 are missing, nothing is
evaluated at the point they would be evaluated.
If expression2 is missing, it is the same as substituting
the value 1 for expression2. (The optional expressions are an
extension. POSIX \fBbc\fR requires all three expressions.)
The following is equivalent code for the for statement:
.nf
.RS
expression1;
while (expression2) {
statement;
expression3;
}
.RE
.fi
.IP "\fBbreak\fR"
This statement causes a forced exit of the most recent enclosing while
statement or for statement.
.IP "\fBcontinue\fR"
The continue statement (an extension) causes the most recent enclosing
for statement to start the next iteration.
.IP "\fBhalt\fR"
The halt statement (an extension) is an executed statement that causes
the \fBbc\fR processor to quit only when it is executed. For example,
"if (0 == 1) halt" will not cause \fBbc\fR to terminate because the halt is
not executed.
.IP "\fBreturn\fR"
Return the value 0 from a function. (See the section on functions.)
.IP "\fBreturn\fR ( expression )"
Return the value of the expression from a function. (See the section on
functions.)
.SS PSEUDO STATEMENTS
These statements are not statements in the traditional sense. They are
not executed statements. Their function is performed at "compile" time.
.IP "\fBlimits\fR"
Print the local limits enforced by the local version of \fBbc\fR. This
is an extension.
.IP "\fBquit\fR"
When the quit statement is read, the \fBbc\fR processor
is terminated, regardless of where the quit statement is found. For
example, "if (0 == 1) quit" will cause \fBbc\fR to terminate.
.IP "\fBwarranty\fR"
Print a longer warranty notice. This is an extension.
.SS FUNCTIONS
Functions provide a method of defining a computation that can be executed
later. Functions in
.B bc
always compute a value and return it to the caller. Function definitions
are "dynamic" in the sense that a function is undefined until a definition
is encountered in the input. That definition is then used until another
definition function for the same name is encountered. The new definition
then replaces the older definition. A function is defined as follows:
.nf
.RS
\fBdefine \fIname \fB( \fIparameters \fB) { \fInewline
\fI auto_list statement_list \fB}\fR
.RE
.fi
A function call is just an expression of the form
"\fIname\fB(\fIparameters\fB)\fR".
.PP
Parameters are numbers or arrays (an extension). In the function definition,
zero or more parameters are defined by listing their names separated by
commas. Numbers are only call by value parameters. Arrays are only
call by variable. Arrays are specified in the parameter definition by
the notation "\fIname\fB[]\fR". In the function call, actual parameters
are full expressions for number parameters. The same notation is used
for passing arrays as for defining array parameters. The named array is
passed by variable to the function. Since function definitions are dynamic,
parameter numbers and types are checked when a function is called. Any
mismatch in number or types of parameters will cause a runtime error.
A runtime error will also occur for the call to an undefined function.
.PP
The \fIauto_list\fR is an optional list of variables that are for
"local" use. The syntax of the auto list (if present) is "\fBauto
\fIname\fR, ... ;". (The semicolon is optional.) Each \fIname\fR is
the name of an auto variable. Arrays may be specified by using the
same notation as used in parameters. These variables have their
values pushed onto a stack at the start of the function. The
variables are then initialized to zero and used throughout the
execution of the function. At function exit, these variables are
popped so that the original value (at the time of the function call)
of these variables are restored. The parameters are really auto
variables that are initialized to a value provided in the function
call. Auto variables are different than traditional local variables
in the fact that if function A calls function B, B may access function
A's auto variables by just using the same name, unless function B has
called them auto variables. Due to the fact that auto variables and
parameters are pushed onto a stack, \fBbc\fR supports recursive functions.
.PP
The function body is a list of \fBbc\fR statements. Again, statements
are separated by semicolons or newlines. Return statements cause the
termination of a function and the return of a value. There are two
versions of the return statement. The first form, "\fBreturn\fR", returns
the value 0 to the calling expression. The second form,
"\fBreturn ( \fIexpression \fB)\fR", computes the value of the expression
and returns that value to the calling expression. There is an implied
"\fBreturn (0)\fR" at the end of every function. This allows a function
to terminate and return 0 without an explicit return statement.
.PP
Functions also change the usage of the variable \fBibase\fR. All
constants in the function body will be converted using the value of
\fBibase\fR at the time of the function call. Changes of \fBibase\fR
will be ignored during the execution of the function except for the
standard function \fBread\fR, which will always use the current value
of \fBibase\fR for conversion of numbers.
.SS MATH LIBRARY
If \fBbc\fR is invoked with the \fB-l\fR option, a math library is preloaded
and the default scale is set to 20. The math functions will calculate their
results to the scale set at the time of their call.
The math library defines the following functions:
.IP "s (\fIx\fR)"
The sine of x, x is in radians.
.IP "c (\fIx\fR)"
The cosine of x, x is in radians.
.IP "a (\fIx\fR)"
The arctangent of x, arctangent returns radians.
.IP "l (\fIx\fR)"
The natural logarithm of x.
.IP "e (\fIx\fR)"
The exponential function of raising e to the value x.
.IP "j (\fIn,x\fR)"
The bessel function of integer order n of x.
.SS EXAMPLES
In /bin/sh, the following will assign the value of "pi" to the shell
variable \fBpi\fR.
.RS
\f(CW
pi=$(echo "scale=10; 4*a(1)" | bc -l)
\fR
.RE
.PP
The following is the definition of the exponential function used in the
math library. This function is written in POSIX \fBbc\fR.
.nf
.RS
\f(CW
scale = 20
/* Uses the fact that e^x = (e^(x/2))^2
When x is small enough, we use the series:
e^x = 1 + x + x^2/2! + x^3/3! + ...
*/
define e(x) {
auto a, d, e, f, i, m, v, z
/* Check the sign of x. */
if (x<0) {
m = 1
x = -x
}
/* Precondition x. */
z = scale;
scale = 4 + z + .44*x;
while (x > 1) {
f += 1;
x /= 2;
}
/* Initialize the variables. */
v = 1+x
a = x
d = 1
for (i=2; 1; i++) {
e = (a *= x) / (d *= i)
if (e == 0) {
if (f>0) while (f--) v = v*v;
scale = z
if (m) return (1/v);
return (v/1);
}
v += e
}
}
\fR
.RE
.fi
.PP
The following is code that uses the extended features of \fBbc\fR to
implement a simple program for calculating checkbook balances. This
program is best kept in a file so that it can be used many times
without having to retype it at every use.
.nf
.RS
\f(CW
scale=2
print "\enCheck book program!\en"
print " Remember, deposits are negative transactions.\en"
print " Exit by a 0 transaction.\en\en"
print "Initial balance? "; bal = read()
bal /= 1
print "\en"
while (1) {
"current balance = "; bal
"transaction? "; trans = read()
if (trans == 0) break;
bal -= trans
bal /= 1
}
quit
\fR
.RE
.fi
.PP
The following is the definition of the recursive factorial function.
.nf
.RS
\f(CW
define f (x) {
if (x <= 1) return (1);
return (f(x-1) * x);
}
\fR
.RE
.fi
.SS READLINE OPTION
GNU \fBbc\fR can be compiled (via a configure option) to use the
GNU \fBreadline\fR input editor library. This allows the user
to do more editing of lines before sending them to \fBbc\fR.
It also allows for a history of previous lines typed. When this
option is selected, \fBbc\fR has one more special variable.
This special variable, \fBhistory\fR is the number of lines of
history retained. A value of -1 means that an unlimited number
of history lines are retained. This is the default value.
Setting the value of \fBhistory\fR to a positive number restricts
the number of history lines to the number given. The value of
0 disables the history feature. For more information, read the
user manuals for the GNU \fBreadline\fR and \fBhistory\fR libraries.
.SS DIFFERENCES
This version of
.B bc
was implemented from the POSIX P1003.2/D11 draft and contains
several differences and extensions relative to the draft and
traditional implementations.
It is not implemented in the traditional way using
.I dc(1).
This version is a single process which parses and runs a byte code
translation of the program. There is an "undocumented" option (-c)
that causes the program to output the byte code to
the standard output instead of running it. It was mainly used for
debugging the parser and preparing the math library.
.PP
A major source of differences is
extensions, where a feature is extended to add more functionality and
additions, where new features are added.
The following is the list of differences and extensions.
.IP LANG environment
This version does not conform to the POSIX standard in the processing
of the LANG environment variable and all environment variables starting
with LC_.
.IP names
Traditional and POSIX
.B bc
have single letter names for functions, variables and arrays. They have
been extended to be multi-character names that start with a letter and
may contain letters, numbers and the underscore character.
.IP Strings
Strings are not allowed to contain NUL characters. POSIX says all characters
must be included in strings.
.IP last
POSIX \fBbc\fR does not have a \fBlast\fR variable. Some implementations
of \fBbc\fR use the period (.) in a similar way.
.IP comparisons
POSIX \fBbc\fR allows comparisons only in the if statement, the while
statement, and the second expression of the for statement. Also, only
one relational operation is allowed in each of those statements.
.IP "if statement, else clause"
POSIX \fBbc\fR does not have an else clause.
.IP "for statement"
POSIX \fBbc\fR requires all expressions to be present in the for statement.
.IP "&&, ||, !"
POSIX \fBbc\fR does not have the logical operators.
.IP "read function"
POSIX \fBbc\fR does not have a read function.
.IP "print statement"
POSIX \fBbc\fR does not have a print statement .
.IP "continue statement"
POSIX \fBbc\fR does not have a continue statement.
.IP "array parameters"
POSIX \fBbc\fR does not (currently) support array parameters in full.
The POSIX grammar allows for arrays in function definitions, but does
not provide a method to specify an array as an actual parameter. (This
is most likely an oversight in the grammar.) Traditional implementations
of \fBbc\fR have only call by value array parameters.
.IP "=+, =-, =*, =/, =%, =^"
POSIX \fBbc\fR does not require these "old style" assignment operators to
be defined. This version may allow these "old style" assignments. Use
the limits statement to see if the installed version supports them. If
it does support the "old style" assignment operators, the statement
"a =- 1" will decrement \fBa\fR by 1 instead of setting \fBa\fR to the
value -1.
.IP "spaces in numbers"
Other implementations of \fBbc\fR allow spaces in numbers. For example,
"x=1 3" would assign the value 13 to the variable x. The same statement
would cause a syntax error in this version of \fBbc\fR.
.IP "errors and execution"
This implementation varies from other implementations in terms of what
code will be executed when syntax and other errors are found in the
program. If a syntax error is found in a function definition, error
recovery tries to find the beginning of a statement and continue to
parse the function. Once a syntax error is found in the function, the
function will not be callable and becomes undefined.
Syntax errors in the interactive execution code will invalidate the
current execution block. The execution block is terminated by an
end of line that appears after a complete sequence of statements.
For example,
.nf
.RS
a = 1
b = 2
.RE
.fi
has two execution blocks and
.nf
.RS
{ a = 1
b = 2 }
.RE
.fi
has one execution block. Any runtime error will terminate the execution
of the current execution block. A runtime warning will not terminate the
current execution block.
.IP "Interrupts"
During an interactive session, the SIGINT signal (usually generated by
the control-C character from the terminal) will cause execution of the
current execution block to be interrupted. It will display a "runtime"
error indicating which function was interrupted. After all runtime
structures have been cleaned up, a message will be printed to notify the
user that \fBbc\fR is ready for more input. All previously defined functions
remain defined and the value of all non-auto variables are the value at
the point of interruption. All auto variables and function parameters
are removed during the
clean up process. During a non-interactive
session, the SIGINT signal will terminate the entire run of \fBbc\fR.
.SS LIMITS
The following are the limits currently in place for this
.B bc
processor. Some of them may have been changed by an installation.
Use the limits statement to see the actual values.
.IP BC_BASE_MAX
The maximum output base is currently set at 999. The maximum input base
is 16.
.IP BC_DIM_MAX
This is currently an arbitrary limit of 65535 as distributed. Your
installation may be different.
.IP BC_SCALE_MAX
The number of digits after the decimal point is limited to INT_MAX digits.
Also, the number of digits before the decimal point is limited to INT_MAX
digits.
.IP BC_STRING_MAX
The limit on the number of characters in a string is INT_MAX characters.
.IP exponent
The value of the exponent in the raise operation (^) is limited to LONG_MAX.
.IP multiply
The multiply routine may yield incorrect results if a number
has more than LONG_MAX / 90 total digits. For 32 bit longs, this number is
23,860,929 digits.
.IP "code size"
Each function and the "main" program are limited to 16384 bytes of
compiled byte code each. This limit (BC_MAX_SEGS) can be easily changed
to have more than 16 segments of 1024 bytes.
.IP "variable names"
The current limit on the number of unique names is 32767 for each of
simple variables, arrays and functions.
.SH ENVIRONMENT VARIABLES
The following environment variables are processed by \fBbc\fR:
.IP "POSIXLY_CORRECT"
This is the same as the \fB-s\fR option.
.IP "BC_ENV_ARGS"
This is another mechanism to get arguments to \fBbc\fR. The
format is the same as the command line arguments. These arguments
are processed first, so any files listed in the environent arguments
are processed before any command line argument files. This allows
the user to set up "standard" options and files to be processed
at every invocation of \fBbc\fR. The files in the environment
variables would typically contain function definitions for functions
the user wants defined every time \fBbc\fR is run.
.IP "BC_LINE_LENGTH"
This should be an integer specifing the number of characters in an
output line for numbers. This includes the backslash and newline characters
for long numbers.
.SH FILES
In most installations, \fBbc\fR is completely self-contained.
Where executable size is of importance or the C compiler does
not deal with very long strings, \fBbc\fR will read
the standard math library from the file /usr/local/lib/libmath.b.
(The actual location may vary. It may be /lib/libmath.b.)
.SH DIAGNOSTICS
If any file on the command line can not be opened, \fBbc\fR will report
that the file is unavailable and terminate. Also, there are compile
and run time diagnostics that should be self-explanatory.
.SH BUGS
Error recovery is not very good yet.
.PP
Email bug reports to
.BR bug-gnu-utils@prep.ai.mit.edu .
Be sure to include the word ``bc'' somewhere in the ``Subject:'' field.
.SH AUTHOR
.nf
Philip A. Nelson
phil@cs.wwu.edu
.fi
.SH ACKNOWLEDGEMENTS
The author would like to thank Steve Sommars (Steve.Sommars@att.com) for
his extensive help in testing the implementation. Many great suggestions
were given. This is a much better product due to his involvement.

436
contrib/bc/doc/dc.1 Normal file
View File

@ -0,0 +1,436 @@
.\"
.\" dc.1 - the *roff document processor source for the dc manual
.\"
.\" This file is part of GNU dc.
.\" Copyright (C) 1994, 1997 Free Software Foundation, Inc.
.\"
.\" 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 2 of the License , 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; see the file COPYING. If not, write to
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
.\"
.TH DC 1 "1997-03-25" "GNU Project"
.ds dc \fIdc\fP
.ds Dc \fIDc\fP
.SH NAME
dc \- an arbitrary precision calculator
.SH SYNOPSIS
dc
.SH DESCRIPTION
.PP
\*(Dc is a reverse-polish desk calculator which supports
unlimited precision arithmetic.
It also allows you to define and call macros.
Normally \*(dc reads from the standard input;
if any command arguments are given to it, they are filenames,
and \*(dc reads and executes the contents of the files before reading
from standard input.
All normal output is to standard output;
all error output is to standard error.
.PP
A reverse-polish calculator stores numbers on a stack.
Entering a number pushes it on the stack.
Arithmetic operations pop arguments off the stack and push the results.
.PP
To enter a number in
.IR dc ,
type the digits with an optional decimal point.
Exponential notation is not supported.
To enter a negative number,
begin the number with ``_''.
``-'' cannot be used for this,
as it is a binary operator for subtraction instead.
To enter two numbers in succession,
separate them with spaces or newlines.
These have no meaning as commands.
.PD
.SH
Printing Commands
.TP
.B p
Prints the value on the top of the stack,
without altering the stack.
A newline is printed after the value.
.TP
.B P
Prints the value on the top of the stack, popping it off,
and does not print a newline after.
.TP
.B f
Prints the entire contents of the stack
.ig
and the contents of all of the registers,
..
without altering anything.
This is a good command to use if you are lost or want
to figure out what the effect of some command has been.
.PD
.SH
Arithmetic
.TP
.B +
Pops two values off the stack, adds them,
and pushes the result.
The precision of the result is determined only
by the values of the arguments,
and is enough to be exact.
.TP
.B -
Pops two values,
subtracts the first one popped from the second one popped,
and pushes the result.
.TP
.B *
Pops two values, multiplies them, and pushes the result.
The number of fraction digits in the result is controlled
by the current precision value (see below) and does not
depend on the values being multiplied.
.TP
.B /
Pops two values,
divides the second one popped from the first one popped,
and pushes the result.
The number of fraction digits is specified by the precision value.
.TP
.B %
Pops two values,
computes the remainder of the division that the
.B /
command would do,
and pushes that.
The division is done with as many fraction digits
as the precision value specifies,
and the remainder is also computed with that many fraction digits.
.TP
.B ~
Pops two values,
divides the second one popped from the first one popped.
The quotient is pushed first, and the remainder is pushed next.
The number of fraction digits used in the division
is specified by the precision value.
(The sequence \fBSdSn lnld/ LnLd%\fP could also accomplish
this function, with slightly different error checking.)
.TP
.B ^
Pops two values and exponentiates,
using the first value popped as the exponent
and the second popped as the base.
The fraction part of the exponent is ignored.
The precision value specifies the number of fraction
digits in the result.
.TP
.B |
Pops three values and computes a modular exponentiation.
The first value popped is used as the reduction modulus;
this value must be a non-zero number,
and should be an integer.
The second popped is used as the exponent;
this value must be a non-negative number,
and any fractional part of this exponent will be ignored.
The third value popped is the base which gets exponentiated.
The precision value specifies the number of fraction
digits in the result.
For small numbers this is like the sequence \fBSm lble^ Lm%\fP,
but, unlike \fB^\fP, this command will work with arbritrarily large exponents.
.TP
.B v
Pops one value,
computes its square root,
and pushes that.
The precision value specifies the number of fraction digits in the result.
.PP
Most arithmetic operations are affected by the ``precision value'',
which you can set with the
.B k
command.
The default precision value is zero,
which means that all arithmetic except for
addition and subtraction produces integer results.
.PP
The remainder operation
.B %
requires some explanation:
applied to arguments ``a'' and ``b'' it produces ``a - (b * (a / b))'',
where ``a / b'' is computed in the current precision.
.SH
Stack Control
.TP
.B c
Clears the stack, rendering it empty.
.TP
.B d
Duplicates the value on the top of the stack,
pushing another copy of it.
Thus, ``4d*p'' computes 4 squared and prints it.
.TP
.B r
Reverses the order of (swaps) the top two values on the stack.
.SH
Registers
.PP
\*(Dc provides 256 memory registers,
each named by a single character.
You can store a number or a string in a register and retrieve it later.
.TP
.BI s r
Pop the value off the top of the stack and store
it into register
.IR r .
.TP
.BI l r
Copy the value in register
.I r
and push it onto the stack.
This does not alter the contents of
.IR r .
.PP
Each register also contains its own stack.
The current register value is the top of the register's stack.
.TP
.BI S r
Pop the value off the top of the (main) stack and
push it onto the stack of register
.IR r .
The previous value of the register becomes inaccessible.
.TP
.BI L r
Pop the value off the top of register
.IR r 's
stack and push it onto the main stack.
The previous value
in register
.IR r 's
stack, if any,
is now accessible via the
.BI l r
command.
.ig
.PP
The
.B f
command prints a list of all registers that have contents stored in them,
together with their contents.
Only the current contents of each register
(the top of its stack)
is printed.
..
.SH
Parameters
.PP
\*(Dc has three parameters that control its operation:
the precision, the input radix, and the output radix.
The precision specifies the number
of fraction digits to keep in the result of most arithmetic operations.
The input radix controls the interpretation of numbers typed in;
all numbers typed in use this radix.
The output radix is used for printing numbers.
.PP
The input and output radices are separate parameters;
you can make them unequal,
which can be useful or confusing.
The input radix must be between 2 and 36 inclusive.
The output radix must be at least 2.
The precision must be zero or greater.
The precision is always measured in decimal digits,
regardless of the current input or output radix.
.TP
.B i
Pops the value off the top of the stack
and uses it to set the input radix.
.TP
.B o
Pops the value off the top of the stack
and uses it to set the output radix.
.TP
.B k
Pops the value off the top of the stack
and uses it to set the precision.
.TP
.B I
Pushes the current input radix on the stack.
.TP
.B O
Pushes the current output radix on the stack.
.TP
.B K
Pushes the current precision on the stack.
.SH
Strings
.PP
\*(Dc can operate on strings as well as on numbers.
The only things you can do with strings are
print them and execute them as macros
(which means that the contents of the string are processed as
\*(dc commands).
All registers and the stack can hold strings,
and \*(dc always knows whether any given object is a string or a number.
Some commands such as arithmetic operations demand numbers
as arguments and print errors if given strings.
Other commands can accept either a number or a string;
for example, the
.B p
command can accept either and prints the object
according to its type.
.TP
.BI [ characters ]
Makes a string containing
.I characters
(contained between balanced
.B [
and
.B ]
characters),
and pushes it on the stack.
For example,
.B [foo]P
prints the characters
.B foo
(with no newline).
.TP
.B a
The top-of-stack is popped.
If it was a number, then the low-order byte of this number
is converted into a string and pushed onto the stack.
Otherwise the top-of-stack was a string,
and the first character of that string is pushed back.
.TP
.B x
Pops a value off the stack and executes it as a macro.
Normally it should be a string;
if it is a number,
it is simply pushed back onto the stack.
For example,
.B [1p]x
executes the macro
.B 1p
which pushes
.B 1
on the stack and prints
.B 1
on a separate line.
.PP
Macros are most often stored in registers;
.B [1p]sa
stores a macro to print
.B 1
into register
.BR a ,
and
.B lax
invokes this macro.
.TP
.BI > r
Pops two values off the stack and compares them
assuming they are numbers,
executing the contents of register
.I r
as a macro if the original top-of-stack
is greater.
Thus,
.B 1 2>a
will invoke register
.BR a 's
contents and
.B 2 1>a
will not.
.TP
.BI < r
Similar but invokes the macro if the original top-of-stack is less.
.TP
.BI = r
Similar but invokes the macro if the two numbers popped are equal.
.ig
This can also be validly used to compare two strings for equality.
..
.TP
.B ?
Reads a line from the terminal and executes it.
This command allows a macro to request input from the user.
.TP
.B q
exits from a macro and also from the macro which invoked it.
If called from the top level,
or from a macro which was called directly from the top level,
the
.B q
command will cause \*(dc to exit.
.TP
.B Q
Pops a value off the stack and uses it as a count
of levels of macro execution to be exited.
Thus,
.B 3Q
exits three levels.
The
.B Q
command will never cause \*(dc to exit.
.SH
Status Inquiry
.TP
.B Z
Pops a value off the stack,
calculates the number of digits it has
(or number of characters, if it is a string)
and pushes that number.
.TP
.B X
Pops a value off the stack,
calculates the number of fraction digits it has,
and pushes that number.
For a string,
the value pushed is
.\" -1.
0.
.TP
.B z
Pushes the current stack depth;
the number of objects on the stack before the execution of the
.B z
command.
.SH
Miscellaneous
.TP
.B !
Will run the rest of the line as a system command.
.TP
.B #
Will interpret the rest of the line as a comment.
.TP
.BI : r
Will pop the top two values off of the stack.
The old second-to-top value will be stored in the array
.IR r ,
indexed by the old top-of-stack value.
.TP
.BI ; r
Pops the top-of-stack and uses it as an index into
the array
.IR r .
The selected value is then pushed onto the stack.
.SH
NOTES
.PP
The array operations
.B :
and
.B ;
are usually only used by traditional implementations of
.IR bc .
(The GNU
.I bc
is self contained and does not need \*(dc to run.)
.SH
BUGS
.PP
Email bug reports to
.BR bug-gnu-utils@prep.ai.mit.edu .
Be sure to include the word ``dc'' somewhere in the ``Subject:'' field.

497
contrib/bc/doc/dc.texi Normal file
View File

@ -0,0 +1,497 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename dc.info
@settitle dc, an arbitrary precision calculator
@c %**end of header
@c This file has the new style title page commands.
@c Run `makeinfo' rather than `texinfo-format-buffer'.
@c smallbook
@c tex
@c \overfullrule=0pt
@c end tex
@c Combine indices.
@synindex cp fn
@syncodeindex vr fn
@syncodeindex ky fn
@syncodeindex pg fn
@syncodeindex tp fn
@ifinfo
This file documents @sc{dc}, an arbitrary precision calculator.
Published by the Free Software Foundation,
675 Massachusetts Avenue,
Cambridge, MA 02139 USA
Copyright (C) 1984 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.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, 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 this permission notice may be stated in a translation approved
by the Foundation.
@end ifinfo
@setchapternewpage off
@titlepage
@title dc, an arbitrary precision calculator
@author by Ken Pizzini
@author original manual by Richard Stallman
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1994, 1997 Free Software Foundation, Inc.
@sp 2
Published by the Free Software Foundation, @*
675 Massachusetts Avenue, @*
Cambridge, MA 02139 USA
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 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 this permission notice may be stated in a translation approved
by the Foundation.
@end titlepage
@page
@node Top, Introduction, (dir), (dir)
@menu
* Introduction:: Introduction
* Invocation:: Invocation
* Printing Commands:: Printing Commands
* Arithmetic:: Arithmetic
* Stack Control:: Stack Control
* Registers:: Registers
* Parameters:: Parameters
* Strings:: Strings
* Status Inquiry:: Status Inquiry
* Miscellaneous:: Other commands
* Notes:: Notes
@end menu
@node Introduction, Invocation, Top, Top
@comment node-name, next, previous, up
@chapter Introduction
@sc{dc} is a reverse-polish desk calculator
which supports unlimited precision arithmetic.
It also allows you to define and call macros.
Normally @sc{dc} reads from the standard input;
if any command arguments are given to it, they are filenames,
and @sc{dc} reads and executes the contents of the files
instead of reading from standard input.
All normal output is to standard output;
all error messages are written to standard error.
To exit, use @samp{q}.
@kbd{C-c} does not exit;
it is used to abort macros that are looping, etc.
(Currently this is not true; @kbd{C-c} does exit.)
A reverse-polish calculator stores numbers on a stack.
Entering a number pushes it on the stack.
Arithmetic operations pop arguments off the stack and push the results.
To enter a number in @sc{dc}, type the digits,
with an optional decimal point.
Exponential notation is not supported.
To enter a negative number, begin the number with @samp{_}.
@samp{-} cannot be used for this, as it is a binary operator
for subtraction instead.
To enter two numbers in succession,
separate them with spaces or newlines.
These have no meaning as commands.
@node Invocation, Printing Commands, Introduction, Top
@chapter Invocation
@sc{dc} may be invoked with the following command-line options:
@table @samp
@item -e @var{expr}
@item --expression=@var{expr}
Evaluate @var{expr} as @sc{dc} commands.
@item -f @var{file}
@item --file=@var{file}
Read and evaluate @sc{dc} commands from @var{file}.
@item -h
@item --help
Print a usage message summarizing the command-line options, then exit.
@item -V
@item --version
Print the version information for this program, then exit.
@end table
If any command-line parameters remain after processing the options,
these parameters are interpreted as additional @var{file}s whose
contents are read and evaluated.
A file name of @code{-} refers to the standard input stream.
If no @code{-e} option was specified, and no files were specified,
then the standard input will be read for commands to evaluate.
@node Printing Commands, Arithmetic, Invocation, Top
@chapter Printing Commands
@table @samp
@item p
Prints the value on the top of the stack,
without altering the stack.
A newline is printed after the value.
@item P
Prints the value on the top of the stack, popping it off,
and does not print a newline after.
@item f
Prints the entire contents of the stack
@c and the contents of all of the registers,
without altering anything.
This is a good command to use if you are lost or want
to figure out what the effect of some command has been.
@end table
@node Arithmetic, Stack Control, Printing Commands, Top
@chapter Arithmetic
@table @samp
@item +
Pops two values off the stack, adds them, and pushes the result.
The precision of the result is determined only
by the values of the arguments, and is enough to be exact.
@item -
Pops two values, subtracts the first one popped
from the second one popped, and pushes the result.
@item *
Pops two values, multiplies them, and pushes the result.
The number of fraction digits in the result is controlled
by the current precision value (see below) and does not
depend on the values being multiplied.
@item /
Pops two values, divides the second one popped
from the first one popped, and pushes the result.
The number of fraction digits is specified by the precision value.
@item %
Pops two values,
computes the remainder of the division that
the @samp{/} command would do,
and pushes that.
The division is done with as many fraction digits
as the precision value specifies,
and the remainder is also computed with that many fraction digits.
@item ~
Pops two values,
divides the second one popped from the first one popped.
The quotient is pushed first, and the remainder is pushed next.
The number of fraction digits used in the division
is specified by the precision value.
(The sequence @code{SdSn lnld/ LnLd%} could also accomplish
this function, with slightly different error checking.)
(This command is a GNU extension.)
@item ^
Pops two values and exponentiates,
using the first value popped as the exponent
and the second popped as the base.
The fraction part of the exponent is ignored.
The precision value specifies the number of fraction
digits in the result.
@item |
Pops three values and computes a modular exponentiation.
The first value popped is used as the reduction modulus;
this value must be a non-zero number,
and the result may not be accurate if the modulus
is not an integer.
The second popped is used as the exponent;
this value must be a non-negative number,
and any fractional part of this exponent will be ignored.
The third value popped is the base which gets exponentiated.
The precision value specifies the number of fraction
digits in the result.
For small numbers this is like the sequence @code{Sm lble^ Lm%},
but, unlike @code{^}, this command will work with arbritrarily large exponents.
@item v
Pops one value, computes its square root, and pushes that.
The precision value specifies the number of fraction digits
in the result.
@end table
Most arithmetic operations are affected by the @emph{precision value},
which you can set with the @samp{k} command.
The default precision value is zero,
which means that all arithmetic except for
addition and subtraction produces integer results.
The remainder operation (@samp{%}) requires some explanation:
applied to arguments @samp{a} and @samp{b}
it produces @samp{a - (b * (a / b))},
where @samp{a / b} is computed in the current precision.
@node Stack Control, Registers, Arithmetic, Top
@chapter Stack Control
@table @samp
@item c
Clears the stack, rendering it empty.
@item d
Duplicates the value on the top of the stack,
pushing another copy of it.
Thus, @samp{4d*p} computes 4 squared and prints it.
@item r
Reverses the order of (swaps) the top two values on the stack.
(This command is a GNU extension.)
@end table
@node Registers, Parameters, Stack Control, Top
@chapter Registers
@sc{dc} provides 256 memory registers, each named by a single character.
You can store a number in a register and retrieve it later.
@table @samp
@item s@var{r}
Pop the value off the top of the stack and
store it into register @var{r}.
@item l@var{r}
Copy the value in register @var{r},
and push it onto the stack.
This does not alter the contents of @var{r}.
Each register also contains its own stack.
The current register value is the top of the register's stack.
@item S@var{r}
Pop the value off the top of the (main) stack and
push it onto the stack of register @var{r}.
The previous value of the register becomes inaccessible.
@item L@var{r}
Pop the value off the top of register @var{r}'s stack
and push it onto the main stack.
The previous value in register @var{r}'s stack, if any,
is now accessible via the @samp{l@var{r}} command.
@end table
@c
@c The @samp{f} command prints a list of all registers that have contents
@c stored in them, together with their contents.
@c Only the current contents of each register (the top of its stack)
@c is printed.
@node Parameters, Strings, Registers, Top
@chapter Parameters
@sc{dc} has three parameters that control its operation:
the precision, the input radix, and the output radix.
The precision specifies the number of fraction digits
to keep in the result of most arithmetic operations.
The input radix controls the interpretation of numbers typed in;
@emph{all} numbers typed in use this radix.
The output radix is used for printing numbers.
The input and output radices are separate parameters;
you can make them unequal, which can be useful or confusing.
The input radix must be between 2 and 36 inclusive.
The output radix must be at least 2.
The precision must be zero or greater.
The precision is always measured in decimal digits,
regardless of the current input or output radix.
@table @samp
@item i
Pops the value off the top of the stack
and uses it to set the input radix.
@item o
Pops the value off the top of the stack
and uses it to set the output radix.
@item k
Pops the value off the top of the stack
and uses it to set the precision.
@item I
Pushes the current input radix on the stack.
@item O
Pushes the current output radix on the stack.
@item K
Pushes the current precision on the stack.
@end table
@node Strings, Status Inquiry, Parameters, Top
@chapter Strings
@sc{dc} can operate on strings as well as on numbers.
The only things you can do with strings are print them
and execute them as macros
(which means that the contents of the string are processed as @sc{dc} commands).
Both registers and the stack can hold strings,
and @sc{dc} always knows whether any given object is a string or a number.
Some commands such as arithmetic operations demand numbers
as arguments and print errors if given strings.
Other commands can accept either a number or a string;
for example, the @samp{p} command can accept either and prints the object
according to its type.
@table @samp
@item [@var{characters}]
Makes a string containing @var{characters} and pushes it on the stack.
For example, @samp{[foo]P} prints the characters @samp{foo}
(with no newline).
@item a
The mnemonic for this is somewhat erroneous: asciify.
The top-of-stack is popped.
If it was a number, then the low-order byte of this number
is converted into a string and pushed onto the stack.
Otherwise the top-of-stack was a string,
and the first character of that string is pushed back.
(This command is a GNU extension.)
@item x
Pops a value off the stack and executes it as a macro.
Normally it should be a string;
if it is a number, it is simply pushed back onto the stack.
For example, @samp{[1p]x} executes the macro @samp{1p},
which pushes 1 on the stack and prints @samp{1} on a separate line.
Macros are most often stored in registers;
@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a},
and @samp{lax} invokes the macro.
@item >@var{r}
Pops two values off the stack and compares them
assuming they are numbers,
executing the contents of register @var{r} as a macro
if the original top-of-stack is greater.
Thus, @samp{1 2>a} will invoke register @samp{a}'s contents
and @samp{2 1>a} will not.
@item <@var{r}
Similar but invokes the macro if the original top-of-stack is less.
@item =@var{r}
Similar but invokes the macro if the two numbers popped are equal.
@c This can also be validly used to compare two strings for equality.
@item ?
Reads a line from the terminal and executes it.
This command allows a macro to request input from the user.
@item q
During the execution of a macro,
this command exits from the macro and also from the macro which invoked it.
If called from the top level,
or from a macro which was called directly from the top level,
the @samp{q} command will cause @sc{dc} to exit.
@item Q
Pops a value off the stack and uses it as a count
of levels of macro execution to be exited.
Thus, @samp{3Q} exits three levels.
@end table
@node Status Inquiry, Miscellaneous, Strings, Top
@chapter Status Inquiry
@table @samp
@item Z
Pops a value off the stack,
calculates the number of digits it has
(or number of characters, if it is a string)
and pushes that number.
@item X
Pops a value off the stack,
calculates the number of fraction digits it has,
and pushes that number.
For a string, the value pushed is
@c -1.
0.
@item z
Pushes the current stack depth;
the number of objects on the stack
before the execution of the @samp{z} command.
@end table
@node Miscellaneous, Notes, Status Inquiry, Top
@chapter Miscellaneous
@table @samp
@item !
Will run the rest of the line as a system command.
@item #
Will interpret the rest of the line as a comment.
(This command is a GNU extension.)
@item :@var{r}
Will pop the top two values off of the stack.
The old second-to-top value will be stored in the array @var{r},
indexed by the old top-of-stack value.
@item ;@var{r}
Pops the top-of-stack and uses it as an index into
the array @var{r}.
The selected value is then pushed onto the stack.
@end table
@node Notes, , Miscellaneous, Top
@chapter Notes
The array operations @samp{:} and @samp{;} are usually
only used by traditional implementations of BC.
(The GNU implementation of BC is self contained
and does not need any version of @sc{dc} to run.)
Email bug reports to @code{bug-gnu-utils@@prep.ai.mit.edu}.
Be sure to include the word ``dc'' somewhere in the ``Subject:'' field.
@contents
@bye

4506
contrib/bc/doc/texinfo.tex Normal file

File diff suppressed because it is too large Load Diff

166
contrib/bc/h/bcdefs.h Normal file
View File

@ -0,0 +1,166 @@
/* bcdefs.h: The single file to include all constants and type definitions. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Include the configuration file. */
#include "config.h"
/* Standard includes for all files. */
#include <stdio.h>
#include <sys/types.h>
#include <ctype.h>
#ifdef STRINGS_H
#include <strings.h>
#else
#include <string.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
/* Include the other definitions. */
#include "const.h"
#include "number.h"
/* These definitions define all the structures used in
code and data storage. This includes the representation of
labels. The "guiding" principle is to make structures that
take a minimum of space when unused but can be built to contain
the full structures. */
/* Labels are first. Labels are generated sequentially in functions
and full code. They just "point" to a single bye in the code. The
"address" is the byte number. The byte number is used to get an
actual character pointer. */
typedef struct bc_label_group
{
long l_adrs [ BC_LABEL_GROUP ];
struct bc_label_group *l_next;
} bc_label_group;
/* Argument list. Recorded in the function so arguments can
be checked at call time. */
typedef struct arg_list
{
int av_name;
int arg_is_var; /* Extension ... variable parameters. */
struct arg_list *next;
} arg_list;
/* Each function has its own code segments and labels. There can be
no jumps between functions so labels are unique to a function. */
typedef struct
{
char f_defined; /* Is this function defined yet. */
char *f_body[BC_MAX_SEGS];
int f_code_size;
bc_label_group *f_label;
arg_list *f_params;
arg_list *f_autos;
} bc_function;
/* Code addresses. */
typedef struct {
int pc_func;
int pc_addr;
} program_counter;
/* Variables are "pushable" (auto) and thus we need a stack mechanism.
This is built into the variable record. */
typedef struct bc_var
{
bc_num v_value;
struct bc_var *v_next;
} bc_var;
/* bc arrays can also be "auto" variables and thus need the same
kind of stacking mechanisms. */
typedef struct bc_array_node
{
union
{
bc_num n_num [NODE_SIZE];
struct bc_array_node *n_down [NODE_SIZE];
} n_items;
} bc_array_node;
typedef struct bc_array
{
bc_array_node *a_tree;
short a_depth;
} bc_array;
typedef struct bc_var_array
{
bc_array *a_value;
char a_param;
struct bc_var_array *a_next;
} bc_var_array;
/* For the stacks, execution and function, we need records to allow
for arbitrary size. */
typedef struct estack_rec {
bc_num s_num;
struct estack_rec *s_next;
} estack_rec;
typedef struct fstack_rec {
int s_val;
struct fstack_rec *s_next;
} fstack_rec;
/* The following are for the name tree. */
typedef struct id_rec {
char *id; /* The program name. */
/* A name == 0 => nothing assigned yet. */
int a_name; /* The array variable name (number). */
int f_name; /* The function name (number). */
int v_name; /* The variable name (number). */
short balance; /* For the balanced tree. */
struct id_rec *left, *right; /* Tree pointers. */
} id_rec;
/* A list of files to process. */
typedef struct file_node {
char *name;
struct file_node *next;
} file_node;

101
contrib/bc/h/const.h Normal file
View File

@ -0,0 +1,101 @@
/* const.h: Constants for bc. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */
#ifndef INT_MAX
#define INT_MAX 0x7FFFFFFF
#endif
#ifndef LONG_MAX
#define LONG_MAX 0x7FFFFFFF
#endif
/* Define constants in some reasonable size. The next 4 constants are
POSIX constants. */
#ifdef BC_BASE_MAX
/* <limits.h> on a POSIX.2 system may have defined these. Override. */
# undef BC_BASE_MAX
# undef BC_SCALE_MAX
# undef BC_STRING_MAX
# undef BC_DIM_MAX
#endif
#define BC_BASE_MAX INT_MAX
#define BC_SCALE_MAX INT_MAX
#define BC_STRING_MAX INT_MAX
/* Definitions for arrays. */
#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */
#define NODE_SIZE 16 /* Must be a power of 2. */
#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */
#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */
#define NODE_DEPTH 4
/* Other BC limits defined but not part of POSIX. */
#define BC_LABEL_GROUP 64
#define BC_LABEL_LOG 6
#define BC_MAX_SEGS 16 /* Code segments. */
#define BC_SEG_SIZE 1024
#define BC_SEG_LOG 10
/* Maximum number of variables, arrays and functions and the
allocation increment for the dynamic arrays. */
#define MAX_STORE 32767
#define STORE_INCR 32
/* Other interesting constants. */
#define FALSE 0
#define TRUE 1
/* for use with lookup (). */
#define SIMPLE 0
#define ARRAY 1
#define FUNCT 2
#define FUNCTDEF 3
#define EXTERN extern
#ifdef __STDC__
#define CONST const
#define VOID void
#else
#define CONST
#define VOID
#endif
/* Include the version definition. */
#include "version.h"

133
contrib/bc/h/getopt.h Normal file
View File

@ -0,0 +1,133 @@
/* Declarations for getopt.
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

147
contrib/bc/h/global.h Normal file
View File

@ -0,0 +1,147 @@
/* global.h: The global variables for bc. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* The current break level's lable. */
EXTERN int break_label;
/* The current if statement's else label or label after else. */
EXTERN int if_label;
/* The current for statement label for continuing the loop. */
EXTERN int continue_label;
/* Next available label number. */
EXTERN int next_label;
/* Byte code character storage. Used in many places for generation of code. */
EXTERN char genstr[80];
/* Count of characters printed to the output in compile_only mode. */
EXTERN int out_count;
/* Have we generated any code since the last initialization of the code
generator. */
EXTERN char did_gen;
/* Is this run an interactive execution. (Is stdin a terminal?) */
EXTERN char interactive;
/* Just generate the byte code. -c flag. */
EXTERN int compile_only;
/* Load the standard math functions. -l flag. */
EXTERN int use_math;
/* Give a warning on use of any non-standard feature (non-POSIX). -w flag. */
EXTERN int warn_not_std;
/* Accept POSIX bc only! -s flag. */
EXTERN int std_only;
/* Don't print the banner at start up. -q flag. */
EXTERN int quiet;
/* The list of file names to process. */
EXTERN file_node *file_names;
/* The name of the current file being processed. */
EXTERN char *file_name;
/* Is the current file a named file or standard input? */
EXTERN char is_std_in;
/* global variables for the bc machine. All will be dynamic in size.*/
/* Function storage. main is (0) and functions (1-f_count) */
EXTERN bc_function *functions;
EXTERN char **f_names;
EXTERN int f_count;
/* Variable stoarge and reverse names. */
EXTERN bc_var **variables;
EXTERN char **v_names;
EXTERN int v_count;
/* Array Variable storage and reverse names. */
EXTERN bc_var_array **arrays;
EXTERN char **a_names;
EXTERN int a_count;
/* Execution stack. */
EXTERN estack_rec *ex_stack;
/* Function return stack. */
EXTERN fstack_rec *fn_stack;
/* Current ibase, obase, scale, and n_history (if needed). */
EXTERN int i_base;
EXTERN int o_base;
EXTERN int scale;
#ifdef READLINE
EXTERN int n_history;
#endif
/* "Condition code" -- false (0) or true (1) */
EXTERN char c_code;
/* Records the number of the runtime error. */
EXTERN char runtime_error;
/* Holds the current location of execution. */
EXTERN program_counter pc;
/* For POSIX bc, this is just for number output, not strings. */
EXTERN int out_col;
/* Keeps track of the current number of characters per output line.
This includes the \n at the end of the line. */
EXTERN int line_size;
/* Input Line numbers and other error information. */
EXTERN int line_no;
EXTERN int had_error;
/* For larger identifiers, a tree, and how many "storage" locations
have been allocated. */
EXTERN int next_array;
EXTERN int next_func;
EXTERN int next_var;
EXTERN id_rec *name_tree;
/* defined in number.c */
extern bc_num _zero_;
extern bc_num _one_;
/* For use with getopt. Do not declare them here.*/
extern int optind;

65
contrib/bc/h/number.h Normal file
View File

@ -0,0 +1,65 @@
/* number.h: Arbitrary precision numbers header file. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
typedef enum {PLUS, MINUS} sign;
typedef struct
{
sign n_sign;
int n_len; /* The number of digits before the decimal point. */
int n_scale; /* The number of digits after the decimal point. */
int n_refs; /* The number of pointers to this number. */
char n_value[1]; /* The storage. Not zero char terminated. It is
allocated with all other fields. */
} bc_struct;
typedef bc_struct *bc_num;
/* The base used in storing the numbers in n_value above.
Currently this MUST be 10. */
#define BASE 10
/* Some useful macros and constants. */
#define CH_VAL(c) (c - '0')
#define BCD_CHAR(d) (d + '0')
#ifdef MIN
#undef MIN
#undef MAX
#endif
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)>(b)?(b):(a))
#define ODD(a) ((a)&1)
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

171
contrib/bc/h/proto.h Normal file
View File

@ -0,0 +1,171 @@
/* proto.h: Prototype function definitions for "external" functions. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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 2 of the License , 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
e-mail: phil@cs.wwu.edu
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* For the pc version using k&r ACK. (minix1.5 and earlier.) */
#ifdef SHORTNAMES
#define init_numbers i_numbers
#define push_constant push__constant
#define load_const in_load_const
#define yy_get_next_buffer yyget_next_buffer
#define yy_init_buffer yyinit_buffer
#define yy_last_accepting_state yylast_accepting_state
#define arglist1 arg1list
#endif
/* Include the standard library header files. */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* Define the _PROTOTYPE macro if it is needed. */
#ifndef _PROTOTYPE
#ifdef __STDC__
#define _PROTOTYPE(func, args) func args
#else
#define _PROTOTYPE(func, args) func()
#endif
#endif
/* From execute.c */
_PROTOTYPE(void stop_execution, (int));
_PROTOTYPE(unsigned char byte, (program_counter *pc));
_PROTOTYPE(void execute, (void));
_PROTOTYPE(char prog_char, (void));
_PROTOTYPE(char input_char, (void));
_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base));
_PROTOTYPE(void push_b10_const, (program_counter *pc));
_PROTOTYPE(void assign, (int c_code));
/* From util.c */
_PROTOTYPE(char *strcopyof, (char *str));
_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val, int is_var));
_PROTOTYPE(char *arg_str, (arg_list *args));
_PROTOTYPE(char *call_str, (arg_list *args));
_PROTOTYPE(void free_args, (arg_list *args));
_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos));
_PROTOTYPE(void init_gen, (void));
_PROTOTYPE(void generate, (char *str));
_PROTOTYPE(void run_code, (void));
_PROTOTYPE(void out_char, (int ch));
_PROTOTYPE(id_rec *find_id, (id_rec *tree, char *id));
_PROTOTYPE(int insert_id_rec, (id_rec **root, id_rec *new_id));
_PROTOTYPE(void init_tree, (void));
_PROTOTYPE(int lookup, (char *name, int namekind));
_PROTOTYPE(char *bc_malloc, (int));
_PROTOTYPE(void out_of_memory, (void));
_PROTOTYPE(void welcome, (void));
_PROTOTYPE(void warranty, (char *));
_PROTOTYPE(void limits, (void));
_PROTOTYPE(void yyerror, (char *str ,...));
_PROTOTYPE(void warn, (char *mesg ,...));
_PROTOTYPE(void rt_error, (char *mesg ,...));
_PROTOTYPE(void rt_warn, (char *mesg ,...));
/* From load.c */
_PROTOTYPE(void init_load, (void));
_PROTOTYPE(void addbyte, (int byte));
_PROTOTYPE(void def_label, (long lab));
_PROTOTYPE(long long_val, (char **str));
_PROTOTYPE(void load_code, (char *code));
/* From main.c */
_PROTOTYPE(int main, (int argc , char *argv []));
_PROTOTYPE(int open_new_file, (void));
_PROTOTYPE(void new_yy_file, (FILE *file));
_PROTOTYPE(void use_quit, (int));
/* From number.c */
_PROTOTYPE(void free_num, (bc_num *num));
_PROTOTYPE(bc_num new_num, (int length, int scale));
_PROTOTYPE(void init_numbers, (void));
_PROTOTYPE(bc_num copy_num, (bc_num num));
_PROTOTYPE(void init_num, (bc_num *num));
_PROTOTYPE(void str2num, (bc_num *num, char *str, int scale));
_PROTOTYPE(char *num2str, (bc_num num));
_PROTOTYPE(void int2num, (bc_num *num, int val));
_PROTOTYPE(long num2long, (bc_num num));
_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2));
_PROTOTYPE(char is_zero, (bc_num num));
_PROTOTYPE(char is_neg, (bc_num num));
_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result, int scale_min));
_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result, int scale_min));
_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale));
_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale));
_PROTOTYPE(int bc_modulo,
(bc_num num1, bc_num num2, bc_num *result, int scale));
_PROTOTYPE(int bc_divmod,
(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale));
_PROTOTYPE(int bc_raisemod,
(bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale));
_PROTOTYPE(void bc_raise,
(bc_num num1, bc_num num2, bc_num *result, int scale));
_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale));
_PROTOTYPE(void out_long, (long val, int size, int space,
void (*out_char)(int)));
_PROTOTYPE(void out_num, (bc_num num, int o_base, void (* out_char)(int)));
/* From storage.c */
_PROTOTYPE(void init_storage, (void));
_PROTOTYPE(void more_functions, (void));
_PROTOTYPE(void more_variables, (void));
_PROTOTYPE(void more_arrays, (void));
_PROTOTYPE(void clear_func, (int func ));
_PROTOTYPE(int fpop, (void));
_PROTOTYPE(void fpush, (int val ));
_PROTOTYPE(void pop, (void));
_PROTOTYPE(void push_copy, (bc_num num ));
_PROTOTYPE(void push_num, (bc_num num ));
_PROTOTYPE(char check_stack, (int depth ));
_PROTOTYPE(bc_var *get_var, (int var_name ));
_PROTOTYPE(bc_num *get_array_num, (int var_index, long index ));
_PROTOTYPE(void store_var, (int var_name ));
_PROTOTYPE(void store_array, (int var_name ));
_PROTOTYPE(void load_var, (int var_name ));
_PROTOTYPE(void load_array, (int var_name ));
_PROTOTYPE(void decr_var, (int var_name ));
_PROTOTYPE(void decr_array, (int var_name ));
_PROTOTYPE(void incr_var, (int var_name ));
_PROTOTYPE(void incr_array, (int var_name ));
_PROTOTYPE(void auto_var, (int name ));
_PROTOTYPE(void free_a_tree, (bc_array_node *root, int depth ));
_PROTOTYPE(void pop_vars, (arg_list *list ));
_PROTOTYPE(void process_params, (program_counter *pc, int func ));
/* For the scanner and parser.... */
_PROTOTYPE(int yyparse, (void));
_PROTOTYPE(int yylex, (void));
/* Other things... */
#ifndef HAVE_UNISTD_H
_PROTOTYPE (int getopt, (int, char *[], CONST char *));
#endif

29
contrib/bc/h/version.h Normal file
View File

@ -0,0 +1,29 @@
/* version.h: version information for GNU bc and GNU dc */
/* This file is part of GNU bc and GNU dc.
* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
*
* 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 2, 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, you can either send email to this
* program's author (see below) or write to: The Free Software Foundation,
* Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
*/
#define BC_VERSION \
"bc 1.04\nCopyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc."
#define DC_VERSION \
"dc 1.1 (GNU bc 1.04)\nCopyright (C) 1994, 1997 Free Software Foundation, Inc."

238
contrib/bc/install-sh Executable file
View File

@ -0,0 +1,238 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
tranformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View File

@ -0,0 +1,9 @@
## Process this file with automake to produce Makefile.in
noinst_LIBRARIES = libbc.a
INCLUDES = -I$(srcdir) -I$(srcdir)/../h
libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c
#libbc_LIBADD = @LIBOBJS@
#libbc_DEPENDENCIES = $(bc_LIBADD)

230
contrib/bc/lib/Makefile.in Normal file
View File

@ -0,0 +1,230 @@
# Makefile.in generated automatically by automake 1.1n from Makefile.am
# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
SHELL = /bin/sh
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = true
PRE_INSTALL = true
POST_INSTALL = true
NORMAL_UNINSTALL = true
PRE_UNINSTALL = true
POST_UNINSTALL = true
CC = @CC@
LEX = @LEX@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
VERSION = @VERSION@
YACC = @YACC@
noinst_LIBRARIES = libbc.a
INCLUDES = -I$(srcdir) -I$(srcdir)/../h
libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
LIBRARIES = $(noinst_LIBRARIES)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
libbc_a_LIBADD =
libbc_a_OBJECTS = getopt.o getopt1.o vfprintf.o number.o
AR = ar
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LINK = $(CC) $(LDFLAGS) -o $@
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP = --best
SOURCES = $(libbc_a_SOURCES)
OBJECTS = $(libbc_a_OBJECTS)
default: all
.SUFFIXES:
.SUFFIXES: .c .o
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-noinstLIBRARIES:
clean-noinstLIBRARIES:
test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
distclean-noinstLIBRARIES:
maintainer-clean-noinstLIBRARIES:
.c.o:
$(COMPILE) -c $<
mostlyclean-compile:
rm -f *.o core
clean-compile:
distclean-compile:
rm -f *.tab.c
maintainer-clean-compile:
libbc.a: $(libbc_a_OBJECTS) $(libbc_a_DEPENDENCIES)
rm -f libbc.a
$(AR) cru libbc.a $(libbc_a_OBJECTS) $(libbc_a_LIBADD)
$(RANLIB) libbc.a
tags: TAGS
ID: $(HEADERS) $(SOURCES)
here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
done; \
test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = lib
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done
info:
dvi:
check: all
$(MAKE)
installcheck:
install-exec:
@$(NORMAL_INSTALL)
install-data:
@$(NORMAL_INSTALL)
install: install-exec install-data all
@:
uninstall:
all: $(LIBRARIES) Makefile
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
installdirs:
mostlyclean-generic:
test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
rm -f Makefile $(DISTCLEANFILES)
rm -f config.cache config.log stamp-h
test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
mostlyclean
distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
distclean-generic clean
rm -f config.status
maintainer-clean: maintainer-clean-noinstLIBRARIES \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-generic distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info dvi installcheck \
install-exec install-data install uninstall all installdirs \
mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
#libbc_LIBADD = @LIBOBJS@
#libbc_DEPENDENCIES = $(bc_LIBADD)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

752
contrib/bc/lib/getopt.c Normal file
View File

@ -0,0 +1,752 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
Free Software Foundation, Inc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if !defined (__STDC__) || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
#endif /* GNU C library. */
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include <string.h>
#define my_index strchr
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
char *getenv ();
static char *
my_index (str, chr)
const char *str;
int chr;
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
#if !defined (__STDC__) || !__STDC__
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
#endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (argv)
char **argv;
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
static const char *
_getopt_initialize (optstring)
const char *optstring;
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
optarg = NULL;
if (optind == 0)
optstring = _getopt_initialize (optstring);
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0'))
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if (nameend - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
else
fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
}
optopt = c;
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: option requires an argument -- %c\n",
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

184
contrib/bc/lib/getopt1.c Normal file
View File

@ -0,0 +1,184 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
Free Software Foundation, Inc.
This file is part of the GNU C Library. Its master source is NOT part of
the C library, however. The master source lives in /gd/gnu/lib.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "getopt.h"
#if !defined (__STDC__) || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#else
char *getenv ();
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == EOF)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

1565
contrib/bc/lib/number.c Normal file

File diff suppressed because it is too large Load Diff

31
contrib/bc/lib/vfprintf.c Normal file
View File

@ -0,0 +1,31 @@
/* vfprintf.c -- this was provided for minix. It may not
work on any other system. */
#include "config.h"
#ifndef HAVE_VPRINTF
#ifndef HAVE_DOPRINT
# error need vfprintf() or doprint()
#else
#ifdef HAVE_LIB_H
#include <lib.h>
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
int vfprintf(file, format, argp)
FILE *file;
_CONST char *format;
va_list argp;
{
_doprintf(file, format, argp);
if (testflag(file, PERPRINTF)) fflush(file);
return 0;
}
#endif /* HAVE_DOPRINT */
#endif /* !HAVE_VFPRINTF */

134
contrib/bc/missing Executable file
View File

@ -0,0 +1,134 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
# 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 2, 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., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
case "$1" in
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison touch file \`y.tab.c'
makeinfo touch the output file
yacc touch file \`y.tab.c'"
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing - GNU libit 0.0"
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
aclocal)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`acinclude.m4' or \`configure.in'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`configure.in'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`acconfig.h' or \`configure.in'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
touch config.h.in
;;
automake)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print \
| sed 's/^\(.*\).am$/touch \1.in/' \
| sh
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
your modified any \`.y' file. For being effective, your
modifications might require the \`Bison' package. Grab it from
any GNU archive site."
touch y.tab.c
;;
makeinfo)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
fi
touch $file
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequirements for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0

36
contrib/bc/mkinstalldirs Executable file
View File

@ -0,0 +1,36 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-05-16
# Last modified: 1994-03-25
# Public domain
errstatus=0
for file in ${1+"$@"} ; do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d in ${1+"$@"} ; do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$?
fi
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here

1
contrib/bc/stamp-h.in Normal file
View File

@ -0,0 +1 @@
timestamp