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:
paul 1993-06-19 00:26:18 +00:00
commit bc8deb7535
22 changed files with 9259 additions and 0 deletions

341
gnu/usr.bin/bc/COPYING Normal file
View File

@ -0,0 +1,341 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

7
gnu/usr.bin/bc/Makefile Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

154
gnu/usr.bin/bc/bcdefs.h Normal file
View 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
View File

@ -0,0 +1,4 @@
/* config.h */
#ifndef __STDC__
#define VARARGS
#endif

87
gnu/usr.bin/bc/const.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

60
gnu/usr.bin/bc/number.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

967
gnu/usr.bin/bc/storage.c Normal file
View 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
View 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
View 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
View 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;