This commit was generated by cvs2svn to compensate for changes in r28,
which included commits to RCS files with non-trunk default branches.
This commit is contained in:
commit
bc8deb7535
341
gnu/usr.bin/bc/COPYING
Normal file
341
gnu/usr.bin/bc/COPYING
Normal 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.
|
||||
|
7
gnu/usr.bin/bc/Makefile
Normal file
7
gnu/usr.bin/bc/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
PROG= bc
|
||||
SRCS= bc.c global.c scan.c util.c main.c number.c storage.c load.c execute.c
|
||||
MAN1= bc.0
|
||||
BINDIR=
|
||||
CFLAGS+= -D_POSIX_SOURCE -I$(.CURDIR)
|
||||
|
||||
.include <bsd.prog.mk>
|
730
gnu/usr.bin/bc/bc.1
Normal file
730
gnu/usr.bin/bc/bc.1
Normal file
@ -0,0 +1,730 @@
|
||||
.\"
|
||||
.\" bc.1 - the *roff document processor source for the bc manual
|
||||
.\"
|
||||
.\" This file is part of bc written for MINIX.
|
||||
.\" Copyright (C) 1991, 1992 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.02 "Feb 3, 1992"
|
||||
.SH NAME
|
||||
bc - An arbitrary precision calculator language
|
||||
.SH SYNTAX
|
||||
\fBbc\fR [ \fB-lws\fR ] [ \fI file ...\fR ]
|
||||
.SH VERSION
|
||||
This man page documents GNU bc version 1.02.
|
||||
.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.
|
||||
.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.
|
||||
.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 (F). 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.
|
||||
.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
|
||||
"b" (bell), "f" (form feed), "n" (newline), "r" (carriage return), "t"
|
||||
(tab), and "\e" (backslash). Any other character following the
|
||||
backslash will be ignored. This still does not allow the double quote
|
||||
character to be part of any string.
|
||||
.IP "{ statement_list }"
|
||||
This is the compound statement. It allows multiple statements to be
|
||||
grouped together for execution.
|
||||
.IP "\fBif\fR ( expression ) \fBthen\fR 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\f 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 in radians.
|
||||
.IP "c (\fIx\fR)"
|
||||
The cosine of x in radians.
|
||||
.IP "a (\fIx\fR)"
|
||||
The arctangent of x.
|
||||
.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 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 have array parameters. Other implementations
|
||||
of \fBbc\fR may have 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 10240 bytes of
|
||||
compiled byte code each. This limit (BC_MAX_SEGS) can be easily changed
|
||||
to have more than 10 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 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.
|
||||
.SH AUTHOR
|
||||
.nf
|
||||
Philip A. Nelson
|
||||
phil@cs.wwu.edu
|
||||
.fi
|
||||
.SH ACKNOWLEDGEMENTS
|
||||
The author would like to thank Steve Sommars (sesv@iwtsf.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.
|
1369
gnu/usr.bin/bc/bc.c
Normal file
1369
gnu/usr.bin/bc/bc.c
Normal file
File diff suppressed because it is too large
Load Diff
154
gnu/usr.bin/bc/bcdefs.h
Normal file
154
gnu/usr.bin/bc/bcdefs.h
Normal file
@ -0,0 +1,154 @@
|
||||
/* bcdefs.h: The single file to include all constants and type definitions. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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
|
||||
#ifndef NO_LIMITS
|
||||
#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;
|
||||
|
||||
|
||||
/* 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 arg_list
|
||||
{
|
||||
int av_name;
|
||||
struct arg_list *next;
|
||||
} arg_list;
|
||||
|
||||
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;
|
4
gnu/usr.bin/bc/config.h
Normal file
4
gnu/usr.bin/bc/config.h
Normal file
@ -0,0 +1,4 @@
|
||||
/* config.h */
|
||||
#ifndef __STDC__
|
||||
#define VARARGS
|
||||
#endif
|
87
gnu/usr.bin/bc/const.h
Normal file
87
gnu/usr.bin/bc/const.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* const.h: Constants for bc. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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... */
|
||||
|
||||
#ifdef NO_LIMITS
|
||||
#define INT_MAX 0x7FFFFFFF
|
||||
#define LONG_MAX 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
|
||||
/* Define constants in some reasonable size. The next 4 constants are
|
||||
POSIX constants. */
|
||||
#if !defined(_POSIX_SOURCE)
|
||||
#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 */
|
||||
#endif
|
||||
|
||||
#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
|
||||
#define SIMPLE 0
|
||||
#define ARRAY 1
|
||||
#define FUNCT 2
|
||||
#define EXTERN extern
|
||||
#ifdef __STDC__
|
||||
#define CONST const
|
||||
#define VOID void
|
||||
#else
|
||||
#define CONST
|
||||
#define VOID
|
||||
#endif
|
||||
|
||||
/* Include the version definition. */
|
||||
#include "version.h"
|
783
gnu/usr.bin/bc/execute.c
Normal file
783
gnu/usr.bin/bc/execute.c
Normal file
@ -0,0 +1,783 @@
|
||||
/* execute.c - run a bc program. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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_char (ch);
|
||||
else
|
||||
{
|
||||
ch = byte(&pc);
|
||||
if (ch == '"') break;
|
||||
switch (ch)
|
||||
{
|
||||
case 'n': out_char ('\n'); break;
|
||||
case 't': out_char ('\t'); break;
|
||||
case 'r': out_char ('\r'); break;
|
||||
case 'b': out_char (007); break;
|
||||
case 'f': out_char ('\f'); break;
|
||||
case '\\': out_char ('\\'); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (interactive) 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 (3); /* Special variable "last". */
|
||||
if (interactive) fflush (stdout);
|
||||
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);
|
||||
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_char (ch);
|
||||
if (interactive) 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Final work. */
|
||||
if (negative)
|
||||
bc_sub (_zero_, build, &build);
|
||||
|
||||
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_);
|
||||
}
|
42
gnu/usr.bin/bc/global.c
Normal file
42
gnu/usr.bin/bc/global.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* global.c: This defines the global variables. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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 "math.h"
|
||||
;
|
||||
#endif
|
108
gnu/usr.bin/bc/global.h
Normal file
108
gnu/usr.bin/bc/global.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* global.h: The global variables for bc. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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 current "break level" and if statements. */
|
||||
EXTERN int break_label;
|
||||
EXTERN int if_label;
|
||||
EXTERN int continue_label;
|
||||
|
||||
/* Label numbers. */
|
||||
EXTERN int next_label;
|
||||
|
||||
/* Used for "code" generation. */
|
||||
EXTERN char genstr[80];
|
||||
EXTERN int out_count;
|
||||
EXTERN char did_gen;
|
||||
|
||||
/* Interactive and other flags. */
|
||||
EXTERN char interactive;
|
||||
EXTERN char compile_only;
|
||||
EXTERN char use_math;
|
||||
EXTERN char warn_not_std;
|
||||
EXTERN char std_only;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Other "storage". */
|
||||
EXTERN int i_base;
|
||||
EXTERN int o_base;
|
||||
EXTERN int scale;
|
||||
EXTERN char c_code;
|
||||
EXTERN int out_col;
|
||||
EXTERN char runtime_error;
|
||||
EXTERN program_counter pc;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* For error message production */
|
||||
EXTERN char **g_argv;
|
||||
EXTERN int g_argc;
|
||||
EXTERN char is_std_in;
|
||||
|
||||
/* defined in number.c */
|
||||
extern bc_num _zero_;
|
||||
extern bc_num _one_;
|
||||
|
||||
/* For use with getopt. Do not declare them here.*/
|
||||
extern int optind;
|
||||
|
255
gnu/usr.bin/bc/libmath.b
Normal file
255
gnu/usr.bin/bc/libmath.b
Normal file
@ -0,0 +1,255 @@
|
||||
/* libmath.b for bc for minix. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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, 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
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
||||
/* Precondition x to make .5 < x < 2.0. */
|
||||
z = scale;
|
||||
scale += 4;
|
||||
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 + 1;
|
||||
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
|
||||
|
||||
/* Special case and for fast answers */
|
||||
if (x==1) {
|
||||
if (scale <= 25) return (.7853981633974483096156608/1)
|
||||
if (scale <= 40) return (.7853981633974483096156608458198757210492/1)
|
||||
if (scale <= 60) \
|
||||
return (.785398163397448309615660845819875721049292349843776455243736/1)
|
||||
}
|
||||
if (x==.2) {
|
||||
if (scale <= 25) return (.1973955598498807583700497/1)
|
||||
if (scale <= 40) return (.1973955598498807583700497651947902934475/1)
|
||||
if (scale <= 60) \
|
||||
return (.197395559849880758370049765194790293447585103787852101517688/1)
|
||||
}
|
||||
|
||||
/* Negative x? */
|
||||
if (x<0) {
|
||||
m = 1;
|
||||
x = -x;
|
||||
}
|
||||
|
||||
/* 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+4;
|
||||
a = a(.2);
|
||||
}
|
||||
|
||||
/* Precondition x. */
|
||||
scale = z+2;
|
||||
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;
|
||||
if (m) return ((f*a+v)/-1);
|
||||
return ((f*a+v)/1);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
333
gnu/usr.bin/bc/load.c
Normal file
333
gnu/usr.bin/bc/load.c
Normal file
@ -0,0 +1,333 @@
|
||||
/* load.c: This code "loads" code into the code segments. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
204
gnu/usr.bin/bc/main.c
Normal file
204
gnu/usr.bin/bc/main.c
Normal file
@ -0,0 +1,204 @@
|
||||
/* main.c: The main program for bc. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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"
|
||||
|
||||
/* Variables for processing multiple files. */
|
||||
char first_file;
|
||||
extern FILE *yyin;
|
||||
|
||||
|
||||
/* The main program for bc. */
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Parse the command line */
|
||||
ch = getopt (argc, argv, "lcisvw");
|
||||
while (ch != EOF)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'c': /* compile only */
|
||||
compile_only = TRUE;
|
||||
break;
|
||||
case 'l': /* math lib */
|
||||
use_math = TRUE;
|
||||
break;
|
||||
case 'i': /* force interactive */
|
||||
interactive = TRUE;
|
||||
break;
|
||||
case 'w': /* Non standard features give warnings. */
|
||||
warn_not_std = TRUE;
|
||||
break;
|
||||
case 's': /* Non standard features give errors. */
|
||||
std_only = TRUE;
|
||||
break;
|
||||
case 'v': /* Print the version. */
|
||||
printf ("%s\n", BC_VERSION);
|
||||
break;
|
||||
}
|
||||
ch = getopt (argc, argv, "lcisvw");
|
||||
}
|
||||
|
||||
/* 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 ();
|
||||
g_argv = argv;
|
||||
g_argc = argc;
|
||||
is_std_in = FALSE;
|
||||
first_file = TRUE;
|
||||
if (!open_new_file ())
|
||||
exit (1);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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. */
|
||||
while (optind < g_argc)
|
||||
{
|
||||
new_file = fopen (g_argv[optind], "r");
|
||||
if (new_file != NULL)
|
||||
{
|
||||
new_yy_file (new_file);
|
||||
optind++;
|
||||
return TRUE;
|
||||
}
|
||||
fprintf (stderr, "File %s is unavailable.\n", g_argv[optind++]);
|
||||
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);
|
||||
}
|
40
gnu/usr.bin/bc/math.h
Normal file
40
gnu/usr.bin/bc/math.h
Normal file
@ -0,0 +1,40 @@
|
||||
"@iK20:s2:p@r\
|
||||
@iF1,4.5,6,7,8,9,10,11,12[l4:0<Z0:1s10:pl4:ns4:pN0:l2:s12:pK4\
|
||||
:l12:+K.44:l4:*+s2:pN1:l4:1>Z2:l8:1+s8:pl4:K2:/s4:pJ1:N2:1l4:\
|
||||
+s11:pl4:s5:p1s6:pK2:s9:pN4:1B5:J3:N6:l9:i9:pJ4:N5:l5:l4:*s5:\
|
||||
l6:l9:*s6:/s7:pl7:0=Z7:l8:0>Z8:N9:l8:d8:Z10:l11:l11:*s11:pJ9:N10:\
|
||||
N8:l12:s2:pl10:Z11:1l11:/RN11:l11:1/RN7:l11:l7:+s11:pJ6:N3:0R]\
|
||||
@r\
|
||||
@iF2,4.7,8,9,10,13,11,12[l4:0{Z0:1K10:l2:^-RN0:l2:s12:pl2:K4:\
|
||||
+s2:pK2:s8:p0s9:pN1:l4:K2:}Z2:l8:K2:*s8:pl4:cRs4:pJ1:N2:N3:l4:\
|
||||
K.5:{Z4:l8:K2:*s8:pl4:cRs4:pJ3:N4:l4:1-l4:1+/s13:s11:pl13:l13:\
|
||||
*s10:pK3:s9:pN6:1B7:J5:N8:l9:K2:+s9:pJ6:N7:l13:l10:*s13:l9:/s7:\
|
||||
pl7:0=Z9:l8:l11:*s11:pl12:s2:pl11:1/RN9:l11:l7:+s11:pJ8:N5:0R]\
|
||||
@r\
|
||||
@iF3,4.7,9,10,13,14,11,12[l2:s12:pK1.1:l12:*1+s2:p1C4,0:s11:p\
|
||||
l4:0<Z0:1s10:pl4:ns4:pN0:0s2:pl4:l11:/K2:+K4:/s13:pl4:K4:l13:\
|
||||
*l11:*-s4:pl13:K2:%Z1:l4:ns4:pN1:l12:K2:+s2:pl4:s7:s11:pl4:nl4:\
|
||||
*s14:pK3:s9:pN3:1B4:J2:N5:l9:K2:+s9:pJ3:N4:l7:l14:l9:l9:1-*/*\
|
||||
s7:pl7:0=Z6:l12:s2:pl10:Z7:l11:n1/RN7:l11:1/RN6:l11:l7:+s11:p\
|
||||
J5:N2:0R]@r\
|
||||
@iF5,4.11[l2:1+s2:pl4:1C4,0:K2:*+C3,0:s11:pl2:1-s2:pl11:1/R0R]\
|
||||
@r\
|
||||
@iF4,4.5,7,8,9,10,13,14,11,12[l4:1=Z0:l2:K25:{Z1:K.7853981633974483096156608\
|
||||
:1/RN1:l2:K40:{Z2:K.7853981633974483096156608458198757210492:\
|
||||
1/RN2:l2:K60:{Z3:K.785398163397448309615660845819875721049292349843776455243736\
|
||||
:1/RN3:N0:l4:K.2:=Z4:l2:K25:{Z5:K.1973955598498807583700497:1\
|
||||
/RN5:l2:K40:{Z6:K.1973955598498807583700497651947902934475:1/\
|
||||
RN6:l2:K60:{Z7:K.197395559849880758370049765194790293447585103787852101517688\
|
||||
:1/RN7:N4:l4:0<Z8:1s10:pl4:ns4:pN8:l2:s12:pl4:K.2:>Z9:l12:K4:\
|
||||
+s2:pK.2:C4,0:s5:pN9:l12:K2:+s2:pN10:l4:K.2:>Z11:l8:1+s8:pl4:\
|
||||
K.2:-1l4:K.2:*+/s4:pJ10:N11:l4:s13:s11:pl4:nl4:*s14:pK3:s9:pN13:\
|
||||
1B14:J12:N15:l9:K2:+s9:pJ13:N14:l13:l14:*s13:l9:/s7:pl7:0=Z16:\
|
||||
l12:s2:pl10:Z17:l8:l5:*l11:+1n/RN17:l8:l5:*l11:+1/RN16:l11:l7:\
|
||||
+s11:pJ15:N12:0R]@r\
|
||||
@iF6,13,4.5,6,7,8,9,10,14,11,12[l2:s12:p0s2:pl13:1/s13:pl13:0\
|
||||
<Z0:l13:ns13:pl13:K2:%1=Z1:1s10:pN1:N0:1s8:pK2:s9:pN3:l9:l13:\
|
||||
{B4:J2:N5:l9:i9:pJ3:N4:l8:l9:*s8:pJ5:N2:K1.5:l12:*s2:pl4:l13:\
|
||||
^K2:l13:^/l8:/s8:p1s7:s11:pl4:nl4:*K4:/s14:pK1.5:l12:*s2:p1s9:\
|
||||
pN7:1B8:J6:N9:l9:i9:pJ7:N8:l7:l14:*l9:/l13:l9:+/s7:pl7:0=Z10:\
|
||||
l12:s2:pl10:Z11:l8:nl11:*1/RN11:l8:l11:*1/RN10:l11:l7:+s11:pJ9:N6:\
|
||||
0R]@r"
|
1405
gnu/usr.bin/bc/number.c
Normal file
1405
gnu/usr.bin/bc/number.c
Normal file
File diff suppressed because it is too large
Load Diff
60
gnu/usr.bin/bc/number.h
Normal file
60
gnu/usr.bin/bc/number.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* number.h: Arbitrary precision numbers header file. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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;
|
||||
|
||||
/* 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
|
165
gnu/usr.bin/bc/proto.h
Normal file
165
gnu/usr.bin/bc/proto.h
Normal file
@ -0,0 +1,165 @@
|
||||
/* proto.h: Prototype function definitions for "external" functions. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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. */
|
||||
#ifndef NO_UNISTD
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifndef NO_STDLIB
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#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));
|
||||
_PROTOTYPE(char *arg_str, (arg_list *args, int));
|
||||
_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));
|
||||
_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result));
|
||||
_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(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... */
|
||||
_PROTOTYPE (int getopt, (int, char *[], CONST char *));
|
||||
|
1368
gnu/usr.bin/bc/scan.c
Normal file
1368
gnu/usr.bin/bc/scan.c
Normal file
File diff suppressed because it is too large
Load Diff
967
gnu/usr.bin/bc/storage.c
Normal file
967
gnu/usr.bin/bc/storage.c
Normal file
@ -0,0 +1,967 @@
|
||||
/* storage.c: Code and data storage manipulations. This includes labels. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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"
|
||||
|
||||
|
||||
/* Initialize the storage at the beginning of the run. */
|
||||
|
||||
void
|
||||
init_storage ()
|
||||
{
|
||||
|
||||
/* Functions: we start with none and ask for more. */
|
||||
f_count = 0;
|
||||
more_functions ();
|
||||
f_names[0] = "(main)";
|
||||
|
||||
/* Variables. */
|
||||
v_count = 0;
|
||||
more_variables ();
|
||||
|
||||
/* Arrays. */
|
||||
a_count = 0;
|
||||
more_arrays ();
|
||||
|
||||
/* Other things... */
|
||||
ex_stack = NULL;
|
||||
fn_stack = NULL;
|
||||
i_base = 10;
|
||||
o_base = 10;
|
||||
scale = 0;
|
||||
c_code = FALSE;
|
||||
init_numbers();
|
||||
}
|
||||
|
||||
/* Three functions for increasing the number of functions, variables, or
|
||||
arrays that are needed. This adds another 32 of the requested object. */
|
||||
|
||||
void
|
||||
more_functions (VOID)
|
||||
{
|
||||
int old_count;
|
||||
int indx1, indx2;
|
||||
bc_function *old_f;
|
||||
bc_function *f;
|
||||
char **old_names;
|
||||
|
||||
/* Save old information. */
|
||||
old_count = f_count;
|
||||
old_f = functions;
|
||||
old_names = f_names;
|
||||
|
||||
/* Add a fixed amount and allocate new space. */
|
||||
f_count += STORE_INCR;
|
||||
functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function));
|
||||
f_names = (char **) bc_malloc (f_count*sizeof (char *));
|
||||
|
||||
/* Copy old ones. */
|
||||
for (indx1 = 0; indx1 < old_count; indx1++)
|
||||
{
|
||||
functions[indx1] = old_f[indx1];
|
||||
f_names[indx1] = old_names[indx1];
|
||||
}
|
||||
|
||||
/* Initialize the new ones. */
|
||||
for (; indx1 < f_count; indx1++)
|
||||
{
|
||||
f = &functions[indx1];
|
||||
f->f_defined = FALSE;
|
||||
for (indx2 = 0; indx2 < BC_MAX_SEGS; indx2++)
|
||||
f->f_body [indx2] = NULL;
|
||||
f->f_code_size = 0;
|
||||
f->f_label = NULL;
|
||||
f->f_autos = NULL;
|
||||
f->f_params = NULL;
|
||||
}
|
||||
|
||||
/* Free the old elements. */
|
||||
if (old_count != 0)
|
||||
{
|
||||
free (old_f);
|
||||
free (old_names);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
more_variables ()
|
||||
{
|
||||
int indx;
|
||||
int old_count;
|
||||
bc_var **old_var;
|
||||
char **old_names;
|
||||
|
||||
/* Save the old values. */
|
||||
old_count = v_count;
|
||||
old_var = variables;
|
||||
old_names = v_names;
|
||||
|
||||
/* Increment by a fixed amount and allocate. */
|
||||
v_count += STORE_INCR;
|
||||
variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *));
|
||||
v_names = (char **) bc_malloc (v_count*sizeof(char *));
|
||||
|
||||
/* Copy the old variables. */
|
||||
for (indx = 3; indx < old_count; indx++)
|
||||
variables[indx] = old_var[indx];
|
||||
|
||||
/* Initialize the new elements. */
|
||||
for (; indx < v_count; indx++)
|
||||
variables[indx] = NULL;
|
||||
|
||||
/* Free the old elements. */
|
||||
if (old_count != 0)
|
||||
{
|
||||
free (old_var);
|
||||
free (old_names);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
more_arrays ()
|
||||
{
|
||||
int indx;
|
||||
int old_count;
|
||||
bc_var_array **old_ary;
|
||||
char **old_names;
|
||||
|
||||
/* Save the old values. */
|
||||
old_count = a_count;
|
||||
old_ary = arrays;
|
||||
old_names = a_names;
|
||||
|
||||
/* Increment by a fixed amount and allocate. */
|
||||
a_count += STORE_INCR;
|
||||
arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *));
|
||||
a_names = (char **) bc_malloc (a_count*sizeof(char *));
|
||||
|
||||
/* Copy the old arrays. */
|
||||
for (indx = 1; indx < old_count; indx++)
|
||||
arrays[indx] = old_ary[indx];
|
||||
|
||||
|
||||
/* Initialize the new elements. */
|
||||
for (; indx < v_count; indx++)
|
||||
arrays[indx] = NULL;
|
||||
|
||||
/* Free the old elements. */
|
||||
if (old_count != 0)
|
||||
{
|
||||
free (old_ary);
|
||||
free (old_names);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* clear_func clears out function FUNC and makes it ready to redefine. */
|
||||
|
||||
void
|
||||
clear_func (func)
|
||||
char func;
|
||||
{
|
||||
bc_function *f;
|
||||
int indx;
|
||||
bc_label_group *lg;
|
||||
|
||||
/* Set the pointer to the function. */
|
||||
f = &functions[func];
|
||||
f->f_defined = FALSE;
|
||||
|
||||
/* Clear the code segments. */
|
||||
for (indx = 0; indx < BC_MAX_SEGS; indx++)
|
||||
{
|
||||
if (f->f_body[indx] != NULL)
|
||||
{
|
||||
free (f->f_body[indx]);
|
||||
f->f_body[indx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
f->f_code_size = 0;
|
||||
if (f->f_autos != NULL)
|
||||
{
|
||||
free_args (f->f_autos);
|
||||
f->f_autos = NULL;
|
||||
}
|
||||
if (f->f_params != NULL)
|
||||
{
|
||||
free_args (f->f_params);
|
||||
f->f_params = NULL;
|
||||
}
|
||||
while (f->f_label != NULL)
|
||||
{
|
||||
lg = f->f_label->l_next;
|
||||
free (f->f_label);
|
||||
f->f_label = lg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Pop the function execution stack and return the top. */
|
||||
|
||||
int
|
||||
fpop()
|
||||
{
|
||||
fstack_rec *temp;
|
||||
int retval;
|
||||
|
||||
if (fn_stack != NULL)
|
||||
{
|
||||
temp = fn_stack;
|
||||
fn_stack = temp->s_next;
|
||||
retval = temp->s_val;
|
||||
free (temp);
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
||||
/* Push VAL on to the function stack. */
|
||||
|
||||
void
|
||||
fpush (val)
|
||||
int val;
|
||||
{
|
||||
fstack_rec *temp;
|
||||
|
||||
temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec));
|
||||
temp->s_next = fn_stack;
|
||||
temp->s_val = val;
|
||||
fn_stack = temp;
|
||||
}
|
||||
|
||||
|
||||
/* Pop and discard the top element of the regular execution stack. */
|
||||
|
||||
void
|
||||
pop ()
|
||||
{
|
||||
estack_rec *temp;
|
||||
|
||||
if (ex_stack != NULL)
|
||||
{
|
||||
temp = ex_stack;
|
||||
ex_stack = temp->s_next;
|
||||
free_num (&temp->s_num);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Push a copy of NUM on to the regular execution stack. */
|
||||
|
||||
void
|
||||
push_copy (num)
|
||||
bc_num num;
|
||||
{
|
||||
estack_rec *temp;
|
||||
|
||||
temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
|
||||
temp->s_num = copy_num (num);
|
||||
temp->s_next = ex_stack;
|
||||
ex_stack = temp;
|
||||
}
|
||||
|
||||
|
||||
/* Push NUM on to the regular execution stack. Do NOT push a copy. */
|
||||
|
||||
void
|
||||
push_num (num)
|
||||
bc_num num;
|
||||
{
|
||||
estack_rec *temp;
|
||||
|
||||
temp = (estack_rec *) bc_malloc (sizeof (estack_rec));
|
||||
temp->s_num = num;
|
||||
temp->s_next = ex_stack;
|
||||
ex_stack = temp;
|
||||
}
|
||||
|
||||
|
||||
/* Make sure the ex_stack has at least DEPTH elements on it.
|
||||
Return TRUE if it has at least DEPTH elements, otherwise
|
||||
return FALSE. */
|
||||
|
||||
char
|
||||
check_stack (depth)
|
||||
int depth;
|
||||
{
|
||||
estack_rec *temp;
|
||||
|
||||
temp = ex_stack;
|
||||
while ((temp != NULL) && (depth > 0))
|
||||
{
|
||||
temp = temp->s_next;
|
||||
depth--;
|
||||
}
|
||||
if (depth > 0)
|
||||
{
|
||||
rt_error ("Stack error.");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* The following routines manipulate simple variables and
|
||||
array variables. */
|
||||
|
||||
/* get_var returns a pointer to the variable VAR_NAME. If one does not
|
||||
exist, one is created. */
|
||||
|
||||
bc_var *
|
||||
get_var (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_var *var_ptr;
|
||||
|
||||
var_ptr = variables[var_name];
|
||||
if (var_ptr == NULL)
|
||||
{
|
||||
var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var));
|
||||
init_num (&var_ptr->v_value);
|
||||
}
|
||||
return var_ptr;
|
||||
}
|
||||
|
||||
|
||||
/* get_array_num returns the address of the bc_num in the array
|
||||
structure. If more structure is requried to get to the index,
|
||||
this routine does the work to create that structure. VAR_INDEX
|
||||
is a zero based index into the arrays storage array. INDEX is
|
||||
the index into the bc array. */
|
||||
|
||||
bc_num *
|
||||
get_array_num (var_index, index)
|
||||
int var_index;
|
||||
long index;
|
||||
{
|
||||
bc_var_array *ary_ptr;
|
||||
bc_array *a_var;
|
||||
bc_array_node *temp;
|
||||
int log, ix, ix1;
|
||||
int sub [NODE_DEPTH];
|
||||
|
||||
/* Get the array entry. */
|
||||
ary_ptr = arrays[var_index];
|
||||
if (ary_ptr == NULL)
|
||||
{
|
||||
ary_ptr = arrays[var_index] =
|
||||
(bc_var_array *) bc_malloc (sizeof (bc_var_array));
|
||||
ary_ptr->a_value = NULL;
|
||||
ary_ptr->a_next = NULL;
|
||||
ary_ptr->a_param = FALSE;
|
||||
}
|
||||
|
||||
a_var = ary_ptr->a_value;
|
||||
if (a_var == NULL) {
|
||||
a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array));
|
||||
a_var->a_tree = NULL;
|
||||
a_var->a_depth = 0;
|
||||
}
|
||||
|
||||
/* Get the index variable. */
|
||||
sub[0] = index & NODE_MASK;
|
||||
ix = index >> NODE_SHIFT;
|
||||
log = 1;
|
||||
while (ix > 0 || log < a_var->a_depth)
|
||||
{
|
||||
sub[log] = ix & NODE_MASK;
|
||||
ix >>= NODE_SHIFT;
|
||||
log++;
|
||||
}
|
||||
|
||||
/* Build any tree that is necessary. */
|
||||
while (log > a_var->a_depth)
|
||||
{
|
||||
temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node));
|
||||
if (a_var->a_depth != 0)
|
||||
{
|
||||
temp->n_items.n_down[0] = a_var->a_tree;
|
||||
for (ix=1; ix < NODE_SIZE; ix++)
|
||||
temp->n_items.n_down[ix] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ix=0; ix < NODE_SIZE; ix++)
|
||||
temp->n_items.n_num[ix] = copy_num(_zero_);
|
||||
}
|
||||
a_var->a_tree = temp;
|
||||
a_var->a_depth++;
|
||||
}
|
||||
|
||||
/* Find the indexed variable. */
|
||||
temp = a_var->a_tree;
|
||||
while ( log-- > 1)
|
||||
{
|
||||
ix1 = sub[log];
|
||||
if (temp->n_items.n_down[ix1] == NULL)
|
||||
{
|
||||
temp->n_items.n_down[ix1] =
|
||||
(bc_array_node *) bc_malloc (sizeof(bc_array_node));
|
||||
temp = temp->n_items.n_down[ix1];
|
||||
if (log > 1)
|
||||
for (ix=0; ix < NODE_SIZE; ix++)
|
||||
temp->n_items.n_down[ix] = NULL;
|
||||
else
|
||||
for (ix=0; ix < NODE_SIZE; ix++)
|
||||
temp->n_items.n_num[ix] = copy_num(_zero_);
|
||||
}
|
||||
else
|
||||
temp = temp->n_items.n_down[ix1];
|
||||
}
|
||||
|
||||
/* Return the address of the indexed variable. */
|
||||
return &(temp->n_items.n_num[sub[0]]);
|
||||
}
|
||||
|
||||
|
||||
/* Store the top of the execution stack into VAR_NAME.
|
||||
This includes the special variables ibase, obase, and scale. */
|
||||
|
||||
void
|
||||
store_var (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_var *var_ptr;
|
||||
long temp;
|
||||
char toobig;
|
||||
|
||||
if (var_name > 2)
|
||||
{
|
||||
/* It is a simple variable. */
|
||||
var_ptr = get_var (var_name);
|
||||
if (var_ptr != NULL)
|
||||
{
|
||||
free_num(&var_ptr->v_value);
|
||||
var_ptr->v_value = copy_num (ex_stack->s_num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It is a special variable... */
|
||||
toobig = FALSE;
|
||||
if (is_neg (ex_stack->s_num))
|
||||
{
|
||||
switch (var_name)
|
||||
{
|
||||
case 0:
|
||||
rt_warn ("negative ibase, set to 2");
|
||||
temp = 2;
|
||||
break;
|
||||
case 1:
|
||||
rt_warn ("negative obase, set to 2");
|
||||
temp = 2;
|
||||
break;
|
||||
case 2:
|
||||
rt_warn ("negative scale, set to 0");
|
||||
temp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = num2long (ex_stack->s_num);
|
||||
if (!is_zero (ex_stack->s_num) && temp == 0)
|
||||
toobig = TRUE;
|
||||
}
|
||||
switch (var_name)
|
||||
{
|
||||
case 0:
|
||||
if (temp < 2 && !toobig)
|
||||
{
|
||||
i_base = 2;
|
||||
rt_warn ("ibase too small, set to 2");
|
||||
}
|
||||
else
|
||||
if (temp > 16 || toobig)
|
||||
{
|
||||
i_base = 16;
|
||||
rt_warn ("ibase too large, set to 16");
|
||||
}
|
||||
else
|
||||
i_base = (int) temp;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (temp < 2 && !toobig)
|
||||
{
|
||||
o_base = 2;
|
||||
rt_warn ("obase too small, set to 2");
|
||||
}
|
||||
else
|
||||
if (temp > BC_BASE_MAX || toobig)
|
||||
{
|
||||
o_base = BC_BASE_MAX;
|
||||
rt_warn ("obase too large, set to %d", BC_BASE_MAX);
|
||||
}
|
||||
else
|
||||
o_base = (int) temp;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* WARNING: The following if statement may generate a compiler
|
||||
warning if INT_MAX == LONG_MAX. This is NOT a problem. */
|
||||
if (temp > BC_SCALE_MAX || toobig )
|
||||
{
|
||||
scale = BC_SCALE_MAX;
|
||||
rt_warn ("scale too large, set to %d", BC_SCALE_MAX);
|
||||
}
|
||||
else
|
||||
scale = (int) temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Store the top of the execution stack into array VAR_NAME.
|
||||
VAR_NAME is the name of an array, and the next to the top
|
||||
of stack for the index into the array. */
|
||||
|
||||
void
|
||||
store_array (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_num *num_ptr;
|
||||
long index;
|
||||
|
||||
if (!check_stack(2)) return;
|
||||
index = num2long (ex_stack->s_next->s_num);
|
||||
if (index < 0 || index > BC_DIM_MAX ||
|
||||
(index == 0 && !is_zero(ex_stack->s_next->s_num)))
|
||||
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
|
||||
else
|
||||
{
|
||||
num_ptr = get_array_num (var_name, index);
|
||||
if (num_ptr != NULL)
|
||||
{
|
||||
free_num (num_ptr);
|
||||
*num_ptr = copy_num (ex_stack->s_num);
|
||||
free_num (&ex_stack->s_next->s_num);
|
||||
ex_stack->s_next->s_num = ex_stack->s_num;
|
||||
init_num (&ex_stack->s_num);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Load a copy of VAR_NAME on to the execution stack. This includes
|
||||
the special variables ibase, obase and scale. */
|
||||
|
||||
void
|
||||
load_var (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_var *var_ptr;
|
||||
|
||||
switch (var_name)
|
||||
{
|
||||
|
||||
case 0:
|
||||
/* Special variable ibase. */
|
||||
push_copy (_zero_);
|
||||
int2num (&ex_stack->s_num, i_base);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Special variable obase. */
|
||||
push_copy (_zero_);
|
||||
int2num (&ex_stack->s_num, o_base);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Special variable scale. */
|
||||
push_copy (_zero_);
|
||||
int2num (&ex_stack->s_num, scale);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* It is a simple variable. */
|
||||
var_ptr = variables[var_name];
|
||||
if (var_ptr != NULL)
|
||||
push_copy (var_ptr->v_value);
|
||||
else
|
||||
push_copy (_zero_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Load a copy of VAR_NAME on to the execution stack. This includes
|
||||
the special variables ibase, obase and scale. */
|
||||
|
||||
void
|
||||
load_array (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_num *num_ptr;
|
||||
long index;
|
||||
|
||||
if (!check_stack(1)) return;
|
||||
index = num2long (ex_stack->s_num);
|
||||
if (index < 0 || index > BC_DIM_MAX ||
|
||||
(index == 0 && !is_zero(ex_stack->s_num)))
|
||||
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
|
||||
else
|
||||
{
|
||||
num_ptr = get_array_num (var_name, index);
|
||||
if (num_ptr != NULL)
|
||||
{
|
||||
pop();
|
||||
push_copy (*num_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Decrement VAR_NAME by one. This includes the special variables
|
||||
ibase, obase, and scale. */
|
||||
|
||||
void
|
||||
decr_var (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_var *var_ptr;
|
||||
|
||||
switch (var_name)
|
||||
{
|
||||
|
||||
case 0: /* ibase */
|
||||
if (i_base > 2)
|
||||
i_base--;
|
||||
else
|
||||
rt_warn ("ibase too small in --");
|
||||
break;
|
||||
|
||||
case 1: /* obase */
|
||||
if (o_base > 2)
|
||||
o_base--;
|
||||
else
|
||||
rt_warn ("obase too small in --");
|
||||
break;
|
||||
|
||||
case 2: /* scale */
|
||||
if (scale > 0)
|
||||
scale--;
|
||||
else
|
||||
rt_warn ("scale can not be negative in -- ");
|
||||
break;
|
||||
|
||||
default: /* It is a simple variable. */
|
||||
var_ptr = get_var (var_name);
|
||||
if (var_ptr != NULL)
|
||||
bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of
|
||||
the execution stack is the index and it is popped off the stack. */
|
||||
|
||||
void
|
||||
decr_array (var_name)
|
||||
char var_name;
|
||||
{
|
||||
bc_num *num_ptr;
|
||||
long index;
|
||||
|
||||
/* It is an array variable. */
|
||||
if (!check_stack (1)) return;
|
||||
index = num2long (ex_stack->s_num);
|
||||
if (index < 0 || index > BC_DIM_MAX ||
|
||||
(index == 0 && !is_zero (ex_stack->s_num)))
|
||||
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
|
||||
else
|
||||
{
|
||||
num_ptr = get_array_num (var_name, index);
|
||||
if (num_ptr != NULL)
|
||||
{
|
||||
pop ();
|
||||
bc_sub (*num_ptr, _one_, num_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Increment VAR_NAME by one. This includes the special variables
|
||||
ibase, obase, and scale. */
|
||||
|
||||
void
|
||||
incr_var (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_var *var_ptr;
|
||||
|
||||
switch (var_name)
|
||||
{
|
||||
|
||||
case 0: /* ibase */
|
||||
if (i_base < 16)
|
||||
i_base++;
|
||||
else
|
||||
rt_warn ("ibase too big in ++");
|
||||
break;
|
||||
|
||||
case 1: /* obase */
|
||||
if (o_base < BC_BASE_MAX)
|
||||
o_base++;
|
||||
else
|
||||
rt_warn ("obase too big in ++");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (scale < BC_SCALE_MAX)
|
||||
scale++;
|
||||
else
|
||||
rt_warn ("Scale too big in ++");
|
||||
break;
|
||||
|
||||
default: /* It is a simple variable. */
|
||||
var_ptr = get_var (var_name);
|
||||
if (var_ptr != NULL)
|
||||
bc_add (var_ptr->v_value, _one_, &var_ptr->v_value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Increment VAR_NAME by one. VAR_NAME is an array and top of
|
||||
execution stack is the index and is popped off the stack. */
|
||||
|
||||
void
|
||||
incr_array (var_name)
|
||||
int var_name;
|
||||
{
|
||||
bc_num *num_ptr;
|
||||
long index;
|
||||
|
||||
if (!check_stack (1)) return;
|
||||
index = num2long (ex_stack->s_num);
|
||||
if (index < 0 || index > BC_DIM_MAX ||
|
||||
(index == 0 && !is_zero (ex_stack->s_num)))
|
||||
rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
|
||||
else
|
||||
{
|
||||
num_ptr = get_array_num (var_name, index);
|
||||
if (num_ptr != NULL)
|
||||
{
|
||||
pop ();
|
||||
bc_add (*num_ptr, _one_, num_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Routines for processing autos variables and parameters. */
|
||||
|
||||
/* NAME is an auto variable that needs to be pushed on its stack. */
|
||||
|
||||
void
|
||||
auto_var (name)
|
||||
int name;
|
||||
{
|
||||
bc_var *v_temp;
|
||||
bc_var_array *a_temp;
|
||||
int ix;
|
||||
|
||||
if (name > 0)
|
||||
{
|
||||
/* A simple variable. */
|
||||
ix = name;
|
||||
v_temp = (bc_var *) bc_malloc (sizeof (bc_var));
|
||||
v_temp->v_next = variables[ix];
|
||||
init_num (&v_temp->v_value);
|
||||
variables[ix] = v_temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An array variable. */
|
||||
ix = -name;
|
||||
a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array));
|
||||
a_temp->a_next = arrays[ix];
|
||||
a_temp->a_value = NULL;
|
||||
a_temp->a_param = FALSE;
|
||||
arrays[ix] = a_temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Free_a_tree frees everything associated with an array variable tree.
|
||||
This is used when popping an array variable off its auto stack. */
|
||||
|
||||
void
|
||||
free_a_tree ( root, depth )
|
||||
bc_array_node *root;
|
||||
int depth;
|
||||
{
|
||||
int ix;
|
||||
|
||||
if (root != NULL)
|
||||
{
|
||||
if (depth > 1)
|
||||
for (ix = 0; ix < NODE_SIZE; ix++)
|
||||
free_a_tree (root->n_items.n_down[ix], depth-1);
|
||||
else
|
||||
for (ix = 0; ix < NODE_SIZE; ix++)
|
||||
free_num ( &(root->n_items.n_num[ix]));
|
||||
free (root);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* LIST is an NULL terminated list of varible names that need to be
|
||||
popped off their auto stacks. */
|
||||
|
||||
void
|
||||
pop_vars (list)
|
||||
arg_list *list;
|
||||
{
|
||||
bc_var *v_temp;
|
||||
bc_var_array *a_temp;
|
||||
int ix;
|
||||
|
||||
while (list != NULL)
|
||||
{
|
||||
ix = list->av_name;
|
||||
if (ix > 0)
|
||||
{
|
||||
/* A simple variable. */
|
||||
v_temp = variables[ix];
|
||||
if (v_temp != NULL)
|
||||
{
|
||||
variables[ix] = v_temp->v_next;
|
||||
free_num (&v_temp->v_value);
|
||||
free (v_temp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An array variable. */
|
||||
ix = -ix;
|
||||
a_temp = arrays[ix];
|
||||
if (a_temp != NULL)
|
||||
{
|
||||
arrays[ix] = a_temp->a_next;
|
||||
if (!a_temp->a_param && a_temp->a_value != NULL)
|
||||
{
|
||||
free_a_tree (a_temp->a_value->a_tree,
|
||||
a_temp->a_value->a_depth);
|
||||
free (a_temp->a_value);
|
||||
}
|
||||
free (a_temp);
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* A call is being made to FUNC. The call types are at PC. Process
|
||||
the parameters by doing an auto on the parameter variable and then
|
||||
store the value at the new variable or put a pointer the the array
|
||||
variable. */
|
||||
|
||||
void
|
||||
process_params (pc, func)
|
||||
program_counter *pc;
|
||||
int func;
|
||||
{
|
||||
char ch;
|
||||
arg_list *params;
|
||||
char warned = FALSE;
|
||||
int ix, ix1;
|
||||
bc_var *v_temp;
|
||||
bc_var_array *a_src, *a_dest;
|
||||
bc_num *n_temp;
|
||||
|
||||
/* Get the parameter names from the function. */
|
||||
params = functions[func].f_params;
|
||||
|
||||
while ((ch = byte(pc)) != ':')
|
||||
{
|
||||
if (params != NULL)
|
||||
{
|
||||
if ((ch == '0') && params->av_name > 0)
|
||||
{
|
||||
/* A simple variable. */
|
||||
ix = params->av_name;
|
||||
v_temp = (bc_var *) bc_malloc (sizeof(bc_var));
|
||||
v_temp->v_next = variables[ix];
|
||||
v_temp->v_value = ex_stack->s_num;
|
||||
init_num (&ex_stack->s_num);
|
||||
variables[ix] = v_temp;
|
||||
}
|
||||
else
|
||||
if ((ch == '1') && (params->av_name < 0))
|
||||
{
|
||||
/* The variables is an array variable. */
|
||||
|
||||
/* Compute source index and make sure some structure exists. */
|
||||
ix = (int) num2long (ex_stack->s_num);
|
||||
n_temp = get_array_num (ix, 0);
|
||||
|
||||
/* Push a new array and Compute Destination index */
|
||||
auto_var (params->av_name);
|
||||
ix1 = -params->av_name;
|
||||
|
||||
/* Set up the correct pointers in the structure. */
|
||||
if (ix == ix1)
|
||||
a_src = arrays[ix]->a_next;
|
||||
else
|
||||
a_src = arrays[ix];
|
||||
a_dest = arrays[ix1];
|
||||
a_dest->a_param = TRUE;
|
||||
a_dest->a_value = a_src->a_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (params->av_name < 0)
|
||||
rt_error ("Parameter type mismatch parameter %s.",
|
||||
a_names[-params->av_name]);
|
||||
else
|
||||
rt_error ("Parameter type mismatch, parameter %s.",
|
||||
v_names[params->av_name]);
|
||||
params++;
|
||||
}
|
||||
pop ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!warned)
|
||||
{
|
||||
rt_error ("Parameter number mismatch");
|
||||
warned = TRUE;
|
||||
}
|
||||
}
|
||||
params = params->next;
|
||||
}
|
||||
if (params != NULL)
|
||||
rt_error ("Parameter number mismatch");
|
||||
}
|
794
gnu/usr.bin/bc/util.c
Normal file
794
gnu/usr.bin/bc/util.c
Normal file
@ -0,0 +1,794 @@
|
||||
/* util.c: Utility routines for bc. */
|
||||
|
||||
/* This file is part of bc written for MINIX.
|
||||
Copyright (C) 1991, 1992 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)
|
||||
arg_list *args;
|
||||
char val;
|
||||
{ arg_list *temp;
|
||||
|
||||
temp = (arg_list *) bc_malloc (sizeof (arg_list));
|
||||
temp->av_name = val;
|
||||
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. COMMAS tells
|
||||
if each number should be seperated by commas.*/
|
||||
|
||||
_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len, int commas));
|
||||
|
||||
static char *
|
||||
make_arg_str (args, len, commas)
|
||||
arg_list *args;
|
||||
int len;
|
||||
int commas;
|
||||
{
|
||||
char *temp;
|
||||
char sval[20];
|
||||
|
||||
/* Recursive call. */
|
||||
if (args != NULL)
|
||||
temp = make_arg_str (args->next, len+11, commas);
|
||||
else
|
||||
{
|
||||
temp = (char *) bc_malloc (len);
|
||||
*temp = 0;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/* Add the current number to the end of the string. */
|
||||
if (len != 1 && commas)
|
||||
sprintf (sval, "%d,", args->av_name);
|
||||
else
|
||||
sprintf (sval, "%d", args->av_name);
|
||||
temp = strcat (temp, sval);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
char *
|
||||
arg_str (args, commas)
|
||||
arg_list *args;
|
||||
int commas;
|
||||
{
|
||||
if (arglist2 != NULL)
|
||||
free (arglist2);
|
||||
arglist2 = arglist1;
|
||||
arglist1 = make_arg_str (args, 1, commas);
|
||||
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->av_name < 0)
|
||||
warn ("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;
|
||||
}
|
||||
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>". */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
next_var = 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
|
||||
}
|
||||
|
||||
|
||||
/* 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:
|
||||
if (id->f_name != 0)
|
||||
{
|
||||
free(name);
|
||||
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 types 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 = g_argv[optind-1];
|
||||
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 = g_argv[optind-1];
|
||||
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 = g_argv[optind-1];
|
||||
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);
|
||||
}
|
3
gnu/usr.bin/bc/version.h
Normal file
3
gnu/usr.bin/bc/version.h
Normal file
@ -0,0 +1,3 @@
|
||||
#define BC_VERSION \
|
||||
"bc 1.02 (Mar 3, 92) Copyright (C) 1991, 1992 Free Software Foundation, Inc."
|
||||
|
40
gnu/usr.bin/bc/y.tab.h
Normal file
40
gnu/usr.bin/bc/y.tab.h
Normal file
@ -0,0 +1,40 @@
|
||||
#define NEWLINE 257
|
||||
#define AND 258
|
||||
#define OR 259
|
||||
#define NOT 260
|
||||
#define STRING 261
|
||||
#define NAME 262
|
||||
#define NUMBER 263
|
||||
#define MUL_OP 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
|
||||
typedef union {
|
||||
char *s_value;
|
||||
char c_value;
|
||||
int i_value;
|
||||
arg_list *a_value;
|
||||
} YYSTYPE;
|
||||
extern YYSTYPE yylval;
|
Loading…
Reference in New Issue
Block a user