diff options
author | paul <paul@FreeBSD.org> | 1993-06-19 00:26:18 +0000 |
---|---|---|
committer | paul <paul@FreeBSD.org> | 1993-06-19 00:26:18 +0000 |
commit | ca423ff42e4945ed170d3b08a672682a56125ae6 (patch) | |
tree | 0c3a652e9c9c401471c58830152e28e0fc4e61cc /gnu/usr.bin/bc | |
parent | 8eb89f70257d1d25fd40e1414846ea1939f7d275 (diff) | |
download | FreeBSD-src-ca423ff42e4945ed170d3b08a672682a56125ae6.zip FreeBSD-src-ca423ff42e4945ed170d3b08a672682a56125ae6.tar.gz |
New bc-1.02 bmake sources
Diffstat (limited to 'gnu/usr.bin/bc')
-rw-r--r-- | gnu/usr.bin/bc/COPYING | 341 | ||||
-rw-r--r-- | gnu/usr.bin/bc/Makefile | 7 | ||||
-rw-r--r-- | gnu/usr.bin/bc/bc.1 | 730 | ||||
-rw-r--r-- | gnu/usr.bin/bc/bc.c | 1369 | ||||
-rw-r--r-- | gnu/usr.bin/bc/bcdefs.h | 154 | ||||
-rw-r--r-- | gnu/usr.bin/bc/config.h | 4 | ||||
-rw-r--r-- | gnu/usr.bin/bc/const.h | 87 | ||||
-rw-r--r-- | gnu/usr.bin/bc/execute.c | 783 | ||||
-rw-r--r-- | gnu/usr.bin/bc/global.c | 42 | ||||
-rw-r--r-- | gnu/usr.bin/bc/global.h | 108 | ||||
-rw-r--r-- | gnu/usr.bin/bc/libmath.b | 255 | ||||
-rw-r--r-- | gnu/usr.bin/bc/load.c | 333 | ||||
-rw-r--r-- | gnu/usr.bin/bc/main.c | 204 | ||||
-rw-r--r-- | gnu/usr.bin/bc/math.h | 40 | ||||
-rw-r--r-- | gnu/usr.bin/bc/number.c | 1405 | ||||
-rw-r--r-- | gnu/usr.bin/bc/number.h | 60 | ||||
-rw-r--r-- | gnu/usr.bin/bc/proto.h | 165 | ||||
-rw-r--r-- | gnu/usr.bin/bc/scan.c | 1368 | ||||
-rw-r--r-- | gnu/usr.bin/bc/storage.c | 967 | ||||
-rw-r--r-- | gnu/usr.bin/bc/util.c | 794 | ||||
-rw-r--r-- | gnu/usr.bin/bc/version.h | 3 | ||||
-rw-r--r-- | gnu/usr.bin/bc/y.tab.h | 40 |
22 files changed, 9259 insertions, 0 deletions
diff --git a/gnu/usr.bin/bc/COPYING b/gnu/usr.bin/bc/COPYING new file mode 100644 index 0000000..86cf81a --- /dev/null +++ b/gnu/usr.bin/bc/COPYING @@ -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. + diff --git a/gnu/usr.bin/bc/Makefile b/gnu/usr.bin/bc/Makefile new file mode 100644 index 0000000..2db220a --- /dev/null +++ b/gnu/usr.bin/bc/Makefile @@ -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> diff --git a/gnu/usr.bin/bc/bc.1 b/gnu/usr.bin/bc/bc.1 new file mode 100644 index 0000000..0dfff0c --- /dev/null +++ b/gnu/usr.bin/bc/bc.1 @@ -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. diff --git a/gnu/usr.bin/bc/bc.c b/gnu/usr.bin/bc/bc.c new file mode 100644 index 0000000..923215e --- /dev/null +++ b/gnu/usr.bin/bc/bc.c @@ -0,0 +1,1369 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley) 01/20/90"; +#endif +#define YYBYACC 1 +#line 2 "bc.y" +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* 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" +#line 38 "bc.y" +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#line 46 "y.tab.c" +#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 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 10, 10, 10, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 15, 15, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 16, 17, 18, + 19, 13, 20, 13, 22, 23, 13, 13, 25, 13, + 24, 24, 26, 26, 21, 27, 21, 28, 14, 5, + 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, + 9, 9, 9, 9, 4, 4, 2, 2, 29, 1, + 30, 1, 31, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, +}; +short yylen[] = { 2, + 0, 2, 2, 1, 2, 0, 1, 3, 2, 0, + 1, 2, 3, 2, 3, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, + 0, 13, 0, 7, 0, 0, 7, 3, 0, 3, + 1, 3, 1, 1, 0, 0, 3, 0, 12, 0, + 1, 0, 3, 3, 1, 3, 3, 5, 0, 1, + 1, 3, 3, 5, 0, 1, 0, 1, 0, 4, + 0, 4, 0, 4, 2, 3, 3, 3, 3, 3, + 2, 1, 1, 3, 4, 2, 2, 4, 4, 4, + 3, 1, 4, 1, 1, 1, 1, +}; +short yydefred[] = { 1, + 0, 0, 0, 21, 0, 83, 0, 0, 22, 24, + 0, 0, 28, 0, 35, 0, 0, 94, 95, 0, + 18, 25, 97, 23, 39, 19, 0, 0, 0, 0, + 0, 2, 0, 16, 4, 7, 5, 17, 0, 0, + 0, 0, 96, 86, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 81, 0, 0, 0, 11, 71, + 73, 0, 0, 0, 0, 0, 69, 87, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 91, 43, 0, 40, 0, 84, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 0, 85, 0, 93, 0, 0, 0, 88, + 27, 0, 0, 33, 0, 89, 90, 0, 13, 15, + 0, 0, 0, 62, 0, 0, 0, 0, 0, 29, + 0, 0, 42, 0, 56, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 46, 34, 37, 0, 48, 58, + 30, 0, 0, 0, 0, 47, 53, 54, 0, 0, + 0, 31, 49, 0, 32, +}; +short yydgoto[] = { 1, + 30, 79, 31, 113, 108, 149, 109, 73, 74, 32, + 33, 58, 34, 35, 59, 48, 138, 155, 164, 131, + 146, 50, 132, 88, 54, 89, 152, 154, 101, 94, + 95, +}; +short yysindex[] = { 0, + -7, 58, 212, 0, -22, 0, -233, -241, 0, 0, + -8, -5, 0, -4, 0, 2, 4, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 212, 212, 91, 725, + -240, 0, -29, 0, 0, 0, 0, 0, 84, 245, + 212, -57, 0, 0, 10, 212, 212, 14, 212, 16, + 212, 212, 23, 156, 0, 549, 127, -52, 0, 0, + 0, 212, 212, 212, 212, 212, 0, 0, 0, 91, + -17, 725, 24, -3, 578, -205, 562, 725, 27, 212, + 606, 212, 669, 716, 0, 0, 725, 0, 19, 0, + 91, 127, 0, 212, 212, -36, -39, -91, -91, -36, + 212, 0, 166, 0, 277, 0, -21, 36, 40, 0, + 0, 725, 28, 0, 725, 0, 0, 156, 0, 0, + 84, 540, -39, 0, -9, 725, -2, -37, -174, 0, + 127, 48, 0, 346, 0, -167, 3, 212, -185, 127, + 0, -188, 6, 37, 0, 0, 0, -205, 0, 0, + 0, 127, -42, 91, 212, 0, 0, 0, -20, 54, + 26, 0, 0, 127, 0, +}; +short yyrindex[] = { 0, + -16, 0, 0, 0, 409, 0, 0, 0, 0, 0, + 0, -58, 0, 0, 0, 0, 426, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -50, 46, + 470, 0, 0, 0, 0, 0, 0, 0, 661, 56, + 0, 525, 0, 0, 0, 0, 59, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, + 705, 7, 0, 60, 0, 61, 0, 63, 0, 49, + 0, 0, 0, 0, 0, 0, 17, 0, 78, 0, + -47, -45, 0, 0, 0, 537, 440, 620, 637, 594, + 0, 0, 0, 0, 0, 0, -33, 0, 66, 0, + 0, -19, 0, 0, 68, 0, 0, 0, 0, 0, + 667, 680, 508, 0, 705, 18, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -31, 49, -44, 0, + 0, -40, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 69, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, +}; +short yygindex[] = { 0, + 958, 0, 104, -118, 0, 0, -35, 0, 0, 0, + 0, -34, 22, 0, 15, 0, 0, 0, 0, 0, + 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, + 0, +}; +#define YYTABLESIZE 1113 +short yytable[] = { 52, + 26, 129, 66, 64, 52, 65, 92, 55, 10, 57, + 55, 12, 57, 14, 45, 36, 158, 40, 52, 144, + 45, 66, 40, 38, 67, 55, 68, 57, 42, 70, + 40, 46, 28, 41, 47, 49, 160, 27, 92, 66, + 105, 51, 6, 52, 43, 18, 19, 61, 53, 76, + 61, 23, 9, 80, 66, 82, 107, 66, 63, 10, + 44, 63, 118, 85, 104, 28, 26, 111, 41, 127, + 27, 12, 93, 103, 10, 44, 128, 12, 38, 14, + 45, 134, 52, 129, 102, 136, 130, 137, 140, 142, + 135, 145, 148, 143, 162, 151, 59, 28, 150, 67, + 60, 50, 27, 68, 20, 119, 51, 65, 36, 65, + 44, 0, 153, 120, 0, 29, 133, 0, 0, 159, + 0, 0, 0, 0, 0, 0, 64, 0, 65, 0, + 28, 0, 0, 0, 0, 27, 41, 0, 0, 0, + 0, 44, 0, 0, 0, 0, 0, 0, 29, 0, + 163, 0, 139, 0, 0, 0, 0, 0, 0, 0, + 0, 147, 0, 0, 0, 0, 28, 0, 0, 0, + 20, 27, 62, 156, 0, 119, 0, 66, 0, 0, + 29, 0, 0, 0, 0, 165, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 0, 0, 26, 0, + 27, 0, 41, 0, 91, 28, 10, 0, 0, 12, + 27, 14, 45, 29, 157, 52, 52, 0, 26, 52, + 52, 52, 52, 55, 62, 57, 52, 69, 52, 52, + 52, 52, 52, 52, 52, 52, 161, 52, 52, 52, + 6, 52, 52, 52, 52, 52, 52, 52, 2, 29, + 9, 28, 3, 4, 5, 6, 27, 10, 124, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 12, + 17, 18, 19, 44, 20, 21, 22, 23, 24, 25, + 26, 57, 0, 0, 28, 3, 4, 5, 6, 27, + 0, 0, 7, 44, 9, 10, 11, 12, 13, 14, + 15, 16, 20, 17, 18, 19, 0, 20, 21, 22, + 23, 24, 25, 26, 37, 0, 28, 3, 4, 5, + 6, 27, 20, 0, 7, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 41, 17, 18, 19, 0, 20, + 21, 22, 23, 24, 25, 26, 57, 62, 0, 63, + 3, 4, 5, 6, 41, 0, 0, 7, 0, 9, + 10, 11, 12, 13, 14, 15, 16, 0, 17, 18, + 19, 0, 20, 21, 22, 23, 24, 25, 26, 0, + 0, 0, 0, 0, 0, 28, 3, 4, 5, 6, + 27, 0, 0, 7, 0, 9, 10, 11, 12, 13, + 14, 15, 16, 0, 17, 18, 19, 0, 20, 21, + 22, 23, 24, 25, 26, 3, 86, 5, 6, 0, + 0, 0, 7, 0, 0, 3, 11, 5, 6, 0, + 0, 16, 7, 17, 18, 19, 11, 20, 141, 0, + 23, 16, 0, 17, 18, 19, 0, 20, 0, 92, + 23, 92, 92, 92, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 96, 92, 96, 96, + 96, 3, 0, 5, 6, 0, 0, 0, 7, 0, + 76, 0, 11, 76, 96, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 76, 0, + 0, 92, 92, 0, 3, 0, 71, 6, 0, 0, + 82, 7, 82, 82, 82, 11, 0, 0, 96, 96, + 16, 0, 17, 18, 19, 0, 20, 0, 82, 23, + 0, 0, 76, 92, 0, 0, 3, 0, 125, 6, + 0, 0, 0, 7, 0, 0, 0, 11, 70, 0, + 96, 70, 16, 0, 17, 18, 19, 0, 20, 0, + 0, 23, 82, 82, 76, 92, 70, 92, 92, 92, + 0, 0, 0, 0, 0, 0, 0, 79, 0, 79, + 79, 79, 64, 92, 65, 0, 0, 0, 0, 90, + 0, 64, 0, 65, 82, 79, 0, 0, 0, 0, + 70, 0, 110, 0, 64, 3, 65, 5, 6, 0, + 0, 0, 7, 0, 0, 0, 11, 92, 92, 0, + 64, 16, 65, 17, 18, 19, 0, 20, 0, 79, + 23, 0, 70, 66, 80, 0, 80, 80, 80, 0, + 0, 0, 66, 0, 0, 0, 114, 0, 64, 92, + 65, 0, 80, 0, 0, 66, 0, 0, 0, 0, + 77, 79, 77, 77, 77, 92, 92, 92, 0, 0, + 106, 66, 92, 92, 92, 92, 0, 78, 77, 78, + 78, 78, 96, 96, 96, 92, 80, 0, 0, 96, + 96, 96, 96, 0, 0, 78, 76, 76, 76, 66, + 0, 75, 96, 0, 75, 76, 0, 72, 0, 116, + 72, 64, 77, 65, 0, 0, 76, 0, 80, 75, + 74, 0, 0, 74, 0, 72, 82, 82, 82, 78, + 0, 0, 0, 82, 0, 82, 0, 0, 74, 0, + 0, 0, 0, 0, 77, 92, 82, 92, 92, 92, + 0, 0, 0, 75, 0, 0, 117, 0, 64, 72, + 65, 78, 66, 0, 70, 70, 70, 64, 0, 65, + 0, 0, 74, 70, 0, 0, 0, 0, 0, 0, + 0, 92, 92, 92, 70, 75, 0, 0, 92, 0, + 92, 72, 0, 79, 79, 79, 0, 60, 92, 0, + 79, 92, 79, 62, 74, 63, 60, 61, 0, 66, + 0, 0, 62, 79, 63, 0, 0, 0, 66, 60, + 61, 0, 0, 0, 0, 62, 0, 63, 0, 0, + 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, + 0, 62, 0, 63, 0, 0, 0, 0, 0, 0, + 80, 80, 80, 0, 0, 0, 0, 80, 0, 80, + 0, 0, 0, 60, 61, 0, 0, 0, 0, 62, + 80, 63, 0, 0, 0, 0, 77, 77, 77, 0, + 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, + 0, 0, 0, 78, 78, 78, 77, 0, 0, 0, + 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 78, 0, 0, 0, 75, 75, 75, + 0, 0, 0, 72, 72, 72, 60, 61, 0, 0, + 0, 0, 62, 0, 63, 0, 74, 75, 74, 0, + 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, + 39, 0, 92, 92, 0, 0, 0, 0, 92, 92, + 92, 92, 0, 60, 61, 0, 0, 0, 0, 62, + 0, 63, 60, 61, 55, 56, 0, 0, 62, 0, + 63, 0, 0, 0, 0, 0, 0, 72, 75, 0, + 0, 0, 0, 77, 78, 0, 81, 0, 83, 84, + 0, 87, 0, 0, 0, 0, 0, 0, 0, 96, + 97, 98, 99, 100, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 112, 0, 115, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 121, 122, 0, 0, 0, 0, 0, 123, 0, + 75, 0, 126, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 75, 0, 0, 0, 112, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 112, +}; +short yycheck[] = { 40, + 59, 44, 94, 43, 45, 45, 59, 41, 59, 41, + 44, 59, 44, 59, 59, 1, 59, 40, 59, 138, + 262, 41, 40, 2, 265, 59, 267, 59, 262, 59, + 40, 40, 40, 91, 40, 40, 155, 45, 59, 59, + 44, 40, 59, 40, 278, 279, 280, 41, 40, 40, + 44, 285, 59, 40, 94, 40, 262, 94, 41, 59, + 44, 44, 44, 41, 41, 40, 125, 41, 91, 91, + 45, 59, 125, 91, 125, 59, 41, 125, 57, 125, + 125, 91, 123, 44, 70, 123, 59, 262, 41, 257, + 93, 277, 281, 91, 41, 59, 41, 40, 93, 41, + 41, 41, 45, 41, 59, 91, 41, 59, 41, 41, + 7, -1, 148, 92, -1, 123, 118, -1, -1, 154, + -1, -1, -1, -1, -1, -1, 43, -1, 45, -1, + 40, -1, -1, -1, -1, 45, 59, -1, -1, -1, + -1, 125, -1, -1, -1, -1, -1, -1, 123, -1, + 125, -1, 131, -1, -1, -1, -1, -1, -1, -1, + -1, 140, -1, -1, -1, -1, 40, -1, -1, -1, + 125, 45, 264, 152, -1, 161, -1, 94, -1, -1, + 123, -1, -1, -1, -1, 164, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 40, -1, -1, 257, -1, + 45, -1, 125, -1, 257, 40, 257, -1, -1, 257, + 45, 257, 257, 123, 257, 256, 257, -1, 277, 260, + 261, 262, 263, 257, 264, 257, 267, 257, 269, 270, + 271, 272, 273, 274, 275, 276, 257, 278, 279, 280, + 257, 282, 283, 284, 285, 286, 287, 288, 256, 123, + 257, 40, 260, 261, 262, 263, 45, 257, 93, 267, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 257, + 278, 279, 280, 257, 282, 283, 284, 285, 286, 287, + 288, 256, -1, -1, 40, 260, 261, 262, 263, 45, + -1, -1, 267, 277, 269, 270, 271, 272, 273, 274, + 275, 276, 257, 278, 279, 280, -1, 282, 283, 284, + 285, 286, 287, 288, 257, -1, 40, 260, 261, 262, + 263, 45, 277, -1, 267, -1, 269, 270, 271, 272, + 273, 274, 275, 276, 257, 278, 279, 280, -1, 282, + 283, 284, 285, 286, 287, 288, 256, 264, -1, 266, + 260, 261, 262, 263, 277, -1, -1, 267, -1, 269, + 270, 271, 272, 273, 274, 275, 276, -1, 278, 279, + 280, -1, 282, 283, 284, 285, 286, 287, 288, -1, + -1, -1, -1, -1, -1, 40, 260, 261, 262, 263, + 45, -1, -1, 267, -1, 269, 270, 271, 272, 273, + 274, 275, 276, -1, 278, 279, 280, -1, 282, 283, + 284, 285, 286, 287, 288, 260, 261, 262, 263, -1, + -1, -1, 267, -1, -1, 260, 271, 262, 263, -1, + -1, 276, 267, 278, 279, 280, 271, 282, 93, -1, + 285, 276, -1, 278, 279, 280, -1, 282, -1, 41, + 285, 43, 44, 45, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 41, 59, 43, 44, + 45, 260, -1, 262, 263, -1, -1, -1, 267, -1, + 41, -1, 271, 44, 59, -1, -1, 276, -1, 278, + 279, 280, -1, 282, -1, -1, 285, -1, 59, -1, + -1, 93, 94, -1, 260, -1, 262, 263, -1, -1, + 41, 267, 43, 44, 45, 271, -1, -1, 93, 94, + 276, -1, 278, 279, 280, -1, 282, -1, 59, 285, + -1, -1, 93, 125, -1, -1, 260, -1, 262, 263, + -1, -1, -1, 267, -1, -1, -1, 271, 41, -1, + 125, 44, 276, -1, 278, 279, 280, -1, 282, -1, + -1, 285, 93, 94, 125, 41, 59, 43, 44, 45, + -1, -1, -1, -1, -1, -1, -1, 41, -1, 43, + 44, 45, 43, 59, 45, -1, -1, -1, -1, 41, + -1, 43, -1, 45, 125, 59, -1, -1, -1, -1, + 93, -1, 41, -1, 43, 260, 45, 262, 263, -1, + -1, -1, 267, -1, -1, -1, 271, 93, 94, -1, + 43, 276, 45, 278, 279, 280, -1, 282, -1, 93, + 285, -1, 125, 94, 41, -1, 43, 44, 45, -1, + -1, -1, 94, -1, -1, -1, 41, -1, 43, 125, + 45, -1, 59, -1, -1, 94, -1, -1, -1, -1, + 41, 125, 43, 44, 45, 257, 258, 259, -1, -1, + 93, 94, 264, 265, 266, 267, -1, 41, 59, 43, + 44, 45, 257, 258, 259, 277, 93, -1, -1, 264, + 265, 266, 267, -1, -1, 59, 257, 258, 259, 94, + -1, 41, 277, -1, 44, 266, -1, 41, -1, 41, + 44, 43, 93, 45, -1, -1, 277, -1, 125, 59, + 41, -1, -1, 44, -1, 59, 257, 258, 259, 93, + -1, -1, -1, 264, -1, 266, -1, -1, 59, -1, + -1, -1, -1, -1, 125, 41, 277, 43, 44, 45, + -1, -1, -1, 93, -1, -1, 41, -1, 43, 93, + 45, 125, 94, -1, 257, 258, 259, 43, -1, 45, + -1, -1, 93, 266, -1, -1, -1, -1, -1, -1, + -1, 257, 258, 259, 277, 125, -1, -1, 264, -1, + 266, 125, -1, 257, 258, 259, -1, 258, 94, -1, + 264, 277, 266, 264, 125, 266, 258, 259, -1, 94, + -1, -1, 264, 277, 266, -1, -1, -1, 94, 258, + 259, -1, -1, -1, -1, 264, -1, 266, -1, -1, + -1, -1, -1, -1, -1, 258, 259, -1, -1, -1, + -1, 264, -1, 266, -1, -1, -1, -1, -1, -1, + 257, 258, 259, -1, -1, -1, -1, 264, -1, 266, + -1, -1, -1, 258, 259, -1, -1, -1, -1, 264, + 277, 266, -1, -1, -1, -1, 257, 258, 259, -1, + -1, -1, -1, -1, -1, 266, -1, -1, -1, -1, + -1, -1, -1, 257, 258, 259, 277, -1, -1, -1, + -1, -1, 266, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 277, -1, -1, -1, 257, 258, 259, + -1, -1, -1, 257, 258, 259, 258, 259, -1, -1, + -1, -1, 264, -1, 266, -1, 257, 277, 259, -1, + -1, -1, -1, 277, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 277, -1, -1, -1, + 3, -1, 258, 259, -1, -1, -1, -1, 264, 265, + 266, 267, -1, 258, 259, -1, -1, -1, -1, 264, + -1, 266, 258, 259, 27, 28, -1, -1, 264, -1, + 266, -1, -1, -1, -1, -1, -1, 40, 41, -1, + -1, -1, -1, 46, 47, -1, 49, -1, 51, 52, + -1, 54, -1, -1, -1, -1, -1, -1, -1, 62, + 63, 64, 65, 66, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 80, -1, 82, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 94, 95, -1, -1, -1, -1, -1, 101, -1, + 103, -1, 105, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 118, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 134, -1, -1, -1, 138, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 155, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 289 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,0,"';'",0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'['",0,"']'","'^'",0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,"NEWLINE","AND","OR","NOT","STRING","NAME","NUMBER","MUL_OP", +"ASSIGN_OP","REL_OP","INCR_DECR","Define","Break","Quit","Length","Return", +"For","If","While","Sqrt","Else","Scale","Ibase","Obase","Auto","Read", +"Warranty","Halt","Last","Continue","Print","Limits","UNARY_MINUS", +}; +char *yyrule[] = { +"$accept : program", +"program :", +"program : program input_item", +"input_item : semicolon_list NEWLINE", +"input_item : function", +"input_item : error NEWLINE", +"semicolon_list :", +"semicolon_list : statement_or_error", +"semicolon_list : semicolon_list ';' statement_or_error", +"semicolon_list : semicolon_list ';'", +"statement_list :", +"statement_list : statement_or_error", +"statement_list : statement_list NEWLINE", +"statement_list : statement_list NEWLINE statement_or_error", +"statement_list : statement_list ';'", +"statement_list : statement_list ';' statement", +"statement_or_error : statement", +"statement_or_error : error statement", +"statement : Warranty", +"statement : Limits", +"statement : expression", +"statement : STRING", +"statement : Break", +"statement : Continue", +"statement : Quit", +"statement : Halt", +"statement : Return", +"statement : Return '(' return_expression ')'", +"$$1 :", +"$$2 :", +"$$3 :", +"$$4 :", +"statement : For $$1 '(' opt_expression ';' $$2 opt_expression ';' $$3 opt_expression ')' $$4 statement", +"$$5 :", +"statement : If '(' expression ')' $$5 statement opt_else", +"$$6 :", +"$$7 :", +"statement : While $$6 '(' expression $$7 ')' statement", +"statement : '{' statement_list '}'", +"$$8 :", +"statement : Print $$8 print_list", +"print_list : print_element", +"print_list : print_element ',' print_list", +"print_element : STRING", +"print_element : expression", +"opt_else :", +"$$9 :", +"opt_else : Else $$9 statement", +"$$10 :", +"function : Define NAME '(' opt_parameter_list ')' '{' NEWLINE opt_auto_define_list $$10 statement_list NEWLINE '}'", +"opt_parameter_list :", +"opt_parameter_list : define_list", +"opt_auto_define_list :", +"opt_auto_define_list : Auto define_list NEWLINE", +"opt_auto_define_list : Auto define_list ';'", +"define_list : NAME", +"define_list : NAME '[' ']'", +"define_list : define_list ',' NAME", +"define_list : define_list ',' NAME '[' ']'", +"opt_argument_list :", +"opt_argument_list : argument_list", +"argument_list : expression", +"argument_list : NAME '[' ']'", +"argument_list : argument_list ',' expression", +"argument_list : argument_list ',' NAME '[' ']'", +"opt_expression :", +"opt_expression : expression", +"return_expression :", +"return_expression : expression", +"$$11 :", +"expression : named_expression ASSIGN_OP $$11 expression", +"$$12 :", +"expression : expression AND $$12 expression", +"$$13 :", +"expression : expression OR $$13 expression", +"expression : NOT expression", +"expression : expression REL_OP expression", +"expression : expression '+' expression", +"expression : expression '-' expression", +"expression : expression MUL_OP expression", +"expression : expression '^' expression", +"expression : '-' expression", +"expression : named_expression", +"expression : NUMBER", +"expression : '(' expression ')'", +"expression : NAME '(' opt_argument_list ')'", +"expression : INCR_DECR named_expression", +"expression : named_expression INCR_DECR", +"expression : Length '(' expression ')'", +"expression : Sqrt '(' expression ')'", +"expression : Scale '(' expression ')'", +"expression : Read '(' ')'", +"named_expression : NAME", +"named_expression : NAME '[' expression ']'", +"named_expression : Ibase", +"named_expression : Obase", +"named_expression : Scale", +"named_expression : Last", +}; +#endif +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#ifdef YYSTACKSIZE +#ifndef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#endif +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#define YYABORT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, reading %d (%s)\n", yystate, + yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, shifting to state %d\n", + yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, error recovery shifting\ + to state %d\n", *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("yydebug: error recovery discarding state %d\n", + *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, error recovery discards token %d (%s)\n", + yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, reducing by rule %d (%s)\n", + yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 106 "bc.y" +{ + yyval.i_value = 0; + if (interactive) + { + printf ("%s\n", BC_VERSION); + welcome (); + } + } +break; +case 3: +#line 117 "bc.y" +{ run_code (); } +break; +case 4: +#line 119 "bc.y" +{ run_code (); } +break; +case 5: +#line 121 "bc.y" +{ + yyerrok; + init_gen (); + } +break; +case 6: +#line 127 "bc.y" +{ yyval.i_value = 0; } +break; +case 10: +#line 133 "bc.y" +{ yyval.i_value = 0; } +break; +case 17: +#line 142 "bc.y" +{ yyval.i_value = yyvsp[0].i_value; } +break; +case 18: +#line 145 "bc.y" +{ warranty (""); } +break; +case 19: +#line 147 "bc.y" +{ limits (); } +break; +case 20: +#line 149 "bc.y" +{ + if (yyvsp[0].i_value & 2) + warn ("comparison in expression"); + if (yyvsp[0].i_value & 1) + generate ("W"); + else + generate ("p"); + } +break; +case 21: +#line 158 "bc.y" +{ + yyval.i_value = 0; + generate ("w"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + } +break; +case 22: +#line 165 "bc.y" +{ + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } +break; +case 23: +#line 175 "bc.y" +{ + warn ("Continue statement"); + if (continue_label == 0) + yyerror ("Continue outside a for"); + else + { + sprintf (genstr, "J%1d:", continue_label); + generate (genstr); + } + } +break; +case 24: +#line 186 "bc.y" +{ exit (0); } +break; +case 25: +#line 188 "bc.y" +{ generate ("h"); } +break; +case 26: +#line 190 "bc.y" +{ generate ("0R"); } +break; +case 27: +#line 192 "bc.y" +{ generate ("R"); } +break; +case 28: +#line 194 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + } +break; +case 29: +#line 199 "bc.y" +{ + if (yyvsp[-1].i_value > 1) + warn ("Comparison in first for expression"); + yyvsp[-1].i_value = next_label++; + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "N%1d:", yyvsp[-1].i_value); + else + sprintf (genstr, "pN%1d:", yyvsp[-1].i_value); + generate (genstr); + } +break; +case 30: +#line 210 "bc.y" +{ + if (yyvsp[-1].i_value < 0) generate ("1"); + yyvsp[-1].i_value = next_label++; + sprintf (genstr, "B%1d:J%1d:", yyvsp[-1].i_value, break_label); + generate (genstr); + yyval.i_value = continue_label; + continue_label = next_label++; + sprintf (genstr, "N%1d:", continue_label); + generate (genstr); + } +break; +case 31: +#line 221 "bc.y" +{ + if (yyvsp[-1].i_value > 1) + warn ("Comparison in third for expression"); + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value); + else + sprintf (genstr, "pJ%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value); + generate (genstr); + } +break; +case 32: +#line 231 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = yyvsp[-12].i_value; + continue_label = yyvsp[-4].i_value; + } +break; +case 33: +#line 239 "bc.y" +{ + yyvsp[-1].i_value = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + } +break; +case 34: +#line 246 "bc.y" +{ + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = yyvsp[-4].i_value; + } +break; +case 35: +#line 252 "bc.y" +{ + yyvsp[0].i_value = next_label++; + sprintf (genstr, "N%1d:", yyvsp[0].i_value); + generate (genstr); + } +break; +case 36: +#line 258 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } +break; +case 37: +#line 265 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", yyvsp[-6].i_value, break_label); + generate (genstr); + break_label = yyvsp[-3].i_value; + } +break; +case 38: +#line 271 "bc.y" +{ yyval.i_value = 0; } +break; +case 39: +#line 273 "bc.y" +{ warn ("print statement"); } +break; +case 43: +#line 280 "bc.y" +{ + generate ("O"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + } +break; +case 44: +#line 286 "bc.y" +{ generate ("P"); } +break; +case 46: +#line 290 "bc.y" +{ + warn ("else clause in if statement"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "J%d:N%1d:", yyvsp[0].i_value, if_label); + generate (genstr); + if_label = yyvsp[0].i_value; + } +break; +case 48: +#line 300 "bc.y" +{ + /* Check auto list against parameter list? */ + check_params (yyvsp[-4].a_value,yyvsp[0].a_value); + sprintf (genstr, "F%d,%s.%s[", lookup(yyvsp[-6].s_value,FUNCT), + arg_str (yyvsp[-4].a_value,TRUE), arg_str (yyvsp[0].a_value,TRUE)); + generate (genstr); + free_args (yyvsp[-4].a_value); + free_args (yyvsp[0].a_value); + yyvsp[-7].i_value = next_label; + next_label = 0; + } +break; +case 49: +#line 312 "bc.y" +{ + generate ("0R]"); + next_label = yyvsp[-11].i_value; + } +break; +case 50: +#line 318 "bc.y" +{ yyval.a_value = NULL; } +break; +case 52: +#line 322 "bc.y" +{ yyval.a_value = NULL; } +break; +case 53: +#line 324 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; } +break; +case 54: +#line 326 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; } +break; +case 55: +#line 329 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[0].s_value,SIMPLE)); } +break; +case 56: +#line 331 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY)); } +break; +case 57: +#line 333 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-2].a_value, lookup (yyvsp[0].s_value,SIMPLE)); } +break; +case 58: +#line 335 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-4].a_value, lookup (yyvsp[-2].s_value,ARRAY)); } +break; +case 59: +#line 338 "bc.y" +{ yyval.a_value = NULL; } +break; +case 61: +#line 342 "bc.y" +{ + if (yyvsp[0].i_value > 1) warn ("comparison in argument"); + yyval.a_value = nextarg (NULL,0); + } +break; +case 62: +#line 347 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (NULL,1); + } +break; +case 63: +#line 353 "bc.y" +{ + if (yyvsp[0].i_value > 1) warn ("comparison in argument"); + yyval.a_value = nextarg (yyvsp[-2].a_value,0); + } +break; +case 64: +#line 358 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (yyvsp[-4].a_value,1); + } +break; +case 65: +#line 365 "bc.y" +{ + yyval.i_value = -1; + warn ("Missing expression in for statement"); + } +break; +case 67: +#line 372 "bc.y" +{ + yyval.i_value = 0; + generate ("0"); + } +break; +case 68: +#line 377 "bc.y" +{ + if (yyvsp[0].i_value > 1) + warn ("comparison in return expresion"); + } +break; +case 69: +#line 383 "bc.y" +{ + if (yyvsp[0].c_value != '=') + { + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "DL%d:", -yyvsp[-1].i_value); + else + sprintf (genstr, "l%d:", yyvsp[-1].i_value); + generate (genstr); + } + } +break; +case 70: +#line 394 "bc.y" +{ + if (yyvsp[0].i_value > 1) warn("comparison in assignment"); + if (yyvsp[-2].c_value != '=') + { + sprintf (genstr, "%c", yyvsp[-2].c_value); + generate (genstr); + } + if (yyvsp[-3].i_value < 0) + sprintf (genstr, "S%d:", -yyvsp[-3].i_value); + else + sprintf (genstr, "s%d:", yyvsp[-3].i_value); + generate (genstr); + yyval.i_value = 0; + } +break; +case 71: +#line 410 "bc.y" +{ + warn("&& operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "DZ%d:p", yyvsp[0].i_value); + generate (genstr); + } +break; +case 72: +#line 417 "bc.y" +{ + sprintf (genstr, "DZ%d:p1N%d:", yyvsp[-2].i_value, yyvsp[-2].i_value); + generate (genstr); + yyval.i_value = yyvsp[-3].i_value | yyvsp[0].i_value; + } +break; +case 73: +#line 423 "bc.y" +{ + warn("|| operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "B%d:", yyvsp[0].i_value); + generate (genstr); + } +break; +case 74: +#line 430 "bc.y" +{ + int tmplab; + tmplab = next_label++; + sprintf (genstr, "B%d:0J%d:N%d:1N%d:", + yyvsp[-2].i_value, tmplab, yyvsp[-2].i_value, tmplab); + generate (genstr); + yyval.i_value = yyvsp[-3].i_value | yyvsp[0].i_value; + } +break; +case 75: +#line 439 "bc.y" +{ + yyval.i_value = yyvsp[0].i_value; + warn("! operator"); + generate ("!"); + } +break; +case 76: +#line 445 "bc.y" +{ + yyval.i_value = 3; + switch (*(yyvsp[-1].s_value)) + { + case '=': + generate ("="); + break; + + case '!': + generate ("#"); + break; + + case '<': + if (yyvsp[-1].s_value[1] == '=') + generate ("{"); + else + generate ("<"); + break; + + case '>': + if (yyvsp[-1].s_value[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } +break; +case 77: +#line 473 "bc.y" +{ + generate ("+"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + } +break; +case 78: +#line 478 "bc.y" +{ + generate ("-"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + } +break; +case 79: +#line 483 "bc.y" +{ + genstr[0] = yyvsp[-1].c_value; + genstr[1] = 0; + generate (genstr); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + } +break; +case 80: +#line 490 "bc.y" +{ + generate ("^"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + } +break; +case 81: +#line 495 "bc.y" +{ + generate ("n"); + yyval.i_value = yyvsp[0].i_value; + } +break; +case 82: +#line 500 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[0].i_value < 0) + sprintf (genstr, "L%d:", -yyvsp[0].i_value); + else + sprintf (genstr, "l%d:", yyvsp[0].i_value); + generate (genstr); + } +break; +case 83: +#line 509 "bc.y" +{ + int len = strlen(yyvsp[0].s_value); + yyval.i_value = 1; + if (len == 1 && *yyvsp[0].s_value == '0') + generate ("0"); + else if (len == 1 && *yyvsp[0].s_value == '1') + generate ("1"); + else + { + generate ("K"); + generate (yyvsp[0].s_value); + generate (":"); + } + free (yyvsp[0].s_value); + } +break; +case 84: +#line 525 "bc.y" +{ yyval.i_value = yyvsp[-1].i_value | 1; } +break; +case 85: +#line 527 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].a_value != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup (yyvsp[-3].s_value,FUNCT), + arg_str (yyvsp[-1].a_value,FALSE)); + free_args (yyvsp[-1].a_value); + } + else + { + sprintf (genstr, "C%d:", lookup (yyvsp[-3].s_value,FUNCT)); + } + generate (genstr); + } +break; +case 86: +#line 543 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[0].i_value < 0) + { + if (yyvsp[-1].c_value == '+') + sprintf (genstr, "DA%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value); + else + sprintf (genstr, "DM%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value); + } + else + { + if (yyvsp[-1].c_value == '+') + sprintf (genstr, "i%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value); + else + sprintf (genstr, "d%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value); + } + generate (genstr); + } +break; +case 87: +#line 562 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].i_value < 0) + { + sprintf (genstr, "DL%d:x", -yyvsp[-1].i_value); + generate (genstr); + if (yyvsp[0].c_value == '+') + sprintf (genstr, "A%d:", -yyvsp[-1].i_value); + else + sprintf (genstr, "M%d:", -yyvsp[-1].i_value); + } + else + { + sprintf (genstr, "l%d:", yyvsp[-1].i_value); + generate (genstr); + if (yyvsp[0].c_value == '+') + sprintf (genstr, "i%d:", yyvsp[-1].i_value); + else + sprintf (genstr, "d%d:", yyvsp[-1].i_value); + } + generate (genstr); + } +break; +case 88: +#line 585 "bc.y" +{ generate ("cL"); yyval.i_value = 1;} +break; +case 89: +#line 587 "bc.y" +{ generate ("cR"); yyval.i_value = 1;} +break; +case 90: +#line 589 "bc.y" +{ generate ("cS"); yyval.i_value = 1;} +break; +case 91: +#line 591 "bc.y" +{ + warn ("read function"); + generate ("cI"); yyval.i_value = 1; + } +break; +case 92: +#line 597 "bc.y" +{ yyval.i_value = lookup(yyvsp[0].s_value,SIMPLE); } +break; +case 93: +#line 599 "bc.y" +{ + if (yyvsp[-1].i_value > 1) warn("comparison in subscript"); + yyval.i_value = lookup(yyvsp[-3].s_value,ARRAY); + } +break; +case 94: +#line 604 "bc.y" +{ yyval.i_value = 0; } +break; +case 95: +#line 606 "bc.y" +{ yyval.i_value = 1; } +break; +case 96: +#line 608 "bc.y" +{ yyval.i_value = 2; } +break; +case 97: +#line 610 "bc.y" +{ yyval.i_value = 3; } +break; +#line 1314 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: after reduction, shifting from state 0 to\ + state %d\n", YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, reading %d (%s)\n", + YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("yydebug: after reduction, shifting from state %d \ +to state %d\n", *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/gnu/usr.bin/bc/bcdefs.h b/gnu/usr.bin/bc/bcdefs.h new file mode 100644 index 0000000..a9d2176 --- /dev/null +++ b/gnu/usr.bin/bc/bcdefs.h @@ -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; diff --git a/gnu/usr.bin/bc/config.h b/gnu/usr.bin/bc/config.h new file mode 100644 index 0000000..a9bd0be --- /dev/null +++ b/gnu/usr.bin/bc/config.h @@ -0,0 +1,4 @@ +/* config.h */ +#ifndef __STDC__ +#define VARARGS +#endif diff --git a/gnu/usr.bin/bc/const.h b/gnu/usr.bin/bc/const.h new file mode 100644 index 0000000..ea91eaf --- /dev/null +++ b/gnu/usr.bin/bc/const.h @@ -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" diff --git a/gnu/usr.bin/bc/execute.c b/gnu/usr.bin/bc/execute.c new file mode 100644 index 0000000..a7bc9c7 --- /dev/null +++ b/gnu/usr.bin/bc/execute.c @@ -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_); +} diff --git a/gnu/usr.bin/bc/global.c b/gnu/usr.bin/bc/global.c new file mode 100644 index 0000000..1e7dc1c --- /dev/null +++ b/gnu/usr.bin/bc/global.c @@ -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 diff --git a/gnu/usr.bin/bc/global.h b/gnu/usr.bin/bc/global.h new file mode 100644 index 0000000..e2b6007 --- /dev/null +++ b/gnu/usr.bin/bc/global.h @@ -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; + diff --git a/gnu/usr.bin/bc/libmath.b b/gnu/usr.bin/bc/libmath.b new file mode 100644 index 0000000..30d9532 --- /dev/null +++ b/gnu/usr.bin/bc/libmath.b @@ -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; + } +} diff --git a/gnu/usr.bin/bc/load.c b/gnu/usr.bin/bc/load.c new file mode 100644 index 0000000..be4ab3a --- /dev/null +++ b/gnu/usr.bin/bc/load.c @@ -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++; + } + } +} diff --git a/gnu/usr.bin/bc/main.c b/gnu/usr.bin/bc/main.c new file mode 100644 index 0000000..33827cc --- /dev/null +++ b/gnu/usr.bin/bc/main.c @@ -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); +} diff --git a/gnu/usr.bin/bc/math.h b/gnu/usr.bin/bc/math.h new file mode 100644 index 0000000..a1fc146 --- /dev/null +++ b/gnu/usr.bin/bc/math.h @@ -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" diff --git a/gnu/usr.bin/bc/number.c b/gnu/usr.bin/bc/number.c new file mode 100644 index 0000000..346b44a --- /dev/null +++ b/gnu/usr.bin/bc/number.c @@ -0,0 +1,1405 @@ +/* number.c: Implements arbitrary precision numbers. */ + +/* 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 "proto.h" + +/* Storage used for special numbers. */ +bc_num _zero_; +bc_num _one_; +bc_num _two_; + + +/* "Frees" a bc_num NUM. Actually decreases reference count and only + frees the storage if reference count is zero. */ + +void +free_num (num) + bc_num *num; +{ + if (*num == NULL) return; + (*num)->n_refs--; + if ((*num)->n_refs == 0) free(*num); + *num = NULL; +} + + +/* new_num allocates a number and sets fields to known values. */ + +bc_num +new_num (length, scale) + int length, scale; +{ + bc_num temp; + + temp = (bc_num) malloc (sizeof(bc_struct)+length+scale); + if (temp == NULL) out_of_memory (); + temp->n_sign = PLUS; + temp->n_len = length; + temp->n_scale = scale; + temp->n_refs = 1; + temp->n_value[0] = 0; + return temp; +} + + +/* Intitialize the number package! */ + +void +init_numbers () +{ + _zero_ = new_num (1,0); + _one_ = new_num (1,0); + _one_->n_value[0] = 1; + _two_ = new_num (1,0); + _two_->n_value[0] = 2; +} + + +/* Make a copy of a number! Just increments the reference count! */ + +bc_num +copy_num (num) + bc_num num; +{ + num->n_refs++; + return num; +} + + +/* Initialize a number NUM by making it a copy of zero. */ + +void +init_num (num) + bc_num *num; +{ + *num = copy_num (_zero_); +} + + +/* Convert an integer VAL to a bc number NUM. */ + +void +int2num (num, val) + bc_num *num; + int val; +{ + char buffer[30]; + char *bptr, *vptr; + int ix = 1; + char neg = 0; + + /* Sign. */ + if (val < 0) + { + neg = 1; + val = -val; + } + + /* Get things going. */ + bptr = buffer; + *bptr++ = val % 10; + val = val / 10; + + /* Extract remaining digits. */ + while (val != 0) + { + *bptr++ = val % 10; + val = val / 10; + ix++; /* Count the digits. */ + } + + /* Make the number. */ + free_num (num); + *num = new_num (ix, 0); + if (neg) (*num)->n_sign = MINUS; + + /* Assign the digits. */ + vptr = (*num)->n_value; + while (ix-- > 0) + *vptr++ = *--bptr; +} + + +/* Convert a number NUM to a long. The function returns only the integer + part of the number. For numbers that are too large to represent as + a long, this function returns a zero. This can be detected by checking + the NUM for zero after having a zero returned. */ + +long +num2long (num) + bc_num num; +{ + long val; + char *nptr; + int index; + + /* Extract the int value, ignore the fraction. */ + val = 0; + nptr = num->n_value; + for (index=num->n_len; (index>0) && (val<=(LONG_MAX/10)); index--) + val = val*10 + *nptr++; + + /* Check for overflow. If overflow, return zero. */ + if (index>0) val = 0; + if (val < 0) val = 0; + + /* Return the value. */ + if (num->n_sign == PLUS) + return (val); + else + return (-val); +} + + +/* The following are some math routines for numbers. */ +_PROTOTYPE(static int _do_compare, (bc_num n1, bc_num n2, int use_sign, + int ignore_last)); +_PROTOTYPE(static void _rm_leading_zeros, (bc_num num)); +_PROTOTYPE(static bc_num _do_add, (bc_num n1, bc_num n2)); +_PROTOTYPE(static bc_num _do_sub, (bc_num n1, bc_num n2)); +_PROTOTYPE(static void _one_mult, (unsigned char *num, int size, int digit, + unsigned char *result)); + + + +/* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less + than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just + compare the magnitudes. */ + +static int +_do_compare (n1, n2, use_sign, ignore_last) + bc_num n1, n2; + int use_sign; + int ignore_last; +{ + char *n1ptr, *n2ptr; + int count; + + /* First, compare signs. */ + if (use_sign && n1->n_sign != n2->n_sign) + { + if (n1->n_sign == PLUS) + return (1); /* Positive N1 > Negative N2 */ + else + return (-1); /* Negative N1 < Positive N1 */ + } + + /* Now compare the magnitude. */ + if (n1->n_len != n2->n_len) + { + if (n1->n_len > n2->n_len) + { + /* Magnitude of n1 > n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (1); + else + return (-1); + } + else + { + /* Magnitude of n1 < n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (-1); + else + return (1); + } + } + + /* If we get here, they have the same number of integer digits. + check the integer part and the equal length part of the fraction. */ + count = n1->n_len + MIN (n1->n_scale, n2->n_scale); + n1ptr = n1->n_value; + n2ptr = n2->n_value; + + while ((count > 0) && (*n1ptr == *n2ptr)) + { + n1ptr++; + n2ptr++; + count--; + } + if (ignore_last && count == 1 && n1->n_scale == n2->n_scale) + return (0); + if (count != 0) + { + if (*n1ptr > *n2ptr) + { + /* Magnitude of n1 > n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (1); + else + return (-1); + } + else + { + /* Magnitude of n1 < n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (-1); + else + return (1); + } + } + + /* They are equal up to the last part of the equal part of the fraction. */ + if (n1->n_scale != n2->n_scale) + if (n1->n_scale > n2->n_scale) + { + for (count = n1->n_scale-n2->n_scale; count>0; count--) + if (*n1ptr++ != 0) + { + /* Magnitude of n1 > n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (1); + else + return (-1); + } + } + else + { + for (count = n2->n_scale-n1->n_scale; count>0; count--) + if (*n2ptr++ != 0) + { + /* Magnitude of n1 < n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (-1); + else + return (1); + } + } + + /* They must be equal! */ + return (0); +} + + +/* This is the "user callable" routine to compare numbers N1 and N2. */ + +int +bc_compare (n1, n2) + bc_num n1, n2; +{ + return _do_compare (n1, n2, TRUE, FALSE); +} + + +/* In some places we need to check if the number NUM is zero. */ + +char +is_zero (num) + bc_num num; +{ + int count; + char *nptr; + + /* Quick check. */ + if (num == _zero_) return TRUE; + + /* Initialize */ + count = num->n_len + num->n_scale; + nptr = num->n_value; + + /* The check */ + while ((count > 0) && (*nptr++ == 0)) count--; + + if (count != 0) + return FALSE; + else + return TRUE; +} + + +/* In some places we need to check if the number is negative. */ + +char +is_neg (num) + bc_num num; +{ + return num->n_sign == MINUS; +} + + +/* For many things, we may have leading zeros in a number NUM. + _rm_leading_zeros just moves the data to the correct + place and adjusts the length. */ + +static void +_rm_leading_zeros (num) + bc_num num; +{ + int bytes; + char *dst, *src; + + /* Do a quick check to see if we need to do it. */ + if (*num->n_value != 0) return; + + /* The first digit is 0, find the first non-zero digit in the 10's or + greater place. */ + bytes = num->n_len; + src = num->n_value; + while (bytes > 1 && *src == 0) src++, bytes--; + num->n_len = bytes; + bytes += num->n_scale; + dst = num->n_value; + while (bytes-- > 0) *dst++ = *src++; + +} + + +/* Perform addition: N1 is added to N2 and the value is + returned. The signs of N1 and N2 are ignored. */ + +static bc_num +_do_add (n1, n2) + bc_num n1, n2; +{ + bc_num sum; + int sum_scale, sum_digits; + char *n1ptr, *n2ptr, *sumptr; + int carry, n1bytes, n2bytes; + + /* Prepare sum. */ + sum_scale = MAX (n1->n_scale, n2->n_scale); + sum_digits = MAX (n1->n_len, n2->n_len) + 1; + sum = new_num (sum_digits,sum_scale); + + /* Start with the fraction part. Initialize the pointers. */ + n1bytes = n1->n_scale; + n2bytes = n2->n_scale; + n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1); + n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1); + sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1); + + /* Add the fraction part. First copy the longer fraction.*/ + if (n1bytes != n2bytes) + { + if (n1bytes > n2bytes) + while (n1bytes>n2bytes) + { *sumptr-- = *n1ptr--; n1bytes--;} + else + while (n2bytes>n1bytes) + { *sumptr-- = *n2ptr--; n2bytes--;} + } + + /* Now add the remaining fraction part and equal size integer parts. */ + n1bytes += n1->n_len; + n2bytes += n2->n_len; + carry = 0; + while ((n1bytes > 0) && (n2bytes > 0)) + { + *sumptr = *n1ptr-- + *n2ptr-- + carry; + if (*sumptr > 9) + { + carry = 1; + *sumptr -= 10; + } + else + carry = 0; + sumptr--; + n1bytes--; + n2bytes--; + } + + /* Now add carry the longer integer part. */ + if (n1bytes == 0) + { n1bytes = n2bytes; n1ptr = n2ptr; } + while (n1bytes-- > 0) + { + *sumptr = *n1ptr-- + carry; + if (*sumptr > 9) + { + carry = 1; + *sumptr -= 10; + } + else + carry = 0; + sumptr--; + } + + /* Set final carry. */ + if (carry == 1) + *sumptr += 1; + + /* Adjust sum and return. */ + _rm_leading_zeros (sum); + return sum; +} + + +/* Perform subtraction: N2 is subtracted from N1 and the value is + returned. The signs of N1 and N2 are ignored. Also, N1 is + assumed to be larger than N2. */ + +static bc_num +_do_sub (n1, n2) + bc_num n1, n2; +{ + bc_num diff; + int diff_scale, diff_len; + int min_scale, min_len; + char *n1ptr, *n2ptr, *diffptr; + int borrow, count, val; + + /* Allocate temporary storage. */ + diff_len = MAX (n1->n_len, n2->n_len); + diff_scale = MAX (n1->n_scale, n2->n_scale); + min_len = MIN (n1->n_len, n2->n_len); + min_scale = MIN (n1->n_scale, n2->n_scale); + diff = new_num (diff_len, diff_scale); + + /* Initialize the subtract. */ + n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1); + n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1); + diffptr = (char *) (diff->n_value + diff_len + diff_scale -1); + + /* Subtract the numbers. */ + borrow = 0; + + /* Take care of the longer scaled number. */ + if (n1->n_scale != min_scale) + { + /* n1 has the longer scale */ + for (count = n1->n_scale - min_scale; count > 0; count--) + *diffptr-- = *n1ptr--; + } + else + { + /* n2 has the longer scale */ + for (count = n2->n_scale - min_scale; count > 0; count--) + { + val = - *n2ptr-- - borrow; + if (val < 0) + { + val += 10; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + } + + /* Now do the equal length scale and integer parts. */ + + for (count = 0; count < min_len + min_scale; count++) + { + val = *n1ptr-- - *n2ptr-- - borrow; + if (val < 0) + { + val += 10; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + + /* If n1 has more digits then n2, we now do that subtract. */ + if (diff_len != min_len) + { + for (count = diff_len - min_len; count > 0; count--) + { + val = *n1ptr-- - borrow; + if (val < 0) + { + val += 10; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + } + + /* Clean up and return. */ + _rm_leading_zeros (diff); + return diff; +} + + +/* Here is the full add routine that takes care of negative numbers. + N1 is added to N2 and the result placed into RESULT. */ + +void +bc_add ( n1, n2, result) + bc_num n1, n2, *result; +{ + bc_num sum; + int cmp_res; + + if (n1->n_sign == n2->n_sign) + { + sum = _do_add (n1, n2); + sum->n_sign = n1->n_sign; + } + else + { + /* subtraction must be done. */ + cmp_res = _do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */ + switch (cmp_res) + { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + sum = _do_sub (n2, n1); + sum->n_sign = n2->n_sign; + break; + case 0: + /* They are equal! return zero! */ + sum = copy_num (_zero_); + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + sum = _do_sub (n1, n2); + sum->n_sign = n1->n_sign; + } + } + + /* Clean up and return. */ + free_num (result); + *result = sum; +} + + +/* Here is the full subtract routine that takes care of negative numbers. + N2 is subtracted from N1 and the result placed in RESULT. */ + +void +bc_sub ( n1, n2, result) + bc_num n1, n2, *result; +{ + bc_num diff; + int cmp_res; + + if (n1->n_sign != n2->n_sign) + { + diff = _do_add (n1, n2); + diff->n_sign = n1->n_sign; + } + else + { + /* subtraction must be done. */ + cmp_res = _do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */ + switch (cmp_res) + { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + diff = _do_sub (n2, n1); + diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS); + break; + case 0: + /* They are equal! return zero! */ + diff = copy_num (_zero_); + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + diff = _do_sub (n1, n2); + diff->n_sign = n1->n_sign; + break; + } + } + + /* Clean up and return. */ + free_num (result); + *result = diff; +} + + +/* The multiply routine. N2 time N1 is put int PROD with the scale of + the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)). + */ + +void +bc_multiply (n1, n2, prod, scale) + bc_num n1, n2, *prod; + int scale; +{ + bc_num pval; /* For the working storage. */ + char *n1ptr, *n2ptr, *pvptr; /* Work pointers. */ + char *n1end, *n2end; /* To the end of n1 and n2. */ + + int indx; + int len1, len2, total_digits; + long sum; + int full_scale, prod_scale; + int toss; + + /* Initialize things. */ + len1 = n1->n_len + n1->n_scale; + len2 = n2->n_len + n2->n_scale; + total_digits = len1 + len2; + full_scale = n1->n_scale + n2->n_scale; + prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale))); + toss = full_scale - prod_scale; + pval = new_num (total_digits-full_scale, prod_scale); + pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + n1end = (char *) (n1->n_value + len1 - 1); + n2end = (char *) (n2->n_value + len2 - 1); + pvptr = (char *) (pval->n_value + total_digits - toss - 1); + sum = 0; + + /* Here are the loops... */ + for (indx = 0; indx < toss; indx++) + { + n1ptr = (char *) (n1end - MAX(0, indx-len2+1)); + n2ptr = (char *) (n2end - MIN(indx, len2-1)); + while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) + sum += *n1ptr-- * *n2ptr++; + sum = sum / 10; + } + for ( ; indx < total_digits-1; indx++) + { + n1ptr = (char *) (n1end - MAX(0, indx-len2+1)); + n2ptr = (char *) (n2end - MIN(indx, len2-1)); + while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) + sum += *n1ptr-- * *n2ptr++; + *pvptr-- = sum % 10; + sum = sum / 10; + } + *pvptr-- = sum; + + /* Assign to prod and clean up the number. */ + free_num (prod); + *prod = pval; + _rm_leading_zeros (*prod); + if (is_zero (*prod)) + (*prod)->n_sign = PLUS; +} + + +/* Some utility routines for the divide: First a one digit multiply. + NUM (with SIZE digits) is multiplied by DIGIT and the result is + placed into RESULT. It is written so that NUM and RESULT can be + the same pointers. */ + +static void +_one_mult (num, size, digit, result) + unsigned char *num; + int size, digit; + unsigned char *result; +{ + int carry, value; + unsigned char *nptr, *rptr; + + if (digit == 0) + memset (result, 0, size); + else + { + if (digit == 1) + memcpy (result, num, size); + else + { + /* Initialize */ + nptr = (unsigned char *) (num+size-1); + rptr = (unsigned char *) (result+size-1); + carry = 0; + + while (size-- > 0) + { + value = *nptr-- * digit + carry; + *rptr-- = value % 10; + carry = value / 10; + } + + if (carry != 0) *rptr = carry; + } + } +} + + +/* The full division routine. This computes N1 / N2. It returns + 0 if the division is ok and the result is in QUOT. The number of + digits after the decimal point is SCALE. It returns -1 if division + by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ + +int +bc_divide (n1, n2, quot, scale) + bc_num n1, n2, *quot; + int scale; +{ + bc_num qval; + unsigned char *num1, *num2; + unsigned char *ptr1, *ptr2, *n2ptr, *qptr; + int scale1, val; + unsigned int len1, len2, scale2, qdigits, extra, count; + unsigned int qdig, qguess, borrow, carry; + unsigned char *mval; + char zero; + unsigned int norm; + + /* Test for divide by zero. */ + if (is_zero (n2)) return -1; + + /* Test for divide by 1. If it is we must truncate. */ + if (n2->n_scale == 0) + { + if (n2->n_len == 1 && *n2->n_value == 1) + { + qval = new_num (n1->n_len, scale); + qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); + memset (&qval->n_value[n1->n_len],0,scale); + memcpy (qval->n_value, n1->n_value, + n1->n_len + MIN(n1->n_scale,scale)); + free_num (quot); + *quot = qval; + } + } + + /* Set up the divide. Move the decimal point on n1 by n2's scale. + Remember, zeros on the end of num2 are wasted effort for dividing. */ + scale2 = n2->n_scale; + n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1; + while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--; + + len1 = n1->n_len + scale2; + scale1 = n1->n_scale - scale2; + if (scale1 < scale) + extra = scale - scale1; + else + extra = 0; + num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2); + if (num1 == NULL) out_of_memory(); + memset (num1, 0, n1->n_len+n1->n_scale+extra+2); + memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale); + + len2 = n2->n_len + scale2; + num2 = (unsigned char *) malloc (len2+1); + if (num2 == NULL) out_of_memory(); + memcpy (num2, n2->n_value, len2); + *(num2+len2) = 0; + n2ptr = num2; + while (*n2ptr == 0) + { + n2ptr++; + len2--; + } + + /* Calculate the number of quotient digits. */ + if (len2 > len1+scale) + { + qdigits = scale+1; + zero = TRUE; + } + else + { + zero = FALSE; + if (len2>len1) + qdigits = scale+1; /* One for the zero integer part. */ + else + qdigits = len1-len2+scale+1; + } + + /* Allocate and zero the storage for the quotient. */ + qval = new_num (qdigits-scale,scale); + memset (qval->n_value, 0, qdigits); + + /* Allocate storage for the temporary storage mval. */ + mval = (unsigned char *) malloc (len2+1); + if (mval == NULL) out_of_memory (); + + /* Now for the full divide algorithm. */ + if (!zero) + { + /* Normalize */ + norm = 10 / ((int)*n2ptr + 1); + if (norm != 1) + { + _one_mult (num1, len1+scale1+extra+1, norm, num1); + _one_mult (n2ptr, len2, norm, n2ptr); + } + + /* Initialize divide loop. */ + qdig = 0; + if (len2 > len1) + qptr = (unsigned char *) qval->n_value+len2-len1; + else + qptr = (unsigned char *) qval->n_value; + + /* Loop */ + while (qdig <= len1+scale-len2) + { + /* Calculate the quotient digit guess. */ + if (*n2ptr == num1[qdig]) + qguess = 9; + else + qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr; + + /* Test qguess. */ + if (n2ptr[1]*qguess > + (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + + num1[qdig+2]) + { + qguess--; + /* And again. */ + if (n2ptr[1]*qguess > + (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + + num1[qdig+2]) + qguess--; + } + + /* Multiply and subtract. */ + borrow = 0; + if (qguess != 0) + { + *mval = 0; + _one_mult (n2ptr, len2, qguess, mval+1); + ptr1 = (unsigned char *) num1+qdig+len2; + ptr2 = (unsigned char *) mval+len2; + for (count = 0; count < len2+1; count++) + { + val = (int) *ptr1 - (int) *ptr2-- - borrow; + if (val < 0) + { + val += 10; + borrow = 1; + } + else + borrow = 0; + *ptr1-- = val; + } + } + + /* Test for negative result. */ + if (borrow == 1) + { + qguess--; + ptr1 = (unsigned char *) num1+qdig+len2; + ptr2 = (unsigned char *) n2ptr+len2-1; + carry = 0; + for (count = 0; count < len2; count++) + { + val = (int) *ptr1 + (int) *ptr2-- + carry; + if (val > 9) + { + val -= 10; + carry = 1; + } + else + carry = 0; + *ptr1-- = val; + } + if (carry == 1) *ptr1 = (*ptr1 + 1) % 10; + } + + /* We now know the quotient digit. */ + *qptr++ = qguess; + qdig++; + } + } + + /* Clean up and return the number. */ + qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + if (is_zero (qval)) qval->n_sign = PLUS; + _rm_leading_zeros (qval); + free_num (quot); + *quot = qval; + + /* Clean up temporary storage. */ + free (mval); + free (num1); + free (num2); + + return 0; /* Everything is OK. */ +} + + +/* Modulo for numbers. This computes NUM1 % NUM2 and puts the + result in RESULT. */ + +int +bc_modulo (num1, num2, result, scale) + bc_num num1, num2, *result; + int scale; +{ + bc_num temp; + int rscale; + + /* Check for correct numbers. */ + if (is_zero (num2)) return -1; + + /* Calculate final scale. */ + rscale = MAX (num1->n_scale, num2->n_scale+scale); + init_num (&temp); + + /* Calculate it. */ + bc_divide (num1, num2, &temp, scale); + bc_multiply (temp, num2, &temp, rscale); + bc_sub (num1, temp, result); + free_num (&temp); + + return 0; /* Everything is OK. */ +} + + +/* Raise NUM1 to the NUM2 power. The result is placed in RESULT. + Maximum exponent is LONG_MAX. If a NUM2 is not an integer, + only the integer part is used. */ + +void +bc_raise (num1, num2, result, scale) + bc_num num1, num2, *result; + int scale; +{ + bc_num temp, power; + long exponent; + int rscale; + char neg; + + /* Check the exponent for scale digits and convert to a long. */ + if (num2->n_scale != 0) + rt_warn ("non-zero scale in exponent"); + exponent = num2long (num2); + if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0)) + rt_error ("exponent too large in raise"); + + /* Special case if exponent is a zero. */ + if (exponent == 0) + { + free_num (result); + *result = copy_num (_one_); + return; + } + + /* Other initializations. */ + if (exponent < 0) + { + neg = TRUE; + exponent = -exponent; + rscale = scale; + } + else + { + neg = FALSE; + rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale)); + } + temp = copy_num (_one_); + power = copy_num (num1); + + /* Do the calculation. */ + while (exponent != 0) + { + if (exponent & 1 != 0) + bc_multiply (temp, power, &temp, rscale); + bc_multiply (power, power, &power, rscale); + exponent = exponent >> 1; + } + + /* Assign the value. */ + if (neg) + { + bc_divide (_one_, temp, result, rscale); + free_num (&temp); + } + else + { + free_num (result); + *result = temp; + } + free_num (&power); +} + + +/* Take the square root NUM and return it in NUM with SCALE digits + after the decimal place. */ + +int +bc_sqrt (num, scale) + bc_num *num; + int scale; +{ + int rscale, cmp_res, done; + int cscale; + bc_num guess, guess1, point5; + + /* Initial checks. */ + cmp_res = bc_compare (*num, _zero_); + if (cmp_res < 0) + return 0; /* error */ + else + { + if (cmp_res == 0) + { + free_num (num); + *num = copy_num (_zero_); + return 1; + } + } + cmp_res = bc_compare (*num, _one_); + if (cmp_res == 0) + { + free_num (num); + *num = copy_num (_one_); + return 1; + } + + /* Initialize the variables. */ + rscale = MAX (scale, (*num)->n_scale); + cscale = rscale + 2; + init_num (&guess); + init_num (&guess1); + point5 = new_num (1,1); + point5->n_value[1] = 5; + + + /* Calculate the initial guess. */ + if (cmp_res < 0) + /* The number is between 0 and 1. Guess should start at 1. */ + guess = copy_num (_one_); + else + { + /* The number is greater than 1. Guess should start at 10^(exp/2). */ + int2num (&guess,10); + int2num (&guess1,(*num)->n_len); + bc_multiply (guess1, point5, &guess1, rscale); + guess1->n_scale = 0; + bc_raise (guess, guess1, &guess, rscale); + free_num (&guess1); + } + + /* Find the square root using Newton's algorithm. */ + done = FALSE; + while (!done) + { + free_num (&guess1); + guess1 = copy_num (guess); + bc_divide (*num,guess,&guess,cscale); + bc_add (guess,guess1,&guess); + bc_multiply (guess,point5,&guess,cscale); + cmp_res = _do_compare (guess,guess1,FALSE,TRUE); + if (cmp_res == 0) done = TRUE; + } + + /* Assign the number and clean up. */ + free_num (num); + bc_divide (guess,_one_,num,rscale); + free_num (&guess); + free_num (&guess1); + free_num (&point5); + return 1; +} + + +/* The following routines provide output for bcd numbers package + using the rules of POSIX bc for output. */ + +/* This structure is used for saving digits in the conversion process. */ +typedef struct stk_rec { + long digit; + struct stk_rec *next; +} stk_rec; + +/* The reference string for digits. */ +char ref_str[] = "0123456789ABCDEF"; + + +/* A special output routine for "multi-character digits." Exactly + SIZE characters must be output for the value VAL. If SPACE is + non-zero, we must output one space before the number. OUT_CHAR + is the actual routine for writing the characters. */ + +void +out_long (val, size, space, out_char) + long val; + int size, space; +#ifdef __STDC__ + void (*out_char)(int); +#else + void (*out_char)(); +#endif +{ + char digits[40]; + int len, ix; + + if (space) (*out_char) (' '); + sprintf (digits, "%ld", val); + len = strlen (digits); + while (size > len) + { + (*out_char) ('0'); + size--; + } + for (ix=0; ix < len; ix++) + (*out_char) (digits[ix]); +} + +/* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR + as the routine to do the actual output of the characters. */ + +void +out_num (num, o_base, out_char) + bc_num num; + int o_base; +#ifdef __STDC__ + void (*out_char)(int); +#else + void (*out_char)(); +#endif +{ + char *nptr; + int index, fdigit, pre_space; + stk_rec *digits, *temp; + bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit; + + /* The negative sign if needed. */ + if (num->n_sign == MINUS) (*out_char) ('-'); + + /* Output the number. */ + if (is_zero (num)) + (*out_char) ('0'); + else + if (o_base == 10) + { + /* The number is in base 10, do it the fast way. */ + nptr = num->n_value; + if (num->n_len > 1 || *nptr != 0) + for (index=num->n_len; index>0; index--) + (*out_char) (BCD_CHAR(*nptr++)); + else + nptr++; + + /* Now the fraction. */ + if (num->n_scale > 0) + { + (*out_char) ('.'); + for (index=0; index<num->n_scale; index++) + (*out_char) (BCD_CHAR(*nptr++)); + } + } + else + { + /* The number is some other base. */ + digits = NULL; + init_num (&int_part); + bc_divide (num, _one_, &int_part, 0); + init_num (&frac_part); + init_num (&cur_dig); + init_num (&base); + bc_sub (num, int_part, &frac_part); + int2num (&base, o_base); + init_num (&max_o_digit); + int2num (&max_o_digit, o_base-1); + + + /* Get the digits of the integer part and push them on a stack. */ + while (!is_zero (int_part)) + { + bc_modulo (int_part, base, &cur_dig, 0); + temp = (stk_rec *) malloc (sizeof(stk_rec)); + if (temp == NULL) out_of_memory(); + temp->digit = num2long (cur_dig); + temp->next = digits; + digits = temp; + bc_divide (int_part, base, &int_part, 0); + } + + /* Print the digits on the stack. */ + if (digits != NULL) + { + /* Output the digits. */ + while (digits != NULL) + { + temp = digits; + digits = digits->next; + if (o_base <= 16) + (*out_char) (ref_str[ (int) temp->digit]); + else + out_long (temp->digit, max_o_digit->n_len, 1, out_char); + free (temp); + } + } + + /* Get and print the digits of the fraction part. */ + if (num->n_scale > 0) + { + (*out_char) ('.'); + pre_space = 0; + t_num = copy_num (_one_); + while (t_num->n_len <= num->n_scale) { + bc_multiply (frac_part, base, &frac_part, num->n_scale); + fdigit = num2long (frac_part); + int2num (&int_part, fdigit); + bc_sub (frac_part, int_part, &frac_part); + if (o_base <= 16) + (*out_char) (ref_str[fdigit]); + else { + out_long (fdigit, max_o_digit->n_len, pre_space, out_char); + pre_space = 1; + } + bc_multiply (t_num, base, &t_num, 0); + } + } + + /* Clean up. */ + free_num (&int_part); + free_num (&frac_part); + free_num (&base); + free_num (&cur_dig); + } +} + + +#if DEBUG > 0 + +/* Debugging procedures. Some are just so one can call them from the + debugger. */ + +/* p_n prints the number NUM in base 10. */ + +void +p_n (num) + bc_num num; +{ + out_num (num, 10, out_char); + return 0; +} + + +/* p_b prints a character array as if it was a string of bcd digits. */ +void +p_v (name, num, len) + char *name; + unsigned char *num; + int len; +{ + int i; + printf ("%s=", name); + for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i])); + printf ("\n"); +} + + +/* Convert strings to bc numbers. Base 10 only.*/ + +void +str2num (num, str, scale) + bc_num *num; + char *str; + int scale; +{ + int digits, strscale; + char *ptr, *nptr; + char zero_int; + + /* Prepare num. */ + free_num (num); + + /* Check for valid number and count digits. */ + ptr = str; + digits = 0; + strscale = 0; + zero_int = FALSE; + if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */ + while (*ptr == '0') ptr++; /* Skip leading zeros. */ + while (isdigit(*ptr)) ptr++, digits++; /* digits */ + if (*ptr == '.') ptr++; /* decimal point */ + while (isdigit(*ptr)) ptr++, strscale++; /* digits */ + if ((*ptr != '\0') || (digits+strscale == 0)) + { + *num = copy_num (_zero_); + return; + } + + /* Adjust numbers and allocate storage and initialize fields. */ + strscale = MIN(strscale, scale); + if (digits == 0) + { + zero_int = TRUE; + digits = 1; + } + *num = new_num (digits, strscale); + + /* Build the whole number. */ + ptr = str; + if (*ptr == '-') + { + (*num)->n_sign = MINUS; + ptr++; + } + else + { + (*num)->n_sign = PLUS; + if (*ptr == '+') ptr++; + } + while (*ptr == '0') ptr++; /* Skip leading zeros. */ + nptr = (*num)->n_value; + if (zero_int) + { + *nptr++ = 0; + digits = 0; + } + for (;digits > 0; digits--) + *nptr++ = CH_VAL(*ptr++); + + + /* Build the fractional part. */ + if (strscale > 0) + { + ptr++; /* skip the decimal point! */ + for (;strscale > 0; strscale--) + *nptr++ = CH_VAL(*ptr++); + } +} + +/* Convert a numbers to a string. Base 10 only.*/ + +char +*num2str (num) + bc_num num; +{ + char *str, *sptr; + char *nptr; + int index, signch; + + /* Allocate the string memory. */ + signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */ + if (num->n_scale > 0) + str = (char *) malloc (num->n_len + num->n_scale + 2 + signch); + else + str = (char *) malloc (num->n_len + 1 + signch); + if (str == NULL) out_of_memory(); + + /* The negative sign if needed. */ + sptr = str; + if (signch) *sptr++ = '-'; + + /* Load the whole number. */ + nptr = num->n_value; + for (index=num->n_len; index>0; index--) + *sptr++ = BCD_CHAR(*nptr++); + + /* Now the fraction. */ + if (num->n_scale > 0) + { + *sptr++ = '.'; + for (index=0; index<num->n_scale; index++) + *sptr++ = BCD_CHAR(*nptr++); + } + + /* Terminate the string and return it! */ + *sptr = '\0'; + return (str); +} +#endif diff --git a/gnu/usr.bin/bc/number.h b/gnu/usr.bin/bc/number.h new file mode 100644 index 0000000..9938515 --- /dev/null +++ b/gnu/usr.bin/bc/number.h @@ -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 diff --git a/gnu/usr.bin/bc/proto.h b/gnu/usr.bin/bc/proto.h new file mode 100644 index 0000000..fea9405 --- /dev/null +++ b/gnu/usr.bin/bc/proto.h @@ -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 *)); + diff --git a/gnu/usr.bin/bc/scan.c b/gnu/usr.bin/bc/scan.c new file mode 100644 index 0000000..59aa6e5 --- /dev/null +++ b/gnu/usr.bin/bc/scan.c @@ -0,0 +1,1368 @@ +/* A lexical scanner generated by flex */ + +/* scanner skeleton version: + * $Header: /usr/fsys/odin/a/vern/flex/RCS/flex.skel,v 2.16 90/08/03 14:09:36 vern Exp $ + */ + +#define FLEX_SCANNER + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <osfcn.h> + +/* use prototypes in function declarations */ +#define YY_USE_PROTOS + +/* the "const" storage-class-modifier is valid */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#ifdef __STDC__ + +#ifdef __GNUC__ +#include <stddef.h> +void *malloc( size_t ); +void free( void* ); +#else +#include <stdlib.h> +#endif /* __GNUC__ */ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + + +#ifdef __TURBOC__ +#define YY_USE_CONST +#endif + + +#ifndef YY_USE_CONST +#define const +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +/* we can't get here if it's an ANSI C compiler, or a C++ compiler, + * so it's got to be a K&R compiler, and therefore there's no standard + * place from which to include these definitions + */ +/* char *malloc(); +int free(); */ +int read(); +#endif + + +/* amount of stuff to slurp up with each read */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* returned upon end-of-file */ +#define YY_END_TOK 0 + +/* copy whatever the last rule matched to the standard output */ + +/* cast to (char *) is because for 8-bit chars, yytext is (unsigned char *) */ +/* this used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite() + */ +#define ECHO (void) fwrite( (char *) yytext, yyleng, 1, yyout ) + +/* gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#define YY_INPUT(buf,result,max_size) \ + if ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#define YY_NULL 0 + +/* no semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#define yyterminate() return ( YY_NULL ) + +/* report a fatal error */ + +/* The funky do-while is used to turn this macro definition into + * a single C statement (which needs a semi-colon terminator). + * This avoids problems with code like: + * + * if ( something_happens ) + * YY_FATAL_ERROR( "oops, the something happened" ); + * else + * everything_okay(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the YY_FATAL_ERROR() call. + */ + +#define YY_FATAL_ERROR(msg) \ + do \ + { \ + (void) fputs( msg, stderr ); \ + (void) putc( '\n', stderr ); \ + exit( 1 ); \ + } \ + while ( 0 ) + +/* default yywrap function - always treat EOF as an EOF */ +#define yywrap() 1 + +/* enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN + */ +#define BEGIN yy_start = 1 + 2 * + +/* action number for EOF rule of a given start state */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* special action meaning "start processing a new file" */ +#define YY_NEW_FILE \ + do \ + { \ + yy_init_buffer( yy_current_buffer, yyin ); \ + yy_load_buffer_state(); \ + } \ + while ( 0 ) + +/* default declaration of generated scanner - a define so the user can + * easily add parameters + */ +#define YY_DECL int yylex YY_PROTO(( void )) + +/* code executed at the end of each rule */ +#define YY_BREAK break; + +#define YY_END_OF_BUFFER_CHAR 0 + +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE (YY_READ_BUF_SIZE * 2) /* size of default input buffer */ +#endif + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +#define YY_CHAR unsigned char +# line 1 "scan.l" +#define INITIAL 0 +# line 2 "scan.l" +/* scan.l: the (f)lex description file for the scanner. */ + +/* 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 "y.tab.h" +#include "global.h" +#include "proto.h" + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#include <errno.h> +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); + +# line 60 "scan.l" + +/* done after the current pattern has been matched and before the + * corresponding action - sets up yytext + */ +#define YY_DO_BEFORE_ACTION \ + yytext = yy_bp; \ + yyleng = yy_cp - yy_bp; \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* return all but the first 'n' matched characters back to the input stream */ +#define yyless(n) \ + do \ + { \ + /* undo effects of setting up yytext */ \ + *yy_cp = yy_hold_char; \ + yy_c_buf_p = yy_cp = yy_bp + n; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext ) + + +struct yy_buffer_state + { + FILE *yy_input_file; + + YY_CHAR *yy_ch_buf; /* input buffer */ + YY_CHAR *yy_buf_pos; /* current position in input buffer */ + + /* size of input buffer in bytes, not including room for EOB characters*/ + int yy_buf_size; + + /* number of characters read into yy_ch_buf, not including EOB characters */ + int yy_n_chars; + + int yy_eof_status; /* whether we've seen an EOF on this buffer */ +#define EOF_NOT_SEEN 0 + /* "pending" happens when the EOF has been seen but there's still + * some text process + */ +#define EOF_PENDING 1 +#define EOF_DONE 2 + }; + +static YY_BUFFER_STATE yy_current_buffer; + +/* we provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state" + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed */ +static YY_CHAR yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + + +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +#ifndef YY_USER_INIT +#define YY_USER_INIT +#endif + +extern YY_CHAR *yytext; +extern int yyleng; +extern FILE *yyin, *yyout; + +YY_CHAR *yytext; +int yyleng; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +#define YY_END_OF_BUFFER 40 +typedef int yy_state_type; +static const short int yy_accept[144] = + { 0, + 0, 0, 40, 38, 33, 31, 25, 38, 26, 38, + 22, 26, 22, 22, 38, 26, 37, 29, 27, 29, + 38, 22, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 38, 33, + 29, 0, 36, 27, 23, 30, 37, 0, 34, 37, + 37, 0, 28, 32, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 7, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 24, 37, 0, 0, 37, + 0, 35, 35, 35, 35, 35, 6, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + + 35, 13, 35, 35, 35, 14, 16, 35, 17, 35, + 35, 35, 35, 3, 15, 35, 35, 9, 35, 35, + 2, 35, 35, 11, 35, 35, 12, 20, 35, 10, + 35, 8, 35, 1, 4, 21, 5, 35, 35, 35, + 19, 18, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 1, 1, 6, 7, 1, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 1, 17, 18, + 19, 20, 1, 1, 21, 21, 21, 21, 21, 21, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 22, 23, 24, 25, 26, 1, 27, 28, 29, 30, + + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 36, 48, 36, + 49, 36, 50, 51, 52, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[53] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, + 1, 1 + } ; + +static const short int yy_base[146] = + { 0, + 0, 0, 193, 194, 190, 194, 172, 185, 170, 181, + 194, 168, 42, 41, 41, 46, 52, 167, 61, 166, + 181, 164, 135, 137, 139, 148, 140, 136, 0, 149, + 27, 50, 147, 130, 126, 141, 40, 36, 120, 168, + 194, 164, 194, 194, 194, 194, 66, 165, 194, 72, + 76, 164, 194, 194, 0, 120, 134, 124, 131, 117, + 117, 122, 132, 0, 113, 117, 117, 128, 119, 118, + 52, 125, 107, 106, 114, 194, 80, 145, 84, 88, + 144, 105, 118, 98, 108, 111, 0, 95, 95, 93, + 105, 102, 91, 95, 88, 103, 85, 93, 84, 85, + + 90, 0, 90, 91, 85, 0, 0, 93, 0, 77, + 76, 90, 74, 0, 0, 75, 87, 0, 90, 85, + 0, 75, 83, 0, 76, 63, 0, 0, 66, 0, + 62, 0, 47, 0, 0, 0, 0, 45, 53, 29, + 0, 0, 194, 111, 56 + } ; + +static const short int yy_def[146] = + { 0, + 143, 1, 143, 143, 143, 143, 143, 144, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 143, 143, + 143, 144, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 143, 143, 143, 143, 143, + 143, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 0, 143, 143 + } ; + +static const short int yy_nxt[247] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, + 13, 11, 14, 15, 16, 17, 11, 18, 19, 20, + 17, 11, 21, 11, 22, 4, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 29, 29, 32, 29, 29, + 33, 34, 35, 36, 37, 29, 29, 38, 29, 11, + 39, 11, 46, 46, 63, 49, 47, 55, 64, 44, + 44, 47, 74, 48, 44, 50, 53, 51, 72, 75, + 53, 53, 51, 53, 52, 53, 65, 142, 96, 41, + 66, 77, 73, 141, 67, 53, 77, 80, 78, 50, + 140, 51, 80, 139, 81, 77, 51, 97, 52, 47, + + 77, 138, 78, 80, 47, 137, 48, 136, 80, 135, + 81, 42, 42, 134, 133, 132, 131, 130, 129, 128, + 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, + 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, + 107, 106, 105, 104, 103, 102, 80, 77, 101, 100, + 99, 98, 95, 94, 93, 92, 91, 90, 89, 88, + 87, 86, 85, 84, 83, 82, 51, 79, 43, 40, + 76, 71, 70, 69, 68, 62, 61, 60, 59, 58, + 57, 56, 44, 54, 41, 41, 44, 45, 44, 43, + 41, 40, 143, 3, 143, 143, 143, 143, 143, 143, + + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143 + } ; + +static const short int yy_chk[247] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 13, 14, 31, 16, 15, 145, 31, 14, + 13, 15, 38, 15, 16, 17, 19, 17, 37, 38, + 19, 19, 17, 19, 17, 19, 32, 140, 71, 19, + 32, 47, 37, 139, 32, 19, 47, 50, 47, 51, + 138, 51, 50, 133, 50, 77, 51, 71, 51, 79, + + 77, 131, 77, 80, 79, 129, 79, 126, 80, 125, + 80, 144, 144, 123, 122, 120, 119, 117, 116, 113, + 112, 111, 110, 108, 105, 104, 103, 101, 100, 99, + 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, + 88, 86, 85, 84, 83, 82, 81, 78, 75, 74, + 73, 72, 70, 69, 68, 67, 66, 65, 63, 62, + 61, 60, 59, 58, 57, 56, 52, 48, 42, 40, + 39, 36, 35, 34, 33, 30, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 18, 12, 10, 9, 8, + 7, 5, 3, 143, 143, 143, 143, 143, 143, 143, + + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143 + } ; + +static yy_state_type yy_last_accepting_state; +static YY_CHAR *yy_last_accepting_cpos; + +/* the intent behind this definition is that it'll catch + * any uses of REJECT which flex missed + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 + +/* these variables are all declared out here so that section 3 code can + * manipulate them + */ +/* points to current character in buffer */ +static YY_CHAR *yy_c_buf_p = (YY_CHAR *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yyunput YY_PROTO(( YY_CHAR c, YY_CHAR *buf_ptr )); +void yyrestart YY_PROTO(( FILE *input_file )); +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); + +#define yy_new_buffer yy_create_buffer + +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif + +YY_DECL + { + register yy_state_type yy_current_state; + register YY_CHAR *yy_cp, *yy_bp; + register int yy_act; + + + + if ( yy_init ) + { + YY_USER_INIT; + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( yy_current_buffer ) + yy_init_buffer( yy_current_buffer, yyin ); + else + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + + yy_init = 0; + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* support of yytext */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of the + * current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[*yy_cp]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 144 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 194 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + YY_USER_ACTION; + +do_action: /* this label is used only to access EOF actions */ + + + switch ( yy_act ) + { + case 0: /* must backtrack */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +# line 61 "scan.l" +return(Define); + YY_BREAK +case 2: +# line 62 "scan.l" +return(Break); + YY_BREAK +case 3: +# line 63 "scan.l" +return(Quit); + YY_BREAK +case 4: +# line 64 "scan.l" +return(Length); + YY_BREAK +case 5: +# line 65 "scan.l" +return(Return); + YY_BREAK +case 6: +# line 66 "scan.l" +return(For); + YY_BREAK +case 7: +# line 67 "scan.l" +return(If); + YY_BREAK +case 8: +# line 68 "scan.l" +return(While); + YY_BREAK +case 9: +# line 69 "scan.l" +return(Sqrt); + YY_BREAK +case 10: +# line 70 "scan.l" +return(Scale); + YY_BREAK +case 11: +# line 71 "scan.l" +return(Ibase); + YY_BREAK +case 12: +# line 72 "scan.l" +return(Obase); + YY_BREAK +case 13: +# line 73 "scan.l" +return(Auto); + YY_BREAK +case 14: +# line 74 "scan.l" +return(Else); + YY_BREAK +case 15: +# line 75 "scan.l" +return(Read); + YY_BREAK +case 16: +# line 76 "scan.l" +return(Halt); + YY_BREAK +case 17: +# line 77 "scan.l" +return(Last); + YY_BREAK +case 18: +# line 78 "scan.l" +return(Warranty); + YY_BREAK +case 19: +# line 79 "scan.l" +return(Continue); + YY_BREAK +case 20: +# line 80 "scan.l" +return(Print); + YY_BREAK +case 21: +# line 81 "scan.l" +return(Limits); + YY_BREAK +case 22: +# line 82 "scan.l" +{ yylval.c_value = yytext[0]; + return((int)yytext[0]); } + YY_BREAK +case 23: +# line 84 "scan.l" +{ return(AND); } + YY_BREAK +case 24: +# line 85 "scan.l" +{ return(OR); } + YY_BREAK +case 25: +# line 86 "scan.l" +{ return(NOT); } + YY_BREAK +case 26: +# line 87 "scan.l" +{ yylval.c_value = yytext[0]; return(MUL_OP); } + YY_BREAK +case 27: +# line 88 "scan.l" +{ yylval.c_value = yytext[0]; return(ASSIGN_OP); } + YY_BREAK +case 28: +# line 89 "scan.l" +{ +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned =<op>"); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } + YY_BREAK +case 29: +# line 103 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(REL_OP); } + YY_BREAK +case 30: +# line 104 "scan.l" +{ yylval.c_value = yytext[0]; return(INCR_DECR); } + YY_BREAK +case 31: +# line 105 "scan.l" +{ line_no++; return(NEWLINE); } + YY_BREAK +case 32: +# line 106 "scan.l" +{ line_no++; /* ignore a "quoted" newline */ } + YY_BREAK +case 33: +# line 107 "scan.l" +{ /* ignore spaces and tabs */ } + YY_BREAK +case 34: +# line 108 "scan.l" +{ + int c; + + for (;;) + { + while ( ((c=input()) != '*') && (c != EOF)) + /* eat it */ + if (c == '\n') line_no++; + if (c == '*') + { + while ( (c=input()) == '*') /* eat it*/; + if (c == '/') break; /* at end of comment */ + if (c == '\n') line_no++; + } + if (c == EOF) + { + fprintf (stderr,"EOF encountered in a comment.\n"); + break; + } + } + } + YY_BREAK +case 35: +# line 129 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(NAME); } + YY_BREAK +case 36: +# line 130 "scan.l" +{ + unsigned char *look; + int count = 0; + yylval.s_value = strcopyof(yytext); + for (look = yytext; *look != 0; look++) + { + if (*look == '\n') line_no++; + if (*look == '"') count++; + } + if (count != 2) yyerror ("NUL character in string."); + return(STRING); + } + YY_BREAK +case 37: +# line 142 "scan.l" +{ + unsigned char *src, *dst; + int len; + /* remove a trailing decimal point. */ + len = strlen(yytext); + if (yytext[len-1] == '.') + yytext[len-1] = 0; + /* remove leading zeros. */ + src = yytext; + dst = yytext; + while (*src == '0') src++; + if (*src == 0) src--; + /* Copy strings removing the newlines. */ + while (*src != 0) + { + if (*src == '\\') + { + src++; src++; + line_no++; + } + else + *dst++ = *src++; + } + *dst = 0; + yylval.s_value = strcopyof(yytext); + return(NUMBER); + } + YY_BREAK +case 38: +# line 169 "scan.l" +{ + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%3d", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } + YY_BREAK +case 39: +# line 178 "scan.l" +ECHO; + YY_BREAK +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* amount of text matched not including the EOB char */ + int yy_amount_of_matched_text = yy_cp - yytext - 1; + + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + + /* note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the end- + * of-buffer state). Contrast this with the test in yyinput(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* this was really a NUL */ + { + yy_state_type yy_next_state; + + yy_c_buf_p = yytext + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* okay, we're now positioned to make the + * NUL transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we + * don't want to build jamming into it because + * then it will run more slowly) + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* consume the NUL */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* note: because we've taken care in + * yy_get_next_buffer() to have set up yytext, + * we can now set up yy_c_buf_p so that if some + * total hoser (like flex itself) wants + * to call the scanner after we return the + * YY_NULL, it'll still work - another YY_NULL + * will get returned. + */ + yy_c_buf_p = yytext + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF((yy_start - 1) / 2); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + } + break; + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: +#ifdef FLEX_DEBUG + printf( "action # %d\n", yy_act ); +#endif + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } + } + } + + +/* yy_get_next_buffer - try to read in a new buffer + * + * synopsis + * int yy_get_next_buffer(); + * + * returns a code representing an action + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + + { + register YY_CHAR *dest = yy_current_buffer->yy_ch_buf; + register YY_CHAR *source = yytext - 1; /* copy prev. char, too */ + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + /* try to read more data */ + + /* first move last chars to start of buffer */ + number_to_move = yy_c_buf_p - yytext; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_eof_status != EOF_NOT_SEEN ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_n_chars = 0; + + else + { + int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + else if ( num_to_read <= 0 ) + YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); + + /* read in more data */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == 1 ) + { + ret_val = EOB_ACT_END_OF_FILE; + yy_current_buffer->yy_eof_status = EOF_DONE; + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_eof_status = EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + /* yytext begins at the second character in yy_ch_buf; the first + * character is the one which preceded it before reading in the latest + * buffer; it needs to be kept around in case it's a newline, so + * yy_get_previous_state() will have with '^' rules active + */ + + yytext = &yy_current_buffer->yy_ch_buf[1]; + + return ( ret_val ); + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached + * + * synopsis + * yy_state_type yy_get_previous_state(); + */ + +static yy_state_type yy_get_previous_state() + + { + register yy_state_type yy_current_state; + register YY_CHAR *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[*yy_cp] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 144 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return ( yy_current_state ); + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( register yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +register yy_state_type yy_current_state; +#endif + + { + register int yy_is_jam; + register YY_CHAR *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 144 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 143); + + return ( yy_is_jam ? 0 : yy_current_state ); + } + + +#ifdef YY_USE_PROTOS +static void yyunput( YY_CHAR c, register YY_CHAR *yy_bp ) +#else +static void yyunput( c, yy_bp ) +YY_CHAR c; +register YY_CHAR *yy_bp; +#endif + + { + register YY_CHAR *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + register int number_to_move = yy_n_chars + 2; /* +2 for EOB chars */ + register YY_CHAR *dest = + &yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size + 2]; + register YY_CHAR *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += dest - source; + yy_bp += dest - source; + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + if ( yy_cp > yy_bp && yy_cp[-1] == '\n' ) + yy_cp[-2] = '\n'; + + *--yy_cp = c; + + /* note: the formal parameter *must* be called "yy_bp" for this + * macro to now work correctly + */ + YY_DO_BEFORE_ACTION; /* set up yytext again */ + } + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + + { + int c; + YY_CHAR *yy_cp = yy_c_buf_p; + + *yy_cp = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* this was really a NUL */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + yytext = yy_c_buf_p; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + { + yy_c_buf_p = yytext + YY_MORE_ADJ; + return ( EOF ); + } + + YY_NEW_FILE; + +#ifdef __cplusplus + return ( yyinput() ); +#else + return ( input() ); +#endif + } + break; + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext + YY_MORE_ADJ; + break; + + case EOB_ACT_LAST_MATCH: +#ifdef __cplusplus + YY_FATAL_ERROR( "unexpected last match in yyinput()" ); +#else + YY_FATAL_ERROR( "unexpected last match in input()" ); +#endif + } + } + } + + c = *yy_c_buf_p; + yy_hold_char = *++yy_c_buf_p; + + return ( c ); + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + + { + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* flush out information for old buffer */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* we don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) malloc( sizeof( struct yy_buffer_state ) ); + + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (YY_CHAR *) malloc( (unsigned) (b->yy_buf_size + 2) ); + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + yy_init_buffer( b, file ); + + return ( b ); + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + free( (char *) b->yy_ch_buf ); + free( (char *) b ); + } + + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + { + b->yy_input_file = file; + + /* we put in the '\n' and start reading from [1] so that an + * initial match-at-newline will be true. + */ + + b->yy_ch_buf[0] = '\n'; + b->yy_n_chars = 1; + + /* we always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[1]; + + b->yy_eof_status = EOF_NOT_SEEN; + } +# line 178 "scan.l" + + + + +/* This is the way to get multiple files input into lex. */ + +int +yywrap() +{ + if (!open_new_file ()) return (1); /* EOF on standard in. */ + return (0); /* We have more input. */ +} diff --git a/gnu/usr.bin/bc/storage.c b/gnu/usr.bin/bc/storage.c new file mode 100644 index 0000000..1edd6e2 --- /dev/null +++ b/gnu/usr.bin/bc/storage.c @@ -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"); +} diff --git a/gnu/usr.bin/bc/util.c b/gnu/usr.bin/bc/util.c new file mode 100644 index 0000000..954c719 --- /dev/null +++ b/gnu/usr.bin/bc/util.c @@ -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); +} diff --git a/gnu/usr.bin/bc/version.h b/gnu/usr.bin/bc/version.h new file mode 100644 index 0000000..6b3f909 --- /dev/null +++ b/gnu/usr.bin/bc/version.h @@ -0,0 +1,3 @@ +#define BC_VERSION \ + "bc 1.02 (Mar 3, 92) Copyright (C) 1991, 1992 Free Software Foundation, Inc." + diff --git a/gnu/usr.bin/bc/y.tab.h b/gnu/usr.bin/bc/y.tab.h new file mode 100644 index 0000000..9e65a2f --- /dev/null +++ b/gnu/usr.bin/bc/y.tab.h @@ -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; |