mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-15 15:06:42 +00:00
adding GNU dc ("desk calculator")
This commit is contained in:
parent
6eefa612a9
commit
e20f62775f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/unlabeled-1.1.1/; revision=220
339
gnu/usr.bin/dc/COPYING
Normal file
339
gnu/usr.bin/dc/COPYING
Normal file
@ -0,0 +1,339 @@
|
||||
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
|
||||
|
||||
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.
|
77
gnu/usr.bin/dc/ChangeLog
Normal file
77
gnu/usr.bin/dc/ChangeLog
Normal file
@ -0,0 +1,77 @@
|
||||
Fri May 21 15:02:52 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* Version 0.2 released.
|
||||
|
||||
Fri May 21 11:48:11 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
|
||||
|
||||
* decimal.c (decimal_rem): Update to match fixes in decimal_div.
|
||||
|
||||
Thu May 20 03:12:41 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* Makefile.in (realclean): Delete dc.info* and configure.
|
||||
(DISTFILES): Add `texinfo.tex' and `NEWS'.
|
||||
texinfo.tex: New file (symlink to canonical source).
|
||||
NEWS: New file.
|
||||
|
||||
Wed May 19 11:30:09 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
|
||||
|
||||
* dc.c (dec_read): Accept only A through F.
|
||||
|
||||
Tue May 18 12:35:54 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
|
||||
|
||||
* dc.c (read_string): New arg STARTC to handle nested brackets.
|
||||
(execute): Change calls to read_string.
|
||||
(condop): Don't assume result of decimal_compare has abs value <= 1.
|
||||
(popmacro): If no macro in progress, exit.
|
||||
|
||||
Sun May 2 00:42:47 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
|
||||
|
||||
* decimal.c (decimal_div): Include in trial_dividend the digit
|
||||
at length2 + i - 2, if there is one.
|
||||
|
||||
Sat May 1 09:54:35 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
|
||||
|
||||
* decimal.c (decimal_parse): Don't use digits without recalculation
|
||||
if some digit exceeds the radix.
|
||||
|
||||
* dc.c (execute): Treat A...F as digits.
|
||||
(dec_read): Treat A...F as digits.
|
||||
|
||||
Thu Apr 29 14:17:30 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
|
||||
|
||||
* decimal.h (bcopy): Use memcpy, not memmove.
|
||||
|
||||
* decimal.c (flush_trailing_digits): Use explicit loop, not bcopy.
|
||||
|
||||
Tue Apr 20 17:21:27 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* dc.c (pushsqrt): `precision' is an argument to `decimal_sqrt', not
|
||||
`push'.
|
||||
|
||||
Sat Apr 17 15:47:55 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* All files: Updated GPL version number.
|
||||
|
||||
* decimal.c: Include decimal.h and delete duplicate declarations.
|
||||
|
||||
* decimal.h [!HAVE_BCOPY]: #define bcopy.
|
||||
[!HAVE_BZERO]: #define bzero.
|
||||
|
||||
Sun Feb 10 22:06:15 1991 Richard Stallman (rms at mole.ai.mit.edu)
|
||||
|
||||
* dc.c (execute): Insert break; in \n case.
|
||||
|
||||
Sun Jul 29 17:50:14 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
|
||||
|
||||
* decimal.c (decimal_neg): New function.
|
||||
|
||||
Fri Jul 27 04:11:34 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* bceval.c, bclex.c, bcprint.c, bcsym.c: Declare some functions
|
||||
static.
|
||||
|
||||
Mon Dec 25 03:01:49 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
|
||||
|
||||
* Makefile: add some missing rules.
|
||||
|
||||
* decimal.c: change a 'max' to 'MAX'.
|
7
gnu/usr.bin/dc/Makefile
Normal file
7
gnu/usr.bin/dc/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
PROG= dc
|
||||
CFLAGS+=-I${.CURDIR} -DHAVE_BCOPY=1 -DHAVE_BZERO=1
|
||||
SRCS= dc.c decimal.c
|
||||
DPADD= ${LIBM}
|
||||
LDADD= -lm
|
||||
|
||||
.include <bsd.prog.mk>
|
7
gnu/usr.bin/dc/NEWS
Normal file
7
gnu/usr.bin/dc/NEWS
Normal file
@ -0,0 +1,7 @@
|
||||
Changes between version 0.2 and 0.1:
|
||||
|
||||
* You can now have nested square bracket pairs within a string.
|
||||
|
||||
* The letters A-F can now be part of a number when the input radix is
|
||||
large enough to make them meaningful.
|
||||
|
13
gnu/usr.bin/dc/README
Normal file
13
gnu/usr.bin/dc/README
Normal file
@ -0,0 +1,13 @@
|
||||
This is a preliminary release of GNU `dc', since people asked for it. GNU
|
||||
`bc' (which doesn't rely on a separate `dc') has been available separately
|
||||
for a couple of years. Eventually this version of `dc' will be merged with
|
||||
the bc package.
|
||||
|
||||
See comments in the file decimal.c for some limitations in the arbitrary
|
||||
precision library. It's questionable whether it's worth fixing these
|
||||
problems since the merged dc will probably use bc's math library instead.
|
||||
However, you might want to be aware of known problems.
|
||||
|
||||
See the file `INSTALL' for instructions on building and installing dc.
|
||||
|
||||
Please report bugs to bug-gnu-utils@prep.ai.mit.edu.
|
909
gnu/usr.bin/dc/dc.c
Normal file
909
gnu/usr.bin/dc/dc.c
Normal file
@ -0,0 +1,909 @@
|
||||
/*
|
||||
* `dc' desk calculator utility.
|
||||
*
|
||||
* Copyright (C) 1984, 1993 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "decimal.h" /* definitions for our decimal arithmetic package */
|
||||
|
||||
FILE *open_file; /* input file now open */
|
||||
int file_count; /* Number of input files not yet opened */
|
||||
char **next_file; /* Pointer to vector of names of input files left */
|
||||
|
||||
struct regstack
|
||||
{
|
||||
decimal value; /* Saved value of register */
|
||||
struct regstack *rest; /* Tail of list */
|
||||
};
|
||||
|
||||
typedef struct regstack *regstack;
|
||||
|
||||
regstack freeregstacks; /* Chain of free regstack structures for fast realloc */
|
||||
|
||||
decimal regs[128]; /* "registers", with single-character names */
|
||||
regstack regstacks[128]; /* For each register, a stack of previous values */
|
||||
|
||||
int stacktop; /* index of last used element in stack */
|
||||
int stacksize; /* Current allocates size of stack */
|
||||
decimal *stack; /* Pointer to computation stack */
|
||||
|
||||
/* A decimal number can be regarded as a string by
|
||||
treating its contents as characters and ignoring the
|
||||
position of its decimal point.
|
||||
Decimal numbers are marked as strings by having an `after' field of -1
|
||||
One use of strings is to execute them as macros.
|
||||
*/
|
||||
|
||||
#define STRING -1
|
||||
|
||||
int macrolevel; /* Current macro nesting; 0 if taking keyboard input */
|
||||
int macrostacksize; /* Current allocated size of macrostack and macroindex */
|
||||
decimal *macrostack; /* Pointer to macro stack array */
|
||||
int *macroindex; /* Pointer to index-within-macro stack array */
|
||||
/* Note that an empty macro is popped from the stack
|
||||
only when an trying to read a character from it
|
||||
or trying to push another macro. */
|
||||
|
||||
int ibase; /* Radix for numeric input. */
|
||||
int obase; /* Radix for numeric output. */
|
||||
int precision; /* Number of digits to keep in multiply and divide. */
|
||||
|
||||
char *buffer; /* Address of buffer used for reading numbers */
|
||||
int bufsize; /* Current size of buffer (made bigger when nec) */
|
||||
|
||||
decimal dec_read ();
|
||||
regstack get_regstack ();
|
||||
int fetch ();
|
||||
int fgetchar ();
|
||||
char *concat ();
|
||||
void pushsqrt ();
|
||||
void condop ();
|
||||
void setibase ();
|
||||
void setobase ();
|
||||
void setprecision ();
|
||||
void pushmacro ();
|
||||
decimal read_string ();
|
||||
void pushlength ();
|
||||
void pushscale ();
|
||||
void unfetch ();
|
||||
void popmacros ();
|
||||
void popmacro ();
|
||||
void popstack ();
|
||||
void print_obj ();
|
||||
void print_string ();
|
||||
void free_regstack ();
|
||||
void pushreg ();
|
||||
void execute ();
|
||||
void fputchar ();
|
||||
void push ();
|
||||
void incref ();
|
||||
void decref ();
|
||||
void binop ();
|
||||
|
||||
main (argc, argv, env)
|
||||
int argc;
|
||||
char **argv, **env;
|
||||
{
|
||||
|
||||
ibase = 10;
|
||||
obase = 10;
|
||||
precision = 0;
|
||||
|
||||
freeregstacks = 0;
|
||||
|
||||
bzero (regs, sizeof regs);
|
||||
bzero (regstacks, sizeof regstacks);
|
||||
|
||||
bufsize = 40;
|
||||
buffer = (char *) xmalloc (40);
|
||||
|
||||
stacksize = 40;
|
||||
stack = (decimal *) xmalloc (stacksize * sizeof (decimal));
|
||||
stacktop = -1;
|
||||
|
||||
macrostacksize = 40;
|
||||
macrostack = (decimal *) xmalloc (macrostacksize * sizeof (decimal));
|
||||
macroindex = (int *) xmalloc (macrostacksize * sizeof (int));
|
||||
macrolevel = 0;
|
||||
/* Initialize for reading input files if any */
|
||||
|
||||
open_file = 0;
|
||||
|
||||
file_count = argc - 1;
|
||||
next_file = argv + 1;
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
execute ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Read and execute one command from the current source of input */
|
||||
|
||||
void
|
||||
execute ()
|
||||
{
|
||||
int c = fetch ();
|
||||
|
||||
if (c < 0) exit (0);
|
||||
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '+': /* Arithmetic operators... */
|
||||
binop (decimal_add);
|
||||
break;
|
||||
|
||||
case '-':
|
||||
binop (decimal_sub);
|
||||
break;
|
||||
|
||||
case '*':
|
||||
binop (decimal_mul_dc); /* Like decimal_mul but hairy
|
||||
way of deciding precision to keep */
|
||||
break;
|
||||
|
||||
case '/':
|
||||
binop (decimal_div);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
binop (decimal_rem);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
binop (decimal_expt);
|
||||
break;
|
||||
|
||||
case '_': /* Begin a negative decimal constant */
|
||||
{
|
||||
decimal tem = dec_read (stdin);
|
||||
tem->sign = !tem->sign;
|
||||
push (tem);
|
||||
}
|
||||
break;
|
||||
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': /* All these begin decimal constants */
|
||||
unfetch (c);
|
||||
push (dec_read (stdin));
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
unfetch (c);
|
||||
push (dec_read (stdin));
|
||||
break;
|
||||
|
||||
case 'c': /* Clear the stack */
|
||||
while (stacktop >= 0)
|
||||
decref (stack[stacktop--]);
|
||||
break;
|
||||
|
||||
case 'd': /* Duplicate top of stack */
|
||||
if (stacktop < 0)
|
||||
error ("stack empty", 0);
|
||||
else push (stack[stacktop]);
|
||||
break;
|
||||
|
||||
case 'f': /* Describe all registers and stack contents */
|
||||
{
|
||||
int regno;
|
||||
int somereg = 0; /* set to 1 if we print any registers */
|
||||
for (regno = 0; regno < 128; regno++)
|
||||
{
|
||||
if (regs[regno])
|
||||
{
|
||||
printf ("register %c: ", regno);
|
||||
print_obj (regs[regno]);
|
||||
somereg = 1;
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
if (somereg)
|
||||
printf ("\n");
|
||||
if (stacktop < 0)
|
||||
printf ("stack empty\n");
|
||||
else
|
||||
{
|
||||
int i;
|
||||
printf ("stack:\n");
|
||||
for (i = 0; i <= stacktop; i++)
|
||||
{
|
||||
print_obj (stack[stacktop - i]);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i': /* ibase <- top of stack */
|
||||
popstack (setibase);
|
||||
break;
|
||||
|
||||
case 'I': /* Push current ibase */
|
||||
push (decimal_from_int (ibase));
|
||||
break;
|
||||
|
||||
case 'k': /* like i, I but for precision instead of ibase */
|
||||
popstack (setprecision);
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
push (decimal_from_int (precision));
|
||||
break;
|
||||
|
||||
case 'l': /* l<x> load register <x> onto stack */
|
||||
{
|
||||
char c1 = fetch ();
|
||||
if (c1 < 0) exit (0);
|
||||
if (!regs[c1])
|
||||
error ("register %c empty", c1);
|
||||
else
|
||||
push (regs[c1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'L': /* L<x> load register <x> to stack, pop <x>'s own stack */
|
||||
{
|
||||
char c1 = fetch ();
|
||||
if (c1 < 0) exit (0);
|
||||
if (!regstacks[c1])
|
||||
error ("nothing pushed on register %c", c1);
|
||||
else
|
||||
{
|
||||
regstack r = regstacks[c1];
|
||||
if (!regs[c1])
|
||||
error ("register %c empty after pop", c1);
|
||||
else
|
||||
push (regs[c1]);
|
||||
regs[c1] = r->value;
|
||||
regstacks[c1] = r->rest;
|
||||
free_regstack (r);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o': /* o, O like i, I but for obase instead of ibase */
|
||||
popstack (setobase);
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
push (decimal_from_int (obase));
|
||||
break;
|
||||
|
||||
case 'p': /* Print tos, don't pop, do print newline afterward */
|
||||
if (stacktop < 0)
|
||||
error ("stack empty", 0);
|
||||
else
|
||||
{
|
||||
print_obj (stack[stacktop]);
|
||||
printf ("\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P': /* Print tos, do pop, no newline afterward */
|
||||
popstack (print_obj);
|
||||
break;
|
||||
|
||||
case 'q': /* Exit */
|
||||
if (macrolevel)
|
||||
{ popmacro (); popmacro (); } /* decrease recursion level by 2 */
|
||||
else
|
||||
exit (0); /* If not in a macro, exit the program. */
|
||||
|
||||
break;
|
||||
|
||||
case 'Q': /* Tos says how many levels to exit */
|
||||
popstack (popmacros);
|
||||
break;
|
||||
|
||||
case 's': /* s<x> -- Pop stack and set register <x> */
|
||||
if (stacktop < 0)
|
||||
empty ();
|
||||
else
|
||||
{
|
||||
int c1 = fetch ();
|
||||
if (c1 < 0) exit (0);
|
||||
if (regs[c1]) decref (regs[c1]);
|
||||
regs[c1] = stack[stacktop--];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S': /* S<x> -- pop stack and push as new value of register <x> */
|
||||
if (stacktop < 0)
|
||||
empty ();
|
||||
else
|
||||
{
|
||||
int c1 = fetch ();
|
||||
if (c1 < 0) exit (0);
|
||||
pushreg (c1);
|
||||
regs[c1] = stack[stacktop--];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v': /* tos gets square root of tos */
|
||||
popstack (pushsqrt);
|
||||
break;
|
||||
|
||||
case 'x': /* pop stack , call as macro */
|
||||
popstack (pushmacro);
|
||||
break;
|
||||
|
||||
case 'X': /* Pop stack, get # fraction digits, push that */
|
||||
popstack (pushscale);
|
||||
break;
|
||||
|
||||
case 'z': /* Compute depth of stack, push that */
|
||||
push (decimal_from_int (stacktop + 1));
|
||||
break;
|
||||
|
||||
case 'Z': /* Pop stack, get # digits, push that */
|
||||
popstack (pushlength);
|
||||
break;
|
||||
|
||||
case '<': /* Conditional: pop two numbers, compare, maybe execute register */
|
||||
/* Note: for no obvious reason, the standard Unix `dc'
|
||||
considers < to be true if the top of stack is less
|
||||
than the next-to-top of stack,
|
||||
and vice versa for >.
|
||||
This seems backwards to me, but I am preserving compatibility. */
|
||||
condop (1);
|
||||
break;
|
||||
|
||||
case '>':
|
||||
condop (-1);
|
||||
break;
|
||||
|
||||
case '=':
|
||||
condop (0);
|
||||
break;
|
||||
|
||||
case '?': /* Read expression from terminal and execute it */
|
||||
/* First ignore any leading newlines */
|
||||
{
|
||||
int c1;
|
||||
while ((c1 = getchar ()) == '\n');
|
||||
ungetc (c1, stdin);
|
||||
}
|
||||
/* Read a line from the terminal and execute it. */
|
||||
pushmacro (read_string ('\n', fgetchar, 0));
|
||||
break;
|
||||
|
||||
case '[': /* Begin string constant */
|
||||
push (read_string (']', fetch, '['));
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\n':
|
||||
break;
|
||||
|
||||
default:
|
||||
error ("undefined command %c", c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Functionals for performing arithmetic, etc */
|
||||
|
||||
/* Call the function `op', with the top of stack value as argument,
|
||||
and then pop the stack.
|
||||
If the stack is empty, print a message and do not call `op'. */
|
||||
|
||||
void
|
||||
popstack (op)
|
||||
void (*op) ();
|
||||
{
|
||||
if (stacktop < 0)
|
||||
empty ();
|
||||
else
|
||||
{
|
||||
decimal value = stack[stacktop--];
|
||||
op (value);
|
||||
decref (value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the function `op' with two arguments taken from the stack top,
|
||||
then pop those arguments and push the value returned by `op'.
|
||||
`op' is assumed to return a decimal number.
|
||||
If there are not two values on the stack, print a message
|
||||
and do not call `op'. */
|
||||
|
||||
void
|
||||
binop (op)
|
||||
decimal (*op) ();
|
||||
{
|
||||
if (stacktop < 1)
|
||||
error ("stack empty", 0);
|
||||
else if (stack[stacktop]->after == STRING || stack[stacktop - 1]->after == STRING)
|
||||
error ("operands not both numeric");
|
||||
else
|
||||
{
|
||||
decimal arg2 = stack [stacktop--];
|
||||
decimal arg1 = stack [stacktop--];
|
||||
|
||||
push (op (arg1, arg2, precision));
|
||||
|
||||
decref (arg1);
|
||||
decref (arg2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
condop (cond)
|
||||
int cond;
|
||||
{
|
||||
int regno = fetch ();
|
||||
if (!regs[regno])
|
||||
error ("register %c is empty", regno);
|
||||
else if (stacktop < 1)
|
||||
empty ();
|
||||
else
|
||||
{
|
||||
decimal arg2 = stack[stacktop--];
|
||||
decimal arg1 = stack[stacktop--];
|
||||
int relation = decimal_compare (arg1, arg2);
|
||||
decref (arg1);
|
||||
decref (arg2);
|
||||
if (cond == relation
|
||||
|| (cond < 0 && relation < 0)
|
||||
|| (cond > 0 && relation > 0))
|
||||
pushmacro (regs[regno]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the command input source */
|
||||
|
||||
/* Fetch the next command character from a macro or from the terminal */
|
||||
|
||||
int
|
||||
fetch()
|
||||
{
|
||||
int c = -1;
|
||||
|
||||
while (macrolevel &&
|
||||
LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
|
||||
popmacro();
|
||||
if (macrolevel)
|
||||
return macrostack[macrolevel - 1]->contents[macroindex[macrolevel-1]++];
|
||||
while (1)
|
||||
{
|
||||
if (open_file)
|
||||
{
|
||||
c = getc (open_file);
|
||||
if (c >= 0) break;
|
||||
fclose (open_file);
|
||||
open_file = 0;
|
||||
}
|
||||
else if (file_count)
|
||||
{
|
||||
open_file = fopen (*next_file++, "r");
|
||||
file_count--;
|
||||
if (!open_file)
|
||||
perror_with_name (*(next_file - 1));
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (c >= 0) return c;
|
||||
return getc (stdin);
|
||||
}
|
||||
|
||||
/* Unread character c on command input stream, whatever it is */
|
||||
|
||||
void
|
||||
unfetch (c)
|
||||
char c;
|
||||
{
|
||||
if (macrolevel)
|
||||
macroindex[macrolevel-1]--;
|
||||
else if (open_file)
|
||||
ungetc (c, open_file);
|
||||
else
|
||||
ungetc (c, stdin);
|
||||
}
|
||||
|
||||
/* Begin execution of macro m. */
|
||||
|
||||
void
|
||||
pushmacro (m)
|
||||
decimal m;
|
||||
{
|
||||
while (macrolevel &&
|
||||
LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1])
|
||||
popmacro();
|
||||
if (m->after == STRING)
|
||||
{
|
||||
if (macrolevel == macrostacksize)
|
||||
{
|
||||
macrostacksize *= 2;
|
||||
macrostack = (decimal *) xrealloc (macrostack, macrostacksize * sizeof (decimal));
|
||||
macroindex = (int *) xrealloc (macroindex, macrostacksize * sizeof (int));
|
||||
}
|
||||
macroindex[macrolevel] = 0;
|
||||
macrostack[macrolevel++] = m;
|
||||
incref (m);
|
||||
}
|
||||
else
|
||||
{ /* Number supplied as a macro! */
|
||||
push (m); /* Its effect wouyld be to push the number. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Pop a specified number of levels of macro execution.
|
||||
The number of levels is specified by a decimal number d. */
|
||||
|
||||
void
|
||||
popmacros (d)
|
||||
decimal d;
|
||||
{
|
||||
int num_pops = decimal_to_int (d);
|
||||
int i;
|
||||
for (i = 0; i < num_pops; i++)
|
||||
popmacro ();
|
||||
}
|
||||
/* Exit one level of macro execution. */
|
||||
|
||||
void
|
||||
popmacro ()
|
||||
{
|
||||
if (!macrolevel)
|
||||
exit (0);
|
||||
else
|
||||
{
|
||||
decref (macrostack[--macrolevel]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
push (d)
|
||||
decimal d;
|
||||
{
|
||||
if (stacktop == stacksize - 1)
|
||||
stack = (decimal *) xrealloc (stack, (stacksize *= 2) * sizeof (decimal));
|
||||
|
||||
incref (d);
|
||||
|
||||
stack[++stacktop] = d;
|
||||
}
|
||||
|
||||
/* Reference counting and storage freeing */
|
||||
|
||||
void
|
||||
decref (d)
|
||||
decimal d;
|
||||
{
|
||||
if (!--d->refcnt)
|
||||
free (d);
|
||||
}
|
||||
|
||||
void
|
||||
incref (d)
|
||||
decimal d;
|
||||
{
|
||||
d->refcnt++;
|
||||
}
|
||||
|
||||
empty ()
|
||||
{
|
||||
error ("stack empty", 0);
|
||||
}
|
||||
|
||||
regstack
|
||||
get_regstack ()
|
||||
{
|
||||
if (freeregstacks)
|
||||
{
|
||||
regstack r = freeregstacks;
|
||||
freeregstacks = r ->rest;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return (regstack) xmalloc (sizeof (struct regstack));
|
||||
}
|
||||
|
||||
void
|
||||
free_regstack (r)
|
||||
regstack r;
|
||||
{
|
||||
r->rest = freeregstacks;
|
||||
freeregstacks = r;
|
||||
}
|
||||
|
||||
void
|
||||
pushreg (c)
|
||||
char c;
|
||||
{
|
||||
regstack r = get_regstack ();
|
||||
|
||||
r->rest = regstacks[c];
|
||||
r->value = regs[c];
|
||||
regstacks[c] = r;
|
||||
regs[c] = 0;
|
||||
}
|
||||
|
||||
/* Input of numbers and strings */
|
||||
|
||||
/* Return a character read from the terminal. */
|
||||
|
||||
fgetchar ()
|
||||
{
|
||||
return getchar ();
|
||||
}
|
||||
|
||||
void
|
||||
fputchar (c)
|
||||
char (c);
|
||||
{
|
||||
putchar (c);
|
||||
}
|
||||
|
||||
/* Read text from command input source up to a close-bracket,
|
||||
make a string out of it, and return it.
|
||||
If STARTC is nonzero, then it and STOPC must balance when nested. */
|
||||
|
||||
decimal
|
||||
read_string (stopc, inputfn, startc)
|
||||
char stopc;
|
||||
int (*inputfn) ();
|
||||
int startc;
|
||||
{
|
||||
int c;
|
||||
decimal result;
|
||||
int i = 0;
|
||||
int count = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
c = inputfn ();
|
||||
if (c < 0 || (c == stopc && count == 0))
|
||||
{
|
||||
if (count != 0)
|
||||
error ("Unmatched `%c'", startc);
|
||||
break;
|
||||
}
|
||||
if (c == stopc)
|
||||
count--;
|
||||
if (c == startc)
|
||||
count++;
|
||||
if (i + 1 >= bufsize)
|
||||
buffer = (char *) xrealloc (buffer, bufsize *= 2);
|
||||
buffer[i++] = c;
|
||||
}
|
||||
result = make_decimal (i, 0);
|
||||
result->after = -1; /* Mark it as a string */
|
||||
result->before++; /* but keep the length unchanged */
|
||||
bcopy (buffer, result->contents, i);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Read a number from the current input source */
|
||||
|
||||
decimal
|
||||
dec_read ()
|
||||
{
|
||||
int c;
|
||||
int i = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
c = fetch ();
|
||||
if (! ((c >= '0' && c <= '9')
|
||||
|| (c >= 'A' && c <= 'F')
|
||||
|| c == '.'))
|
||||
break;
|
||||
if (i + 1 >= bufsize)
|
||||
buffer = (char *) xrealloc (buffer, bufsize *= 2);
|
||||
buffer[i++] = c;
|
||||
}
|
||||
buffer[i++] = 0;
|
||||
unfetch (c);
|
||||
|
||||
return decimal_parse (buffer, ibase);
|
||||
}
|
||||
|
||||
/* Output of numbers and strings */
|
||||
|
||||
/* Print the contents of obj, either numerically or as a string,
|
||||
according to what obj says it is. */
|
||||
|
||||
void
|
||||
print_obj (obj)
|
||||
decimal obj;
|
||||
{
|
||||
if (obj->after == STRING)
|
||||
print_string (obj);
|
||||
else
|
||||
decimal_print (obj, fputchar, obase);
|
||||
}
|
||||
|
||||
/* Print the contents of the decimal number `string', treated as a string. */
|
||||
|
||||
void
|
||||
print_string (string)
|
||||
decimal string;
|
||||
{
|
||||
char *p = string->contents;
|
||||
int len = LENGTH (string);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
putchar (*p++);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the input radix from the value of the decimal number d, if valid. */
|
||||
|
||||
void
|
||||
setibase (d)
|
||||
decimal d;
|
||||
{
|
||||
int value = decimal_to_int (d);
|
||||
if (value < 2 || value > 36)
|
||||
error ("input radix must be from 2 to 36", 0);
|
||||
else
|
||||
ibase = value;
|
||||
}
|
||||
|
||||
/* Set the output radix from the value of the decimal number d, if valid. */
|
||||
|
||||
void
|
||||
setobase (d)
|
||||
decimal d;
|
||||
{
|
||||
int value = decimal_to_int (d);
|
||||
if (value < 2 || value > 36)
|
||||
error ("output radix must be from 2 to 36", 0);
|
||||
else
|
||||
obase = value;
|
||||
}
|
||||
|
||||
/* Set the precision for mul and div from the value of the decimal number d, if valid. */
|
||||
|
||||
void
|
||||
setprecision (d)
|
||||
decimal d;
|
||||
{
|
||||
int value = decimal_to_int (d);
|
||||
if (value < 0 || value > 30000)
|
||||
error ("precision must be nonnegative and < 30000", 0);
|
||||
else
|
||||
precision = value;
|
||||
}
|
||||
|
||||
/* Push the number of digits in decimal number d, as a decimal number. */
|
||||
|
||||
void
|
||||
pushlength (d)
|
||||
decimal d;
|
||||
{
|
||||
push (decimal_from_int (LENGTH (d)));
|
||||
}
|
||||
|
||||
/* Push the number of fraction digits in d. */
|
||||
|
||||
void
|
||||
pushscale (d)
|
||||
decimal d;
|
||||
{
|
||||
push (decimal_from_int (d->after));
|
||||
}
|
||||
|
||||
/* Push the square root of decimal number d. */
|
||||
|
||||
void
|
||||
pushsqrt (d)
|
||||
decimal d;
|
||||
{
|
||||
push (decimal_sqrt (d, precision));
|
||||
}
|
||||
|
||||
/* Print error message and exit. */
|
||||
|
||||
fatal (s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
error (s1, s2);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Print error message. `s1' is printf control string, `s2' is arg for it. */
|
||||
|
||||
error (s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
printf ("dc: ");
|
||||
printf (s1, s2);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
decimal_error (s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
error (s1, s2);
|
||||
}
|
||||
|
||||
perror_with_name (name)
|
||||
char *name;
|
||||
{
|
||||
extern int errno, sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
char *s;
|
||||
|
||||
if (errno < sys_nerr)
|
||||
s = concat ("", sys_errlist[errno], " for %s");
|
||||
else
|
||||
s = "cannot open %s";
|
||||
error (s, name);
|
||||
}
|
||||
|
||||
/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char *s1, *s2, *s3;
|
||||
{
|
||||
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
|
||||
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
|
||||
|
||||
strcpy (result, s1);
|
||||
strcpy (result + len1, s2);
|
||||
strcpy (result + len1 + len2, s3);
|
||||
*(result + len1 + len2 + len3) = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Like malloc but get fatal error if memory is exhausted. */
|
||||
|
||||
int
|
||||
xmalloc (size)
|
||||
int size;
|
||||
{
|
||||
int result = malloc (size);
|
||||
if (!result)
|
||||
fatal ("virtual memory exhausted", 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
xrealloc (ptr, size)
|
||||
char *ptr;
|
||||
int size;
|
||||
{
|
||||
int result = realloc (ptr, size);
|
||||
if (!result)
|
||||
fatal ("virtual memory exhausted");
|
||||
return result;
|
||||
}
|
330
gnu/usr.bin/dc/dc.info
Normal file
330
gnu/usr.bin/dc/dc.info
Normal file
@ -0,0 +1,330 @@
|
||||
This is Info file dc.info, produced by Makeinfo-1.52 from the input
|
||||
file dc.texinfo.
|
||||
|
||||
This file documents 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
File: dc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir)
|
||||
|
||||
* Menu:
|
||||
|
||||
* Introduction:: Introduction
|
||||
* Printing Commands:: Printing Commands
|
||||
* Arithmetic:: Arithmetic
|
||||
* Stack Control:: Stack Control
|
||||
* Registers:: Registers
|
||||
* Parameters:: Parameters
|
||||
* Strings:: Strings
|
||||
* Status Inquiry:: Status Inquiry
|
||||
* Notes:: Notes
|
||||
|
||||
|
||||
File: dc.info, Node: Introduction, Next: Printing Commands, Prev: Top, Up: Top
|
||||
|
||||
Introduction
|
||||
************
|
||||
|
||||
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 output is to
|
||||
standard output.
|
||||
|
||||
To exit, use `q'. `C-c' does not exit; it is used to abort macros
|
||||
that are looping, etc. (Currently this is not true; `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 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.
|
||||
|
||||
|
||||
File: dc.info, Node: Printing Commands, Next: Arithmetic, Prev: Introduction, Up: Top
|
||||
|
||||
Printing Commands
|
||||
*****************
|
||||
|
||||
`p'
|
||||
Prints the value on the top of the stack, without altering the
|
||||
stack. A newline is printed after the value.
|
||||
|
||||
`P'
|
||||
Prints the value on the top of the stack, popping it off, and does
|
||||
not print a newline after.
|
||||
|
||||
`f'
|
||||
Prints the entire contents of the stack 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.
|
||||
|
||||
|
||||
File: dc.info, Node: Arithmetic, Next: Stack Control, Prev: Printing Commands, Up: Top
|
||||
|
||||
Arithmetic
|
||||
**********
|
||||
|
||||
`+'
|
||||
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.
|
||||
|
||||
`-'
|
||||
Pops two values, subtracts the first one popped from the second
|
||||
one popped, and pushes the result.
|
||||
|
||||
`*'
|
||||
Pops two values, multiplies them, and pushes the result. The
|
||||
number of fraction digits in the result is controlled by the
|
||||
current precision flag (see below) and does not depend on the
|
||||
values being multiplied.
|
||||
|
||||
`/'
|
||||
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 flag.
|
||||
|
||||
`%'
|
||||
Pops two values, computes the remainder of the division that the
|
||||
`/' command would do, and pushes that. The division is done with
|
||||
as many fraction digits as the precision flag specifies, and the
|
||||
remainder is also computed with that many fraction digits.
|
||||
|
||||
`^'
|
||||
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 flag specifies the
|
||||
number of fraction digits in the result.
|
||||
|
||||
`v'
|
||||
Pops one value, computes its square root, and pushes that. The
|
||||
precision flag specifies the number of fraction digits in the
|
||||
result.
|
||||
|
||||
Most arithmetic operations are affected by the "precision flag",
|
||||
which you can set with the `k' command. The default precision value is
|
||||
zero, which means that all arithmetic except for addition and
|
||||
subtraction produces integer results.
|
||||
|
||||
The remainder operation (`%') requires some explanation: applied to
|
||||
arguments `a' and `b' it produces `a - (b * (a / b))', where `a / b' is
|
||||
computed in the current precision.
|
||||
|
||||
|
||||
File: dc.info, Node: Stack Control, Next: Registers, Prev: Arithmetic, Up: Top
|
||||
|
||||
Stack Control
|
||||
*************
|
||||
|
||||
`c'
|
||||
Clears the stack, rendering it empty.
|
||||
|
||||
`d'
|
||||
Duplicates the value on the top of the stack, pushing another copy
|
||||
of it. Thus, `4d*p' computes 4 squared and prints it.
|
||||
|
||||
|
||||
File: dc.info, Node: Registers, Next: Parameters, Prev: Stack Control, Up: Top
|
||||
|
||||
Registers
|
||||
*********
|
||||
|
||||
DC provides 128 memory registers, each named by a single ASCII
|
||||
character. You can store a number in a register and retrieve it later.
|
||||
|
||||
`sR'
|
||||
Pop the value off the top of the stack and store it into register
|
||||
R.
|
||||
|
||||
`lR'
|
||||
Copy the value in register R, and push it onto the stack. This
|
||||
does not alter the contents of R.
|
||||
|
||||
Each register also contains its own stack. The current register
|
||||
value is the top of the register's stack.
|
||||
|
||||
`SR'
|
||||
Pop the value off the top of the (main) stack and push it onto the
|
||||
stack of register R. The previous value of the register becomes
|
||||
inaccessible.
|
||||
|
||||
`LR'
|
||||
Pop the value off the top of register R's stack and push it onto
|
||||
the main stack. The previous value in register R's stack, if any,
|
||||
is now accessible via the `lR' command.
|
||||
|
||||
The `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.
|
||||
|
||||
|
||||
File: dc.info, Node: Parameters, Next: Strings, Prev: Registers, Up: Top
|
||||
|
||||
Parameters
|
||||
**********
|
||||
|
||||
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.
|
||||
|
||||
The input and output radices are separate parameters; you can make
|
||||
them unequal, which can be useful or confusing. Each radix must be
|
||||
between 2 and 36 inclusive. The precision must be zero or greater.
|
||||
The precision is always measured in decimal digits, regardless of the
|
||||
current input or output radix.
|
||||
|
||||
`i'
|
||||
Pops the value off the top of the stack and uses it to set the
|
||||
input radix.
|
||||
|
||||
`o'
|
||||
`k'
|
||||
Similarly set the output radix and the precision.
|
||||
|
||||
`I'
|
||||
Pushes the current input radix on the stack.
|
||||
|
||||
`O'
|
||||
`K'
|
||||
Similarly push the current output radix and the current precision.
|
||||
|
||||
|
||||
File: dc.info, Node: Strings, Next: Status Inquiry, Prev: Parameters, Up: Top
|
||||
|
||||
Strings
|
||||
*******
|
||||
|
||||
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).
|
||||
Both 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 `p' command can accept either and prints the object
|
||||
according to its type.
|
||||
|
||||
`[CHARACTERS]'
|
||||
Makes a string containing CHARACTERS and pushes it on the stack.
|
||||
For example, `[foo]P' prints the characters `foo' (with no
|
||||
newline).
|
||||
|
||||
`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, `[1p]x' executes the macro `1p',
|
||||
which pushes 1 on the stack and prints `1' on a separate line.
|
||||
|
||||
Macros are most often stored in registers; `[1p]sa' stores a macro
|
||||
to print `1' into register `a', and `lax' invokes the macro.
|
||||
|
||||
`>R'
|
||||
Pops two values off the stack and compares them assuming they are
|
||||
numbers, executing the contents of register R as a macro if the
|
||||
original top-of-stack is greater. Thus, `1 2>a' will invoke
|
||||
register `a''s contents and `2 1>a' will not.
|
||||
|
||||
`<R'
|
||||
Similar but invokes the macro if the original top-of-stack is less.
|
||||
|
||||
`=R'
|
||||
Similar but invokes the macro if the two numbers popped are equal.
|
||||
This can also be validly used to compare two strings for equality.
|
||||
|
||||
`?'
|
||||
Reads a line from the terminal and executes it. This command
|
||||
allows a macro to request input from the user.
|
||||
|
||||
`q'
|
||||
During the execution of a macro, this comand does not exit DC.
|
||||
Instead, it exits from that macro and also from the macro which
|
||||
invoked it (if any).
|
||||
|
||||
`Q'
|
||||
Pops a value off the stack and uses it as a count of levels of
|
||||
macro execution to be exited. Thus, `3Q' exits three levels.
|
||||
|
||||
|
||||
File: dc.info, Node: Status Inquiry, Next: Notes, Prev: Strings, Up: Top
|
||||
|
||||
Status Inquiry
|
||||
**************
|
||||
|
||||
`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.
|
||||
|
||||
`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.
|
||||
|
||||
`z'
|
||||
Pushes the current stack depth; the number of objects on the stack
|
||||
before the execution of the `z' command.
|
||||
|
||||
`I'
|
||||
Pushes the current value of the input radix.
|
||||
|
||||
`O'
|
||||
Pushes the current value of the output radix.
|
||||
|
||||
`K'
|
||||
Pushes the current value of the precision.
|
||||
|
||||
|
||||
File: dc.info, Node: Notes, Prev: Status Inquiry, Up: Top
|
||||
|
||||
Notes
|
||||
*****
|
||||
|
||||
The `:' and `;' commands of the Unix DC program are not supported,
|
||||
as the documentation does not say what they do. The `!' command is not
|
||||
supported, but will be supported as soon as a library for executing a
|
||||
line as a command exists.
|
||||
|
||||
|
||||
|
||||
Tag Table:
|
||||
Node: Top960
|
||||
Node: Introduction1440
|
||||
Node: Printing Commands2603
|
||||
Node: Arithmetic3211
|
||||
Node: Stack Control5168
|
||||
Node: Registers5468
|
||||
Node: Parameters6586
|
||||
Node: Strings7659
|
||||
Node: Status Inquiry9857
|
||||
Node: Notes10571
|
||||
|
||||
End Tag Table
|
381
gnu/usr.bin/dc/dc.texinfo
Normal file
381
gnu/usr.bin/dc/dc.texinfo
Normal file
@ -0,0 +1,381 @@
|
||||
\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 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 odd
|
||||
|
||||
@titlepage
|
||||
@title DC, An Arbitrary Precision Calculator
|
||||
|
||||
@author by Richard Stallman
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
Copyright @copyright{} 1984 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
|
||||
* Printing Commands:: Printing Commands
|
||||
* Arithmetic:: Arithmetic
|
||||
* Stack Control:: Stack Control
|
||||
* Registers:: Registers
|
||||
* Parameters:: Parameters
|
||||
* Strings:: Strings
|
||||
* Status Inquiry:: Status Inquiry
|
||||
* Notes:: Notes
|
||||
@end menu
|
||||
|
||||
@node Introduction, Printing Commands, Top, Top
|
||||
@comment node-name, next, previous, up
|
||||
@chapter Introduction
|
||||
|
||||
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 output
|
||||
is to standard output.
|
||||
|
||||
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 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 Printing Commands, Arithmetic, Introduction, 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
|
||||
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 flag (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 flag.
|
||||
|
||||
@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 flag specifies, and the remainder
|
||||
is also computed with that many fraction digits.
|
||||
|
||||
@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 flag specifies the number of fraction
|
||||
digits in the result.
|
||||
|
||||
@item v
|
||||
Pops one value, computes its square root, and pushes that.
|
||||
The precision flag specifies the number of fraction digits
|
||||
in the result.
|
||||
@end table
|
||||
|
||||
Most arithmetic operations are affected by the "precision flag",
|
||||
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,
|
||||
`4d*p' computes 4 squared and prints it.
|
||||
@end table
|
||||
|
||||
@node Registers, Parameters, Stack Control, Top
|
||||
@chapter Registers
|
||||
|
||||
DC provides 128 memory registers, each named by a single
|
||||
ASCII 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 `l@var{r}' command.
|
||||
@end table
|
||||
|
||||
The @samp{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.
|
||||
|
||||
@node Parameters, Strings, Registers, Top
|
||||
@chapter Parameters
|
||||
|
||||
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. Each radix must be between 2
|
||||
and 36 inclusive. 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
|
||||
@itemx k
|
||||
Similarly set the output radix and the precision.
|
||||
|
||||
@item I
|
||||
Pushes the current input radix on the stack.
|
||||
|
||||
@item O
|
||||
@itemx K
|
||||
Similarly push the current output radix and the current precision.
|
||||
@end table
|
||||
|
||||
@node Strings, Status Inquiry, Parameters, Top
|
||||
@chapter Strings
|
||||
|
||||
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).
|
||||
Both 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 @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 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. 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 comand
|
||||
does not exit DC. Instead, it exits from that
|
||||
macro and also from the macro which invoked it (if any).
|
||||
|
||||
@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, Notes, 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 -1.
|
||||
|
||||
@item z
|
||||
Pushes the current stack depth; the number of
|
||||
objects on the stack before the execution of the @samp{z} command.
|
||||
|
||||
@item I
|
||||
Pushes the current value of the input radix.
|
||||
|
||||
@item O
|
||||
Pushes the current value of the output radix.
|
||||
|
||||
@item K
|
||||
Pushes the current value of the precision.
|
||||
@end table
|
||||
|
||||
@node Notes, , Status Inquiry, Top
|
||||
@chapter Notes
|
||||
|
||||
The @samp{:} and @samp{;} commands of the Unix DC program are
|
||||
not supported, as the documentation does not say what they do.
|
||||
The @samp{!} command is not supported, but will be supported
|
||||
as soon as a library for executing a line as a command exists.
|
||||
|
||||
@contents
|
||||
@bye
|
1235
gnu/usr.bin/dc/decimal.c
Normal file
1235
gnu/usr.bin/dc/decimal.c
Normal file
File diff suppressed because it is too large
Load Diff
93
gnu/usr.bin/dc/decimal.h
Normal file
93
gnu/usr.bin/dc/decimal.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Header file for decimal.c (arbitrary precision decimal arithmetic)
|
||||
*
|
||||
* Copyright (C) 1984 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.
|
||||
*/
|
||||
|
||||
/* Autoconf stuff */
|
||||
#ifndef HAVE_BCOPY
|
||||
#undef bcopy
|
||||
#define bcopy(s2, s1, n) memcpy (s1, s2, n)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BZERO
|
||||
#undef bzero
|
||||
#define bzero(b, l) memset (b, 0, l)
|
||||
#endif
|
||||
|
||||
/* Define the radix to use by default, and for representing the
|
||||
numbers internally. This does not need to be decimal; that is just
|
||||
the default for it. */
|
||||
|
||||
/* Currently, this is required to be even for this program to work. */
|
||||
|
||||
#ifndef RADIX
|
||||
#define RADIX 10
|
||||
#endif
|
||||
|
||||
/* The user must define the external function `decimal_error'
|
||||
which is called with two arguments to report errors in this package.
|
||||
The two arguments may be passed to `printf' to print a message. */
|
||||
|
||||
/* Structure that represents a decimal number */
|
||||
|
||||
struct decimal
|
||||
{
|
||||
unsigned int sign: 1; /* One for negative number */
|
||||
/* The sign should always be zero for the number 0 */
|
||||
int after: 15; /* number of fraction digits */
|
||||
unsigned short before; /* number of non-fraction digits */
|
||||
unsigned short refcnt; /* number of pointers to this number */
|
||||
/* (used by calling program) */
|
||||
char contents[1]; /* the digits themselves, least significant first. */
|
||||
/* digits are just numbers 0 .. RADIX-1 */
|
||||
};
|
||||
|
||||
/* There may never be leading nonfraction zeros or trailing fraction
|
||||
zeros in a number. They must be removed by all the arithmetic
|
||||
functions. Therefore, the number zero always has no digits stored. */
|
||||
|
||||
typedef struct decimal *decimal;
|
||||
|
||||
/* Decimal numbers are always passed around as pointers.
|
||||
All the external entries in this file allocate new numbers
|
||||
using `malloc' to store values in.
|
||||
They never modify their arguments or any existing numbers. */
|
||||
|
||||
/* Return the total number of digits stored in the number `b' */
|
||||
#define LENGTH(b) ((b)->before + (b)->after)
|
||||
|
||||
/* Some constant decimal numbers */
|
||||
|
||||
|
||||
#define DECIMAL_ZERO &decimal_zero
|
||||
|
||||
|
||||
#define DECIMAL_ONE &decimal_one
|
||||
|
||||
#define DECIMAL_HALF &decimal_half
|
||||
|
||||
decimal decimal_add (), decimal_sub (), decimal_mul (), decimal_div ();
|
||||
decimal decimal_mul_dc (), decimal_mul_rounded (), decimal_rem ();
|
||||
decimal decimal_round_digits ();
|
||||
decimal make_decimal (), decimal_copy (), decimal_parse ();
|
||||
decimal decimal_sqrt (), decimal_expt ();
|
||||
|
||||
void decimal_print ();
|
||||
|
||||
/* End of decimal.h */
|
Loading…
Reference in New Issue
Block a user