From: jk7744.park Date: Sat, 24 Oct 2015 06:50:44 +0000 (+0900) Subject: tizen 2.4 release X-Git-Tag: accepted/tizen/2.4/mobile/20151029.040702 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aa010f5f46cb1dbf215e5d85b0261b29de36e0c1;p=external%2Fbc.git tizen 2.4 release --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..b665a63 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Phil Nelson wrote bc, including the number.c +source in the "lib" directory. + +Ken Pizzini wrote dc. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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. + + , 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/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..c4792dd --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,515 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. +^L + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +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. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper +mail. + +You should also get your employer (if you work as a programmer) or +your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James +Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..f277079 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1043 @@ +Wed Sep 27 17:19:48 2000 Phil Nelson + + * doc/bc.texi: Added new file. Mainly translated from bc.1 + by Brian Youmans. + doc/bc.1: Minor changes made as part of reviewing bc.texi. + +Wed Sep 20 11:45:00 2000 Phil Nelson + + * bc/bc.y: Added a comment on the meanings of lvals. + +Wed Sep 13 11:40:24 2000 Phil Nelson + + * bc/main.c: add --interactive to long options. + bc/bc.1: add -i/--interactive to doc. + MANY: Update FSF address and Phil's e-mail. + +Tue Sep 12 13:58:16 2000 Phil Nelson + + * NEWS: update for recent changes. + bc/bc.y: remove required parens around return expression. + doc/bc.1: update for recent changes. + +Fri Sep 8 10:20:01 2000 Phil Nelson + + * bc/Makefile.am, dc/Makefile.am, lib/Makefile.am: + Compile with unsigned characters. + bc/main.c: Add --help option. + bc/scan.l: Print illegal, non-printable characters in octal. + +Fri Sep 8 09:36:54 2000 Phil Nelson + + * bc/bc.y: Allow more newlines in function definitions. + bc/proto.h: Don't prototype main. + +Fri Sep 1 16:09:50 2000 Phil Nelson + + * bc/bc.y: Spelling correction + bc/execute.c: Correct expressions for multi-byte names. + bc/load.c: Add parens for correct casting. + doc/bc.1: Typos. + Above fixes pointed out by kwzh@gnu.org (Karl Heuer). + +Tue Aug 29 23:03:30 PDT 2000 Phil Nelson + + * lib/testmul.c: #ifdef out a declaration matching #ifdef out + code. + +Mon Jul 31 07:01:42 2000 Ken Pizzini + + * dc/numeric.c: use of the "n" command can cause a number to be printed + without a trailing newline, which would cause the column counter to + fail to be reset and result in inappropriately wrapped numeric outputs. + Fixed by always clearing the column counter before outputting each number. + + * dc/stack.c: if a stack is used without ever using the correspondingly + named register, it is perfectly legitimate for the register to be + uninitialized; added an "else if" to handle this case without aborting. + + * dc/eval.c: updated the comment explaining the restrictions + on the | command to better reflect reality. + + * doc/dc.texi: update the FSF office address in the copyright notice + +Thu Jul 13 18:13:00 2000 Phil Nelson + + * README: note --with-libedit configure parameter. + +Tue Jun 20 22:52:10 2000 Phil Nelson + + * bc/bcdefs.h: Include to quiet warnings. + + * configure.in: make --with-readline and --with-libedit work correctly. + + * Makefile.am: use $(MAKE) instead of directly calling make. + + * lib/testmul.c: Update to use bc_ on all number.c routines. + +Sat Jun 10 22:44:29 2000 Phil Nelson + + * bc/Makefile.am: Add scan.c to maintainer-clean target. + + * acconfig.h configure.in stamp-h.in bc/Makefile.am bc/execute.c + bc/fix-libmath_h bc/global.c bc/load.c bc/main.c bc/storage.c: + Remove long string for libmath. Clean up for compiler errors. + + * dc/numeric.c: Correct parameter name. + +Wed May 10 15:51:16 2000 Phil Nelson + + * {bc,doc,dc,lib}/Makefile.am: Add Makefile.in to maintainer-clean. + + * bootstrap.sh: Added script to run the auto* tools. + + * Imported all into CVS tree. + +Sun 2000-05-07 Phil Nelson + + * bc/Makefile.am, dc/Makefile.am, lib/Makefile.am: Add -Wall to CFLAGS. + + * bc/{execute.c,proto.h,storage.c,util.c}, dc/numeric.c: Changes for + -Wall and for name changes in lib/number.c. (Added bc_ to several + routine. Updated copyright notice.) + + * h/number.h, lib/number.c: Now comes from bcmath library which is + distributed in a different place. + +Wed Mar 29 17:47:34 2000 Phil Nelson + + * bc/{bc.y,bcdefs.h,global.h,main.c,proto.h,scan.l,storage.c}: + Added BSD libedit support. Generic support for both where possible. + Fixed bugs in readline support noticed during libedit addition. + Works with NetBSD-1.4.1 libedit. + * doc/bc.1: Documented libedit addition. + +Wed Mar 29 10:20:18 2000 Phil Nelson + + * FAQ: Added this file. + * Makfile.am: Added FAQ to distribution + +Tue Mar 28 13:52:35 2000 Phil Nelson + + * lib/number.c, h/number.h: Moved definitions so + number.c/number.h is a stand-alone "library". + Changed definition of out_num to not reference a global. + * lib/testmul.c: updated #includes for number.h changes. + * h/{bcdefs.h,const.h,global.h,proto.h} moved to + bc where they really belong. + * bc/execute.c: Changed calls to out_num for correctness. + * dc/numeric.c: Changed calls to out_num for correctness, + include only number.h now and not all the other junk. + * configure.in, acconfig.h: Start of support for BSD libedit, + added --with-pkg for NetBSD /usr/pkg tree. + +Tue Mar 28 11:20:00 2000 Phil Nelson + + * Test/{exp.b,fact.b,jn.b,mul.b,raise.b}: Tweeks on the tests + run to do more computation and test the recursive multiply. + * bc/scan.l: Removed a printf('\r') that was unneeded. + +Mon Mar 27 14:00:00 2000 Phil Nelson + + * NEWS: Updated for 1.06. + * lib/number.c, h/number.h: Fixed bugs in recursive multiply. + Changed these files to be under the LGPL. + * Tests/jn.b: Added more tests. + * lib/Makefile.am: Only generate a timed version of number.o if + requested. + * README: Updated with information on how to generate a timed + version of number.o. + * h/version.h: Updated copyright and version number for dc. + +Thu Mar 16 14:01:45 2000 Phil Nelson + + * doc/bc.1, doc/dc.1, doc/dc.texi: Changed bug reporting address + to bug-bc@gnu.org to update with what we hope will be reality. + +Tue Feb 8 08:54:19 2000 Phil Nelson + + * doc/bc.1, bc/util.c: Removed "multiply digits" + limit due to new recursive algorithm that doesn't + have those limits. + +Tue Feb 8 08:47:05 2000 Phil Nelson + + * lib/Makefile.am, lib/testmul.c, lib/number.c, Makefile.am: + Finally got a resonable version of the program + to test the crossover between non-recursive and + recursive multiply algorithms. Added to distribution + and build process. Does increase build time by + about 10 minutes. + +Wed Oct 6 13:28:59 1999 Phil Nelson + + * lib/Makefile.am: Added rules to allow DEFSADD definitions. + +Sat Oct 2 19:59:51 1999 Phil Nelson + + * bc/libmath.b: Correctly do the cosine accuracy. + +Fri Oct 1 12:41:51 1999 Phil Nelson + + * lib/number.c: Increase accuracy of computing raise. + Also turn off use of recursive multiply routines + until furthur testing. + * bc/libmath.b: Increase accuracy of cosine. + * bc/Makefile.am: Remove -lfl from items to make. + +Wed Jul 28 10:29:28 1999 Phil Nelson + + * bc/scan.l: rl_len from char to int. (From FreeBSD + bug tracking system and Nick Hibma ) + +Tue Jun 22 08:00:28 1999 Phil Nelson + + * lib/number.c: Rewrote bc_multiply to use a faster + algorithm. Old code not removed yet. + +Mon Jun 21 03:08:02 1999 Phil Nelson + + * h/version.h: Updated version number to 1.06. + bc/bc.y: Corrected bug in for statement, not popping. + bc/execute.c: Improved stack dump/instruction tracing. + +Tue Jun 15 22:30:42 1999 Phil Nelson + + * configure.in: Updated bc version to 1.06. + +Tue Jun 15 22:27:44 1999 Phil Nelson + + * h/bcdefs.h, h/const.h, bc/execute.c, bc/load.c, bc/storage.c, + bc/util.c: Removed segmented function storaged. Now + dynamically expands (by doubling, starting at 1024 bytes) + to allow arbitrary sized functions. + +Thu Jun 10 22:33:44 1999 Phil Nelson + + * bc/libmath.b: change scaling in computation of j(n,x) so + it correctly computes the value. + +Wed Jun 10 10:10:10 1998 Release of bc-1.05a. + +Fri Apr 17 10:40:59 1998 Phil Nelson + + * bc/main.c: Enable readline only if interactive. + +Thu Apr 16 16:49:22 1998 Phil Nelson + + * bc/configure.in: Tweeking of AM_PROG_LEX and associated + special case goo for solaris. + +Sat Mar 28 21:43:18 1998 Phil Nelson + + * bc/Makefile.am: Added "YFLAGS = -d" to get bc.h to build properly. + +Mon Mar 9 12:54:42 PST 1998 Ken Pizzini + + * doc/dc.texi, doc/dc.1: correct some documentation bugs. + +Sun Mar 8 23:56:24 PST 1998 Ken Pizzini + + * dc/numeric.c: eliminate superfluous variable from dc_dump_num(); + annotate unused parameters in dc_add() and dc_sub(). + + * h/version.h: change dc version number to 1.2 for release. + +Sun Mar 8 21:13:50 1998 Phil Nelson + + * bc/main.c: Applied patch from Ken Pizzini to force line + mode buffering on stdout. + +Tue Jan 6 09:15:04 PST 1998 Ken Pizzini + + * h/version.h: dc is now up to version 1.1.5. + + * dc/eval.c, dc/numeric.c, doc/dc.texi, doc/dc.1: once again + changed the behavior of the 'P' command with a numeric argument + to make it more general. It now dumps out the *whole* number + (or rather, the whole of its positive integer portion) as a + byte stream. (For small values this is still the same as 'aP'.) + + * dc/dc-proto.h, dc/dc.h, dc/eval.c, dc/misc.c, dc/numeric.c, + dc/stack.c, dc/string.c: Changed most uses of dc_boolean to + either dc_discard or dc_newline, and instances of DC_TRUE and + DC_FALSE to appropriate instances of DC_TOSS, DC_KEEP, DC_NONL, + or DC_WITHNL so that the code self-documents a little better. + +Sun Jan 4 15:39:46 PST 1998 Ken Pizzini + + * dc/eval.c, doc/dc.texi, doc/dc.1: Changed the functionality + of the 'P' command, and added the 'n' command. Due to + a quirk of the implementation of traditional dc, some + people have come to expect that the 'P' command on a + numeric argument in the range of 1 to 99 should output + the corresponding character, despite the fact that this + usage can have very weird results for numbers outside + that range. This functionality is why the 'a' command + was introduced last March, but people really want it to + "just work" without needing to use the 'a' command. + Bowing to this demand, the 'P' command now does the + equivalent of "aP" if the argument is numeric, and the + 'n' command has been added to support the previous + functionality of the 'P' command. + + * dc/misc.c, dc/eval.c, dc/stack.c, dc/dc-proto.h: + Changed prototype for dc_print(). It now additionally + takes two flags, newline_p and discard_p, which it + passes through to dc_out_num() and dc_out_str() as + needed. + + * h/version.h: dc is now up to version 1.1.4. + +Sat Sep 27 13:48:53 1997 Ken Pizzini + + * h/version.h: dc is now up to version 1.1.3. + + * dc/stack.c, dc/array.c, dc/dc-proto.h, doc/dc.texi, doc/dc.1: + It has come to my attention that, though undocumented, + traditional dc stacked its arrays in parallel with the + stacking of simple registers. I have now duplicated + this functionality. + + * dc/dc.c, configure.in: line-buffer dc's output if setvbuf() + is supported. This was requested to simplify using dc as + an inferior process under emacs. + +Fri Sep 26 19:56:15 1997 Ken Pizzini + + * dc/dc.c: fixed bug reporting address for --help. + + * doc/dc.1, doc/dc.texi: corrected documentation of the maximum + admissible input base. + + * doc/dc.texi: corrected sample code equivalence for the | command. + + * lib/number.c: added a warning for non-zero scale in the base + for bc_raisemod(). + +Fri Sep 26 18:15:31 1997 Ken Pizzini + + * dc/eval.c, doc/dc.1, doc/dc.texi: added !=, !<, and !> commands. + + * dc/eval.c: eliminated double-free in 'a' command. + + * dc/dc.c: changed placment of check for filename "-" so that + "-f -" will work. + + * h/version.h: updated dc version to 1.1.2. + +Thu Sep 18 17:41:10 1997 Ken Pizzini + + * dc/eval.c: fixed off-by-one error for Q and q commands. + + * dc/dc.c: added missing f: to third argument of getopt(). + + * h/version.h: updated dc version to 1.1.1. + +Thu May 22 08:24:08 1997 Phil Nelson + + * lib/number.c(bc_sqrt): Fixed a bug that computed 0 for sqrt + of most numbers less than .000001. + +Thu May 1 10:41:38 1997 Phil Nelson + + * Test/timetest: change path to bc executable. + +Wed Apr 30 12:00:00 1997 Phil Nelson + + * Froze bc-1.04, started new directory for bc-1.05. + Fixes to bc-1.04 will be distributed as bc-1.05. + +Mon Apr 21 14:57:14 1997 Phil Nelson + + * bc/scan.l: Changed rules for single line comment to work + with lex as well as flex. Also, do not include \n in the + comment. + + * doc/bc.1: Clarified the single line comment and that \n + is processed outside of the comment. + +Sun Apr 20 22:21:30 1997 Phil Nelson + + * bc/scan.l: Added rules for a single line comment starting + with the # character. + + * doc/bc.1: Documented the single line comment. + + * bc/Makefile.am: Added DISTCLEANFILES for proper clean up. + +Sat Apr 19 22:08:05 1997 Phil Nelson + + * dc/Makefile.am: Removed file from distribution list. + + * h/version.h: Updated dc version to 1.1. + +Fri Apr 18 16:43:04 1997 Phil Nelson + + * lib/number.c (bc_add, bc_sub) Added 1 to the length + of the memset call to make sure it zeroed all the + storage. + +Fri Apr 18 13:58:56 1997 Phil Nelson + + * configure.in: Tweeks to get things right. Not sure if things + changed much. Still working with autoconf/automake to do + the right thing. + +Wed Apr 16 16:49:17 1997 Phil Nelson + + * bc/main.c (main): Changed processing of BC_ENV_ARGS. + + * bc/main.c (parse_args): Removed "start" parameter. + +Tue Apr 15 13:21:28 1997 Phil Nelson + + * acconfig.h: Included support for PACKAGE and VERSION. + + * configure.in: More tweeks for automake support. + + * h/number.h: Improve definition of MIN and MAX. + + * doc/bc.1: Changed copyright, tweeked other text, added + e-mail address for bugs. + + * doc/dc.1: Added copyright and GPL license information, + Changed a few .SH formats. + +Fri Apr 11 16:14:42 1997 Phil Nelson + + * Makefile.am configure.in doc/Makefile.am lib/Makefile.am + bc/Makefile.am bc/bc.y dc/Makefile.am: Changes to accomodate + automake-1.1n (pre-release version of automake 1.2). + + * bc/bc.y bc/sbc.y: Changes to make sure tokens are numbered the + same in bc/bc.h and bc/sbc.h. + + * bc/scan.l: Changes for automake's naming convention. + + * NEWS: Fixed a typo. + +Thu Apr 10 14:42:55 1997 Phil Nelson + + * bc/{execute.c, global.c, libmath.b, load.c, main.c, sbc.y + scan.l, storage.c, util.c}: Changed copyright comment and + added 1997 to copyright years. + + * h/{bcdefs.h, const.h, global.h, number.h proto.h, version.h}: + Changed copyright comment and added 1997 to copyright years. + + * h/version.h: Changed bc version to 1.04. + + * lib/number.c: Changed copyright comment and added 1997 to + copyright years. + + * lib/vfprintf.c: Noted that this was only for minix. + + * NEWS, README: README is now comp.sources.reviewed readme only. + NEWS now lists changes from version to version. + +Thu Apr 10 13:41:56 1997 Phil Nelson + + * Makefile.am: Removed FIXME stuff. + +Thu Apr 8 13:39:53 1997 Phil Nelson + + * bc/Makefile.am: Remove files that should not be distributed. + +Mon Apr 7 17:14:28 1997 Phil Nelson + + * Makefile.am: Removed Misc directory from distribution. + +Mon Apr 7 16:16:01 1997 Phil Nelson + + * bc/sbc.y: Corrected use of nextarg(). + +Tue Mar 25 19:32:28 1997 Ken Pizzini + + * dc/eval.c, dc/misc.c, dc/stack.c, dc/string.c, + dc/dc.h, dc/dc-proto.h, dc/dc.c, dc/numeric.c, + doc/dc.texi: updated years in copyright + notices. + + * dc/dc.1: updated last-revision date. + +Tue Mar 25 16:35:46 1997 Ken Pizzini + + * lib/number.c: give a run-time warning in bc_raisemod() + if the modulus does not appear to be an integer. + + * doc/dc.texi, doc/dc.1: documented a warning against + the use of the new | command in conjunction with a + non-integral modulus. + +Tue Mar 25 15:36:04 1997 Ken Pizzini + + * dc/string.c: dc_out_str() updated to use fwrite() + instead of printf(), to allow for the existence of + a NUL character in the string. + +Tue Mar 25 13:42:51 1997 Ken Pizzini + + * doc/dc.texi, doc/dc.1: added documentation for new | command. + +Tue Mar 25 13:19:55 1997 Ken Pizzini + + * dc/dc-proto.h: added prototype for dc_triop(). + +Tue Mar 25 12:00:38 1997 Ken Pizzini + + * lib/number.c: add bc_modexp() modular-exponentiation function. + + * h/proto.h: add prototypes for bc_modexp() and bc_divmod(). + +Tue Mar 25 09:07:13 1997 Ken Pizzini + + * doc/dc.texi, doc/dc.1: updated documentation with the + new command-line options. + + * doc/dc.texi, doc/dc.1: updated documentation with the + new '~', 'r', and 'a' commands. + + * dc/dc.c: added bug reporting information to --version text. + +Mon Mar 24 19:37:30 1997 Ken Pizzini + + * lib/number.c: added new "bc_divmod" function. + + * dc/numeric.c: added new "dc_divrem" glue function to bc_divmod. + + * dc/stack.c: added new "dc_binop2" function. + + * dc/dc-proto.h: added new prototypes for dc_divrem() and dc_binop2(). + + * dc/eval.c, dc/numeric.c: add new '~' command which + returns both the quotient and remainder from division. + +Mon Mar 24 18:13:42 1997 Ken Pizzini + + * dc/eval.c: Add new 'r' (reverse top two stack elements) command. + +Mon Mar 24 17:47:02 1997 Ken Pizzini + + * dc/misc.c: split out the main() related functions into + a seperate dc/dc.c file. + + * dc/Makefile.am: updated to reflect this split. + +Sat Mar 1 04:57:54 1997 Ken Pizzini + + * dc/misc.c: added "--file" option. + +Sat Mar 1 02:13:06 1997 Ken Pizzini + + * dc/eval.c: fixed bug of an excess increment in + dc_evalstr()'s DC_COMMENT case. (Probably would + never show up in practice, but did violate the + letter of the C Standard.) + + * renamed dc/number.c to dc/numeric.c, to avoid + confusion with lib/number.c. + +Thu Feb 27 19:45:45 1997 Ken Pizzini + + * dc/string.c, dc/dc.h: changed implementation of dc_str + type from a void * to a type which is only completed + in dc/string.c. No functional change, just prettier code. + +Thu Feb 27 18:25:19 1997 Ken Pizzini + + * Cleaned up Makefile.am files. + +Thu Feb 6 00:41:02 1997 Ken Pizzini + + * Noticed pre-autoconf vestages (NO_XXX configuration options); + fixed to refer to autoconf HAVE_XXX definitions. + + * The definition of BC_XXX values in h/const.h might + conflict with values of the same name from ; + fixed to override without spewing warnings. + + * Added check for ptrdiff_t to configure.in; removed + special ptrdiff_t definition from dc/string.c . + +Wed Feb 5 22:28:37 1997 Ken Pizzini + + * Only compile (guts of) lib/vfprintf.c if system does + not have its own version. + +Wed Feb 5 22:26:16 1997 Ken Pizzini + + * Changed dc/misc.c source to use standard GNU option + parsing routine (instead of special-case code). + + * Added "-e" option to dc. + + * Bumped dc version number to 1.0.4. + +Wed Feb 5 22:08:06 1997 Ken Pizzini + + * rearranged source layout (added subdirectory structure); + removed "dc-" prefix from dc C source in its new home. + + * merged bc's "version.h" and dc's "dc-version.h" files + into h/version.h; patched dc/misc.c to refer to new + DC_VERSION macro name. + + * Tweaked configure.in in anticipation of using automake. + +Wed Jul 24 16:27:20 1996 Phil Nelson + + * number.c (out_num): Move free of t_num to proper place. + +Mon Jun 3 00:31:10 1996 Phil Nelson + + * number.c: (bc_sqrt, is_near_zero) Was hanging in an infinite + loop on sqrt(.9999). Rewrote to take difference. New routine + is_near_zero to check for one digit off. + +Thu Feb 22 12:14:38 1996 Phil Nelson + + * dc-eval.c (dc_func): Added the 'a' (number to ascii character) + command. + +Thu Feb 22 11:55:15 1996 Phil Nelson + + * dc-eval.c: (Changes from Ken) Changes dealing with stdin_lookahead + and peekc. + + * dc-misc.c: (Changes from Ken) Changes in option processing. + + * dc-version.c: (Change from Ken) Version is 1.0.2. + +Mon Oct 9 15:40:06 1995 Phil Nelson + + * execute.c (execute): Add a pop to 'W' and 'P' codes. Otherwise, + the stack continues to grow. + + * number.c (out_num): Free all bc_nums used. + +Thu Jun 29 00:35:57 1995 Phil Nelson + + * bc.1: Added information about long options and use of the + readline library. + +Wed Jun 28 21:03:45 1995 Phil Nelson + + * scan.l: rl_input: detect EOF. + +Wed Jun 28 19:03:51 1995 Phil Nelson + + * Makefile.in: fbc target, changed $(LEXLIB) => $(LIBS) + +Wed Jun 28 01:33:07 1995 Phil Nelson + + * acconfig.h, bc.y, scan.l, storage.c, util.c, configure.in: + Improved readline support with a new pseudo variable "history" + that controls the number of history lines available. + Also removed "optional" history. + +Wed Jun 28 01:03:52 1995 Phil Nelson + + * getopt.h, getopt.c, getopt1.c: Imported from glibc-1.09 + to allow long option processing. + + * main.c (parse_args): Make it use long arguments. + + * global.h: Change option flag variables from "char" to "int" + to allow long_arguments easy access to the variables. + + * Makefile.in: Add getopt.h, getopt.c, and getopt1.c in the + proper places in the Makefile. + +Fri Jun 23 12:00:16 1995 Phil Nelson + + * scan.l, main.c (main), acconfig.h, configure.in: + Added support for readline input on stdin. + +Thu Jun 22 20:08:57 1995 Phil Nelson + + * bc.1: Change documentation on POSIX array parameter support. + +Fri Apr 7 12:29:28 1995 Phil Nelson + + * main.c (parse_args): change "char ch" to "int optch" with + related changes. + +Thu Mar 23 04:11:00 1995 Phil Nelson + + * bc.1: Update documentation to include new -q + option and the environment variables. + +Thu Mar 23 03:30:38 1995 Phil Nelson + + * bcdefs.h, global.h, main.c, util.c, bc.y: Reworked + argument processing to allow for getting arguments + from the environment and the command line. Added + a new mechanism to access file names for opening + and for error messages. Also added a "quiet" + option to turn off the welcome banner. + +Thu Mar 23 03:12:11 1995 Phil Nelson + + * util.c: Corrected a comment. + +Tue Mar 21 13:36:24 1995 Phil Nelson + + * bc.y: Added "opt_newline" to allow more newlines + in non-POSIX mode. + +Tue Mar 21 09:38:28 1995 Phil Nelson + + * execute.c, main.c, util.c: Add support for user + defined line length, "correct POSIX line length", + no breaking of strings in std_only mode. This + included adding a new function "out_schar" to + util.c. Also removed "if (interactive)" before + all fflushes. + +Tue Mar 21 09:12:16 1995 Phil Nelson + + * global.h: Added new variable "line_size". Cleaned up + some definitions by adding comments. + +Mon Mar 20 23:33:01 1995 Phil Nelson + + * proto.h: Define getopt only if no unistd.h file. + +Mon Mar 20 23:23:34 1995 Phil Nelson + + * number.c, proto.h, execute.c, storage.c, dc-number.c: + Changes to bc_add and bc_sub parameters to allow for + different scale results than were possible. This is + for correct implementation of modulo. All calls were + updated. + +Mon Mar 20 19:26:06 1995 Phil Nelson + + * sbc.y: Removed second parameter on calls to arg_str to match + real function. + +Tue Feb 28 14:30:18 1995 Phil Nelson + + * Makefile.in: Change realclean to maintainer-clean. Added warning. + +Mon Feb 27 17:08:24 1995 Phil Nelson + + * number.c: Change output to conform with POSIX standard for zero + only when the -s flag is given. Otherwise it does the tradational + thing. + + * dc-misc.c: Add the "std_only" flag, always set to zero. This is + needed due to the above change. + +Tue Nov 29 15:18:20 1994 Phil Nelson + + * bc.1: Remove the "then" keyword in the if statement documentation. + +Mon Nov 28 16:50:25 1994 Phil Nelson + + * bc.1: Fixed a font change error. + + * Makefile.in: Added missing \ in two targets. + +Tue Nov 22 11:09:08 1994 Phil Nelson + + * bc.1: clarified ibase and math routines. + +Thu Nov 3 14:09:31 1994 Phil Nelson (phil@cs.wwu.edu) + + * Makefile.in: added targets uninstall, installdirs and modified + other targets to get makes in a directory other than srcdir to + work. + + * configure.in: added shell commands to get configure to work + correctly in directories other than srcdir. + +Wed Nov 2 10:18:19 1994 Phil Nelson (phil@cs.wwu.edu) + + * bc.1 bc.y bcdefs.h const.h execute.c global.c global.h load.c + main.c number.c number.h proto.h sbc.y scan.l storage.c util.c: + updated copyright to 1994. + + * version.h: updated version number and copyright date. + + * Makefile.in, configure.in, Install: updated for use with + autoconf-2.0 and install-sh. Changed target install a bit. + + * install-sh: Included this file from the autoconf-2.0 + distribution to have configure run without errors. + + * README: updated to version 1.03. + +Mon Oct 31 10:26:28 1994 Phil Nelson (phil@cs.wwu.edu) + + * Added Ken Pizzini's dc implementation that uses bc numeric + routines. The following files have been added: + dc-Concerns dc-array.c dc-eval.c dc-misc.c dc-number.c + dc-proto.h dc-regdef.h dc-stack.c dc-string.c dc-version.h + dc.1 dc.h dc.texinfo + + * dc-array.c: Added a conditional include of stdlib.h to get + size_t defined on my SunOS 4.1.3 system. + + * configure.in: Added support for dc. + + * Makefile.in: Added support for dc. Added rule to make + config.h.in. + +Sun Aug 7 15:09:19 1994 Phil Nelson (phil@cs.wwu.edu) + + * configure.in, Makefile.in, acconfig.h: Add support for autoconf. + Removed old Makefile. + +Wed Jul 20 22:46:32 1994 Phil Nelson (phil@cs.wwu.edu) + + * bc.y: change definition of next_label in function definition. + Previous value of 0 caused break to not work. It is now 1. + +Fri Apr 8 14:16:37 1994 Phil Nelson (phil@cs.wwu.edu) + + * Makefile: Change the distribution to include libmath.h.dist + which is a copy of libmath.h that has the compiled libmath.b. + +Sun Feb 13 01:08:14 1994 Phil Nelson (phil@cs.wwu.edu) + + * execute.c: Change the string quote characters to be more like + C. \a => alert (bell) \b => backspace and added \q => ". + + * bc.1: Updated information on above changes. + +Wed Oct 27 23:34:40 1993 Phil Nelson (phil@cs.wwu.edu) + + * Makefile: Changed compress to gzip. Changed the + comment and definition of the DOT_IS_LAST compile option. + + * scan.l: Changed DOT_IS_LAST to NO_DOT_LAST and changed + the test so "." is the last variable is standard. + +Wed May 19 15:15:12 1993 Phil Nelson (phil at cs.wwu.edu) + + * number.c: Fixed output of negative numbers in bases other than + base 10. + +Wed Apr 21 11:56:31 1993 Phil Nelson (phil at cs.wwu.edu) + + * bc.1: Changed Steve Sommars e-mail address. + +Wed Apr 14 12:13:39 1993 Phil Nelson (phil at cs.wwu.edu) + + * sbc.y: removed leading , on first line. + +Wed Mar 31 16:12:39 1993 Phil Nelson (phil at cs.wwu.edu) + + * bc.1: Updated segment number for function bodies. + +Thu Mar 11 15:34:34 1993 Phil Nelson (phil at cs.wwu.edu) + + * Makefile: added version.h to bc.o's dependency list. + +Mon Mar 1 14:00:46 1993 Phil Nelson (phil at cs.wwu.edu) + + * util.c: (nextarg) changed parameter "val" to be an int. + +Tue Feb 16 10:06:45 1993 Phil Nelson (phil at cs.wwu.edu) + + * util.c: (call_str, arg_str) added a function call_str that + correctly produces the string of argmuent types for a function + call. arg_str produced them in the reverse order. This + eliminated the need for the "comma" argument to arg_str, which + was removed. + + * bc.y: changed the calls to arg_str to have only one parameter + in the function definition rule and replaced the call to arg_str + with call_str in the function call rule. + +Tue Nov 24 17:38:40 1992 Phil Nelson (phil at cs.wwu.edu) + + * Makefile: Added LEXLIB definitions for use with lex. + +Thu Oct 22 13:43:16 1992 Phil Nelson (phil at cs.wwu.edu) + + * number.c (bc_raise): Rearranged and added code to speed up + the computation by not doing unneeded multiplications. + +Wed Sep 30 10:43:52 1992 Phil Nelson (phil at cs.wwu.edu) + + * global.h: Fixed documentation. + +Tue Sep 29 15:27:50 1992 Phil Nelson (phil at cs.wwu.edu) + + * storage.c (process_params): Changed processing of more arguments + than in a function definition to just a return. + + * Makefile: Made changes to make it more in conformance with the + GNU coding standards. + +Tue Jul 7 21:09:07 1992 Phil Nelson (phil at cs.wwu.edu) + + * (const.h, bc.y, util.c) Added code so that when the math + library is loaded, redefinition of any math library function + will not cause the other functions to quit working correctly. + Before this change, redefining a(x) would cause s(x) and c(x) + to quit working and redefining s(x) would cause c(x) to quit + working. + +Wed Jul 1 14:35:29 1992 Phil Nelson (phil at cs.wwu.edu) + + * (libmath.b) Changed the calculation of scale for computing + e(x) and l(x). This provides a little more accuracy in the + last digit at the expense of a little speed. + + * (Test/checklib.b) Changed tests to be parameterized and test + more values. + +Thu Jun 25 09:22:59 1992 Phil Nelson (phil at cs.wwu.edu) + + * (configure) changed the script from looking in the + include directory for a .h file to asking cc (gcc) to + find the .h file. This will allow better detection + of include files available to the C compiler. + +Wed Jun 24 22:11:37 1992 Phil Nelson (phil at cs.wwu.edu) + + * (bc.y) Added a warning for the "last" variable. + + * (scan.l) Added code to allow for a single dot (.) to be the + same as the variable "last". This is not a "standard" feature, + but is provided for those who want it. + + * (Install) Documented the new define for dot (.). + + * (bc.1) Documented the use of dot (.) for "last". + + * (Makefile) Added an easy method for adding extra defines for + use during the compile. Set DOT_IS_LAST as a standard + extra define. + + * (number.c) Changed the code for sqrt for better speed. + +Mon Jun 22 21:47:05 1992 Phil Nelson (phil at cs.wwu.edu) + + * Changed the name of math.h to libmath.h to avoid conflict + with /usr/include/math.h. Changed all references to math.h + to libmath.h in all files. + + * (configure) Changed the test for long strings accepted by + cc to not include libmath.h and thus not need to distribute + a file that is generated by the system. + + * (Makefile) Changed PREFIX, BINDIR, LIBDIR, and MANDIR to + lower case. + +Tue Mar 3 10:16:07 1992 Phil Nelson (phil at cs.wwu.edu) + + * (main.c) Added missing } at line 140. + + * (version.h) Changed date of version 1.02 to March 3, 1992. + +Mon Feb 3 16:07:57 1992 Phil Nelson (phil at cs.wwu.edu) + + * (version.h) Updated version number and date. + + * (bc.1) Added a new "VERSION" section. + +Wed Jan 29 14:13:55 1992 Phil Nelson (phil at cs.wwu.edu) + + * (execute.c) Removed the setjmp and longjmp calls that may have + caused some problems with interrupted programs. + +Thu Jan 16 17:08:16 1992 Phil Nelson (phil at cs.wwu.edu) + + * (Makefile) Changed install to install the manual. + +Wed Jan 8 13:23:42 1992 Phil Nelson (phil at cs.wwu.edu) + + * Change all copyright notices to include 1992. + + * (load.c) Added termination to "load_code" to ignore code + after an error has been found. + + * (scan.l) Changed the check for NUL characters in STRING tokens + (before the close quote) to work correctly. Also added code to + report illegal characters in a more readable output format. + + * (bc.1) Added the exclusion of NUL characters from strings in + the "differences" section and updated date of last change. + + * (const.h) Changed BC_MAX_SEGS to 16. + +Mon Jan 6 14:20:02 1992 Phil Nelson (phil at cs.wwu.edu) + + * (number.c) Changed the out_num routine to use a correct field + size for bases greater than 16. e.g. For base 1000, each + "digit" is a three digit number. + + * (Makefile) Added the "8" flag to get an 8 bit scanner. + + * (scan.l) Changed "char *" to "unsigned char *" to match the + declaration of yytext for the 8 bit scanner. Also added code + to detect the null character in strings and generate an error. + +Sat Jan 4 20:32:20 1992 Phil Nelson (phil at cs.wwu.edu) + + * (const.h) Changed BC_BASE_MAX to INT_MAX to allow more bases! + +Mon Dec 30 21:47:28 1991 Phil Nelson (phil at cs.wwu.edu) + + * (main.c) Fixed the bug that loaded the math library before + every file. + + * (bc.y) Removed some type declarations that duplicated token + definitions so it could be run through bison. + + * (load.c) Added a check for maximum code size. + + * (Makefile) Added a prefix for LIBDIR and BINDIR so it can be + changed easily. + +Mon Nov 25 13:11:17 1991 Phil Nelson (phil at cs.wwu.edu) + + * Changed version number in version.h to 1.01 with current date. + + * Changed LIBFILE definition in Makefile. + + * Added a recursive function example to bc.1. + +Sun Nov 24 21:24:01 1991 Phil Nelson (phil at cs.wwu.edu) + + * Changed the Makefile to make sure configure is run first. + Added the $(CC) the configure call. Moved some defines + toward the front of the Makefile to make sure they are + read by installers. Also added SUBDIRS variable and updated + the GNU distribution to include the subdirectories. Included + math.h in the distribution for use by configure. Included + ChangeLog in the distribution. + + * Split the README into README and Install. Changed Install + to have current information. Documented the STRINGS_H define. + Updated the version number in README. + + * Added a check for in configure. + +Fri Nov 22 15:06:32 1991 Phil Nelson (phil at cs.wwu.edu) + + * Changed configure to check for varargs.h first. Also, added + checks to see if long strings (math.h) are accepted by the + C compiler. Also added parameters to configure. + + * Deleted #include from proto.h. Also made only + ANSI C compilers include . + + * Changed the Makefile to have the install bin directory be + /usr/local/bin and the install lib directory be /usr/local/lib. + + * Changed some files in the Test directory to eliminate the + = form that some older bcs don't like. + + * Made some small corrections in bc.1. + +Tue Oct 29 10:06:32 1991 Phil Nelson (phil at cs.wwu.edu) + + * Called current version 1.00. + + * Submitted GNU bc-1.00 to comp.sources.reviewed diff --git a/Examples/ckbook.b b/Examples/ckbook.b new file mode 100644 index 0000000..5815ea0 --- /dev/null +++ b/Examples/ckbook.b @@ -0,0 +1,16 @@ +scale=2 +print "\nCheck book program!\n" +print " Remember, deposits are negative transactions.\n" +print " Exit by a 0 transaction.\n\n" + +print "Initial balance? "; bal = read() +bal /= 1 +print "\n" +while (1) { + "current balance = "; bal + "transaction? "; trans = read() + if (trans == 0) break; + bal -= trans + bal /= 1 +} +quit diff --git a/Examples/pi.b b/Examples/pi.b new file mode 100644 index 0000000..0d840cf --- /dev/null +++ b/Examples/pi.b @@ -0,0 +1,53 @@ +/* + This is a program to determine the distribution of digits in the + fraction part of PI. It will look at the first scale digits. + + The results are left in the global variable digits. + digits[0] is the number of 0's in PI. + + This program requires the math library. +*/ + +define pi () { + auto ix, pi, save_scale, work; + + save_scale = scale; + scale += 5; + print "\n\nCalculating PI to ",scale," digits. Please wait . . ."; + pi = 4*a(1); + scale -= 5; + work = pi; + + print "\nCounting digits. . ."; + for (ix = 0; ix < 10; ix++) digits[ix] = 0; + + /* Extract the One's digit from pi. */ + scale = 0; + one_digit = work / 1; + + for (ix = save_scale; ix > 0; ix--) { + + /* Remove the One's digit and multiply by 10. */ + scale = ix; + work = (work - one_digit) / 1 * 10; + + /* Extract the One's digit. */ + scale = 0; + one_digit = work / 1; + + digits[one_digit] += 1; + } + + /* Restore the scale. */ + scale = save_scale; + + /* Report. */ + print "\n\n" + print "PI to ", scale, " digits is:\n", pi/1, "\n\n" + print "The frequency of the digits are:\n" + for (ix = 0; ix < 10; ix++) { + print " ", ix, " - ", digits[ix], " times\n" + } + + print "\n\n" +} diff --git a/Examples/primes.b b/Examples/primes.b new file mode 100644 index 0000000..2b52ca7 --- /dev/null +++ b/Examples/primes.b @@ -0,0 +1,32 @@ + +/* An example that finds all primes between 2 and limit. */ + +define primes (limit) { + auto num, p, root, i + + prime[1] = 2; + prime[2] = 3; + num = 2; + if (limit >= 2) print "prime 1 = 2\n" + if (limit >= 3) print "prime 2 = 3\n"; + scale = 0; + + for ( p=5; p <= limit; p += 2) { + root = sqrt(p); + isprime = 1; + for ( i = 1; i < num && prime[i] <= root; i++ ) { + if ( p % prime[i] == 0 ) { + isprime = 0; + break; + } + } + if (isprime) { + num += 1; + prime [num] = p; + print "prime ", num, " = ", p, "\n" + } + } +} + + +print "\ntyping 'primes (10)' will print all primes less than 10.\n" diff --git a/Examples/twins.b b/Examples/twins.b new file mode 100644 index 0000000..de910a7 --- /dev/null +++ b/Examples/twins.b @@ -0,0 +1,40 @@ + +/* An example that finds all primes between 2 and limit. */ + +define primes (limit) { + auto num, p, root, i + + prime[1] = 2; + prime[2] = 3; + num = 2; + scale = 0; + + for ( p=5; p <= limit; p += 2) { + root = sqrt(p); + isprime = 1; + for ( i = 1; i < num && prime[i] <= root; i++ ) { + if ( p % prime[i] == 0 ) { + isprime = 0; + break; + } + } + if (isprime) { + num += 1; + prime [num] = p; + } + } +} + + +print "\ntyping 'twins (10)' will print all twin primes less than 10.\n" + +define twins (limit) { + auto i; + + i = primes(limit+2); + + for (i=1; prime[i] > 0; i++) { + if ((prime[i]+2) == prime[i+1]) \ + print "twins are ", prime[i], " and ", prime[i+1], "\n" + } +} diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..32dd051 --- /dev/null +++ b/FAQ @@ -0,0 +1,17 @@ +Because of frequent questions ....... here is the BC FAQ + + +1) Why does BC have its own arbitrary precision number routines + (found in lib/number.c) rather than using GMP? + +GMP has "integers" (no digits after a decimal), "rational numbers" +(stored as 2 integers) and "floats". None of these will correctly +represent a POSIX BC number. Floats are the closest, but will not +behave correctly for many computations. For example, BC numbers have +a "scale" that represent the number of digits to represent after the +decimal point. The multiplying two of these numbers requires one to +calculate an exact number of digits after the decimal point regardless +of the number of digits in the integer part. GMP floats have a +"fixed, but arbitrary" mantissa and so multiplying two floats will end +up dropping digits BC must calculate. + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..3b50ea9 --- /dev/null +++ b/INSTALL @@ -0,0 +1,176 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..6703d74 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = lib bc dc doc + +MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in \ + $(distdir).tar.gz h/number.h + +dist-hook: + mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test + cp -p $(srcdir)/h/*.h $(distdir)/h + cp -p $(srcdir)/Examples/*.b $(distdir)/Examples + cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test + cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test + cp -p $(srcdir)/lib/testmul.c $(distdir)/lib + cp -p $(srcdir)/FAQ $(distdir) + +timetest: + (cd lib; $(MAKE) specialnumber) diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..b57eae5 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,368 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = lib bc dc doc + +MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in $(distdir).tar.gz h/number.h + +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = README ./stamp-h.in AUTHORS COPYING COPYING.LIB ChangeLog \ +INSTALL Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 config.h.in \ +configure configure.in install-sh missing mkinstalldirs + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): configure.in + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/config.h.in: $(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +all-recursive-am: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile config.h +all-redirect: all-recursive-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +install-data-recursive uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \ +install-exec-am install-exec install-data-am install-data install-am \ +install uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +dist-hook: + mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test + cp -p $(srcdir)/h/*.h $(distdir)/h + cp -p $(srcdir)/Examples/*.b $(distdir)/Examples + cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test + cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test + cp -p $(srcdir)/lib/testmul.c $(distdir)/lib + cp -p $(srcdir)/FAQ $(distdir) + +timetest: + (cd lib; $(MAKE) specialnumber) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..fc02a0d --- /dev/null +++ b/NEWS @@ -0,0 +1,68 @@ +This is GNU bc version 1.06. (And dc version 1.2) + +Changes in dc from 1.2 to 1.3: + Minor bug fixes. + New multiply algorithm of bc. + +Changes in bc from 1.05 to 1.06: + New multiply algoirthm and many other changes in lib/number.c + Function size now done dynamically. + Function syntax in non-posix mode allows newlines in more places. + Bug fixes: + improved computation of j(n,x). + enables readline only if interactive. + for statment bug fixed. + use int instead of char for readline char counts. + improved cosine accuracy. + +Changes in dc from 1.1 to 1.2: + added !< != !> commands + arrays now stack + output is now line buffered, provided setvbuf() is available + fixed known bugs in 'q', 'Q', 'a' commands, '-f' command-line option, + and documentation + changed the 'P' command's behavior on a numeric argument: + due to popular demand it now does the equivalent of 'aP' + (for small values) + added new 'n' command to do what the old 'P' command did + +Changes in bc from 1.04 to 1.05: + Solaris makes work better. + bug fixes + stdout now always does line buffering. + sqrt bug fixed for small numbers. + readline (if support is compiled in) is enabled only for + interactive executions of bc. + + +This is GNU bc version 1.04. (And dc version 1.1) + +Changes from 1.03 + + reorganization of source tree + use of automake + + new commands for dc (|, ~, r, a) + new command line options for dc + + fixed infinite loop in sqrt in bc + fixed an I/O bug in bc + made bc conform to POSIX for array parameters + added long option support for bc + new commandline options for bc (-q) + added support for readline to bc (use configure --with-readline) + command line argumens can now be taken from an environment variable + + +Changes from 1.02 + + minor bug fixes in bc. + + addition of Ken Pizzini's dc program that uses the GNU bc + arbitrary precision arithmetic routines. + +Changes from 1.01 + + minor bug fixes. + + diff --git a/README b/README new file mode 100644 index 0000000..2813fb8 --- /dev/null +++ b/README @@ -0,0 +1,86 @@ +GNU bc version 1.06: + +Extra configuration options: + + --with-readline tells bc to use the readline package that allows + for editing input lines when run interactive. + + --with-editline tells bc to use the BSD editline package that + allows for editing input lines when run interactive. + +Extra make steps: + + The simple make compiles a version of bc with fixed parameters + for the recursive multiplication algorithm. The fixed parameter + is the number of digits where a sequential algorithm is used + instead of the recursive algorithm. It is set to a value that + is known good on a couple of machines. (Sparc Ultra 10, Pentium + II, 450.) I'm calling this point the crossover point. + + To make a version of bc with a custom crossover point for your + machine, do the following steps: + + make timetest + make + + The timetest step takes a minimum of 10 minutes to complete. + + +-------- Original comp.sources.reviewed README -------- + +Program: GNU bc +Author: Philip A. Nelson +E-mail: phil@cs.wwu.edu +OS: UNIX (BSD, System V, MINIX, POSIX) +Copying: GNU GPL version 2 +Copyright holder: Free Software Foundation, Inc. +Version: bc version 1.01 +Required: vsprintf and vfprintf routines. +Machines: It has been compiled and run on the following environments: + BSD4.3 (VAX 11) + MINIX 1.5 (IBM PC, both K&R and ANSI compilers) + MINIX 1.5 (pc532) + SUN-OS 4.1 (SUN 3 and SUN 4) + SVR3V5 (Motorola 68K) + SVR3.2 (3B2) + SVR4.0.2 (a 386 box) + ULTRIX 4.1 (DEC 5000) + UTS (Amdahl) + +bc is an arbitrary precision numeric processing language. Syntax is +similar to C, but differs in many substantial areas. It supports +interactive execution of statements. bc is a utility included in the +POSIX P1003.2/D11 draft standard. + +This version was written to be a POSIX compliant bc processor with +several extensions to the draft standard. Option flags are available +to cause warning or rejection of the extensions to the POSIX standard. +For those who want only POSIX bc with no extensions, a grammar is +provided for exactly the language described in the POSIX document. +The grammar (sbc.y) comes from the POSIX document. The Makefile +contains rules to make sbc. (for Standard BC) + +Since the POSIX document does not specify how bc must be implemented, +this version does not use the historical method of having bc be a +compiler for the dc calculator. This version has a single executable +that both compiles the language and runs the a resulting "byte code". +The "byte code" is NOT the dc language. + +Also, included in the initial distribution is the library file +vfprintf.c for MINIX systems. My minix 1.5 did not have this file. +Also, you should verify that vsprintf.c works correctly on your +system. + +The extensions add some features I think are missing. The major +changes and additions for bc are (a) names are allowed to be full +identifiers ([a-z][a-z0-9_]*), (b) addition of the &&, ||, and ! +operators, (c) allowing comparison and boolean operations in any +expression, (d) addition of an else clause to the if statement, (e) +addition of a new standard function "read()" that reads a number from +the standard input under program control, (f) passing of arrays as +parameters by variable, (g) addition of the "halt" statement that is +an executable statement unlike the quit (i.e. "if (1 == 0) quit" will +halt bc but "if (1 == 0) halt" will not halt bc.), and (h) the +addition of the special variable "last" that is assigned the value of +each print as the number is printed. +----------------------------------------------------------------------- diff --git a/Test/BUG.bc b/Test/BUG.bc new file mode 100644 index 0000000..254eefe --- /dev/null +++ b/Test/BUG.bc @@ -0,0 +1,40 @@ +/* <--- bug.bc ---><--- bug.bc ---><--- bug.bc ---><--- bug.bc ---> */ + +/* + * See the file "signum" for a description and reference for this + * program. + * + * THIS BUG IS *NOT* IN GNU BC!!! + * + */ + +obase=16 +ibase=16 +x=1A8F5C99605AE52 /* dividend */ +y=BB0B404 /* divisor */ +q=245A07AD /* (correct) quotient */ +r=147EB9E /* (correct) remainder */ +"Base 16 +" +"x = "; x /* output numbers just to be sure... */ +"y = "; y +"quo = "; q +"rem = "; r +"x/y = "; x/y /* watch this result! */ +"x%y = "; x%y /* watch this result! */ +"y*q+r= "; y*q+r /* check quotient & remainder */ +/* + * Do the same thing in base 10: + */ +" +Base 10 +" +ibase=A +obase=10 +"x = "; x /* output numbers just to be sure... */ +"y = "; y +"q = "; q +"r = "; r +"x/y = "; x/y /* watch this result! */ +"x%y = "; x%y /* watch this result! */ +"y*q+r= "; y*q+r /* check quotient & remainder */ diff --git a/Test/array.b b/Test/array.b new file mode 100644 index 0000000..a0341ec --- /dev/null +++ b/Test/array.b @@ -0,0 +1,14 @@ +"This tests arrays! +" +define p(x,y) { + auto i; + for (i=x; i= t) { + "Bad Scales. Try again. +"; return; + } + + for (i = x; i < y; i += d) { + scale = s; + u = f(i); + scale = t; + v = f(i); + scale = s; + w = v / 1; + b += 1; + if (u != w) { + c += 1; +" +Failed: +" + " index = "; i; + " val1 = "; u; + " val2 = "; v; +" +" + } + } + +" +Total tests: "; b; +" +Total failures: "; c; +" +Percent failed: "; scale = 2; c*100/b; + +} + +/* + b = begining scale value, + l = limit scale value, + i = increment scale value. + + if b is set to a non-zero value before this file is executed, + b, l and i are not reset. +*/ + +if (b == 0) { b = 10; l = 61; i = 10; } + +" +Checking e(x)" +define f(x) { + return (e(x)) +} +for (s=10; ss. + the result from scale t is divided by 1 at scale s and the + results are compared. If they are different, the function is + said to have failed. It will then print out the value of i + (called index) and the two original values val1 (scale s) and + val2 (scale t) */ + +define t (x,y,d,s,t) { + auto u, v, w, i, b, c; + + if (s >= t) { + "Bad Scales. Try again. +"; return; + } + + for (i = x; i < y; i += d) { + scale = s; + u = f(i); + scale = t; + v = f(i); + scale = s; + w = v / 1; + b += 1; + if (u != w) { + c += 1; +" +Failed: +" + " index = "; i; + " val1 = "; u; + " val2 = "; v; +" +" + } + } + +" +Total tests: "; b; +" +Total failures: "; c; +" +Percent failed: "; scale = 2; c*100/b; + +} diff --git a/Test/timetest b/Test/timetest new file mode 100755 index 0000000..1a4d0ea --- /dev/null +++ b/Test/timetest @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Time the functions. +# +SYSBC=/usr/bin/bc +if [ x$BC = x ] ; then + BC=../bc/bc +fi +for file in exp.b ln.b sine.b atan.b jn.b mul.b div.b raise.b sqrt.b +do +for prog in $BC $SYSBC $OTHERBC +do +echo Timing $file with $prog +time $prog -l $file +done +done diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..ff17f82 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,24 @@ +/* PACKAGE name */ +#undef PACKAGE + +/* Package VERSION number */ +#undef VERSION + +/* VERSION number for DC target*/ +#undef DC_VERSION + +/* COPYRIGHT notice for DC target */ +#undef DC_COPYRIGHT + +/* COPYRIGHT notice for BC target */ +#undef BC_COPYRIGHT + +/* Define to use the readline library. */ +#undef READLINE + +/* Define to use the BSD libedit library. */ +#undef LIBEDIT + +/* Define to `size_t' if and don't define. */ +#undef ptrdiff_t + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..102dc3e --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,136 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + diff --git a/bc/Makefile.am b/bc/Makefile.am new file mode 100644 index 0000000..9187339 --- /dev/null +++ b/bc/Makefile.am @@ -0,0 +1,42 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = bc + +bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c + +EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h \ + sbc.y +noinst_HEADERS = libmath.h + +DISTCLEANFILES = sbc sbc.c sbc.h + +MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h +LIBBC = ../lib/libbc.a +LIBL = @LEXLIB@ +LDADD = $(LIBBC) $(LIBL) @READLINELIB@ + +YFLAGS = -d + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +$(PROGRAMS): $(LIBBC) + +scan.o: bc.h +global.o: libmath.h + +libmath.h: libmath.b + echo '{0}' > libmath.h + $(MAKE) fbc + ./fbc -c $(srcdir)/libmath.b libmath.h + $(srcdir)/fix-libmath_h + rm -f ./fbc + +fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o +fbc: $(fbcOBJ) + $(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) + +sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o +sbc.o: sbc.c +sbc: $(sbcOBJ) + $(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) diff --git a/bc/Makefile.in b/bc/Makefile.in new file mode 100644 index 0000000..18ebce0 --- /dev/null +++ b/bc/Makefile.in @@ -0,0 +1,345 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +bin_PROGRAMS = bc + +bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c + +EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h sbc.y + +noinst_HEADERS = libmath.h + +DISTCLEANFILES = sbc sbc.c sbc.h + +MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h +LIBBC = ../lib/libbc.a +LIBL = @LEXLIB@ +LDADD = $(LIBBC) $(LIBL) @READLINELIB@ + +YFLAGS = -d + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o + +sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +bc_OBJECTS = main.o bc.o scan.o execute.o load.o storage.o util.o \ +global.o +bc_LDADD = $(LDADD) +bc_DEPENDENCIES = ../lib/libbc.a +bc_LDFLAGS = +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LEXLIB = @LEXLIB@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = Makefile.am Makefile.in bc.c scan.c + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(bc_SOURCES) +OBJECTS = $(bc_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .l .o .s .y +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps bc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +bc: $(bc_OBJECTS) $(bc_DEPENDENCIES) + @rm -f bc + $(LINK) $(bc_LDFLAGS) $(bc_OBJECTS) $(bc_LDADD) $(LIBS) +.l.c: + $(LEX) $(AM_LFLAGS) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@ +.y.c: + $(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c + if test -f y.tab.h; then \ + if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \ + else :; fi +bc.h: bc.c + + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = bc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +bc.o: bc.c bcdefs.h ../config.h const.h ../h/number.h global.h proto.h +execute.o: execute.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h +global.o: global.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + libmath.h +load.o: load.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h +main.o: main.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h ../h/getopt.h +scan.o: scan.c bcdefs.h ../config.h const.h ../h/number.h bc.h global.h \ + proto.h +storage.o: storage.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h +util.o: util.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + -test -z "scanlbchbcc$(MAINTAINERCLEANFILES)" || rm -f scanl bch bcc $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LIBBC) + +scan.o: bc.h +global.o: libmath.h + +libmath.h: libmath.b + echo '{0}' > libmath.h + $(MAKE) fbc + ./fbc -c $(srcdir)/libmath.b libmath.h + $(srcdir)/fix-libmath_h + rm -f ./fbc +fbc: $(fbcOBJ) + $(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) +sbc.o: sbc.c +sbc: $(sbcOBJ) + $(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bc/bc.c b/bc/bc.c new file mode 100644 index 0000000..6750bb6 --- /dev/null +++ b/bc/bc.c @@ -0,0 +1,1886 @@ + +/* A Bison parser, made from bc.y + by GNU Bison version 1.27 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define ENDOFLINE 257 +#define AND 258 +#define OR 259 +#define NOT 260 +#define STRING 261 +#define NAME 262 +#define NUMBER 263 +#define ASSIGN_OP 264 +#define REL_OP 265 +#define INCR_DECR 266 +#define Define 267 +#define Break 268 +#define Quit 269 +#define Length 270 +#define Return 271 +#define For 272 +#define If 273 +#define While 274 +#define Sqrt 275 +#define Else 276 +#define Scale 277 +#define Ibase 278 +#define Obase 279 +#define Auto 280 +#define Read 281 +#define Warranty 282 +#define Halt 283 +#define Last 284 +#define Continue 285 +#define Print 286 +#define Limits 287 +#define UNARY_MINUS 288 +#define HistoryVar 289 + +#line 1 "bc.y" + +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to: + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + 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 40 "bc.y" +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#include + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 185 +#define YYFLAG -32768 +#define YYNTBASE 50 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 289 ? yytranslate[x] : 84) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 40, 2, 2, 43, + 44, 38, 36, 47, 37, 2, 39, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 42, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 48, 2, 49, 41, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 45, 2, 46, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 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, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 1, 4, 7, 9, 12, 13, 15, 16, 18, + 22, 25, 26, 28, 31, 35, 38, 42, 44, 47, + 49, 51, 53, 55, 57, 59, 61, 63, 66, 67, + 68, 69, 70, 85, 86, 95, 96, 97, 106, 110, + 111, 115, 117, 121, 123, 125, 126, 127, 132, 133, + 146, 147, 149, 150, 154, 158, 160, 164, 169, 173, + 179, 186, 187, 189, 191, 195, 199, 205, 206, 208, + 209, 211, 212, 217, 218, 223, 224, 229, 232, 236, + 240, 244, 248, 252, 256, 260, 263, 265, 267, 271, + 276, 279, 282, 287, 292, 297, 301, 303, 308, 310, + 312, 314, 316, 318, 319, 321 +}; + +static const short yyrhs[] = { -1, + 50, 51, 0, 53, 3, 0, 69, 0, 1, 3, + 0, 0, 3, 0, 0, 55, 0, 53, 42, 55, + 0, 53, 42, 0, 0, 55, 0, 54, 3, 0, + 54, 3, 55, 0, 54, 42, 0, 54, 42, 56, + 0, 56, 0, 1, 56, 0, 28, 0, 33, 0, + 78, 0, 7, 0, 14, 0, 31, 0, 15, 0, + 29, 0, 17, 77, 0, 0, 0, 0, 0, 18, + 57, 43, 76, 42, 58, 76, 42, 59, 76, 44, + 60, 52, 56, 0, 0, 19, 43, 78, 44, 61, + 52, 56, 67, 0, 0, 0, 20, 62, 43, 78, + 63, 44, 52, 56, 0, 45, 54, 46, 0, 0, + 32, 64, 65, 0, 66, 0, 66, 47, 65, 0, + 7, 0, 78, 0, 0, 0, 22, 68, 52, 56, + 0, 0, 13, 8, 43, 71, 44, 52, 45, 83, + 72, 70, 54, 46, 0, 0, 73, 0, 0, 26, + 73, 3, 0, 26, 73, 42, 0, 8, 0, 8, + 48, 49, 0, 38, 8, 48, 49, 0, 73, 47, + 8, 0, 73, 47, 8, 48, 49, 0, 73, 47, + 38, 8, 48, 49, 0, 0, 75, 0, 78, 0, + 8, 48, 49, 0, 75, 47, 78, 0, 75, 47, + 8, 48, 49, 0, 0, 78, 0, 0, 78, 0, + 0, 82, 10, 79, 78, 0, 0, 78, 4, 80, + 78, 0, 0, 78, 5, 81, 78, 0, 6, 78, + 0, 78, 11, 78, 0, 78, 36, 78, 0, 78, + 37, 78, 0, 78, 38, 78, 0, 78, 39, 78, + 0, 78, 40, 78, 0, 78, 41, 78, 0, 37, + 78, 0, 82, 0, 9, 0, 43, 78, 44, 0, + 8, 43, 74, 44, 0, 12, 82, 0, 82, 12, + 0, 16, 43, 78, 44, 0, 21, 43, 78, 44, + 0, 23, 43, 78, 44, 0, 27, 43, 44, 0, + 8, 0, 8, 48, 78, 49, 0, 24, 0, 25, + 0, 23, 0, 35, 0, 30, 0, 0, 3, 0, + 83, 3, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 107, 116, 118, 120, 122, 128, 129, 132, 134, 135, + 136, 138, 140, 141, 142, 143, 144, 146, 147, 150, + 152, 154, 163, 170, 180, 191, 193, 195, 197, 202, + 212, 223, 233, 241, 248, 254, 260, 267, 273, 275, + 278, 279, 280, 282, 288, 291, 292, 300, 301, 315, + 321, 323, 325, 327, 329, 332, 334, 336, 338, 340, + 342, 345, 347, 349, 354, 360, 365, 381, 386, 388, + 393, 401, 413, 428, 436, 441, 449, 457, 463, 491, + 496, 501, 506, 511, 516, 521, 526, 535, 551, 553, + 569, 588, 611, 613, 615, 617, 623, 625, 630, 632, + 634, 636, 640, 647, 648, 649 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","ENDOFLINE", +"AND","OR","NOT","STRING","NAME","NUMBER","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", +"HistoryVar","'+'","'-'","'*'","'/'","'%'","'^'","';'","'('","')'","'{'","'}'", +"','","'['","']'","program","input_item","opt_newline","semicolon_list","statement_list", +"statement_or_error","statement","@1","@2","@3","@4","@5","@6","@7","@8","print_list", +"print_element","opt_else","@9","function","@10","opt_parameter_list","opt_auto_define_list", +"define_list","opt_argument_list","argument_list","opt_expression","return_expression", +"expression","@11","@12","@13","named_expression","required_eol", NULL +}; +#endif + +static const short yyr1[] = { 0, + 50, 50, 51, 51, 51, 52, 52, 53, 53, 53, + 53, 54, 54, 54, 54, 54, 54, 55, 55, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 57, 58, + 59, 60, 56, 61, 56, 62, 63, 56, 56, 64, + 56, 65, 65, 66, 66, 67, 68, 67, 70, 69, + 71, 71, 72, 72, 72, 73, 73, 73, 73, 73, + 73, 74, 74, 75, 75, 75, 75, 76, 76, 77, + 77, 79, 78, 80, 78, 81, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 82, 82, 82, 82, + 82, 82, 82, 83, 83, 83 +}; + +static const short yyr2[] = { 0, + 0, 2, 2, 1, 2, 0, 1, 0, 1, 3, + 2, 0, 1, 2, 3, 2, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, + 0, 0, 14, 0, 8, 0, 0, 8, 3, 0, + 3, 1, 3, 1, 1, 0, 0, 4, 0, 12, + 0, 1, 0, 3, 3, 1, 3, 4, 3, 5, + 6, 0, 1, 1, 3, 3, 5, 0, 1, 0, + 1, 0, 4, 0, 4, 0, 4, 2, 3, 3, + 3, 3, 3, 3, 3, 2, 1, 1, 3, 4, + 2, 2, 4, 4, 4, 3, 1, 4, 1, 1, + 1, 1, 1, 0, 1, 2 +}; + +static const short yydefact[] = { 1, + 0, 0, 0, 23, 97, 88, 0, 0, 24, 26, + 0, 70, 29, 0, 36, 0, 101, 99, 100, 0, + 20, 27, 103, 25, 40, 21, 102, 0, 0, 0, + 2, 0, 9, 18, 4, 22, 87, 5, 19, 78, + 62, 0, 97, 101, 91, 0, 0, 28, 71, 0, + 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, + 13, 3, 0, 74, 76, 0, 0, 0, 0, 0, + 0, 0, 72, 92, 97, 0, 63, 64, 0, 51, + 0, 68, 0, 0, 0, 0, 96, 44, 41, 42, + 45, 89, 0, 16, 39, 10, 0, 0, 79, 80, + 81, 82, 83, 84, 85, 0, 0, 90, 0, 98, + 56, 0, 0, 52, 93, 0, 69, 34, 37, 94, + 95, 0, 15, 17, 75, 77, 73, 65, 97, 66, + 0, 0, 6, 0, 30, 6, 0, 43, 0, 57, + 0, 7, 0, 59, 0, 68, 0, 6, 67, 58, + 104, 0, 0, 0, 46, 0, 105, 53, 60, 0, + 31, 47, 35, 38, 106, 0, 49, 61, 68, 6, + 0, 0, 0, 0, 54, 55, 0, 32, 48, 50, + 6, 0, 33, 0, 0 +}; + +static const short yydefgoto[] = { 1, + 31, 143, 32, 60, 61, 34, 50, 146, 169, 181, + 136, 52, 137, 56, 89, 90, 163, 170, 35, 172, + 113, 167, 114, 76, 77, 116, 48, 36, 106, 97, + 98, 37, 158 +}; + +static const short yypact[] = {-32768, + 170, 375, 567,-32768, -25,-32768, -3, 7,-32768,-32768, + -32, 567,-32768, -29,-32768, -26, -7,-32768,-32768, -5, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 567, 567, 213, +-32768, 16,-32768,-32768,-32768, 642, 14,-32768,-32768, 63, + 597, 567, -9,-32768,-32768, 18, 567,-32768, 642, 19, + 567, 20, 567, 567, 15, 537,-32768, 122, 505, 3, +-32768,-32768, 305,-32768,-32768, 567, 567, 567, 567, 567, + 567, 567,-32768,-32768, -18, 21, 26, 642, 39, -4, + 410, 567, 419, 567, 428, 466,-32768,-32768,-32768, 36, + 642,-32768, 259, 505,-32768,-32768, 567, 567, 404, 316, + 316, 44, 44, 44, 44, 567, 107,-32768, 627,-32768, + -8, 79, 45, 43,-32768, 49, 642,-32768, 642,-32768, +-32768, 537,-32768,-32768, 63, 652, 404,-32768, 38, 642, + 46, 48, 90, -1,-32768, 90, 61,-32768, 337,-32768, + 59,-32768, 65, 64, 103, 567, 505, 90,-32768,-32768, + 111, 68, 70, 78, 99, 505,-32768, 5,-32768, 75, +-32768,-32768,-32768,-32768,-32768, -4,-32768,-32768, 567, 90, + 13, 213, 81, 505,-32768,-32768, 6,-32768,-32768,-32768, + 90, 505,-32768, 129,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, -135,-32768, -37, 1, -2,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768, 25,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, -30,-32768,-32768, -136,-32768, 0,-32768,-32768, +-32768, 131,-32768 +}; + + +#define YYLAST 693 + + +static const short yytable[] = { 39, + 147, 33, 40, 111, 43, 93, 144, 165, 93, 154, + 47, 49, 156, 51, 46, 175, 53, 41, 62, 44, + 18, 19, 42, 73, 41, 74, 23, 57, 58, 107, + 166, 27, 173, 112, 174, 54, 145, 55, 42, 131, + 78, 79, 64, 65, 94, 182, 81, 94, 95, 66, + 83, 180, 85, 86, 176, 91, 39, 63, 87, 134, + 80, 82, 84, 96, 108, 99, 100, 101, 102, 103, + 104, 105, 109, 66, 67, 68, 69, 70, 71, 72, + 41, 117, 122, 119, 72, 139, 132, 110, 133, 134, + 135, 124, 142, 123, 140, 141, 125, 126, 67, 68, + 69, 70, 71, 72, 148, 127, 79, 150, 130, 151, + 153, 152, 3, 157, 5, 6, 159, 160, 7, 161, + 162, 91, 11, 168, 178, 64, 65, 16, 185, 17, + 18, 19, 66, 20, 177, 171, 23, 45, 79, 0, + 0, 27, 0, 28, 155, 117, 138, 0, 0, 29, + 0, 0, 0, 164, 0, 128, 0, 67, 68, 69, + 70, 71, 72, 0, 0, 92, 0, 0, 117, 184, + 2, 179, -8, 0, 0, 3, 4, 5, 6, 183, + 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 0, 17, 18, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 0, 27, 0, 28, 0, 0, 0, + 0, -8, 29, 59, 30, -12, 0, 0, 3, 4, + 5, 6, 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, 27, 0, 28, + 0, 0, 0, 0, -12, 29, 0, 30, -12, 59, + 0, -14, 0, 0, 3, 4, 5, 6, 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, 27, 0, 28, 0, 0, 0, 0, + -14, 29, 0, 30, -14, 59, 0, -11, 0, 0, + 3, 4, 5, 6, 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, 27, + 0, 28, 3, 0, 5, 6, -11, 29, 7, 30, + 0, 0, 11, 69, 70, 71, 72, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 0, 28, 0, 0, 0, 38, 0, 29, + 3, 4, 5, 6, 0, 149, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 0, 64, 65, 0, 0, 29, 0, 30, + 66, 0, 64, 65, 0, 0, 0, 0, 0, 66, + 0, 64, 65, 0, 0, 0, 0, 0, 66, 67, + 68, 69, 70, 71, 72, 67, 68, 69, 70, 71, + 72, 0, 0, 115, 67, 68, 69, 70, 71, 72, + 0, 0, 118, 67, 68, 69, 70, 71, 72, 64, + 65, 120, 0, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 67, 68, 69, 70, 71, 72, 0, 0, 121, + 3, 4, 5, 6, 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, 27, + 0, 28, 3, 88, 5, 6, 0, 29, 7, 30, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 5, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 75, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 129, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 64, 65, 16, 0, 17, + 18, 19, 66, 20, 0, 64, 23, 0, 0, 0, + 0, 27, 66, 28, 0, 0, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 0, 0, 67, 68, 69, + 70, 71, 72, 0, 0, 0, 0, 67, 68, 69, + 70, 71, 72 +}; + +static const short yycheck[] = { 2, + 136, 1, 3, 8, 8, 3, 8, 3, 3, 146, + 43, 12, 148, 43, 8, 3, 43, 43, 3, 23, + 24, 25, 48, 10, 43, 12, 30, 28, 29, 48, + 26, 35, 169, 38, 170, 43, 38, 43, 48, 48, + 41, 42, 4, 5, 42, 181, 47, 42, 46, 11, + 51, 46, 53, 54, 42, 56, 59, 42, 44, 47, + 43, 43, 43, 63, 44, 66, 67, 68, 69, 70, + 71, 72, 47, 11, 36, 37, 38, 39, 40, 41, + 43, 82, 47, 84, 41, 48, 8, 49, 44, 47, + 42, 94, 3, 93, 49, 48, 97, 98, 36, 37, + 38, 39, 40, 41, 44, 106, 107, 49, 109, 45, + 8, 48, 6, 3, 8, 9, 49, 48, 12, 42, + 22, 122, 16, 49, 44, 4, 5, 21, 0, 23, + 24, 25, 11, 27, 172, 166, 30, 7, 139, -1, + -1, 35, -1, 37, 147, 146, 122, -1, -1, 43, + -1, -1, -1, 156, -1, 49, -1, 36, 37, 38, + 39, 40, 41, -1, -1, 44, -1, -1, 169, 0, + 1, 174, 3, -1, -1, 6, 7, 8, 9, 182, + -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, -1, 23, 24, 25, -1, 27, 28, 29, 30, + 31, 32, 33, -1, 35, -1, 37, -1, -1, -1, + -1, 42, 43, 1, 45, 3, -1, -1, 6, 7, + 8, 9, -1, -1, 12, -1, 14, 15, 16, 17, + 18, 19, 20, 21, -1, 23, 24, 25, -1, 27, + 28, 29, 30, 31, 32, 33, -1, 35, -1, 37, + -1, -1, -1, -1, 42, 43, -1, 45, 46, 1, + -1, 3, -1, -1, 6, 7, 8, 9, -1, -1, + 12, -1, 14, 15, 16, 17, 18, 19, 20, 21, + -1, 23, 24, 25, -1, 27, 28, 29, 30, 31, + 32, 33, -1, 35, -1, 37, -1, -1, -1, -1, + 42, 43, -1, 45, 46, 1, -1, 3, -1, -1, + 6, 7, 8, 9, -1, -1, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, 6, -1, 8, 9, 42, 43, 12, 45, + -1, -1, 16, 38, 39, 40, 41, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, -1, 37, -1, -1, -1, 3, -1, 43, + 6, 7, 8, 9, -1, 49, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, -1, 4, 5, -1, -1, 43, -1, 45, + 11, -1, 4, 5, -1, -1, -1, -1, -1, 11, + -1, 4, 5, -1, -1, -1, -1, -1, 11, 36, + 37, 38, 39, 40, 41, 36, 37, 38, 39, 40, + 41, -1, -1, 44, 36, 37, 38, 39, 40, 41, + -1, -1, 44, 36, 37, 38, 39, 40, 41, 4, + 5, 44, -1, -1, -1, -1, 11, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 36, 37, 38, 39, 40, 41, -1, -1, 44, + 6, 7, 8, 9, -1, -1, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, 6, 7, 8, 9, -1, 43, 12, 45, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, 4, 5, 21, -1, 23, + 24, 25, 11, 27, -1, 4, 30, -1, -1, -1, + -1, 35, 11, 37, -1, -1, -1, -1, -1, 43, + -1, -1, -1, -1, -1, -1, -1, 36, 37, 38, + 39, 40, 41, -1, -1, -1, -1, 36, 37, 38, + 39, 40, 41 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/gnu/share/bison.simple" +/* This file comes from bison-1.27. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 216 "/usr/gnu/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 108 "bc.y" +{ + yyval.i_value = 0; + if (interactive && !quiet) + { + show_bc_version (); + welcome (); + } + ; + break;} +case 3: +#line 119 "bc.y" +{ run_code (); ; + break;} +case 4: +#line 121 "bc.y" +{ run_code (); ; + break;} +case 5: +#line 123 "bc.y" +{ + yyerrok; + init_gen (); + ; + break;} +case 7: +#line 130 "bc.y" +{ warn ("newline not allowed"); ; + break;} +case 8: +#line 133 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 12: +#line 139 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 19: +#line 148 "bc.y" +{ yyval.i_value = yyvsp[0].i_value; ; + break;} +case 20: +#line 151 "bc.y" +{ warranty (""); ; + break;} +case 21: +#line 153 "bc.y" +{ limits (); ; + break;} +case 22: +#line 155 "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 23: +#line 164 "bc.y" +{ + yyval.i_value = 0; + generate ("w"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + ; + break;} +case 24: +#line 171 "bc.y" +{ + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + ; + break;} +case 25: +#line 181 "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 26: +#line 192 "bc.y" +{ exit (0); ; + break;} +case 27: +#line 194 "bc.y" +{ generate ("h"); ; + break;} +case 28: +#line 196 "bc.y" +{ generate ("R"); ; + break;} +case 29: +#line 198 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + ; + break;} +case 30: +#line 203 "bc.y" +{ + if (yyvsp[-1].i_value & 2) + warn ("Comparison in first for expression"); + if (yyvsp[-1].i_value >= 0) + generate ("p"); + yyvsp[-1].i_value = next_label++; + sprintf (genstr, "N%1d:", yyvsp[-1].i_value); + generate (genstr); + ; + break;} +case 31: +#line 213 "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 32: +#line 224 "bc.y" +{ + if (yyvsp[-1].i_value & 2 ) + warn ("Comparison in third for expression"); + if (yyvsp[-1].i_value & 16) + 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 33: +#line 234 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = yyvsp[-13].i_value; + continue_label = yyvsp[-5].i_value; + ; + break;} +case 34: +#line 242 "bc.y" +{ + yyvsp[-1].i_value = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + ; + break;} +case 35: +#line 249 "bc.y" +{ + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = yyvsp[-5].i_value; + ; + break;} +case 36: +#line 255 "bc.y" +{ + yyvsp[0].i_value = next_label++; + sprintf (genstr, "N%1d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 37: +#line 261 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + ; + break;} +case 38: +#line 268 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, break_label); + generate (genstr); + break_label = yyvsp[-4].i_value; + ; + break;} +case 39: +#line 274 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 40: +#line 276 "bc.y" +{ warn ("print statement"); ; + break;} +case 44: +#line 283 "bc.y" +{ + generate ("O"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + ; + break;} +case 45: +#line 289 "bc.y" +{ generate ("P"); ; + break;} +case 47: +#line 293 "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 49: +#line 303 "bc.y" +{ + /* Check auto list against parameter list? */ + check_params (yyvsp[-5].a_value,yyvsp[0].a_value); + sprintf (genstr, "F%d,%s.%s[", + lookup(yyvsp[-7].s_value,FUNCTDEF), + arg_str (yyvsp[-5].a_value), arg_str (yyvsp[0].a_value)); + generate (genstr); + free_args (yyvsp[-5].a_value); + free_args (yyvsp[0].a_value); + yyvsp[-8].i_value = next_label; + next_label = 1; + ; + break;} +case 50: +#line 316 "bc.y" +{ + generate ("0R]"); + next_label = yyvsp[-11].i_value; + ; + break;} +case 51: +#line 322 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 53: +#line 326 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 54: +#line 328 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; ; + break;} +case 55: +#line 330 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; ; + break;} +case 56: +#line 333 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[0].s_value,SIMPLE), FALSE);; + break;} +case 57: +#line 335 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY), FALSE); ; + break;} +case 58: +#line 337 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY), TRUE); ; + break;} +case 59: +#line 339 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-2].a_value, lookup (yyvsp[0].s_value,SIMPLE), FALSE); ; + break;} +case 60: +#line 341 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-4].a_value, lookup (yyvsp[-2].s_value,ARRAY), FALSE); ; + break;} +case 61: +#line 343 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-5].a_value, lookup (yyvsp[-2].s_value,ARRAY), TRUE); ; + break;} +case 62: +#line 346 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 64: +#line 350 "bc.y" +{ + if (yyvsp[0].i_value & 2) warn ("comparison in argument"); + yyval.a_value = nextarg (NULL,0,FALSE); + ; + break;} +case 65: +#line 355 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (NULL,1,FALSE); + ; + break;} +case 66: +#line 361 "bc.y" +{ + if (yyvsp[0].i_value & 2) warn ("comparison in argument"); + yyval.a_value = nextarg (yyvsp[-2].a_value,0,FALSE); + ; + break;} +case 67: +#line 366 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (yyvsp[-4].a_value,1,FALSE); + ; + break;} +case 68: +#line 382 "bc.y" +{ + yyval.i_value = 16; + warn ("Missing expression in for statement"); + ; + break;} +case 70: +#line 389 "bc.y" +{ + yyval.i_value = 0; + generate ("0"); + ; + break;} +case 71: +#line 394 "bc.y" +{ + if (yyvsp[0].i_value & 2) + warn ("comparison in return expresion"); + if (!(yyvsp[0].i_value & 4)) + warn ("return expression requires parenthesis"); + ; + break;} +case 72: +#line 402 "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 73: +#line 413 "bc.y" +{ + if (yyvsp[0].i_value & 2) 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 74: +#line 429 "bc.y" +{ + warn("&& operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "DZ%d:p", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 75: +#line 436 "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) & ~4; + ; + break;} +case 76: +#line 442 "bc.y" +{ + warn("|| operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "B%d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 77: +#line 449 "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) & ~4; + ; + break;} +case 78: +#line 458 "bc.y" +{ + yyval.i_value = yyvsp[0].i_value & ~4; + warn("! operator"); + generate ("!"); + ; + break;} +case 79: +#line 464 "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 80: +#line 492 "bc.y" +{ + generate ("+"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 81: +#line 497 "bc.y" +{ + generate ("-"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 82: +#line 502 "bc.y" +{ + generate ("*"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 83: +#line 507 "bc.y" +{ + generate ("/"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 84: +#line 512 "bc.y" +{ + generate ("%"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 85: +#line 517 "bc.y" +{ + generate ("^"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 86: +#line 522 "bc.y" +{ + generate ("n"); + yyval.i_value = yyvsp[0].i_value & ~4; + ; + break;} +case 87: +#line 527 "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 88: +#line 536 "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 89: +#line 552 "bc.y" +{ yyval.i_value = yyvsp[-1].i_value | 5; ; + break;} +case 90: +#line 554 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].a_value != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup (yyvsp[-3].s_value,FUNCT), + call_str (yyvsp[-1].a_value)); + free_args (yyvsp[-1].a_value); + } + else + { + sprintf (genstr, "C%d:", lookup (yyvsp[-3].s_value,FUNCT)); + } + generate (genstr); + ; + break;} +case 91: +#line 570 "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 92: +#line 589 "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 93: +#line 612 "bc.y" +{ generate ("cL"); yyval.i_value = 1;; + break;} +case 94: +#line 614 "bc.y" +{ generate ("cR"); yyval.i_value = 1;; + break;} +case 95: +#line 616 "bc.y" +{ generate ("cS"); yyval.i_value = 1;; + break;} +case 96: +#line 618 "bc.y" +{ + warn ("read function"); + generate ("cI"); yyval.i_value = 1; + ; + break;} +case 97: +#line 624 "bc.y" +{ yyval.i_value = lookup(yyvsp[0].s_value,SIMPLE); ; + break;} +case 98: +#line 626 "bc.y" +{ + if (yyvsp[-1].i_value > 1) warn("comparison in subscript"); + yyval.i_value = lookup(yyvsp[-3].s_value,ARRAY); + ; + break;} +case 99: +#line 631 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 100: +#line 633 "bc.y" +{ yyval.i_value = 1; ; + break;} +case 101: +#line 635 "bc.y" +{ yyval.i_value = 2; ; + break;} +case 102: +#line 637 "bc.y" +{ yyval.i_value = 3; + warn ("History variable"); + ; + break;} +case 103: +#line 641 "bc.y" +{ yyval.i_value = 4; + warn ("Last variable"); + ; + break;} +case 104: +#line 647 "bc.y" +{ warn ("End of line required"); ; + break;} +case 106: +#line 650 "bc.y" +{ warn ("Too many end of lines"); ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 542 "/usr/gnu/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} +#line 653 "bc.y" + + diff --git a/bc/bc.h b/bc/bc.h new file mode 100644 index 0000000..4a1f59e --- /dev/null +++ b/bc/bc.h @@ -0,0 +1,42 @@ +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#define ENDOFLINE 257 +#define AND 258 +#define OR 259 +#define NOT 260 +#define STRING 261 +#define NAME 262 +#define NUMBER 263 +#define ASSIGN_OP 264 +#define REL_OP 265 +#define INCR_DECR 266 +#define Define 267 +#define Break 268 +#define Quit 269 +#define Length 270 +#define Return 271 +#define For 272 +#define If 273 +#define While 274 +#define Sqrt 275 +#define Else 276 +#define Scale 277 +#define Ibase 278 +#define Obase 279 +#define Auto 280 +#define Read 281 +#define Warranty 282 +#define Halt 283 +#define Last 284 +#define Continue 285 +#define Print 286 +#define Limits 287 +#define UNARY_MINUS 288 +#define HistoryVar 289 + + +extern YYSTYPE yylval; diff --git a/bc/bc.y b/bc/bc.y new file mode 100644 index 0000000..c538eec --- /dev/null +++ b/bc/bc.y @@ -0,0 +1,654 @@ +%{ +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to: + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" +%} + +%start program + +%union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } + +/* Extensions over POSIX bc. + a) NAME was LETTER. This grammar allows longer names. + Single letter names will still work. + b) Relational_expression allowed only one comparison. + This grammar has added boolean expressions with + && (and) || (or) and ! (not) and allowed all of them in + full expressions. + c) Added an else to the if. + d) Call by variable array parameters + e) read() procedure that reads a number under program control from stdin. + f) halt statement that halts the the program under program control. It + is an executed statement. + g) continue statement for for loops. + h) optional expressions in the for loop. + i) print statement to print multiple numbers per line. + j) warranty statement to print an extended warranty notice. + j) limits statement to print the processor's limits. +*/ + +%token ENDOFLINE AND OR NOT +%token STRING NAME NUMBER +/* '-', '+' are tokens themselves */ +/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */ +%token ASSIGN_OP +/* '==', '<=', '>=', '!=', '<', '>' */ +%token REL_OP +/* '++', '--' */ +%token INCR_DECR +/* 'define', 'break', 'quit', 'length' */ +%token Define Break Quit Length +/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */ +%token Return For If While Sqrt Else +/* 'scale', 'ibase', 'obase', 'auto', 'read' */ +%token Scale Ibase Obase Auto Read +/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */ +%token Warranty, Halt, Last, Continue, Print, Limits +/* 'history' */ +%token UNARY_MINUS HistoryVar + +/* Types of all other things. */ +%type expression return_expression named_expression opt_expression +%type '+' '-' '*' '/' '%' +%type opt_parameter_list opt_auto_define_list define_list +%type opt_argument_list argument_list +%type program input_item semicolon_list statement_list +%type statement function statement_or_error required_eol + +/* precedence */ +%left OR +%left AND +%nonassoc NOT +%left REL_OP +%right ASSIGN_OP +%left '+' '-' +%left '*' '/' '%' +%right '^' +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%% +program : /* empty */ + { + $$ = 0; + if (interactive && !quiet) + { + show_bc_version (); + welcome (); + } + } + | program input_item + ; +input_item : semicolon_list ENDOFLINE + { run_code (); } + | function + { run_code (); } + | error ENDOFLINE + { + yyerrok; + init_gen (); + } + ; +opt_newline : /* empty */ + | ENDOFLINE + { warn ("newline not allowed"); } + ; +semicolon_list : /* empty */ + { $$ = 0; } + | statement_or_error + | semicolon_list ';' statement_or_error + | semicolon_list ';' + ; +statement_list : /* empty */ + { $$ = 0; } + | statement_or_error + | statement_list ENDOFLINE + | statement_list ENDOFLINE statement_or_error + | statement_list ';' + | statement_list ';' statement + ; +statement_or_error : statement + | error statement + { $$ = $2; } + ; +statement : Warranty + { warranty (""); } + | Limits + { limits (); } + | expression + { + if ($1 & 2) + warn ("comparison in expression"); + if ($1 & 1) + generate ("W"); + else + generate ("p"); + } + | STRING + { + $$ = 0; + generate ("w"); + generate ($1); + free ($1); + } + | Break + { + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } + | Continue + { + warn ("Continue statement"); + if (continue_label == 0) + yyerror ("Continue outside a for"); + else + { + sprintf (genstr, "J%1d:", continue_label); + generate (genstr); + } + } + | Quit + { exit (0); } + | Halt + { generate ("h"); } + | Return return_expression + { generate ("R"); } + | For + { + $1 = break_label; + break_label = next_label++; + } + '(' opt_expression ';' + { + if ($4 & 2) + warn ("Comparison in first for expression"); + if (!($4 & 16)) + generate ("p"); + $4 = next_label++; + sprintf (genstr, "N%1d:", $4); + generate (genstr); + } + opt_expression ';' + { + if ($7 & 16) generate ("1"); + $7 = next_label++; + sprintf (genstr, "B%1d:J%1d:", $7, break_label); + generate (genstr); + $$ = continue_label; + continue_label = next_label++; + sprintf (genstr, "N%1d:", continue_label); + generate (genstr); + } + opt_expression ')' + { + if ($10 & 2 ) + warn ("Comparison in third for expression"); + if ($10 & 16) + sprintf (genstr, "J%1d:N%1d:", $4, $7); + else + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } + opt_newline statement + { + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = $1; + continue_label = $9; + } + | If '(' expression ')' + { + $3 = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + } + opt_newline statement opt_else + { + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = $3; + } + | While + { + $1 = next_label++; + sprintf (genstr, "N%1d:", $1); + generate (genstr); + } + '(' expression + { + $4 = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } + ')' opt_newline statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + break_label = $4; + } + | '{' statement_list '}' + { $$ = 0; } + | Print + { warn ("print statement"); } + print_list + ; +print_list : print_element + | print_element ',' print_list + ; +print_element : STRING + { + generate ("O"); + generate ($1); + free ($1); + } + | expression + { generate ("P"); } + ; +opt_else : /* nothing */ + | Else + { + warn ("else clause in if statement"); + $1 = next_label++; + sprintf (genstr, "J%d:N%1d:", $1, if_label); + generate (genstr); + if_label = $1; + } + opt_newline statement +function : Define NAME '(' opt_parameter_list ')' opt_newline + '{' required_eol opt_auto_define_list + { + /* Check auto list against parameter list? */ + check_params ($4,$9); + sprintf (genstr, "F%d,%s.%s[", + lookup($2,FUNCTDEF), + arg_str ($4), arg_str ($9)); + generate (genstr); + free_args ($4); + free_args ($9); + $1 = next_label; + next_label = 1; + } + statement_list /* ENDOFLINE */ '}' + { + generate ("0R]"); + next_label = $1; + } + ; +opt_parameter_list : /* empty */ + { $$ = NULL; } + | define_list + ; +opt_auto_define_list : /* empty */ + { $$ = NULL; } + | Auto define_list ENDOFLINE + { $$ = $2; } + | Auto define_list ';' + { $$ = $2; } + ; +define_list : NAME + { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);} + | NAME '[' ']' + { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); } + | '*' NAME '[' ']' + { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); } + | define_list ',' NAME '[' ']' + { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); } + | define_list ',' '*' NAME '[' ']' + { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); } + ; +opt_argument_list : /* empty */ + { $$ = NULL; } + | argument_list + ; +argument_list : expression + { + if ($1 & 2) warn ("comparison in argument"); + $$ = nextarg (NULL,0,FALSE); + } + | NAME '[' ']' + { + sprintf (genstr, "K%d:", -lookup ($1,ARRAY)); + generate (genstr); + $$ = nextarg (NULL,1,FALSE); + } + | argument_list ',' expression + { + if ($3 & 2) warn ("comparison in argument"); + $$ = nextarg ($1,0,FALSE); + } + | argument_list ',' NAME '[' ']' + { + sprintf (genstr, "K%d:", -lookup ($3,ARRAY)); + generate (genstr); + $$ = nextarg ($1,1,FALSE); + } + ; + +/* Expression lval meanings! (Bits mean something!) + * 0 => Top op is assignment. + * 1 => Top op is not assignment. + * 2 => Comparison is somewhere in expression. + * 4 => Expression is in parenthesis. + * 16 => Empty optional expression. + */ + +opt_expression : /* empty */ + { + $$ = 16; + warn ("Missing expression in for statement"); + } + | expression + ; +return_expression : /* empty */ + { + $$ = 0; + generate ("0"); + } + | expression + { + if ($1 & 2) + warn ("comparison in return expresion"); + if (!($1 & 4)) + warn ("return expression requires parenthesis"); + } + ; +expression : named_expression ASSIGN_OP + { + if ($2 != '=') + { + if ($1 < 0) + sprintf (genstr, "DL%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + } + expression + { + if ($4 & 2) warn("comparison in assignment"); + if ($2 != '=') + { + sprintf (genstr, "%c", $2); + generate (genstr); + } + if ($1 < 0) + sprintf (genstr, "S%d:", -$1); + else + sprintf (genstr, "s%d:", $1); + generate (genstr); + $$ = 0; + } + ; + | expression AND + { + warn("&& operator"); + $2 = next_label++; + sprintf (genstr, "DZ%d:p", $2); + generate (genstr); + } + expression + { + sprintf (genstr, "DZ%d:p1N%d:", $2, $2); + generate (genstr); + $$ = ($1 | $4) & ~4; + } + | expression OR + { + warn("|| operator"); + $2 = next_label++; + sprintf (genstr, "B%d:", $2); + generate (genstr); + } + expression + { + int tmplab; + tmplab = next_label++; + sprintf (genstr, "B%d:0J%d:N%d:1N%d:", + $2, tmplab, $2, tmplab); + generate (genstr); + $$ = ($1 | $4) & ~4; + } + | NOT expression + { + $$ = $2 & ~4; + warn("! operator"); + generate ("!"); + } + | expression REL_OP expression + { + $$ = 3; + switch (*($2)) + { + case '=': + generate ("="); + break; + + case '!': + generate ("#"); + break; + + case '<': + if ($2[1] == '=') + generate ("{"); + else + generate ("<"); + break; + + case '>': + if ($2[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } + | expression '+' expression + { + generate ("+"); + $$ = ($1 | $3) & ~4; + } + | expression '-' expression + { + generate ("-"); + $$ = ($1 | $3) & ~4; + } + | expression '*' expression + { + generate ("*"); + $$ = ($1 | $3) & ~4; + } + | expression '/' expression + { + generate ("/"); + $$ = ($1 | $3) & ~4; + } + | expression '%' expression + { + generate ("%"); + $$ = ($1 | $3) & ~4; + } + | expression '^' expression + { + generate ("^"); + $$ = ($1 | $3) & ~4; + } + | '-' expression %prec UNARY_MINUS + { + generate ("n"); + $$ = $2 & ~4; + } + | named_expression + { + $$ = 1; + if ($1 < 0) + sprintf (genstr, "L%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + | NUMBER + { + int len = strlen($1); + $$ = 1; + if (len == 1 && *$1 == '0') + generate ("0"); + else if (len == 1 && *$1 == '1') + generate ("1"); + else + { + generate ("K"); + generate ($1); + generate (":"); + } + free ($1); + } + | '(' expression ')' + { $$ = $2 | 5; } + | NAME '(' opt_argument_list ')' + { + $$ = 1; + if ($3 != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup ($1,FUNCT), + call_str ($3)); + free_args ($3); + } + else + { + sprintf (genstr, "C%d:", lookup ($1,FUNCT)); + } + generate (genstr); + } + | INCR_DECR named_expression + { + $$ = 1; + if ($2 < 0) + { + if ($1 == '+') + sprintf (genstr, "DA%d:L%d:", -$2, -$2); + else + sprintf (genstr, "DM%d:L%d:", -$2, -$2); + } + else + { + if ($1 == '+') + sprintf (genstr, "i%d:l%d:", $2, $2); + else + sprintf (genstr, "d%d:l%d:", $2, $2); + } + generate (genstr); + } + | named_expression INCR_DECR + { + $$ = 1; + if ($1 < 0) + { + sprintf (genstr, "DL%d:x", -$1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "A%d:", -$1); + else + sprintf (genstr, "M%d:", -$1); + } + else + { + sprintf (genstr, "l%d:", $1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "i%d:", $1); + else + sprintf (genstr, "d%d:", $1); + } + generate (genstr); + } + | Length '(' expression ')' + { generate ("cL"); $$ = 1;} + | Sqrt '(' expression ')' + { generate ("cR"); $$ = 1;} + | Scale '(' expression ')' + { generate ("cS"); $$ = 1;} + | Read '(' ')' + { + warn ("read function"); + generate ("cI"); $$ = 1; + } + ; +named_expression : NAME + { $$ = lookup($1,SIMPLE); } + | NAME '[' expression ']' + { + if ($3 > 1) warn("comparison in subscript"); + $$ = lookup($1,ARRAY); + } + | Ibase + { $$ = 0; } + | Obase + { $$ = 1; } + | Scale + { $$ = 2; } + | HistoryVar + { $$ = 3; + warn ("History variable"); + } + | Last + { $$ = 4; + warn ("Last variable"); + } + ; + + +required_eol : { warn ("End of line required"); } + | ENDOFLINE + | required_eol ENDOFLINE + { warn ("Too many end of lines"); } + ; + +%% + diff --git a/bc/bcdefs.h b/bc/bcdefs.h new file mode 100644 index 0000000..260cd12 --- /dev/null +++ b/bc/bcdefs.h @@ -0,0 +1,188 @@ +/* bcdefs.h: The single file to include all constants and type definitions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + 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 +#include +#include +#ifdef HAVE_STRINGS_H +#include +#else +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif + +#if defined(LIBEDIT) +#include +#endif + +#if defined(READLINE) +#include +#include +#endif + +/* Include the other definitions. */ +#include "const.h" +#include "number.h" + +/* These definitions define all the structures used in + code and data storage. This includes the representation of + labels. The "guiding" principle is to make structures that + take a minimum of space when unused but can be built to contain + the full structures. */ + +/* Labels are first. Labels are generated sequentially in functions + and full code. They just "point" to a single bye in the code. The + "address" is the byte number. The byte number is used to get an + actual character pointer. */ + +typedef struct bc_label_group + { + long l_adrs [ BC_LABEL_GROUP ]; + struct bc_label_group *l_next; + } bc_label_group; + +/* Argument list. Recorded in the function so arguments can + be checked at call time. */ + +typedef struct arg_list + { + int av_name; + int arg_is_var; /* Extension ... variable parameters. */ + struct arg_list *next; + } arg_list; + +/* Each function has its own code segments and labels. There can be + no jumps between functions so labels are unique to a function. */ + +typedef struct + { + char f_defined; /* Is this function defined yet. */ + char *f_body; + int f_body_size; /* Size of body. Power of 2. */ + int f_code_size; + bc_label_group *f_label; + arg_list *f_params; + arg_list *f_autos; + } bc_function; + +/* Code addresses. */ +typedef struct { + int pc_func; + int pc_addr; + } program_counter; + + +/* Variables are "pushable" (auto) and thus we need a stack mechanism. + This is built into the variable record. */ + +typedef struct bc_var + { + bc_num v_value; + struct bc_var *v_next; + } bc_var; + + +/* bc arrays can also be "auto" variables and thus need the same + kind of stacking mechanisms. */ + +typedef struct bc_array_node + { + union + { + bc_num n_num [NODE_SIZE]; + struct bc_array_node *n_down [NODE_SIZE]; + } n_items; + } bc_array_node; + +typedef struct bc_array + { + bc_array_node *a_tree; + short a_depth; + } bc_array; + +typedef struct bc_var_array + { + bc_array *a_value; + char a_param; + struct bc_var_array *a_next; + } bc_var_array; + + +/* For the stacks, execution and function, we need records to allow + for arbitrary size. */ + +typedef struct estack_rec { + bc_num s_num; + struct estack_rec *s_next; +} estack_rec; + +typedef struct fstack_rec { + int s_val; + struct fstack_rec *s_next; +} fstack_rec; + + +/* The following are for the name tree. */ + +typedef struct id_rec { + char *id; /* The program name. */ + /* A name == 0 => nothing assigned yet. */ + int a_name; /* The array variable name (number). */ + int f_name; /* The function name (number). */ + int v_name; /* The variable name (number). */ + short balance; /* For the balanced tree. */ + struct id_rec *left, *right; /* Tree pointers. */ +} id_rec; + + +/* A list of files to process. */ + +typedef struct file_node { + char *name; + struct file_node *next; +} file_node; + +/* Macro Definitions */ + +#if defined(LIBEDIT) +#define HISTORY_SIZE(n) history(hist, &histev, H_SETSIZE, n) +#define UNLIMIT_HISTORY history(hist, &histev, H_SETSIZE, INT_MAX) +#endif + +#if defined(READLINE) +#define HISTORY_SIZE(n) stifle_history(n) +#define UNLIMIT_HISTORY unstifle_history() +#endif diff --git a/bc/const.h b/bc/const.h new file mode 100644 index 0000000..1a7c5b8 --- /dev/null +++ b/bc/const.h @@ -0,0 +1,98 @@ +/* const.h: Constants for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */ + +#ifndef INT_MAX +#define INT_MAX 0x7FFFFFFF +#endif +#ifndef LONG_MAX +#define LONG_MAX 0x7FFFFFFF +#endif + + +/* Define constants in some reasonable size. The next 4 constants are + POSIX constants. */ + +#ifdef BC_BASE_MAX + /* on a POSIX.2 system may have defined these. Override. */ +# undef BC_BASE_MAX +# undef BC_SCALE_MAX +# undef BC_STRING_MAX +# undef BC_DIM_MAX +#endif + +#define BC_BASE_MAX INT_MAX +#define BC_SCALE_MAX INT_MAX +#define BC_STRING_MAX INT_MAX + + +/* Definitions for arrays. */ + +#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */ + +#define NODE_SIZE 16 /* Must be a power of 2. */ +#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */ +#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */ +#define NODE_DEPTH 4 + + +/* Other BC limits defined but not part of POSIX. */ + +#define BC_LABEL_GROUP 64 +#define BC_LABEL_LOG 6 +#define BC_START_SIZE 1024 /* Initial code body size. */ + +/* Maximum number of variables, arrays and functions and the + allocation increment for the dynamic arrays. */ + +#define MAX_STORE 32767 +#define STORE_INCR 32 + +/* Other interesting constants. */ + +#define FALSE 0 +#define TRUE 1 + +/* for use with lookup (). */ +#define SIMPLE 0 +#define ARRAY 1 +#define FUNCT 2 +#define FUNCTDEF 3 + +#define EXTERN extern +#ifdef __STDC__ +#define CONST const +#define VOID void +#else +#define CONST +#define VOID +#endif diff --git a/bc/execute.c b/bc/execute.c new file mode 100644 index 0000000..d2864d1 --- /dev/null +++ b/bc/execute.c @@ -0,0 +1,788 @@ +/* execute.c - run a bc program. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include +#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; +{ + return (functions[pc->pc_func].f_body[pc->pc_addr++]); +} + + +/* 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; + bc_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); + bc_out_num (temp->s_num, 10, out_char, std_only); + depth++; + temp = temp->s_next; + } + out_char ('\n'); + } + } +#endif + + switch ( inst ) + { + + case 'A' : /* increment array variable (Add one). */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + 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 = !bc_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 & 0x7f) << 8) + 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 & 0x7f) << 8) + 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 & 0x7f) << 8) + byte(&pc); + decr_array (var_name); + break; + + case 'O' : /* Write a string to the output with processing. */ + while ((ch = byte(&pc)) != '"') + if (ch != '\\') + out_schar (ch); + else + { + ch = byte(&pc); + if (ch == '"') break; + switch (ch) + { + case 'a': out_schar (007); break; + case 'b': out_schar ('\b'); break; + case 'f': out_schar ('\f'); break; + case 'n': out_schar ('\n'); break; + case 'q': out_schar ('"'); break; + case 'r': out_schar ('\r'); break; + case 't': out_schar ('\t'); break; + case '\\': out_schar ('\\'); break; + default: break; + } + } + fflush (stdout); + break; + + case 'R' : /* Return from function */ + if (pc.pc_func != 0) + { + /* "Pop" autos and parameters. */ + pop_vars(functions[pc.pc_func].f_autos); + pop_vars(functions[pc.pc_func].f_params); + /* reset the pc. */ + fpop (); + pc.pc_addr = fpop (); + pc.pc_func = fpop (); + } + else + rt_error ("Return from main program."); + break; + + case 'S' : /* store array variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f ) << 8) + byte(&pc); + store_array (var_name); + break; + + case 'T' : /* Test tos for zero */ + c_code = bc_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. */ + bc_out_num (ex_stack->s_num, o_base, out_char, std_only); + if (inst == 'W') out_char ('\n'); + store_var (4); /* Special variable "last". */ + fflush (stdout); + pop (); + break; + + case 'c' : /* Call special function. */ + new_func = byte(&pc); + + switch (new_func) + { + case 'L': /* Length function. */ + /* For the number 0.xxxx, 0 is not significant. */ + if (ex_stack->s_num->n_len == 1 && + ex_stack->s_num->n_scale != 0 && + ex_stack->s_num->n_value[0] == 0 ) + bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); + else + bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len + + ex_stack->s_num->n_scale); + break; + + case 'S': /* Scale function. */ + bc_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 & 0x7f) << 8) + 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 & 0x7f) << 8) + byte(&pc); + incr_var (var_name); + break; + + case 'l' : /* load variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + load_var (var_name); + break; + + case 'n' : /* Negate top of stack. */ + bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0); + break; + + case 'p' : /* Pop the execution stack. */ + pop (); + break; + + case 's' : /* store variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + store_var (var_name); + break; + + case 'w' : /* Write a string to the output. */ + while ((ch = byte(&pc)) != '"') out_schar (ch); + fflush (stdout); + break; + + case 'x' : /* Exchange Top of Stack with the one under the tos. */ + if (check_stack(2)) { + bc_num temp = ex_stack->s_num; + ex_stack->s_num = ex_stack->s_next->s_num; + ex_stack->s_next->s_num = temp; + } + break; + + case '0' : /* Load Constant 0. */ + push_copy (_zero_); + break; + + case '1' : /* Load Constant 0. */ + push_copy (_one_); + break; + + case '!' : /* Negate the boolean value on top of the stack. */ + c_code = bc_is_zero (ex_stack->s_num); + assign (c_code); + break; + + case '&' : /* compare greater than */ + if (check_stack(2)) + { + c_code = !bc_is_zero (ex_stack->s_next->s_num) + && !bc_is_zero (ex_stack->s_num); + pop (); + assign (c_code); + } + break; + + case '|' : /* compare greater than */ + if (check_stack(2)) + { + c_code = !bc_is_zero (ex_stack->s_next->s_num) + || !bc_is_zero (ex_stack->s_num); + pop (); + assign (c_code); + } + break; + + case '+' : /* add */ + if (check_stack(2)) + { + bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0); + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + break; + + case '-' : /* subtract */ + if (check_stack(2)) + { + bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0); + pop(); + pop(); + push_num (temp_num); + bc_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); + bc_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); + bc_init_num (&temp_num); + } + else + rt_error ("Divide by zero"); + } + break; + + case '%' : /* remainder */ + if (check_stack(2)) + { + if (bc_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); + bc_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 (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num)) + rt_error ("divide by zero"); + pop(); + pop(); + push_num (temp_num); + bc_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((int)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 */ + bc_init_num (&temp); + bc_init_num (&result); + bc_init_num (&mult); + build = bc_copy_num (_zero_); + negative = FALSE; + + /* The conversion base. */ + bc_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; + bc_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); + bc_int2num (&temp, (int) in_ch); + bc_add (result, temp, &build, 0); + in_ch = in_char(); + } + if (in_ch == '.') + { + in_ch = in_char(); + if (in_ch >= conv_base) in_ch = conv_base-1; + bc_free_num (&result); + bc_free_num (&temp); + divisor = bc_copy_num (_one_); + result = bc_copy_num (_zero_); + digits = 0; + while (in_ch < 16) + { + bc_multiply (result, mult, &result, 0); + bc_int2num (&temp, (int) in_ch); + bc_add (result, temp, &result, 0); + bc_multiply (divisor, mult, &divisor, 0); + digits++; + in_ch = in_char(); + if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; + } + bc_divide (result, divisor, &result, digits); + bc_add (build, result, &build, 0); + } + + /* Final work. */ + if (negative) + bc_sub (_zero_, build, &build, 0); + + push_num (build); + bc_free_num (&temp); + bc_free_num (&result); + bc_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) + { + bc_init_num (&build); + bc_int2num (&build, inchar); + push_num (build); + inchar = byte(pc); + return; + } + } + + /* Build the new number. */ + if (kdigits == 0) + { + build = bc_new_num (1,kscale); + ptr = build->n_value; + *ptr++ = 0; + } + else + { + build = bc_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; +{ + bc_free_num (&ex_stack->s_num); + if (c_code) + ex_stack->s_num = bc_copy_num (_one_); + else + ex_stack->s_num = bc_copy_num (_zero_); +} + diff --git a/bc/fix-libmath_h b/bc/fix-libmath_h new file mode 100755 index 0000000..f973a8c --- /dev/null +++ b/bc/fix-libmath_h @@ -0,0 +1,9 @@ +ed libmath.h < 1) { + f += 1; + x /= 2; + scale += 1; + } + + /* Initialize the variables. */ + scale = n; + v = 1+x + a = x + d = 1 + + for (i=2; 1; i++) { + e = (a *= x) / (d *= i) + if (e == 0) { + if (f>0) while (f--) v = v*v; + scale = z + if (m) return (1/v); + return (v/1); + } + v += e + } +} + +/* Natural log. Uses the fact that ln(x^2) = 2*ln(x) + The series used is: + ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1) +*/ + +define l(x) { + auto e, f, i, m, n, v, z + + /* return something for the special case. */ + if (x <= 0) return ((1 - 10^scale)/1) + + /* Precondition x to make .5 < x < 2.0. */ + z = scale; + scale = 6 + scale; + f = 2; + i=0 + while (x >= 2) { /* for large numbers */ + f *= 2; + x = sqrt(x); + } + while (x <= .5) { /* for small numbers */ + f *= 2; + x = sqrt(x); + } + + /* Set up the loop. */ + v = n = (x-1)/(x+1) + m = n*n + + /* Sum the series. */ + for (i=3; 1; i+=2) { + e = (n *= m) / i + if (e == 0) { + v = f*v + scale = z + return (v/1) + } + v += e + } +} + +/* Sin(x) uses the standard series: + sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */ + +define s(x) { + auto e, i, m, n, s, v, z + + /* precondition x. */ + z = scale + scale = 1.1*z + 2; + v = a(1) + if (x < 0) { + m = 1; + x = -x; + } + scale = 0 + n = (x / v + 2 )/4 + x = x - 4*n*v + if (n%2) x = -x + + /* Do the loop. */ + scale = z + 2; + v = e = x + s = -x*x + for (i=3; 1; i+=2) { + e *= s/(i*(i-1)) + if (e == 0) { + scale = z + if (m) return (-v/1); + return (v/1); + } + v += e + } +} + +/* Cosine : cos(x) = sin(x+pi/2) */ +define c(x) { + auto v, z; + z = scale; + scale = scale*1.2; + v = s(x+a(1)*2); + scale = z; + return (v/1); +} + +/* Arctan: Using the formula: + atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here) + For under .2, use the series: + atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */ + +define a(x) { + auto a, e, f, i, m, n, s, v, z + + /* a is the value of a(.2) if it is needed. */ + /* f is the value to multiply by a in the return. */ + /* e is the value of the current term in the series. */ + /* v is the accumulated value of the series. */ + /* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */ + /* i is the denominator value for series element. */ + /* n is the numerator value for the series element. */ + /* s is -x*x. */ + /* z is the saved user's scale. */ + + /* Negative x? */ + m = 1; + if (x<0) { + m = -1; + x = -x; + } + + /* Special case and for fast answers */ + if (x==1) { + if (scale <= 25) return (.7853981633974483096156608/m) + if (scale <= 40) return (.7853981633974483096156608458198757210492/m) + if (scale <= 60) \ + return (.785398163397448309615660845819875721049292349843776455243736/m) + } + if (x==.2) { + if (scale <= 25) return (.1973955598498807583700497/m) + if (scale <= 40) return (.1973955598498807583700497651947902934475/m) + if (scale <= 60) \ + return (.197395559849880758370049765194790293447585103787852101517688/m) + } + + + /* Save the scale. */ + z = scale; + + /* Note: a and f are known to be zero due to being auto vars. */ + /* Calculate atan of a known number. */ + if (x > .2) { + scale = z+5; + a = a(.2); + } + + /* Precondition x. */ + scale = z+3; + while (x > .2) { + f += 1; + x = (x-.2) / (1+x*.2); + } + + /* Initialize the series. */ + v = n = x; + s = -x*x; + + /* Calculate the series. */ + for (i=3; 1; i+=2) { + e = (n *= s) / i; + if (e == 0) { + scale = z; + return ((f*a+v)/m); + } + v += e + } +} + + +/* Bessel function of integer order. Uses the following: + j(-n,x) = (-1)^n*j(n,x) + j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2)) + - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... ) +*/ +define j(n,x) { + auto a, b, 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; + } + + /* save ibase */ + b = ibase; + ibase = A; + + /* 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 + length(f) - scale(f); + + /* The Loop.... */ + for (i=1; 1; i++) { + e = e * s / i / (n+i); + if (e == 0) { + ibase = b; + scale = z + if (m) return (-f*v/1); + return (f*v/1); + } + v += e; + } +} diff --git a/bc/libmath.h b/bc/libmath.h new file mode 100644 index 0000000..7611e11 --- /dev/null +++ b/bc/libmath.h @@ -0,0 +1 @@ +{0} diff --git a/bc/load.c b/bc/load.c new file mode 100644 index 0000000..7465481 --- /dev/null +++ b/bc/load.c @@ -0,0 +1,351 @@ +/* load.c: This code "loads" code into the code segments. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + 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 pc; + bc_function *f; + char *new_body; + + /* If there was an error, don't continue. */ + if (had_error) return; + + /* Calculate the segment and offset. */ + pc = load_adr.pc_addr++; + f = &functions[load_adr.pc_func]; + + if (pc >= f->f_body_size) + { + f->f_body_size *= 2; + new_body = (char *) bc_malloc (f->f_body_size); + memcpy(new_body, f->f_body, f->f_body_size/2); + free (f->f_body); + f->f_body = new_body; + } + + /* Store the byte. */ + f->f_body[pc] = byte; + f->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((int)(**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 = { 0, 0 };; + + /* Initialize. */ + str = code; + + /* Scan the code. */ + while (*str != 0) + { + /* If there was an error, don't continue. */ + if (had_error) return; + + if (load_str) + { + if (*str == '"') load_str = FALSE; + addbyte (*str++); + } + else + if (load_const) + { + if (*str == '\n') + str++; + else + { + if (*str == ':') + { + load_const = FALSE; + addbyte (*str++); + } + else + if (*str == '.') + addbyte (*str++); + else + if (*str >= 'A') + addbyte (*str++ + 10 - 'A'); + else + addbyte (*str++ - '0'); + } + } + else + { + switch (*str) + { + + case '"': /* Starts a string. */ + load_str = TRUE; + break; + + case 'N': /* A label */ + str++; + label_no = long_val (&str); + def_label (label_no); + break; + + case 'B': /* Branch to label. */ + case 'J': /* Jump to label. */ + case 'Z': /* Branch Zero to label. */ + addbyte(*str++); + label_no = long_val (&str); + if (label_no > 65535L) + { /* Better message? */ + fprintf (stderr,"Program too big.\n"); + exit(1); + } + addbyte ( (char) (label_no & 0xFF)); + addbyte ( (char) (label_no >> 8)); + break; + + case 'F': /* A function, get the name and initialize it. */ + str++; + func = long_val (&str); + clear_func (func); +#if DEBUG > 2 + printf ("Loading function number %d\n", func); +#endif + /* get the parameters */ + while (*str++ != '.') + { + if (*str == '.') + { + str++; + break; + } + if (*str == '*') + { + str++; + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("var parameter number %d\n", ap_name); +#endif + functions[(int)func].f_params = + nextarg (functions[(int)func].f_params, ap_name, + TRUE); + } + else + { + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("parameter number %d\n", ap_name); +#endif + functions[(int)func].f_params = + nextarg (functions[(int)func].f_params, ap_name, + FALSE); + } + } + + /* get the auto vars */ + while (*str != '[') + { + if (*str == ',') str++; + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("auto number %d\n", ap_name); +#endif + functions[(int)func].f_autos = + nextarg (functions[(int)func].f_autos, ap_name, FALSE); + } + save_adr = load_adr; + load_adr.pc_func = func; + load_adr.pc_addr = 0; + break; + + case ']': /* A function end */ + functions[load_adr.pc_func].f_defined = TRUE; + load_adr = save_adr; + break; + + case 'C': /* Call a function. */ + addbyte (*str++); + func = long_val (&str); + if (func < 128) + addbyte ( (char) func); + else + { + addbyte (((func >> 8) & 0xff) | 0x80); + addbyte (func & 0xff); + } + if (*str == ',') str++; + while (*str != ':') + addbyte (*str++); + addbyte (':'); + break; + + case 'c': /* Call a special function. */ + addbyte (*str++); + addbyte (*str); + break; + + case 'K': /* A constant.... may have an "F" in it. */ + addbyte (*str); + load_const = TRUE; + break; + + case 'd': /* Decrement. */ + case 'i': /* Increment. */ + case 'l': /* Load. */ + case 's': /* Store. */ + case 'A': /* Array Increment */ + case 'M': /* Array Decrement */ + case 'L': /* Array Load */ + case 'S': /* Array Store */ + addbyte (*str++); + vaf_name = long_val (&str); + if (vaf_name < 128) + addbyte (vaf_name); + else + { + addbyte (((vaf_name >> 8) & 0xff) | 0x80); + addbyte (vaf_name & 0xff); + } + break; + + case '@': /* A command! */ + switch (*(++str)) + { + case 'i': + init_load (); + break; + case 'r': + execute (); + break; + } + break; + + case '\n': /* Ignore the newlines */ + break; + + default: /* Anything else */ + addbyte (*str); + } + str++; + } + } +} diff --git a/bc/main.c b/bc/main.c new file mode 100644 index 0000000..b94525f --- /dev/null +++ b/bc/main.c @@ -0,0 +1,355 @@ +/* main.c: The main program for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 1998, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include +#include "global.h" +#include "proto.h" +#include "getopt.h" + + +/* Variables for processing multiple files. */ +static char first_file; + +/* Points to the last node in the file name list for easy adding. */ +static file_node *last = NULL; + +/* long option support */ +static struct option long_options[] = +{ + {"compile", 0, &compile_only, TRUE}, + {"help", 0, 0, 'h'}, + {"interactive", 0, 0, 'i'}, + {"mathlib", 0, &use_math, TRUE}, + {"quiet", 0, &quiet, TRUE}, + {"standard", 0, &std_only, TRUE}, + {"version", 0, 0, 'v'}, + {"warn", 0, &warn_not_std, TRUE}, + + {0, 0, 0, 0} +}; + + +void +usage (char *progname) +{ + printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, + " -h --help print this usage and exit\n", + " -i --interactive force interactive mode\n", + " -l --mathlib use the predefine math routnes\n", + " -q --quiet don't print initial banner\n", + " -s --standard non-standard bc constructs are errors\n", + " -w --warn warn about non-standard bc constructs\n", + " -v --version print version information and exit\n"); +} + + +void +parse_args (argc, argv) + int argc; + char **argv; +{ + int optch; + int long_index; + file_node *temp; + + /* Force getopt to initialize. Depends on GNU getopt. */ + optind = 0; + + /* Parse the command line */ + while (1) + { + optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index); + + if (optch == EOF) /* End of arguments. */ + break; + + switch (optch) + { + case 0: /* long option */ + break; + + case 'c': /* compile only */ + compile_only = TRUE; + break; + + case 'h': /* help */ + usage(argv[0]); + exit (0); + break; + + case 'i': /* force interactive */ + interactive = TRUE; + break; + + case 'l': /* math lib */ + use_math = TRUE; + break; + + case 'q': /* quiet mode */ + quiet = TRUE; + break; + + case 's': /* Non standard features give errors. */ + std_only = TRUE; + break; + + case 'v': /* Print the version. */ + show_bc_version (); + exit (0); + break; + + case 'w': /* Non standard features give warnings. */ + warn_not_std = TRUE; + break; + + default: + usage(argv[0]); + exit (1); + } + } + + /* Add file names to a list of files to process. */ + while (optind < argc) + { + temp = (file_node *) bc_malloc(sizeof(file_node)); + temp->name = argv[optind]; + temp->next = NULL; + if (last == NULL) + file_names = temp; + else + last->next = temp; + last = temp; + optind++; + } +} + +/* The main program for bc. */ +int +main (argc, argv) + int argc; + char *argv[]; +{ + char *env_value; + char *env_argv[30]; + int env_argc; + + /* Initialize many variables. */ + compile_only = FALSE; + use_math = FALSE; + warn_not_std = FALSE; + std_only = FALSE; + if (isatty(0) && isatty(1)) + interactive = TRUE; + else + interactive = FALSE; + quiet = FALSE; + file_names = NULL; + +#ifdef HAVE_SETVBUF + /* attempt to simplify interaction with applications such as emacs */ + (void) setvbuf(stdout, NULL, _IOLBF, 0); +#endif + + /* Environment arguments. */ + env_value = getenv ("BC_ENV_ARGS"); + if (env_value != NULL) + { + env_argc = 1; + env_argv[0] = "BC_ENV_ARGS"; + while (*env_value != 0) + { + if (*env_value != ' ') + { + env_argv[env_argc++] = env_value; + while (*env_value != ' ' && *env_value != 0) + env_value++; + if (*env_value != 0) + { + *env_value = 0; + env_value++; + } + } + else + env_value++; + } + parse_args (env_argc, env_argv); + } + + /* Command line arguments. */ + parse_args (argc, argv); + + /* Other environment processing. */ + if (getenv ("POSIXLY_CORRECT") != NULL) + std_only = TRUE; + + env_value = getenv ("BC_LINE_LENGTH"); + if (env_value != NULL) + { + line_size = atoi (env_value); + if (line_size < 2) + line_size = 70; + } + else + line_size = 70; + + /* Initialize the machine. */ + init_storage(); + init_load(); + + /* Set up interrupts to print a message. */ + if (interactive) + signal (SIGINT, use_quit); + + /* Initialize the front end. */ + init_tree(); + init_gen (); + is_std_in = FALSE; + first_file = TRUE; + if (!open_new_file ()) + exit (1); + +#if defined(LIBEDIT) + if (interactive) { + /* Enable libedit support. */ + edit = el_init ("bc", stdin, stdout, stderr); + hist = history_init(); + el_set (edit, EL_EDITOR, "emacs"); + el_set (edit, EL_HIST, history, hist); + el_set (edit, EL_PROMPT, null_prompt); + el_source (edit, NULL); + history (hist, &histev, H_SETSIZE, INT_MAX); + } +#endif + +#if defined(READLINE) + if (interactive) { + /* Readline support. Set both application name and input file. */ + rl_readline_name = "bc"; + rl_instream = stdin; + using_history (); + } +#endif + + /* Do the parse. */ + yyparse (); + + /* End the compile only output with a newline. */ + if (compile_only) + printf ("\n"); + + exit (0); +} + + +/* This is the function that opens all the files. + It returns TRUE if the file was opened, otherwise + it returns FALSE. */ + +int +open_new_file () +{ + FILE *new_file; + file_node *temp; + + /* Set the line number. */ + line_no = 1; + + /* Check to see if we are done. */ + if (is_std_in) return (FALSE); + + /* Open the other files. */ + if (use_math && first_file) + { + /* Load the code from a precompiled version of the math libarary. */ + extern char *libmath[]; + char **mstr; + 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); + mstr = libmath; + while (*mstr) { + load_code (*mstr); + mstr++; + } + } + + /* One of the argv values. */ + if (file_names != NULL) + { + new_file = fopen (file_names->name, "r"); + if (new_file != NULL) + { + new_yy_file (new_file); + temp = file_names; + file_name = temp->name; + file_names = temp->next; + free (temp); + return TRUE; + } + fprintf (stderr, "File %s is unavailable.\n", file_names->name); + exit (1); + } + + /* If we fall through to here, we should return stdin. */ + new_yy_file (stdin); + is_std_in = TRUE; + return TRUE; +} + + +/* Set yyin to the new file. */ + +void +new_yy_file (file) + FILE *file; +{ + if (!first_file) fclose (yyin); + yyin = file; + first_file = FALSE; +} + + +/* Message to use quit. */ + +void +use_quit (sig) + int sig; +{ + printf ("\n(interrupt) use quit to exit.\n"); + signal (SIGINT, use_quit); +} diff --git a/bc/proto.h b/bc/proto.h new file mode 100644 index 0000000..1e7311f --- /dev/null +++ b/bc/proto.h @@ -0,0 +1,148 @@ +/* proto.h: Prototype function definitions for "external" functions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +/* For the pc version using k&r ACK. (minix1.5 and earlier.) */ +#ifdef SHORTNAMES +#define init_numbers i_numbers +#define push_constant push__constant +#define load_const in_load_const +#define yy_get_next_buffer yyget_next_buffer +#define yy_init_buffer yyinit_buffer +#define yy_last_accepting_state yylast_accepting_state +#define arglist1 arg1list +#endif + +/* Include the standard library header files. */ +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +/* Define the _PROTOTYPE macro if it is needed. */ + +#ifndef _PROTOTYPE +#ifdef __STDC__ +#define _PROTOTYPE(func, args) func args +#else +#define _PROTOTYPE(func, args) func() +#endif +#endif + +/* From execute.c */ +_PROTOTYPE(void stop_execution, (int)); +_PROTOTYPE(unsigned char byte, (program_counter *pc)); +_PROTOTYPE(void execute, (void)); +_PROTOTYPE(char prog_char, (void)); +_PROTOTYPE(char input_char, (void)); +_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base)); +_PROTOTYPE(void push_b10_const, (program_counter *pc)); +_PROTOTYPE(void assign, (int c_code)); + +/* From util.c */ +_PROTOTYPE(char *strcopyof, (char *str)); +_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val, int is_var)); +_PROTOTYPE(char *arg_str, (arg_list *args)); +_PROTOTYPE(char *call_str, (arg_list *args)); +_PROTOTYPE(void free_args, (arg_list *args)); +_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos)); +_PROTOTYPE(void init_gen, (void)); +_PROTOTYPE(void generate, (char *str)); +_PROTOTYPE(void run_code, (void)); +_PROTOTYPE(void out_char, (int ch)); +_PROTOTYPE(void out_schar, (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 show_bc_version, (void)); +_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 open_new_file, (void)); +_PROTOTYPE(void new_yy_file, (FILE *file)); +_PROTOTYPE(void use_quit, (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)); + +#if defined(LIBEDIT) +/* The *?*&^ prompt function */ +_PROTOTYPE(char *null_prompt, (EditLine *)); +#endif + +/* Other things... */ +#ifndef HAVE_UNISTD_H +_PROTOTYPE (int getopt, (int, char *[], CONST char *)); +#endif diff --git a/bc/sbc.y b/bc/sbc.y new file mode 100644 index 0000000..b1ff1d1 --- /dev/null +++ b/bc/sbc.y @@ -0,0 +1,448 @@ +%{ +/* sbc.y: A POSIX bc processor written for minix with no extensions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" /* To get the global variables. */ +#include "proto.h" +%} + +%start program + +%union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } + +%token ENDOFLINE AND OR NOT +%token STRING NAME NUMBER +/* '-', '+' are tokens themselves */ +%token ASSIGN_OP +/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */ +%token REL_OP +/* '==', '<=', '>=', '!=', '<', '>' */ +%token INCR_DECR +/* '++', '--' */ +%token Define Break Quit Length +/* 'define', 'break', 'quit', 'length' */ +%token Return For If While Sqrt Else +/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */ +%token Scale Ibase Obase Auto Read +/* 'scale', 'ibase', 'obase', 'auto', 'read' */ +%token Warranty, Halt, Last, Continue, Print, Limits +/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */ + +/* The types of all other non-terminals. */ +%type expression named_expression return_expression +%type opt_parameter_list parameter_list opt_auto_define_list +%type define_list opt_argument_list argument_list +%type program input_item semicolon_list statement_list +%type statement_or_error statement function relational_expression + +/* precedence */ +%nonassoc REL_OP +%right ASSIGN_OP +%left '+' '-' +%left '*' '/' '%' +%right '^' +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%% +program : /* empty */ + { + $$ = 0; + std_only = TRUE; + if (interactive) + { + printf ("s%s\n", BC_VERSION); + welcome(); + } + } + | program input_item + ; +input_item : semicolon_list ENDOFLINE + { run_code(); } + | function + { run_code(); } + | error ENDOFLINE + { + yyerrok; + init_gen() ; + } + ; +semicolon_list : /* empty */ + { $$ = 0; } + | statement_or_error + | semicolon_list ';' statement_or_error + | semicolon_list ';' + ; +statement_list : /* empty */ + { $$ = 0; } + | statement + | statement_list ENDOFLINE + | statement_list ENDOFLINE statement + | statement_list ';' + | statement_list ';' statement + ; +statement_or_error : statement + | error statement + { $$ = $2; } + ; +statement : Warranty + { warranty("s"); } + | expression + { + if ($1 & 1) + generate ("W"); + else + generate ("p"); + } + | STRING + { + $$ = 0; + generate ("w"); + generate ($1); + free ($1); + } + | Break + { + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } + | Quit + { exit(0); } + | Return + { generate ("0R"); } + | Return '(' return_expression ')' + { generate ("R"); } + | For + { + $1 = break_label; + break_label = next_label++; + } + '(' expression ';' + { + $4 = next_label++; + sprintf (genstr, "pN%1d:", $4); + generate (genstr); + } + relational_expression ';' + { + $7 = next_label++; + sprintf (genstr, "B%1d:J%1d:", $7, break_label); + generate (genstr); + $$ = next_label++; + sprintf (genstr, "N%1d:", $$); + generate (genstr); + } + expression ')' + { + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } + statement + { + sprintf (genstr, "J%1d:N%1d:", $9, + break_label); + generate (genstr); + break_label = $1; + } + | If '(' relational_expression ')' + { + $3 = next_label++; + sprintf (genstr, "Z%1d:", $3); + generate (genstr); + } + statement + { + sprintf (genstr, "N%1d:", $3); + generate (genstr); + } + | While + { + $1 = next_label++; + sprintf (genstr, "N%1d:", $1); + generate (genstr); + } + '(' relational_expression + { + $4 = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } + ')' statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + break_label = $4; + } + | '{' statement_list '}' + { $$ = 0; } + ; +function : Define NAME '(' opt_parameter_list ')' '{' + ENDOFLINE opt_auto_define_list + { + check_params ($4,$8); + sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT), + arg_str ($4), arg_str ($8)); + generate (genstr); + free_args ($4); + free_args ($8); + $1 = next_label; + next_label = 0; + } + statement_list ENDOFLINE '}' + { + generate ("0R]"); + next_label = $1; + } + ; +opt_parameter_list : /* empty */ + { $$ = NULL; } + | parameter_list + ; +parameter_list : NAME + { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); } + ; +opt_auto_define_list : /* empty */ + { $$ = NULL; } + | Auto define_list ENDOFLINE + { $$ = $2; } + | Auto define_list ';' + { $$ = $2; } + ; +define_list : NAME + { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); } + | NAME '[' ']' + { $$ = nextarg (NULL, lookup($1,ARRAY), FALSE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); } + | define_list ',' NAME '[' ']' + { $$ = nextarg ($1, lookup($3,ARRAY), FALSE); } + ; +opt_argument_list : /* empty */ + { $$ = NULL; } + | argument_list + ; +argument_list : expression + { $$ = nextarg (NULL,0, FALSE); } + | argument_list ',' expression + { $$ = nextarg ($1,0, FALSE); } + ; +relational_expression : expression + { $$ = 0; } + | expression REL_OP expression + { + $$ = 0; + switch (*($2)) + { + case '=': + generate ("="); + break; + case '!': + generate ("#"); + break; + case '<': + if ($2[1] == '=') + generate ("{"); + else + generate ("<"); + break; + case '>': + if ($2[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } + ; +return_expression : /* empty */ + { + $$ = 0; + generate ("0"); + } + | expression + ; +expression : named_expression ASSIGN_OP + { + if ($2 != '=') + { + if ($1 < 0) + sprintf (genstr, "DL%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + } + expression + { + $$ = 0; + if ($2 != '=') + { + sprintf (genstr, "%c", $2); + generate (genstr); + } + if ($1 < 0) + sprintf (genstr, "S%d:", -$1); + else + sprintf (genstr, "s%d:", $1); + generate (genstr); + } + | expression '+' expression + { generate ("+"); } + | expression '-' expression + { generate ("-"); } + | expression '*' expression + { generate ("*"); } + | expression '/' expression + { generate ("/"); } + | expression '%' expression + { generate ("%"); } + | expression '^' expression + { generate ("^"); } + | '-' expression %prec UNARY_MINUS + { generate ("n"); $$ = 1;} + | named_expression + { + $$ = 1; + if ($1 < 0) + sprintf (genstr, "L%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + | NUMBER + { + int len = strlen($1); + $$ = 1; + if (len == 1 && *$1 == '0') + generate ("0"); + else + { + if (len == 1 && *$1 == '1') + generate ("1"); + else + { + generate ("K"); + generate ($1); + generate (":"); + } + free ($1); + } + } + | '(' expression ')' + { $$ = 1; } + | NAME '(' opt_argument_list ')' + { + $$ = 1; + if ($3 != NULL) + { + sprintf (genstr, "C%d,%s:", lookup($1,FUNCT), + arg_str ($3)); + free_args ($3); + } + else + sprintf (genstr, "C%d:", lookup($1,FUNCT)); + generate (genstr); + } + | INCR_DECR named_expression + { + $$ = 1; + if ($2 < 0) + { + if ($1 == '+') + sprintf (genstr, "DA%d:L%d:", -$2, -$2); + else + sprintf (genstr, "DM%d:L%d:", -$2, -$2); + } + else + { + if ($1 == '+') + sprintf (genstr, "i%d:l%d:", $2, $2); + else + sprintf (genstr, "d%d:l%d:", $2, $2); + } + generate (genstr); + } + | named_expression INCR_DECR + { + $$ = 1; + if ($1 < 0) + { + sprintf (genstr, "DL%d:x", -$1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "A%d:", -$1); + else + sprintf (genstr, "M%d:", -$1); + } + else + { + sprintf (genstr, "l%d:", $1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "i%d:", $1); + else + sprintf (genstr, "d%d:", $1); + } + generate (genstr); + } + | Length '(' expression ')' + { generate ("cL"); $$ = 1;} + | Sqrt '(' expression ')' + { generate ("cR"); $$ = 1;} + | Scale '(' expression ')' + { generate ("cS"); $$ = 1;} + ; +named_expression : NAME + { $$ = lookup($1,SIMPLE); } + | NAME '[' expression ']' + { $$ = lookup($1,ARRAY); } + | Ibase + { $$ = 0; } + | Obase + { $$ = 1; } + | Scale + { $$ = 2; } + ; + +%% diff --git a/bc/scan.c b/bc/scan.c new file mode 100644 index 0000000..8d9c92d --- /dev/null +++ b/bc/scan.c @@ -0,0 +1,2259 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* 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 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* 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 yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * 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 yyless() call. + */ + +/* 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_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* 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 char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (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; + +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 )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +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 yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 44 +#define YY_END_OF_BUFFER 45 +static yyconst short int yy_accept[298] = + { 0, + 0, 0, 2, 2, 45, 43, 38, 36, 30, 43, + 1, 31, 43, 27, 31, 27, 27, 26, 31, 42, + 34, 32, 34, 43, 27, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 43, 2, 2, 3, 2, 2, 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, 2, 2, 2, 2, 2, 2, 2, 38, + 34, 0, 41, 32, 28, 35, 42, 0, 39, 42, + 42, 0, 33, 37, 40, 40, 40, 40, 40, 40, + + 40, 40, 40, 40, 10, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 29, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 42, 0, 0, 42, 0, + 40, 40, 40, 40, 40, 9, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + + 2, 2, 2, 2, 2, 2, 16, 40, 40, 40, + 17, 19, 40, 40, 20, 40, 40, 40, 40, 6, + 18, 40, 40, 12, 40, 40, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 40, 40, 40, + 14, 40, 40, 15, 24, 40, 13, 40, 11, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 40, 4, 40, 7, 25, 8, 40, 2, + 2, 2, 2, 2, 2, 2, 40, 21, 40, 2, + 2, 2, 23, 22, 2, 2, 0 + + } ; + +static yyconst int 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, 6, 1, 7, 8, 1, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 1, 18, 19, + 20, 21, 1, 1, 22, 22, 22, 22, 22, 22, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 23, 24, 25, 26, 27, 1, 28, 29, 30, 31, + + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 37, 49, 37, + 50, 37, 51, 52, 53, 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 yyconst int yy_meta[54] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1 + } ; + +static yyconst short int yy_base[302] = + { 0, + 0, 0, 53, 0, 525, 526, 522, 526, 503, 517, + 526, 501, 512, 526, 499, 95, 94, 94, 99, 105, + 498, 114, 497, 513, 495, 466, 468, 470, 479, 471, + 467, 0, 81, 102, 105, 479, 462, 458, 473, 94, + 104, 452, 0, 501, 526, 482, 139, 0, 481, 492, + 0, 479, 131, 132, 131, 125, 132, 478, 150, 477, + 493, 475, 160, 115, 117, 126, 130, 125, 446, 183, + 184, 186, 187, 123, 445, 180, 185, 192, 440, 489, + 526, 485, 526, 526, 526, 526, 158, 486, 526, 162, + 221, 485, 526, 526, 0, 440, 454, 444, 451, 437, + + 437, 442, 434, 451, 0, 432, 436, 436, 447, 438, + 437, 195, 444, 426, 425, 433, 526, 0, 466, 0, + 178, 0, 0, 0, 0, 222, 464, 0, 230, 233, + 463, 0, 417, 65, 189, 208, 193, 205, 213, 220, + 214, 235, 416, 218, 224, 227, 241, 234, 237, 243, + 246, 231, 232, 245, 0, 275, 460, 278, 279, 459, + 419, 432, 412, 422, 425, 0, 409, 408, 408, 406, + 418, 415, 404, 408, 401, 416, 398, 406, 397, 398, + 403, 287, 438, 288, 437, 182, 250, 239, 270, 275, + 391, 266, 268, 271, 273, 274, 288, 279, 285, 281, + + 299, 390, 292, 287, 293, 298, 0, 399, 400, 394, + 0, 0, 392, 401, 0, 385, 384, 398, 382, 0, + 0, 383, 395, 0, 398, 393, 376, 294, 303, 302, + 375, 374, 306, 312, 373, 305, 308, 313, 310, 372, + 371, 314, 317, 370, 335, 332, 0, 376, 384, 370, + 0, 379, 367, 0, 0, 371, 0, 370, 0, 362, + 325, 336, 322, 361, 137, 323, 360, 359, 331, 358, + 333, 357, 356, 0, 353, 0, 0, 0, 355, 349, + 343, 327, 342, 340, 334, 338, 346, 0, 238, 344, + 236, 339, 0, 0, 177, 102, 526, 392, 120, 395, + + 398 + } ; + +static yyconst short int yy_def[302] = + { 0, + 297, 1, 297, 3, 297, 297, 297, 297, 297, 298, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 297, 300, 300, 297, 300, 301, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 300, 297, + 297, 298, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 299, 299, 299, 299, 299, 299, + + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 297, 300, 300, 300, + 301, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 300, 297, 297, 297, 297, 297, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 300, 300, 300, 300, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 63, 63, 63, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 299, 299, 299, 299, 299, 299, 299, 63, + 63, 63, 63, 63, 63, 63, 299, 299, 299, 63, + 63, 63, 299, 299, 63, 63, 0, 297, 297, 297, + + 297 + } ; + +static yyconst short int yy_nxt[580] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 15, 16, 14, 17, 18, 19, 20, 14, 21, 22, + 23, 20, 14, 24, 14, 25, 6, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 32, 32, 35, 32, + 32, 36, 37, 38, 39, 40, 32, 32, 41, 32, + 14, 42, 14, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 51, 52, 53, 51, 54, 55, 56, 57, + 51, 58, 59, 60, 57, 51, 61, 51, 62, 43, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 69, + 69, 72, 69, 69, 73, 74, 75, 76, 77, 69, + + 69, 78, 69, 51, 79, 51, 86, 86, 102, 89, + 87, 186, 133, 84, 84, 87, 103, 88, 84, 90, + 93, 91, 95, 113, 93, 93, 91, 93, 92, 93, + 104, 115, 106, 81, 105, 128, 107, 114, 116, 93, + 108, 82, 125, 122, 123, 125, 129, 126, 130, 133, + 123, 123, 126, 130, 127, 131, 132, 137, 136, 135, + 132, 132, 133, 132, 133, 132, 139, 148, 138, 120, + 133, 283, 133, 133, 156, 132, 133, 133, 159, 156, + 82, 157, 122, 159, 133, 160, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + + 133, 133, 133, 133, 133, 133, 133, 134, 133, 133, + 140, 150, 142, 144, 151, 147, 143, 145, 141, 153, + 187, 146, 176, 227, 133, 189, 154, 133, 152, 133, + 133, 133, 133, 133, 133, 90, 133, 91, 182, 133, + 133, 177, 91, 182, 92, 183, 184, 129, 188, 130, + 190, 184, 133, 185, 130, 133, 131, 191, 192, 193, + 133, 133, 194, 195, 196, 133, 197, 133, 198, 199, + 201, 133, 200, 203, 133, 204, 205, 228, 133, 133, + 206, 133, 133, 133, 133, 229, 133, 294, 133, 202, + 133, 156, 133, 133, 87, 159, 156, 133, 157, 87, + + 159, 88, 160, 182, 184, 230, 231, 236, 182, 184, + 183, 185, 232, 133, 233, 133, 234, 133, 133, 235, + 133, 133, 133, 237, 238, 239, 133, 240, 133, 241, + 243, 260, 133, 244, 133, 133, 246, 245, 261, 133, + 133, 133, 262, 264, 267, 133, 133, 263, 270, 133, + 133, 265, 133, 133, 266, 133, 268, 133, 269, 133, + 133, 133, 271, 272, 133, 280, 282, 281, 284, 133, + 133, 285, 133, 286, 133, 295, 291, 293, 133, 133, + 133, 133, 133, 133, 292, 133, 133, 133, 296, 133, + 133, 133, 82, 82, 82, 118, 290, 118, 121, 121, + + 121, 289, 288, 287, 133, 133, 133, 133, 133, 133, + 279, 278, 277, 276, 275, 274, 273, 133, 133, 133, + 133, 133, 133, 133, 259, 258, 257, 256, 255, 254, + 253, 252, 251, 250, 249, 248, 247, 242, 133, 159, + 156, 226, 225, 224, 223, 222, 221, 220, 219, 218, + 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, + 207, 159, 156, 133, 133, 91, 158, 119, 181, 180, + 179, 178, 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 91, 158, 83, + 80, 155, 149, 133, 123, 94, 120, 120, 123, 124, + + 123, 120, 119, 117, 112, 111, 110, 109, 101, 100, + 99, 98, 97, 96, 84, 94, 81, 81, 84, 85, + 84, 83, 81, 80, 297, 5, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297 + } ; + +static yyconst short int yy_chk[580] = + { 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, 1, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 16, 17, 33, 19, + 18, 134, 134, 17, 16, 18, 33, 18, 19, 20, + 22, 20, 299, 40, 22, 22, 20, 22, 20, 22, + 34, 41, 35, 22, 34, 56, 35, 40, 41, 22, + 35, 47, 53, 47, 56, 54, 57, 55, 57, 296, + 53, 54, 55, 57, 55, 57, 59, 66, 65, 64, + 59, 59, 64, 59, 65, 59, 68, 74, 67, 59, + 74, 265, 68, 66, 87, 59, 63, 67, 90, 87, + 121, 87, 121, 90, 265, 90, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 70, 76, 71, 72, 77, 73, 71, 72, 70, 78, + 135, 72, 112, 186, 295, 137, 78, 76, 77, 186, + 70, 71, 77, 72, 73, 91, 135, 91, 126, 78, + 137, 112, 91, 126, 91, 126, 129, 130, 136, 130, + 138, 129, 138, 129, 130, 136, 130, 139, 140, 141, + 139, 141, 142, 144, 145, 144, 146, 140, 147, 148, + 150, 145, 149, 151, 146, 152, 153, 187, 152, 153, + 154, 148, 142, 291, 149, 188, 188, 289, 147, 150, + 150, 156, 154, 151, 158, 159, 156, 187, 156, 158, + + 159, 158, 159, 182, 184, 189, 190, 196, 182, 184, + 182, 184, 192, 192, 193, 193, 194, 189, 194, 195, + 195, 196, 190, 197, 198, 199, 198, 200, 200, 201, + 203, 228, 199, 204, 204, 197, 206, 205, 229, 203, + 205, 228, 230, 234, 238, 206, 201, 233, 243, 230, + 229, 236, 236, 233, 237, 237, 239, 239, 242, 234, + 238, 242, 245, 246, 243, 261, 263, 262, 266, 263, + 266, 269, 261, 271, 282, 290, 282, 287, 269, 246, + 271, 285, 245, 262, 286, 286, 292, 284, 292, 283, + 281, 290, 298, 298, 298, 300, 280, 300, 301, 301, + + 301, 279, 275, 273, 272, 270, 268, 267, 264, 260, + 258, 256, 253, 252, 250, 249, 248, 244, 241, 240, + 235, 232, 231, 227, 226, 225, 223, 222, 219, 218, + 217, 216, 214, 213, 210, 209, 208, 202, 191, 185, + 183, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 172, 171, 170, 169, 168, 167, 165, 164, 163, 162, + 161, 160, 157, 143, 133, 131, 127, 119, 116, 115, + 114, 113, 111, 110, 109, 108, 107, 106, 104, 103, + 102, 101, 100, 99, 98, 97, 96, 92, 88, 82, + 80, 79, 75, 69, 62, 61, 60, 58, 52, 50, + + 49, 46, 44, 42, 39, 38, 37, 36, 31, 30, + 29, 28, 27, 26, 25, 24, 23, 21, 15, 13, + 12, 10, 9, 7, 5, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297 + } ; + +static yy_state_type yy_last_accepting_state; +static 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 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#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 GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "bc.h" +#include "global.h" +#include "proto.h" +#include + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* Force . as last for now. */ +#define DOT_IS_LAST + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +#if defined(LIBEDIT) +/* Support for the BSD libedit with history for + nicer input on the interactive part of input. */ + +#include + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + bcel_input((char *)buf, &result, max_size) + +/* Variables to help interface editline with bc. */ +static const char *bcel_line = (char *)NULL; +static int bcel_len = 0; + + +/* Required to get rid of that ugly ? default prompt! */ +char * +null_prompt (EditLine *el) +{ + return ""; +} + + +/* bcel_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + stdin, use editline. Otherwise, just read it. +*/ + +static void +bcel_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (!edit || yyin != stdin) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (bcel_len == 0) + { + bcel_line = el_gets(edit, &bcel_len); + if (bcel_line == NULL) { + /* end of file */ + *result = 0; + bcel_len = 0; + return; + } + if (bcel_len != 0) + history (hist, &histev, H_ENTER, bcel_line); + fflush (stdout); + } + + if (bcel_len <= max) + { + strncpy (buf, bcel_line, bcel_len); + *result = bcel_len; + bcel_len = 0; + } + else + { + strncpy (buf, bcel_line, max); + *result = max; + bcel_line += max; + bcel_len -= max; + } +} +#endif + +#ifdef READLINE +/* Support for the readline and history libraries. This allows + nicer input on the interactive part of input. */ + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + rl_input((char *)buf, &result, max_size) + +/* Variables to help interface readline with bc. */ +static char *rl_line = (char *)NULL; +static char *rl_start = (char *)NULL; +static int rl_len = 0; + +/* Definitions for readline access. */ +extern FILE *rl_instream; +_PROTOTYPE(char *readline, (char *)); + +/* rl_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + rl_instream (stdin), use readline. Otherwise, just read it. +*/ + +static void +rl_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (yyin != rl_instream) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (rl_len == 0) + { + if (rl_start) + free(rl_start); + rl_start = readline (""); + if (rl_start == NULL) { + /* end of file */ + *result = 0; + rl_len = 0; + return; + } + rl_line = rl_start; + rl_len = strlen (rl_line)+1; + if (rl_len != 1) + add_history (rl_line); + rl_line[rl_len-1] = '\n'; + fflush (stdout); + } + + if (rl_len <= max) + { + strncpy (buf, rl_line, rl_len); + *result = rl_len; + rl_len = 0; + } + else + { + strncpy (buf, rl_line, max); + *result = max; + rl_line += max; + rl_len -= max; + } +} +#endif + +#if !defined(READLINE) && !defined(LIBEDIT) + +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#endif + +#define slcomment 1 + +#line 809 "lex.yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* 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. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 222 "scan.l" + +#line 962 "lex.yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + 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_SC_TO_UI(*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 = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 526 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* 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: +YY_RULE_SETUP +#line 223 "scan.l" +{ + if (!std_only) + BEGIN(slcomment); + else + yyerror ("illegal character: #"); + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 229 "scan.l" +{ BEGIN(INITIAL); } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 230 "scan.l" +{ line_no++; BEGIN(INITIAL); return(ENDOFLINE); } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 231 "scan.l" +return(Define); + YY_BREAK +case 5: +YY_RULE_SETUP +#line 232 "scan.l" +return(Break); + YY_BREAK +case 6: +YY_RULE_SETUP +#line 233 "scan.l" +return(Quit); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 234 "scan.l" +return(Length); + YY_BREAK +case 8: +YY_RULE_SETUP +#line 235 "scan.l" +return(Return); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 236 "scan.l" +return(For); + YY_BREAK +case 10: +YY_RULE_SETUP +#line 237 "scan.l" +return(If); + YY_BREAK +case 11: +YY_RULE_SETUP +#line 238 "scan.l" +return(While); + YY_BREAK +case 12: +YY_RULE_SETUP +#line 239 "scan.l" +return(Sqrt); + YY_BREAK +case 13: +YY_RULE_SETUP +#line 240 "scan.l" +return(Scale); + YY_BREAK +case 14: +YY_RULE_SETUP +#line 241 "scan.l" +return(Ibase); + YY_BREAK +case 15: +YY_RULE_SETUP +#line 242 "scan.l" +return(Obase); + YY_BREAK +case 16: +YY_RULE_SETUP +#line 243 "scan.l" +return(Auto); + YY_BREAK +case 17: +YY_RULE_SETUP +#line 244 "scan.l" +return(Else); + YY_BREAK +case 18: +YY_RULE_SETUP +#line 245 "scan.l" +return(Read); + YY_BREAK +case 19: +YY_RULE_SETUP +#line 246 "scan.l" +return(Halt); + YY_BREAK +case 20: +YY_RULE_SETUP +#line 247 "scan.l" +return(Last); + YY_BREAK +case 21: +YY_RULE_SETUP +#line 248 "scan.l" +{ +#if defined(READLINE) || defined(LIBEDIT) + return(HistoryVar); +#else + yylval.s_value = strcopyof(yytext); return(NAME); +#endif + } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 256 "scan.l" +return(Warranty); + YY_BREAK +case 23: +YY_RULE_SETUP +#line 257 "scan.l" +return(Continue); + YY_BREAK +case 24: +YY_RULE_SETUP +#line 258 "scan.l" +return(Print); + YY_BREAK +case 25: +YY_RULE_SETUP +#line 259 "scan.l" +return(Limits); + YY_BREAK +case 26: +YY_RULE_SETUP +#line 260 "scan.l" +{ +#ifdef DOT_IS_LAST + return(Last); +#else + yyerror ("illegal character: %s",yytext); +#endif + } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 267 "scan.l" +{ yylval.c_value = yytext[0]; + return((int)yytext[0]); } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 269 "scan.l" +{ return(AND); } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 270 "scan.l" +{ return(OR); } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 271 "scan.l" +{ return(NOT); } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 272 "scan.l" +{ yylval.c_value = yytext[0]; return((int)yytext[0]); } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 273 "scan.l" +{ yylval.c_value = yytext[0]; return(ASSIGN_OP); } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 274 "scan.l" +{ +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned ="); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 288 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(REL_OP); } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 289 "scan.l" +{ yylval.c_value = yytext[0]; return(INCR_DECR); } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 290 "scan.l" +{ line_no++; return(ENDOFLINE); } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 291 "scan.l" +{ line_no++; /* ignore a "quoted" newline */ } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 292 "scan.l" +{ /* ignore spaces and tabs */ } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 293 "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 40: +YY_RULE_SETUP +#line 314 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(NAME); } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 315 "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 42: +YY_RULE_SETUP +#line 327 "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 43: +YY_RULE_SETUP +#line 354 "scan.l" +{ + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%03o", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 363 "scan.l" +ECHO; + YY_BREAK +#line 1361 "lex.yy.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(slcomment): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* 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 input(). + */ + 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_ptr + 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_ptr + 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 + { + yy_cp = yy_c_buf_p; + 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_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + 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_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + 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_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new 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 char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + 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" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_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_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*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 = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) 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( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register 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 = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 297); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register 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 */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + 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" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = 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 */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + 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 + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + 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_ptr = 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) yy_flex_alloc( 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 = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + 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 ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#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 + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* 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[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 363 "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/bc/scan.l b/bc/scan.l new file mode 100644 index 0000000..38aa2f0 --- /dev/null +++ b/bc/scan.l @@ -0,0 +1,374 @@ +%{ +/* scan.l: the (f)lex description file for the scanner. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "bc.h" +#include "global.h" +#include "proto.h" +#include + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* Force . as last for now. */ +#define DOT_IS_LAST + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +#if defined(LIBEDIT) +/* Support for the BSD libedit with history for + nicer input on the interactive part of input. */ + +#include + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + bcel_input((char *)buf, &result, max_size) + +/* Variables to help interface editline with bc. */ +static const char *bcel_line = (char *)NULL; +static int bcel_len = 0; + + +/* Required to get rid of that ugly ? default prompt! */ +char * +null_prompt (EditLine *el) +{ + return ""; +} + + +/* bcel_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + stdin, use editline. Otherwise, just read it. +*/ + +static void +bcel_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (!edit || yyin != stdin) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (bcel_len == 0) + { + bcel_line = el_gets(edit, &bcel_len); + if (bcel_line == NULL) { + /* end of file */ + *result = 0; + bcel_len = 0; + return; + } + if (bcel_len != 0) + history (hist, &histev, H_ENTER, bcel_line); + fflush (stdout); + } + + if (bcel_len <= max) + { + strncpy (buf, bcel_line, bcel_len); + *result = bcel_len; + bcel_len = 0; + } + else + { + strncpy (buf, bcel_line, max); + *result = max; + bcel_line += max; + bcel_len -= max; + } +} +#endif + +#ifdef READLINE +/* Support for the readline and history libraries. This allows + nicer input on the interactive part of input. */ + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + rl_input((char *)buf, &result, max_size) + +/* Variables to help interface readline with bc. */ +static char *rl_line = (char *)NULL; +static char *rl_start = (char *)NULL; +static int rl_len = 0; + +/* Definitions for readline access. */ +extern FILE *rl_instream; +/* _PROTOTYPE(char *readline, (char *)); */ + +/* rl_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + rl_instream (stdin), use readline. Otherwise, just read it. +*/ + +static void +rl_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (yyin != rl_instream) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (rl_len == 0) + { + if (rl_start) + free(rl_start); + rl_start = readline (""); + if (rl_start == NULL) { + /* end of file */ + *result = 0; + rl_len = 0; + return; + } + rl_line = rl_start; + rl_len = strlen (rl_line)+1; + if (rl_len != 1) + add_history (rl_line); + rl_line[rl_len-1] = '\n'; + fflush (stdout); + } + + if (rl_len <= max) + { + strncpy (buf, rl_line, rl_len); + *result = rl_len; + rl_len = 0; + } + else + { + strncpy (buf, rl_line, max); + *result = max; + rl_line += max; + rl_len -= max; + } +} +#endif + +#if !defined(READLINE) && !defined(LIBEDIT) + +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#endif + +%} +DIGIT [0-9A-F] +LETTER [a-z] +%s slcomment +%% +"#" { + if (!std_only) + BEGIN(slcomment); + else + yyerror ("illegal character: #"); + } +[^\n]* { BEGIN(INITIAL); } +"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); } +define return(Define); +break return(Break); +quit return(Quit); +length return(Length); +return return(Return); +for return(For); +if return(If); +while return(While); +sqrt return(Sqrt); +scale return(Scale); +ibase return(Ibase); +obase return(Obase); +auto return(Auto); +else return(Else); +read return(Read); +halt return(Halt); +last return(Last); +history { +#if defined(READLINE) || defined(LIBEDIT) + return(HistoryVar); +#else + yylval.s_value = strcopyof(yytext); return(NAME); +#endif + } + +warranty return(Warranty); +continue return(Continue); +print return(Print); +limits return(Limits); +"." { +#ifdef DOT_IS_LAST + return(Last); +#else + yyerror ("illegal character: %s",yytext); +#endif + } +"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; + return((int)yytext[0]); } +&& { return(AND); } +\|\| { return(OR); } +"!" { return(NOT); } +"*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); } +"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); } +=\+|=-|=\*|=\/|=%|=\^ { +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned ="); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } +==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); } +\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); } +"\n" { line_no++; return(ENDOFLINE); } +\\\n { line_no++; /* ignore a "quoted" newline */ } +[ \t]+ { /* ignore spaces and tabs */ } +"/*" { + int c; + + for (;;) + { + while ( ((c=input()) != '*') && (c != EOF)) + /* eat it */ + if (c == '\n') line_no++; + if (c == '*') + { + while ( (c=input()) == '*') /* eat it*/; + if (c == '/') break; /* at end of comment */ + if (c == '\n') line_no++; + } + if (c == EOF) + { + fprintf (stderr,"EOF encountered in a comment.\n"); + break; + } + } + } +[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); } +\"[^\"]*\" { + unsigned char *look; + int count = 0; + yylval.s_value = strcopyof(yytext); + for (look = yytext; *look != 0; look++) + { + if (*look == '\n') line_no++; + if (*look == '"') count++; + } + if (count != 2) yyerror ("NUL character in string."); + return(STRING); + } +{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* { + unsigned char *src, *dst; + int len; + /* remove a trailing decimal point. */ + len = strlen(yytext); + if (yytext[len-1] == '.') + yytext[len-1] = 0; + /* remove leading zeros. */ + src = yytext; + dst = yytext; + while (*src == '0') src++; + if (*src == 0) src--; + /* Copy strings removing the newlines. */ + while (*src != 0) + { + if (*src == '\\') + { + src++; src++; + line_no++; + } + else + *dst++ = *src++; + } + *dst = 0; + yylval.s_value = strcopyof(yytext); + return(NUMBER); + } +. { + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%03o", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } +%% + + + +/* This is the way to get multiple files input into lex. */ + +int +yywrap() +{ + if (!open_new_file ()) return (1); /* EOF on standard in. */ + return (0); /* We have more input. */ +} diff --git a/bc/storage.c b/bc/storage.c new file mode 100644 index 0000000..10ebf5c --- /dev/null +++ b/bc/storage.c @@ -0,0 +1,1067 @@ +/* storage.c: Code and data storage manipulations. This includes labels. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + 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; +#if defined(READLINE) || defined(LIBEDIT) + n_history = -1; +#endif + c_code = FALSE; + bc_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 indx; + 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 (indx = 0; indx < old_count; indx++) + { + functions[indx] = old_f[indx]; + f_names[indx] = old_names[indx]; + } + + /* Initialize the new ones. */ + for (; indx < f_count; indx++) + { + f = &functions[indx]; + f->f_defined = FALSE; + f->f_body = (char *) bc_malloc (BC_START_SIZE); + f->f_body_size = BC_START_SIZE; + 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) + int func; +{ + bc_function *f; + bc_label_group *lg; + + /* Set the pointer to the function. */ + f = &functions[func]; + f->f_defined = FALSE; + /* XXX restore f_body to initial size??? */ + 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); + } + else + { + retval = 0; + rt_error ("function stack underflow, contact maintainer."); + } + 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; + bc_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 = bc_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)); + bc_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] = bc_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] = bc_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 > 3) + { + /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + { + bc_free_num(&var_ptr->v_value); + var_ptr->v_value = bc_copy_num (ex_stack->s_num); + } + } + else + { + /* It is a special variable... */ + toobig = FALSE; + temp = 0; + if (bc_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; +#if defined(READLINE) || defined(LIBEDIT) + case 3: + temp = -1; + break; +#endif + } + } + else + { + temp = bc_num2long (ex_stack->s_num); + if (!bc_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; + break; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: + if (toobig) + { + temp = -1; + rt_warn ("history too large, set to unlimited"); + UNLIMIT_HISTORY; + } + else + { + n_history = temp; + if (temp < 0) + UNLIMIT_HISTORY; + else + HISTORY_SIZE(n_history); + } +#endif + } + } +} + + +/* 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 = bc_num2long (ex_stack->s_next->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_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) + { + bc_free_num (num_ptr); + *num_ptr = bc_copy_num (ex_stack->s_num); + bc_free_num (&ex_stack->s_next->s_num); + ex_stack->s_next->s_num = ex_stack->s_num; + bc_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_); + bc_int2num (&ex_stack->s_num, i_base); + break; + + case 1: + /* Special variable obase. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, o_base); + break; + + case 2: + /* Special variable scale. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, scale); + break; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: + /* Special variable history. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, n_history); + break; +#endif + + 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 = bc_num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_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; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: /* history */ + n_history--; + if (n_history >= 0) + HISTORY_SIZE(n_history); + else + { + n_history = -1; + rt_warn ("history is negative, set to unlimited"); + UNLIMIT_HISTORY; + } +#endif + + 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, 0); + } +} + + +/* 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) + int var_name; +{ + bc_num *num_ptr; + long index; + + /* It is an array variable. */ + if (!check_stack (1)) return; + index = bc_num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_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, 0); + } + } +} + + +/* 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; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: /* history */ + n_history++; + if (n_history > 0) + HISTORY_SIZE(n_history); + else + { + n_history = -1; + rt_warn ("history set to unlimited"); + UNLIMIT_HISTORY; + } +#endif + + 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, 0); + + } +} + + +/* 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 = bc_num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_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, 0); + } + } +} + + +/* 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]; + bc_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++) + bc_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; + bc_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; + } +} + +/* COPY_NODE: Copies an array node for a call by value parameter. */ +bc_array_node * +copy_tree (ary_node, depth) + bc_array_node *ary_node; + int depth; +{ + bc_array_node *res = (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + int i; + + if (depth > 1) + for (i=0; in_items.n_down[i] != NULL) + res->n_items.n_down[i] = + copy_tree (ary_node->n_items.n_down[i], depth - 1); + else + res->n_items.n_down[i] = NULL; + else + for (i=0; in_items.n_num[i] != NULL) + res->n_items.n_num[i] = bc_copy_num (ary_node->n_items.n_num[i]); + else + res->n_items.n_num[i] = NULL; + return res; +} + +/* COPY_ARRAY: Copies an array for a call by value array parameter. + ARY is the pointer to the bc_array structure. */ + +bc_array * +copy_array (ary) + bc_array *ary; +{ + bc_array *res = (bc_array *) bc_malloc (sizeof(bc_array)); + res->a_depth = ary->a_depth; + res->a_tree = copy_tree (ary->a_tree, ary->a_depth); + return (res); +} + + +/* 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; + 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; + bc_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) bc_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]; + if (params->arg_is_var) + { + a_dest->a_param = TRUE; + a_dest->a_value = a_src->a_value; + } + else + { + a_dest->a_param = FALSE; + a_dest->a_value = copy_array (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 + { + rt_error ("Parameter number mismatch"); + return; + } + params = params->next; + } + if (params != NULL) + rt_error ("Parameter number mismatch"); +} diff --git a/bc/util.c b/bc/util.c new file mode 100644 index 0000000..48bcbe0 --- /dev/null +++ b/bc/util.c @@ -0,0 +1,873 @@ +/* util.c: Utility routines for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +#include "bcdefs.h" +#ifndef VARARGS +#include +#else +#include +#endif +#include "global.h" +#include "proto.h" + + +/* strcopyof mallocs new memory and copies a string to to the new + memory. */ + +char * +strcopyof (str) + char *str; +{ + char *temp; + + temp = (char *) bc_malloc (strlen (str)+1); + return (strcpy (temp,str)); +} + + +/* nextarg adds another value to the list of arguments. */ + +arg_list * +nextarg (args, val, is_var) + arg_list *args; + int val; + int is_var; +{ arg_list *temp; + + temp = (arg_list *) bc_malloc (sizeof (arg_list)); + temp->av_name = val; + temp->arg_is_var = is_var; + temp->next = args; + + return (temp); +} + + +/* For generate, we must produce a string in the form + "val,val,...,val". We also need a couple of static variables + for retaining old generated strings. It also uses a recursive + function that builds the string. */ + +static char *arglist1 = NULL, *arglist2 = NULL; + + +/* make_arg_str does the actual construction of the argument string. + ARGS is the pointer to the list and LEN is the maximum number of + characters needed. 1 char is the minimum needed. + */ + +_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len)); + +static char * +make_arg_str (args, len) + arg_list *args; + int len; +{ + char *temp; + char sval[20]; + + /* Recursive call. */ + if (args != NULL) + temp = make_arg_str (args->next, len+12); + else + { + temp = (char *) bc_malloc (len); + *temp = 0; + return temp; + } + + /* Add the current number to the end of the string. */ + if (args->arg_is_var) + if (len != 1) + sprintf (sval, "*%d,", args->av_name); + else + sprintf (sval, "*%d", args->av_name); + else + if (len != 1) + sprintf (sval, "%d,", args->av_name); + else + sprintf (sval, "%d", args->av_name); + temp = strcat (temp, sval); + return (temp); +} + +char * +arg_str (args) + arg_list *args; +{ + if (arglist2 != NULL) + free (arglist2); + arglist2 = arglist1; + arglist1 = make_arg_str (args, 1); + return (arglist1); +} + +char * +call_str (args) + arg_list *args; +{ + arg_list *temp; + int arg_count; + int ix; + + if (arglist2 != NULL) + free (arglist2); + arglist2 = arglist1; + + /* Count the number of args and add the 0's and 1's. */ + for (temp = args, arg_count = 0; temp != NULL; temp = temp->next) + arg_count++; + arglist1 = (char *) bc_malloc(arg_count+1); + for (temp = args, ix=0; temp != NULL; temp = temp->next) + arglist1[ix++] = ( temp->av_name ? '1' : '0'); + arglist1[ix] = 0; + + return (arglist1); +} + +/* free_args frees an argument list ARGS. */ + +void +free_args (args) + arg_list *args; +{ + arg_list *temp; + + temp = args; + while (temp != NULL) + { + args = args->next; + free (temp); + temp = args; + } +} + + +/* Check for valid parameter (PARAMS) and auto (AUTOS) lists. + There must be no duplicates any where. Also, this is where + warnings are generated for array parameters. */ + +void +check_params ( params, autos ) + arg_list *params, *autos; +{ + arg_list *tmp1, *tmp2; + + /* Check for duplicate parameters. */ + if (params != NULL) + { + tmp1 = params; + while (tmp1 != NULL) + { + tmp2 = tmp1->next; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("duplicate parameter names"); + tmp2 = tmp2->next; + } + if (tmp1->arg_is_var) + warn ("Variable array parameter"); + tmp1 = tmp1->next; + } + } + + /* Check for duplicate autos. */ + if (autos != NULL) + { + tmp1 = autos; + while (tmp1 != NULL) + { + tmp2 = tmp1->next; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("duplicate auto variable names"); + tmp2 = tmp2->next; + } + if (tmp1->arg_is_var) + yyerror ("* not allowed here"); + tmp1 = tmp1->next; + } + } + + /* Check for duplicate between parameters and autos. */ + if ((params != NULL) && (autos != NULL)) + { + tmp1 = params; + while (tmp1 != NULL) + { + tmp2 = autos; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("variable in both parameter and auto lists"); + tmp2 = tmp2->next; + } + tmp1 = tmp1->next; + } + } +} + + +/* Initialize the code generator the parser. */ + +void +init_gen () +{ + /* Get things ready. */ + break_label = 0; + continue_label = 0; + next_label = 1; + out_count = 2; + if (compile_only) + printf ("@i"); + else + init_load (); + had_error = FALSE; + did_gen = FALSE; +} + + +/* generate code STR for the machine. */ + +void +generate (str) + char *str; +{ + did_gen = TRUE; + if (compile_only) + { + printf ("%s",str); + out_count += strlen(str); + if (out_count > 60) + { + printf ("\n"); + out_count = 0; + } + } + else + load_code (str); +} + + +/* Execute the current code as loaded. */ + +void +run_code() +{ + /* If no compile errors run the current code. */ + if (!had_error && did_gen) + { + if (compile_only) + { + printf ("@r\n"); + out_count = 0; + } + else + execute (); + } + + /* Reinitialize the code generation and machine. */ + if (did_gen) + init_gen(); + else + had_error = FALSE; +} + + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\". Always used for numbers. */ + +void +out_char (ch) + int ch; +{ + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + out_col++; + if (out_col == line_size-1) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + putchar (ch); + } +} + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\". This one is for strings. + In POSIX bc, strings are not broken across lines. */ + +void +out_schar (ch) + int ch; +{ + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + if (!std_only) + { + out_col++; + if (out_col == line_size-1) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + } + putchar (ch); + } +} + + +/* The following are "Symbol Table" routines for the parser. */ + +/* find_id returns a pointer to node in TREE that has the correct + ID. If there is no node in TREE with ID, NULL is returned. */ + +id_rec * +find_id (tree, id) + id_rec *tree; + char *id; +{ + int cmp_result; + + /* Check for an empty tree. */ + if (tree == NULL) + return NULL; + + /* Recursively search the tree. */ + cmp_result = strcmp (id, tree->id); + if (cmp_result == 0) + return tree; /* This is the item. */ + else if (cmp_result < 0) + return find_id (tree->left, id); + else + return find_id (tree->right, id); +} + + +/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is + provided. insert_id_rec returns TRUE if the tree height from + ROOT down is increased otherwise it returns FALSE. This is a + recursive balanced binary tree insertion algorithm. */ + +int insert_id_rec (root, new_id) + id_rec **root; + id_rec *new_id; +{ + id_rec *A, *B; + + /* If root is NULL, this where it is to be inserted. */ + if (*root == NULL) + { + *root = new_id; + new_id->left = NULL; + new_id->right = NULL; + new_id->balance = 0; + return (TRUE); + } + + /* We need to search for a leaf. */ + if (strcmp (new_id->id, (*root)->id) < 0) + { + /* Insert it on the left. */ + if (insert_id_rec (&((*root)->left), new_id)) + { + /* The height increased. */ + (*root)->balance --; + + switch ((*root)->balance) + { + case 0: /* no height increase. */ + return (FALSE); + case -1: /* height increase. */ + return (TRUE); + 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 (TRUE); + case 2: /* we need to do a rebalancing act. */ + A = *root; + B = (*root)->right; + if (B->balance >= 0) + { + /* Single Rotate. */ + A->right = B->left; + B->left = A; + *root = B; + A->balance = 0; + B->balance = 0; + } + else + { + /* Double Rotate. */ + *root = B->left; + B->left = (*root)->right; + A->right = (*root)->left; + (*root)->left = A; + (*root)->right = B; + switch ((*root)->balance) + { + case -1: + A->balance = 0; + B->balance = 1; + break; + case 0: + A->balance = 0; + B->balance = 0; + break; + case 1: + A->balance = -1; + B->balance = 0; + break; + } + (*root)->balance = 0; + } + } + } + } + + /* If we fall through to here, the tree did not grow in height. */ + return (FALSE); +} + + +/* Initialize variables for the symbol table tree. */ + +void +init_tree() +{ + name_tree = NULL; + next_array = 1; + next_func = 1; + /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */ + next_var = 5; +} + + +/* Lookup routines for symbol table names. */ + +int +lookup (name, namekind) + char *name; + int namekind; +{ + id_rec *id; + + /* Warn about non-standard name. */ + if (strlen(name) != 1) + warn ("multiple letter name - %s", name); + + /* Look for the id. */ + id = find_id (name_tree, name); + if (id == NULL) + { + /* We need to make a new item. */ + id = (id_rec *) bc_malloc (sizeof (id_rec)); + id->id = strcopyof (name); + id->a_name = 0; + id->f_name = 0; + id->v_name = 0; + insert_id_rec (&name_tree, id); + } + + /* Return the correct value. */ + switch (namekind) + { + + case ARRAY: + /* ARRAY variable numbers are returned as negative numbers. */ + if (id->a_name != 0) + { + free (name); + return (-id->a_name); + } + id->a_name = next_array++; + a_names[id->a_name] = name; + if (id->a_name < MAX_STORE) + { + if (id->a_name >= a_count) + more_arrays (); + return (-id->a_name); + } + yyerror ("Too many array variables"); + exit (1); + + case FUNCT: + case FUNCTDEF: + if (id->f_name != 0) + { + free(name); + /* Check to see if we are redefining a math lib function. */ + if (use_math && namekind == FUNCTDEF && id->f_name <= 6) + id->f_name = next_func++; + return (id->f_name); + } + id->f_name = next_func++; + f_names[id->f_name] = name; + if (id->f_name < MAX_STORE) + { + if (id->f_name >= f_count) + more_functions (); + return (id->f_name); + } + yyerror ("Too many functions"); + exit (1); + + case SIMPLE: + if (id->v_name != 0) + { + free(name); + return (id->v_name); + } + id->v_name = next_var++; + v_names[id->v_name - 1] = name; + if (id->v_name <= MAX_STORE) + { + if (id->v_name >= v_count) + more_variables (); + return (id->v_name); + } + yyerror ("Too many variables"); + exit (1); + } + + yyerror ("End of util.c/lookup() reached. Please report this bug."); + exit (1); + /* not reached */ +} + + +/* 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 version information. */ +void +show_bc_version() +{ + printf("%s %s\n%s\n", PACKAGE, VERSION, BC_COPYRIGHT); +} + + +/* Print out the warranty information. */ + +void +warranty(prefix) + char *prefix; +{ + printf ("\n%s", prefix); + show_bc_version (); + printf ("\n" +" 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\n\n" +" The Free Software Foundation, Inc.\n" +" 59 Temple Place, Suite 330\n" +" Boston, MA 02111, 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 ("Number of vars = %ld\n", (long) MAX_STORE); +#ifdef OLD_EQ_OP + printf ("Old assignment operatiors are valid. (=-, =+, ...)\n"); +#endif +} + +/* bc_malloc will check the return value so all other places do not + have to do it! SIZE is the number of bytes to allocate. */ + +char * +bc_malloc (size) + int size; +{ + char *ptr; + + ptr = (char *) malloc (size); + if (ptr == NULL) + out_of_memory (); + + return ptr; +} + + +/* The following routines are error routines for various problems. */ + +/* Malloc could not get enought memory. */ + +void +out_of_memory() +{ + fprintf (stderr, "Fatal error: Out of memory for malloc.\n"); + exit (1); +} + + + +/* The standard yyerror routine. Built with variable number of argumnets. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +yyerror (char *str, ...) +#else +void +yyerror (str) + char *str; +#endif +#else +void +yyerror (str, va_alist) + char *str; +#endif +{ + char *name; + va_list args; + +#ifndef VARARGS + va_start (args, str); +#else + va_start (args); +#endif + if (is_std_in) + name = "(standard_in)"; + else + name = file_name; + fprintf (stderr,"%s %d: ",name,line_no); + vfprintf (stderr, str, args); + fprintf (stderr, "\n"); + had_error = TRUE; + va_end (args); +} + + +/* The routine to produce warnings about non-standard features + found during parsing. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +warn (char *mesg, ...) +#else +void +warn (mesg) + char *mesg; +#endif +#else +void +warn (mesg, va_alist) + char *mesg; +#endif +{ + char *name; + va_list args; + +#ifndef VARARGS + va_start (args, mesg); +#else + va_start (args); +#endif + if (std_only) + { + if (is_std_in) + name = "(standard_in)"; + else + name = file_name; + fprintf (stderr,"%s %d: ",name,line_no); + vfprintf (stderr, mesg, args); + fprintf (stderr, "\n"); + had_error = TRUE; + } + else + if (warn_not_std) + { + if (is_std_in) + name = "(standard_in)"; + else + name = file_name; + fprintf (stderr,"%s %d: (Warning) ",name,line_no); + vfprintf (stderr, mesg, args); + fprintf (stderr, "\n"); + } + va_end (args); +} + +/* Runtime error will print a message and stop the machine. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +rt_error (char *mesg, ...) +#else +void +rt_error (mesg) + char *mesg; +#endif +#else +void +rt_error (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + + fprintf (stderr, "Runtime error (func=%s, adr=%d): ", + f_names[pc.pc_func], pc.pc_addr); +#ifndef VARARGS + va_start (args, mesg); +#else + va_start (args); +#endif + vfprintf (stderr, mesg, args); + va_end (args); + + fprintf (stderr, "\n"); + 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; + + fprintf (stderr, "Runtime warning (func=%s, adr=%d): ", + f_names[pc.pc_func], pc.pc_addr); +#ifndef VARARGS + va_start (args, mesg); +#else + va_start (args); +#endif + vfprintf (stderr, mesg, args); + va_end (args); + + fprintf (stderr, "\n"); +} diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..ebb9e34 --- /dev/null +++ b/config.h.in @@ -0,0 +1,81 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#undef YYTEXT_POINTER + +/* VERSION number for DC target*/ +#undef DC_VERSION + +/* COPYRIGHT notice for DC target */ +#undef DC_COPYRIGHT + +/* COPYRIGHT notice for BC target */ +#undef BC_COPYRIGHT + +/* Define to use the readline library. */ +#undef READLINE + +/* Define to use the BSD libedit library. */ +#undef LIBEDIT + +/* Define to `size_t' if and don't define. */ +#undef ptrdiff_t + +/* Define if you have the isgraph function. */ +#undef HAVE_ISGRAPH + +/* Define if you have the setvbuf function. */ +#undef HAVE_SETVBUF + +/* Define if you have the header file. */ +#undef HAVE_LIB_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/configure b/configure new file mode 100755 index 0000000..e5fc7d9 --- /dev/null +++ b/configure @@ -0,0 +1,2656 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-pkg use software installed in /usr/pkg tree" +ac_help="$ac_help + --with-libedit support fancy BSD command input +editing" +ac_help="$ac_help + --with-readline support fancy command input editing" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=doc/bc.1 + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:563: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:616: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:673: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE="bc" + +VERSION="1.06" + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:719: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:732: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:745: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:758: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:771: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + + + + +cat >> confdefs.h <<\EOF +#define DC_VERSION "1.3" +EOF + +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:804: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:834: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:885: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:917: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 928 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:933: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:959: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:964: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:992: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1024: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1045: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1062: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1079: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 +echo "configure:1105: checking for minix/config.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1115: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MINIX=yes +else + echo "$ac_t""no" 1>&6 +MINIX= +fi + +if test "$MINIX" = yes; then + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_1_SOURCE 2 +EOF + + cat >> confdefs.h <<\EOF +#define _MINIX 1 +EOF + +fi + + +missing_dir=`cd $ac_aux_dir && pwd` +for ac_prog in flex lex +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1159: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LEX" && break +done +test -n "$LEX" || LEX=""$missing_dir/missing flex"" + +# Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1192: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="flex" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 +echo "configure:1226: checking for yywrap in -l$ac_lib" >&5 +ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-l$ac_lib $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LEXLIB="-l$ac_lib" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking lex output file root""... $ac_c" 1>&6 +echo "configure:1268: checking lex output file root" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; } +fi +fi + +echo "$ac_t""$ac_cv_prog_lex_root" 1>&6 +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6 +echo "configure:1289: checking whether yytext is a pointer" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_prog_lex_yytext_pointer=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" + +fi + +echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6 +if test $ac_cv_prog_lex_yytext_pointer = yes; then + cat >> confdefs.h <<\EOF +#define YYTEXT_POINTER 1 +EOF + +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1334: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1376: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1431: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1459: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +for ac_hdr in stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1490: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1500: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:1527: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:1581: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1602: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1615: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:1706: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6 +echo "configure:1739: checking for ptrdiff_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_ptrdiff_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])ptrdiff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_ptrdiff_t=yes +else + rm -rf conftest* + ac_cv_type_ptrdiff_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_ptrdiff_t" 1>&6 +if test $ac_cv_type_ptrdiff_t = no; then + cat >> confdefs.h <<\EOF +#define ptrdiff_t size_t +EOF + +fi + + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:1773: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1801: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:1825: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1853: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +for ac_func in isgraph setvbuf +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1880: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1908: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +# Check whether --with-pkg or --without-pkg was given. +if test "${with_pkg+set}" = set; then + withval="$with_pkg" + + CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" + LDFLAGS="$LDFLAGS -L/usr/pkg/lib" + echo Using /usr/pkg/include and /usr/pkg/lib + +fi + + +bcle=n +# Check whether --with-libedit or --without-libedit was given. +if test "${with_libedit+set}" = set; then + withval="$with_libedit" + + echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 +echo "configure:1950: checking for tgetent in -ltermcap" >&5 +ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ltermcap $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + TERMLIB=-ltermcap +else + echo "$ac_t""no" 1>&6 +fi + + LDSAVE=$LDFLAGS + LDFLAGS="$LDFLAGS $TERMLIB" + echo $ac_n "checking for el_gets in -ledit""... $ac_c" 1>&6 +echo "configure:1992: checking for el_gets in -ledit" >&5 +ac_lib_var=`echo edit'_'el_gets | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ledit $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_safe=`echo "histedit.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for histedit.h""... $ac_c" 1>&6 +echo "configure:2028: checking for histedit.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2038: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + READLINELIB="-ledit $TERMLIB";bcle=y +else + echo "$ac_t""no" 1>&6 +fi + +else + echo "$ac_t""no" 1>&6 +READLINELIB="" +fi + + if test "$bcle" = "y"; then + echo Using the libedit library. + cat >> confdefs.h <<\EOF +#define LIBEDIT 1 +EOF + + fi + LDFLAGS=$LDSAVE + +fi + + +bcrl=n +# Check whether --with-readline or --without-readline was given. +if test "${with_readline+set}" = set; then + withval="$with_readline" + + echo $ac_n "checking for tparm in -lncurses""... $ac_c" 1>&6 +echo "configure:2082: checking for tparm in -lncurses" >&5 +ac_lib_var=`echo ncurses'_'tparm | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lncurses $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + TERMLIB=-lncurses +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 +echo "configure:2120: checking for tgetent in -ltermcap" >&5 +ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ltermcap $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + TERMLIB=-ltermcap +else + echo "$ac_t""no" 1>&6 +fi + +fi + + LDSAVE=$LDFLAGS + LDFLAGS="$LDFLAGS $TERMLIB" + echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 +echo "configure:2164: checking for readline in -lreadline" >&5 +ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lreadline $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_safe=`echo "readline/readline.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for readline/readline.h""... $ac_c" 1>&6 +echo "configure:2200: checking for readline/readline.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2210: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + READLINELIB="-lreadline $TERMLIB";bcrl=y +else + echo "$ac_t""no" 1>&6 +fi + +else + echo "$ac_t""no" 1>&6 +READLINELIB="" +fi + + if test "$bcrl" = "y" ; then + echo Using the readline library. + cat >> confdefs.h <<\EOF +#define READLINE 1 +EOF + + fi + LDFLAGS=$LDSAVE + +fi + + +if test "$LEX" = "flex" ; then + LEX="flex -I8" +else + if test "$bcrl" = "y" ; then + echo "configure: warning: readline works only with flex." 1>&2 + fi +fi + +if test "$bcrl" = "y" -a "$bcle" = "y" ; then + { echo "configure: error: Can not use both readline and libedit. Aborting." 1>&2; exit 1; } +fi + +if test "$LEX" = "lex" -a `uname -s` = "SunOS" ; then + LEXLIB="" + echo "SunOS using lex does not have a -ll." +fi + + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@LEX@%$LEX%g +s%@LEXLIB@%$LEXLIB%g +s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g +s%@YACC@%$YACC%g +s%@RANLIB@%$RANLIB%g +s%@READLINELIB@%$READLINELIB%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..dfa8d68 --- /dev/null +++ b/configure.in @@ -0,0 +1,89 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(doc/bc.1) +AM_INIT_AUTOMAKE("bc", "1.06") +AM_CONFIG_HEADER(config.h) + +AC_DEFINE(DC_VERSION,"1.3") +AC_DEFINE_UNQUOTED(BC_COPYRIGHT, dnl + ["Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc."]) +AC_DEFINE_UNQUOTED(DC_COPYRIGHT, dnl + ["Copyright 1994, 1997, 1998, 2000 Free Software Foundation, Inc."]) + +AC_PROG_CC +AC_MINIX +dnl AC_ISC_POSIX + +AM_PROG_LEX +AC_PROG_YACC +AC_PROG_INSTALL +AC_PROG_RANLIB +AC_PROG_MAKE_SET + +AC_CHECK_HEADERS(stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h) +AC_C_CONST +AC_TYPE_SIZE_T +AC_CHECK_TYPE(ptrdiff_t, size_t) + +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(isgraph setvbuf) + +AC_ARG_WITH(pkg,[ --with-pkg use software installed in /usr/pkg tree], [ + CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" + LDFLAGS="$LDFLAGS -L/usr/pkg/lib" + echo Using /usr/pkg/include and /usr/pkg/lib +]) + +bcle=n +AC_ARG_WITH(libedit,[ --with-libedit support fancy BSD command input +editing], [ + AC_CHECK_LIB(termcap,tgetent,TERMLIB=-ltermcap) + LDSAVE=$LDFLAGS + LDFLAGS="$LDFLAGS $TERMLIB" + AC_CHECK_LIB(edit,el_gets, + [AC_CHECK_HEADER(histedit.h, + READLINELIB="-ledit $TERMLIB";bcle=y)], + READLINELIB="") + if test "$bcle" = "y"; then + echo Using the libedit library. + AC_DEFINE(LIBEDIT,1) + fi + LDFLAGS=$LDSAVE +]) + +bcrl=n +AC_ARG_WITH(readline,[ --with-readline support fancy command input editing], [ + AC_CHECK_LIB(ncurses,tparm,TERMLIB=-lncurses, + AC_CHECK_LIB(termcap,tgetent,TERMLIB=-ltermcap)) + LDSAVE=$LDFLAGS + LDFLAGS="$LDFLAGS $TERMLIB" + AC_CHECK_LIB(readline,readline, + [AC_CHECK_HEADER(readline/readline.h, + READLINELIB="-lreadline $TERMLIB";bcrl=y)], + READLINELIB="") + if test "$bcrl" = "y" ; then + echo Using the readline library. + AC_DEFINE(READLINE,1) + fi + LDFLAGS=$LDSAVE +]) + +if test "$LEX" = "flex" ; then + LEX="flex -I -8" +else + if test "$bcrl" = "y" ; then + AC_MSG_WARN(readline works only with flex.) + fi +fi + +if test "$bcrl" = "y" -a "$bcle" = "y" ; then + AC_MSG_ERROR(Can not use both readline and libedit. Aborting.) +fi + +if test "$LEX" = "lex" -a `uname -s` = "SunOS" ; then + LEXLIB="" + echo "SunOS using lex does not have a -ll." +fi + +AC_SUBST(READLINELIB) +AC_ARG_PROGRAM +AC_OUTPUT(Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile) diff --git a/dc/Makefile.am b/dc/Makefile.am new file mode 100644 index 0000000..99164ba --- /dev/null +++ b/dc/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = dc + +dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c +noinst_HEADERS = dc.h dc-proto.h dc-regdef.h + +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h +LDADD = ../lib/libbc.a + +MAINTAINERCLEANFILES = Makefile.in + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +$(PROGRAMS): $(LDADD) diff --git a/dc/Makefile.in b/dc/Makefile.in new file mode 100644 index 0000000..0772dd6 --- /dev/null +++ b/dc/Makefile.in @@ -0,0 +1,296 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +bin_PROGRAMS = dc + +dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c +noinst_HEADERS = dc.h dc-proto.h dc-regdef.h + +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h +LDADD = ../lib/libbc.a + +MAINTAINERCLEANFILES = Makefile.in + +CFLAGS = @CFLAGS@ -Wall -funsigned-char +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +dc_OBJECTS = dc.o misc.o eval.o stack.o array.o numeric.o string.o +dc_LDADD = $(LDADD) +dc_DEPENDENCIES = ../lib/libbc.a +dc_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(dc_SOURCES) +OBJECTS = $(dc_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps dc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +dc: $(dc_OBJECTS) $(dc_DEPENDENCIES) + @rm -f dc + $(LINK) $(dc_LDFLAGS) $(dc_OBJECTS) $(dc_LDADD) $(LIBS) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = dc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +array.o: array.c ../config.h dc.h dc-proto.h dc-regdef.h +dc.o: dc.c ../config.h ../h/getopt.h dc.h dc-proto.h +eval.o: eval.c ../config.h dc.h dc-proto.h +misc.o: misc.c ../config.h ../h/getopt.h dc.h dc-proto.h +numeric.o: numeric.c ../config.h ../h/number.h dc.h dc-proto.h +stack.o: stack.c ../config.h dc.h dc-proto.h dc-regdef.h +string.o: string.c ../config.h dc.h dc-proto.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/dc/array.c b/dc/array.c new file mode 100644 index 0000000..d97f716 --- /dev/null +++ b/dc/array.c @@ -0,0 +1,122 @@ +/* + * implement arrays for dc + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* This module is the only one that knows what arrays look like. */ + +#include "config.h" + +#include /* "dc-proto.h" wants this */ +#ifdef HAVE_STDLIB_H +/* get size_t definition from "almost ANSI" compiling environments. */ +#include +#endif +#include "dc.h" +#include "dc-proto.h" +#include "dc-regdef.h" + +/* what's most useful: quick access or sparse arrays? */ +/* I'll go with sparse arrays for now */ +struct dc_array { + int Index; + dc_data value; + struct dc_array *next; +}; + + +/* initialize the arrays */ +void +dc_array_init DC_DECLVOID() +{ +} + +/* store value into array_id[Index] */ +void +dc_array_set DC_DECLARG((array_id, Index, value)) + int array_id DC_DECLSEP + int Index DC_DECLSEP + dc_data value DC_DECLEND +{ + struct dc_array *cur; + struct dc_array *prev=NULL; + struct dc_array *newentry; + + cur = dc_get_stacked_array(array_id); + while (cur && cur->Index < Index){ + prev = cur; + cur = cur->next; + } + if (cur && cur->Index == Index){ + if (cur->value.dc_type == DC_NUMBER) + dc_free_num(&cur->value.v.number); + else if (cur->value.dc_type == DC_STRING) + dc_free_str(&cur->value.v.string); + else + dc_garbage(" in array", array_id); + cur->value = value; + }else{ + newentry = dc_malloc(sizeof *newentry); + newentry->Index = Index; + newentry->value = value; + newentry->next = cur; + if (prev) + prev->next = newentry; + else + dc_set_stacked_array(array_id, newentry); + } +} + +/* retrieve a dup of a value from array_id[Index] */ +/* A zero value is returned if the specified value is unintialized. */ +dc_data +dc_array_get DC_DECLARG((array_id, Index)) + int array_id DC_DECLSEP + int Index DC_DECLEND +{ + struct dc_array *cur; + + for (cur=dc_get_stacked_array(array_id); cur; cur=cur->next) + if (cur->Index == Index) + return dc_dup(cur->value); + return dc_int2data(0); +} + +/* free an array chain */ +void +dc_array_free DC_DECLARG((a_head)) + struct dc_array *a_head DC_DECLEND +{ + struct dc_array *cur; + struct dc_array *next; + + for (cur=a_head; cur; cur=next) { + next = cur->next; + if (cur->value.dc_type == DC_NUMBER) + dc_free_num(&cur->value.v.number); + else if (cur->value.dc_type == DC_STRING) + dc_free_str(&cur->value.v.string); + else + dc_garbage("in stack", -1); + free(cur); + } +} diff --git a/dc/dc-proto.h b/dc/dc-proto.h new file mode 100644 index 0000000..f0ac28b --- /dev/null +++ b/dc/dc-proto.h @@ -0,0 +1,90 @@ +/* + * prototypes of all externally visible dc functions + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +extern const char *dc_str2charp DC_PROTO((dc_str)); +extern const char *dc_system DC_PROTO((const char *)); +extern void *dc_malloc DC_PROTO((size_t)); +extern struct dc_array *dc_get_stacked_array DC_PROTO((int)); + +extern void dc_array_set DC_PROTO((int, int, dc_data)); +extern void dc_array_free DC_PROTO((struct dc_array *)); +extern void dc_array_init DC_PROTO((void)); +extern void dc_binop DC_PROTO((int (*)(dc_num, dc_num, int, dc_num *), int)); +extern void dc_binop2 DC_PROTO((int (*)(dc_num, dc_num, int, + dc_num *, dc_num *), int)); +extern void dc_triop DC_PROTO((int (*)(dc_num, dc_num, dc_num, int, + dc_num *), int)); +extern void dc_clear_stack DC_PROTO((void)); +extern void dc_dump_num(dc_num, dc_discard); +extern void dc_free_num DC_PROTO((dc_num *)); +extern void dc_free_str DC_PROTO((dc_str *)); +extern void dc_garbage DC_PROTO((const char *, int)); +extern void dc_math_init DC_PROTO((void)); +extern void dc_memfail DC_PROTO((void)); +extern void dc_out_num DC_PROTO((dc_num, int, dc_newline, dc_discard)); +extern void dc_out_str DC_PROTO((dc_str, dc_newline, dc_discard)); +extern void dc_print DC_PROTO((dc_data, int, dc_newline, dc_discard)); +extern void dc_printall DC_PROTO((int)); +extern void dc_push DC_PROTO((dc_data)); +extern void dc_register_init DC_PROTO((void)); +extern void dc_register_push DC_PROTO((int, dc_data)); +extern void dc_register_set DC_PROTO((int, dc_data)); +extern void dc_set_stacked_array DC_PROTO((int, struct dc_array *)); +extern void dc_show_id DC_PROTO((FILE *, int, const char *)); +extern void dc_string_init DC_PROTO((void)); + +extern int dc_cmpop DC_PROTO((void)); +extern int dc_compare DC_PROTO((dc_num, dc_num)); +extern int dc_evalfile DC_PROTO((FILE *)); +extern int dc_evalstr DC_PROTO((dc_data)); +extern int dc_num2int DC_PROTO((dc_num, dc_discard)); +extern int dc_numlen DC_PROTO((dc_num)); +extern int dc_pop DC_PROTO((dc_data *)); +extern int dc_register_get DC_PROTO((int, dc_data *)); +extern int dc_register_pop DC_PROTO((int, dc_data *)); +extern int dc_tell_length DC_PROTO((dc_data, dc_discard)); +extern int dc_tell_scale DC_PROTO((dc_num, dc_discard)); +extern int dc_tell_stackdepth DC_PROTO((void)); +extern int dc_top_of_stack DC_PROTO((dc_data *)); + +extern size_t dc_strlen DC_PROTO((dc_str)); + +extern dc_data dc_array_get DC_PROTO((int, int)); +extern dc_data dc_dup DC_PROTO((dc_data)); +extern dc_data dc_dup_num DC_PROTO((dc_num)); +extern dc_data dc_dup_str DC_PROTO((dc_str)); +extern dc_data dc_getnum DC_PROTO((int (*)(void), int, int *)); +extern dc_data dc_int2data DC_PROTO((int)); +extern dc_data dc_makestring DC_PROTO((const char *, size_t)); +extern dc_data dc_readstring DC_PROTO((FILE *, int , int)); + +extern int dc_add DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_div DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_divrem DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)); +extern int dc_exp DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_modexp DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)); +extern int dc_mul DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_rem DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_sub DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_sqrt DC_PROTO((dc_num, int, dc_num *)); diff --git a/dc/dc-regdef.h b/dc/dc-regdef.h new file mode 100644 index 0000000..540268c --- /dev/null +++ b/dc/dc-regdef.h @@ -0,0 +1,43 @@ +/* + * definitions for dc's "register" declarations + * + * Copyright (C) 1994 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +#ifdef HAVE_LIMITS_H +# include /* UCHAR_MAX */ +#endif + +/* determine how many register stacks there are */ +#ifndef DC_REGCOUNT +# ifndef UCHAR_MAX +# define DC_REGCOUNT 256 +# else +# define DC_REGCOUNT (UCHAR_MAX+1) +# endif +#endif /* not DC_REGCOUNT */ + +/* efficiency hack for masking arbritrary integers to 0..(DC_REGCOUNT-1) */ +#if (DC_REGCOUNT & (DC_REGCOUNT-1)) == 0 /* DC_REGCOUNT is power of 2 */ +# define regmap(r) ((r) & (DC_REGCOUNT-1)) +#else +# define regmap(r) ((r) % DC_REGCOUNT) +#endif diff --git a/dc/dc.c b/dc/dc.c new file mode 100644 index 0000000..a72644c --- /dev/null +++ b/dc/dc.c @@ -0,0 +1,183 @@ +/* + * implement the "dc" Desk Calculator language. + * + * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* Written with strong hiding of implementation details + * in their own specialized modules. + */ +/* This module contains the argument processing/main functions. + */ + +#include "config.h" + +#include +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif +#include +#include "dc.h" +#include "dc-proto.h" + +#ifndef EXIT_SUCCESS /* C89 */ +# define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE /* C89 */ +# define EXIT_FAILURE 1 +#endif + +const char *progname; /* basename of program invocation */ + +static void +bug_report_info DC_DECLVOID() +{ + printf("Email bug reports to: bug-dc@gnu.org .\n"); +} + +static void +show_version DC_DECLVOID() +{ + printf("dc (GNU %s %s) %s\n", PACKAGE, VERSION, DC_VERSION); + printf("\n%s\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\ +to the extent permitted by law.\n", DC_COPYRIGHT); +} + +/* your generic usage function */ +static void +usage DC_DECLARG((f)) + FILE *f DC_DECLEND +{ + fprintf(f, "\ +Usage: %s [OPTION] [file ...]\n\ + -e, --expression=EXPR evaluate expression\n\ + -f, --file=FILE evaluate contents of file\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n\ +\n\ +", progname); + bug_report_info(); +} + +/* returns a pointer to one past the last occurance of c in s, + * or s if c does not occur in s. + */ +static char * +r1bindex DC_DECLARG((s, c)) + char *s DC_DECLSEP + int c DC_DECLEND +{ + char *p = strrchr(s, c); + + if (!p) + return s; + return p + 1; +} + +static void +try_file(const char *filename) +{ + FILE *input; + + if (strcmp(filename, "-") == 0) { + input = stdin; + } else if ( !(input=fopen(filename, "r")) ) { + fprintf(stderr, "Could not open file "); + perror(filename); + exit(EXIT_FAILURE); + } + if (dc_evalfile(input)) + exit(EXIT_FAILURE); + if (input != stdin) + fclose(input); +} + + +int +main DC_DECLARG((argc, argv)) + int argc DC_DECLSEP + char **argv DC_DECLEND +{ + static struct option const long_opts[] = { + {"expression", required_argument, NULL, 'e'}, + {"file", required_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} + }; + int did_eval = 0; + int c; + + progname = r1bindex(*argv, '/'); +#ifdef HAVE_SETVBUF + /* attempt to simplify interaction with applications such as emacs */ + (void) setvbuf(stdout, NULL, _IOLBF, 0); +#endif + dc_math_init(); + dc_string_init(); + dc_register_init(); + dc_array_init(); + + while ((c = getopt_long(argc, argv, "hVe:f:", long_opts, (int *)0)) != EOF) { + switch (c) { + case 'e': + { dc_data string = dc_makestring(optarg, strlen(optarg)); + if (dc_evalstr(string)) + return EXIT_SUCCESS; + dc_free_str(&string.v.string); + did_eval = 1; + } + break; + case 'f': + try_file(optarg); + did_eval = 1; + break; + case 'h': + usage(stdout); + return EXIT_SUCCESS; + case 'V': + show_version(); + return EXIT_SUCCESS; + default: + usage(stderr); + return EXIT_FAILURE; + } + } + + for (; optind < argc; ++optind) { + try_file(argv[optind]); + did_eval = 1; + } + if (!did_eval) { + /* if no -e commands and no command files, then eval stdin */ + if (dc_evalfile(stdin)) + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/dc/dc.h b/dc/dc.h new file mode 100644 index 0000000..3300f44 --- /dev/null +++ b/dc/dc.h @@ -0,0 +1,82 @@ +/* + * Header file for dc routines + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +#ifndef DC_DEFS_H +#define DC_DEFS_H + +/* 'I' is a command, and bases 17 and 18 are quite + * unusual, so we limit ourselves to bases 2 to 16 + */ +#define DC_IBASE_MAX 16 + +#define DC_SUCCESS 0 +#define DC_DOMAIN_ERROR 1 +#define DC_FAIL 2 /* generic failure */ + + +#ifndef __STDC__ +# define DC_PROTO(x) () +# define DC_DECLVOID() () +# define DC_DECLARG(arglist) arglist +# define DC_DECLSEP ; +# define DC_DECLEND ; +#else /* __STDC__ */ +# define DC_PROTO(x) x +# define DC_DECLVOID() (void) +# define DC_DECLARG(arglist) ( +# define DC_DECLSEP , +# define DC_DECLEND ) +#endif /* __STDC__ */ + + +typedef enum {DC_TOSS, DC_KEEP} dc_discard; +typedef enum {DC_NONL, DC_WITHNL} dc_newline; + + +/* type discriminant for dc_data */ +typedef enum {DC_UNINITIALIZED, DC_NUMBER, DC_STRING} dc_value_type; + +/* only numeric.c knows what dc_num's *really* look like */ +typedef struct dc_number *dc_num; + +/* only string.c knows what dc_str's *really* look like */ +typedef struct dc_string *dc_str; + + +/* except for the two implementation-specific modules, all + * dc functions only know of this one generic type of object + */ +typedef struct { + dc_value_type dc_type; /* discriminant for union */ + union { + dc_num number; + dc_str string; + } v; +} dc_data; + + +/* This is dc's only global variable: */ +extern const char *progname; /* basename of program invocation */ + +#endif /* not DC_DEFS_H */ diff --git a/dc/eval.c b/dc/eval.c new file mode 100644 index 0000000..21592d9 --- /dev/null +++ b/dc/eval.c @@ -0,0 +1,682 @@ +/* + * evaluate the dc language, from a FILE* or a string + * + * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* This is the only module which knows about the dc input language */ + +#include "config.h" + +#include +#ifdef HAVE_STRING_H +# include /* memchr */ +#else +# ifdef HAVE_MEMORY_H +# include /* memchr, maybe */ +# else +# ifdef HAVE_STRINGS_H +# include /* memchr, maybe */ +# endif +#endif +#endif +#include "dc.h" +#include "dc-proto.h" + +typedef enum {DC_FALSE, DC_TRUE} dc_boolean; + +typedef enum { + DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */ + DC_EATONE, /* caller needs to eat the lookahead char */ + DC_QUIT, /* quit out of unwind_depth levels of evaluation */ + + /* with the following return values, the caller does not have to + * fret about stdin_lookahead's value + */ + DC_INT, /* caller needs to parse a dc_num from input stream */ + DC_STR, /* caller needs to parse a dc_str from input stream */ + DC_SYSTEM, /* caller needs to run a system() on next input line */ + DC_COMMENT, /* caller needs to skip to the next input line */ + DC_NEGCMP, /* caller needs to re-call dc_func() with `negcmp' set */ + + DC_EOF_ERROR /* unexpected end of input; abort current eval */ +} dc_status; + +static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */ +static int dc_obase=10; /* output base, 2 <= dc_obase */ +static int dc_scale=0; /* scale (see user documentaton) */ + +/* for Quitting evaluations */ +static int unwind_depth=0; + +/* if true, active Quit will not exit program */ +static dc_boolean unwind_noexit=DC_FALSE; + +/* + * Used to synchronize lookahead on stdin for '?' command. + * If set to EOF then lookahead is used up. + */ +static int stdin_lookahead=EOF; + + +/* input_fil and input_str are passed as arguments to dc_getnum */ + +/* used by the input_* functions: */ +static FILE *input_fil_fp; +static const char *input_str_string; + +/* Since we have a need for two characters of pushback, and + * ungetc() only guarantees one, we place the second pushback here + */ +static int input_pushback; + +/* passed as an argument to dc_getnum */ +static int +input_fil DC_DECLVOID() +{ + if (input_pushback != EOF){ + int c = input_pushback; + input_pushback = EOF; + return c; + } + return getc(input_fil_fp); +} + +/* passed as an argument to dc_getnum */ +static int +input_str DC_DECLVOID() +{ + if (!*input_str_string) + return EOF; + return *input_str_string++; +} + + + +/* takes a string and evals it; frees the string when done */ +/* Wrapper around dc_evalstr to avoid duplicating the free call + * at all possible return points. + */ +static int +dc_eval_and_free_str DC_DECLARG((string)) + dc_data string DC_DECLEND +{ + dc_status status; + + status = dc_evalstr(string); + if (string.dc_type == DC_STRING) + dc_free_str(&string.v.string); + return status; +} + + +/* dc_func does the grunt work of figuring out what each input + * character means; used by both dc_evalstr and dc_evalfile + * + * c -> the "current" input character under consideration + * peekc -> the lookahead input character + * negcmp -> negate comparison test (for <,=,> commands) + */ +static dc_status +dc_func DC_DECLARG((c, peekc, negcmp)) + int c DC_DECLSEP + int peekc DC_DECLSEP + int negcmp DC_DECLEND +{ + /* we occasionally need these for temporary data */ + /* Despite the GNU coding standards, it is much easier + * to have these declared once here, since this function + * is just one big switch statement. + */ + dc_data datum; + int tmpint; + + switch (c){ + case '_': case '.': + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': case 'A': case 'B': + case 'C': case 'D': case 'E': case 'F': + return DC_INT; + case ' ': + case '\t': + case '\n': + /* standard command separators */ + break; + + case '+': /* add top two stack elements */ + dc_binop(dc_add, dc_scale); + break; + case '-': /* subtract top two stack elements */ + dc_binop(dc_sub, dc_scale); + break; + case '*': /* multiply top two stack elements */ + dc_binop(dc_mul, dc_scale); + break; + case '/': /* divide top two stack elements */ + dc_binop(dc_div, dc_scale); + break; + case '%': + /* take the remainder from division of the top two stack elements */ + dc_binop(dc_rem, dc_scale); + break; + case '~': + /* Do division on the top two stack elements. Return the + * quotient as next-to-top of stack and the remainder as + * top-of-stack. + */ + dc_binop2(dc_divrem, dc_scale); + break; + case '|': + /* Consider the top three elements of the stack as (base, exp, mod), + * where mod is top-of-stack, exp is next-to-top, and base is + * second-from-top. Mod must be non-zero, exp must be non-negative, + * and all three must be integers. Push the result of raising + * base to the exp power, reduced modulo mod. If we had base in + * register b, exp in register e, and mod in register m then this + * is conceptually equivalent to "lble^lm%", but it is implemented + * in a more efficient manner, and can handle arbritrarily large + * values for exp. + */ + dc_triop(dc_modexp, dc_scale); + break; + case '^': /* exponientiation of the top two stack elements */ + dc_binop(dc_exp, dc_scale); + break; + case '<': + /* eval register named by peekc if + * less-than holds for top two stack elements + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if ( (dc_cmpop() < 0) == !negcmp ) + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + return DC_EATONE; + case '=': + /* eval register named by peekc if + * equal-to holds for top two stack elements + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if ( (dc_cmpop() == 0) == !negcmp ) + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + return DC_EATONE; + case '>': + /* eval register named by peekc if + * greater-than holds for top two stack elements + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if ( (dc_cmpop() > 0) == !negcmp ) + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + return DC_EATONE; + case '?': /* read a line from standard-input and eval it */ + if (stdin_lookahead != EOF){ + ungetc(stdin_lookahead, stdin); + stdin_lookahead = EOF; + } + if (dc_eval_and_free_str(dc_readstring(stdin, '\n', '\n')) == DC_QUIT) + return DC_QUIT; + return DC_OKAY; + case '[': /* read to balancing ']' into a dc_str */ + return DC_STR; + case '!': /* read to newline and call system() on resulting string */ + if (peekc == '<' || peekc == '=' || peekc == '>') + return DC_NEGCMP; + return DC_SYSTEM; + case '#': /* comment; skip remainder of current line */ + return DC_COMMENT; + + case 'a': /* Convert top of stack to an ascii character. */ + if (dc_pop(&datum) == DC_SUCCESS){ + char tmps; + if (datum.dc_type == DC_NUMBER){ + tmps = (char) dc_num2int(datum.v.number, DC_TOSS); + }else if (datum.dc_type == DC_STRING){ + tmps = *dc_str2charp(datum.v.string); + dc_free_str(&datum.v.string); + }else{ + dc_garbage("at top of stack", -1); + } + dc_push(dc_makestring(&tmps, 1)); + } + break; + case 'c': /* clear whole stack */ + dc_clear_stack(); + break; + case 'd': /* duplicate the datum on the top of stack */ + if (dc_top_of_stack(&datum) == DC_SUCCESS) + dc_push(dc_dup(datum)); + break; + case 'f': /* print list of all stack items */ + dc_printall(dc_obase); + break; + case 'i': /* set input base to value on top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if ( ! (2 <= tmpint && tmpint <= DC_IBASE_MAX) ) + fprintf(stderr, + "%s: input base must be a number \ +between 2 and %d (inclusive)\n", + progname, DC_IBASE_MAX); + else + dc_ibase = tmpint; + } + break; + case 'k': /* set scale to value on top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = -1; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if ( ! (tmpint >= 0) ) + fprintf(stderr, + "%s: scale must be a nonnegative number\n", + progname); + else + dc_scale = tmpint; + } + break; + case 'l': /* "load" -- push value on top of register stack named + * by peekc onto top of evaluation stack; does not + * modify the register stack + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + dc_push(datum); + return DC_EATONE; + case 'n': /* print the value popped off of top-of-stack; + * do not add a trailing newline + */ + if (dc_pop(&datum) == DC_SUCCESS) + dc_print(datum, dc_obase, DC_NONL, DC_TOSS); + break; + case 'o': /* set output base to value on top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if ( ! (tmpint > 1) ) + fprintf(stderr, + "%s: output base must be a number greater than 1\n", + progname); + else + dc_obase = tmpint; + } + break; + case 'p': /* print the datum on the top of stack, + * with a trailing newline + */ + if (dc_top_of_stack(&datum) == DC_SUCCESS) + dc_print(datum, dc_obase, DC_WITHNL, DC_KEEP); + break; + case 'q': /* quit two levels of evaluation, posibly exiting program */ + unwind_depth = 1; /* the return below is the first level of returns */ + unwind_noexit = DC_FALSE; + return DC_QUIT; + case 'r': /* rotate (swap) the top two elements on the stack + */ + if (dc_pop(&datum) == DC_SUCCESS) { + dc_data datum2; + int two_status; + two_status = dc_pop(&datum2); + dc_push(datum); + if (two_status == DC_SUCCESS) + dc_push(datum2); + } + break; + case 's': /* "store" -- replace top of register stack named + * by peekc with the value popped from the top + * of the evaluation stack + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS) + dc_register_set(peekc, datum); + return DC_EATONE; + case 'v': /* replace top of stack with its square root */ + if (dc_pop(&datum) == DC_SUCCESS){ + dc_num tmpnum; + if (datum.dc_type != DC_NUMBER){ + fprintf(stderr, + "%s: square root of nonnumeric attempted\n", + progname); + }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){ + dc_free_num(&datum.v.number); + datum.v.number = tmpnum; + dc_push(datum); + } + } + break; + case 'x': /* eval the datum popped from top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + if (datum.dc_type == DC_STRING){ + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + }else if (datum.dc_type == DC_NUMBER){ + dc_push(datum); + }else{ + dc_garbage("at top of stack", -1); + } + } + break; + case 'z': /* push the current stack depth onto the top of stack */ + dc_push(dc_int2data(dc_tell_stackdepth())); + break; + + case 'I': /* push the current input base onto the stack */ + dc_push(dc_int2data(dc_ibase)); + break; + case 'K': /* push the current scale onto the stack */ + dc_push(dc_int2data(dc_scale)); + break; + case 'L': /* pop a value off of register stack named by peekc + * and push it onto the evaluation stack + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_register_pop(peekc, &datum) == DC_SUCCESS) + dc_push(datum); + return DC_EATONE; + case 'O': /* push the current output base onto the stack */ + dc_push(dc_int2data(dc_obase)); + break; + case 'P': + /* Pop the value off the top of a stack. If it is + * a number, dump out the integer portion of its + * absolute value as a "base UCHAR_MAX+1" byte stream; + * if it is a string, just print it. + * In either case, do not append a trailing newline. + */ + if (dc_pop(&datum) == DC_SUCCESS){ + if (datum.dc_type == DC_NUMBER) + dc_dump_num(datum.v.number, DC_TOSS); + else if (datum.dc_type == DC_STRING) + dc_out_str(datum.v.string, DC_NONL, DC_TOSS); + else + dc_garbage("at top of stack", -1); + } + break; + case 'Q': /* quit out of top-of-stack nested evals; + * pops value from stack; + * does not exit program (stops short if necessary) + */ + if (dc_pop(&datum) == DC_SUCCESS){ + unwind_depth = 0; + unwind_noexit = DC_TRUE; + if (datum.dc_type == DC_NUMBER) + unwind_depth = dc_num2int(datum.v.number, DC_TOSS); + if (unwind_depth-- > 0) + return DC_QUIT; + unwind_depth = 0; /* paranoia */ + fprintf(stderr, + "%s: Q command requires a number >= 1\n", + progname); + } + break; +#if 0 + case 'R': /* pop a value off of the evaluation stack,; + * rotate the top + remaining stack elements that many + * places forward (negative numbers mean rotate + * backward). + */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + dc_stack_rotate(tmpint); + } + break; +#endif + case 'S': /* pop a value off of the evaluation stack + * and push it onto the register stack named by peekc + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS) + dc_register_push(peekc, datum); + return DC_EATONE; + case 'X': /* replace the number on top-of-stack with its scale factor */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_tell_scale(datum.v.number, DC_TOSS); + dc_push(dc_int2data(tmpint)); + } + break; + case 'Z': /* replace the datum on the top-of-stack with its length */ + if (dc_pop(&datum) == DC_SUCCESS) + dc_push(dc_int2data(dc_tell_length(datum, DC_TOSS))); + break; + + case ':': /* store into array */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = -1; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if (dc_pop(&datum) == DC_SUCCESS){ + if (tmpint < 0) + fprintf(stderr, + "%s: array index must be a nonnegative integer\n", + progname); + else + dc_array_set(peekc, tmpint, datum); + } + } + return DC_EATONE; + case ';': /* retreive from array */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = -1; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if (tmpint < 0) + fprintf(stderr, + "%s: array index must be a nonnegative integer\n", + progname); + else + dc_push(dc_array_get(peekc, tmpint)); + } + return DC_EATONE; + + default: /* What did that user mean? */ + fprintf(stderr, "%s: ", progname); + dc_show_id(stdout, c, " unimplemented\n"); + break; + } + return DC_OKAY; +} + + +/* takes a string and evals it */ +int +dc_evalstr DC_DECLARG((string)) + dc_data string DC_DECLEND +{ + const char *s; + const char *end; + const char *p; + size_t len; + int c; + int peekc; + int count; + int negcmp; + int next_negcmp = 0; + + if (string.dc_type != DC_STRING){ + fprintf(stderr, + "%s: eval called with non-string argument\n", + progname); + return DC_OKAY; + } + s = dc_str2charp(string.v.string); + end = s + dc_strlen(string.v.string); + while (s < end){ + c = *(const unsigned char *)s++; + peekc = EOF; + if (s < end) + peekc = *(const unsigned char *)s; + negcmp = next_negcmp; + next_negcmp = 0; + switch (dc_func(c, peekc, negcmp)){ + case DC_OKAY: + break; + case DC_EATONE: + if (peekc != EOF) + ++s; + break; + case DC_QUIT: + if (unwind_depth > 0){ + --unwind_depth; + return DC_QUIT; + } + return DC_OKAY; + + case DC_INT: + input_str_string = s - 1; + dc_push(dc_getnum(input_str, dc_ibase, &peekc)); + s = input_str_string; + if (peekc != EOF) + --s; + break; + case DC_STR: + count = 1; + for (p=s; p0; ++p) + if (*p == ']') + --count; + else if (*p == '[') + ++count; + len = p - s; + dc_push(dc_makestring(s, len-1)); + s = p; + break; + case DC_SYSTEM: + s = dc_system(s); + case DC_COMMENT: + s = memchr(s, '\n', (size_t)(end-s)); + if (!s) + s = end; + else + ++s; + break; + case DC_NEGCMP: + next_negcmp = 1; + break; + + case DC_EOF_ERROR: + fprintf(stderr, "%s: unexpected EOS\n", progname); + return DC_OKAY; + } + } + return DC_OKAY; +} + + +/* This is the main function of the whole DC program. + * Reads the file described by fp, calls dc_func to do + * the dirty work, and takes care of dc_func's shortcomings. + */ +int +dc_evalfile DC_DECLARG((fp)) + FILE *fp DC_DECLEND +{ + int c; + int peekc; + int negcmp; + int next_negcmp = 0; + dc_data datum; + + stdin_lookahead = EOF; + for (c=getc(fp); c!=EOF; c=peekc){ + peekc = getc(fp); + /* + * The following if() is the only place where ``stdin_lookahead'' + * might be set to other than EOF: + */ + if (fp == stdin) + stdin_lookahead = peekc; + negcmp = next_negcmp; + next_negcmp = 0; + switch (dc_func(c, peekc, negcmp)){ + case DC_OKAY: + if (stdin_lookahead != peekc && fp == stdin) + peekc = getc(fp); + break; + case DC_EATONE: + peekc = getc(fp); + break; + case DC_QUIT: + if (unwind_noexit != DC_TRUE) + return DC_SUCCESS; + fprintf(stderr, + "%s: Q command argument exceeded string execution depth\n", + progname); + if (stdin_lookahead != peekc && fp == stdin) + peekc = getc(fp); + break; + + case DC_INT: + input_fil_fp = fp; + input_pushback = c; + ungetc(peekc, fp); + dc_push(dc_getnum(input_fil, dc_ibase, &peekc)); + break; + case DC_STR: + ungetc(peekc, fp); + datum = dc_readstring(fp, '[', ']'); + dc_push(datum); + peekc = getc(fp); + break; + case DC_SYSTEM: + ungetc(peekc, fp); + datum = dc_readstring(stdin, '\n', '\n'); + (void)dc_system(dc_str2charp(datum.v.string)); + dc_free_str(&datum.v.string); + peekc = getc(fp); + break; + case DC_COMMENT: + while (peekc!=EOF && peekc!='\n') + peekc = getc(fp); + if (peekc != EOF) + peekc = getc(fp); + break; + case DC_NEGCMP: + next_negcmp = 1; + break; + + case DC_EOF_ERROR: + fprintf(stderr, "%s: unexpected EOF\n", progname); + return DC_FAIL; + } + } + return DC_SUCCESS; +} diff --git a/dc/misc.c b/dc/misc.c new file mode 100644 index 0000000..fa94de1 --- /dev/null +++ b/dc/misc.c @@ -0,0 +1,179 @@ +/* + * misc. functions for the "dc" Desk Calculator language. + * + * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* This module contains miscelaneous functions that have no + * special knowledge of any private data structures. + * They could all be moved to their own separate modules, but + * are agglomerated here for convenience. + */ + +#include "config.h" + +#include +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif +#include +#ifndef isgraph +# ifndef HAVE_ISGRAPH +# define isgraph isprint +# endif +#endif +#include +#include "dc.h" +#include "dc-proto.h" + +#ifndef EXIT_FAILURE /* C89 */ +# define EXIT_FAILURE 1 +#endif + + +/* print an "out of memory" diagnostic and exit program */ +void +dc_memfail DC_DECLVOID() +{ + fprintf(stderr, "%s: out of memory\n", progname); + exit(EXIT_FAILURE); +} + +/* malloc or die */ +void * +dc_malloc DC_DECLARG((len)) + size_t len DC_DECLEND +{ + void *result = malloc(len); + + if (!result) + dc_memfail(); + return result; +} + + +/* print the id in a human-understandable form + * fp is the output stream to place the output on + * id is the name of the register (or command) to be printed + * suffix is a modifier (such as "stack") to be printed + */ +void +dc_show_id DC_DECLARG((fp, id, suffix)) + FILE *fp DC_DECLSEP + int id DC_DECLSEP + const char *suffix DC_DECLEND +{ + if (isgraph(id)) + fprintf(fp, "'%c' (%#o)%s", id, id, suffix); + else + fprintf(fp, "%#o%s", id, suffix); +} + + +/* report that corrupt data has been detected; + * use the msg and regid (if nonnegative) to give information + * about where the garbage was found, + * + * will abort() so that a debugger might be used to help find + * the bug + */ +/* If this routine is called, then there is a bug in the code; + * i.e. it is _not_ a data or user error + */ +void +dc_garbage DC_DECLARG((msg, regid)) + const char *msg DC_DECLSEP + int regid DC_DECLEND +{ + if (regid < 0) { + fprintf(stderr, "%s: garbage %s\n", progname, msg); + } else { + fprintf(stderr, "%s:%s register ", progname, msg); + dc_show_id(stderr, regid, " is garbage\n"); + } + abort(); +} + + +/* call system() with the passed string; + * if the string contains a newline, terminate the string + * there before calling system. + * Return a pointer to the first unused character in the string + * (i.e. past the '\n' if there was one, to the '\0' otherwise). + */ +const char * +dc_system DC_DECLARG((s)) + const char *s DC_DECLEND +{ + const char *p; + char *tmpstr; + size_t len; + + p = strchr(s, '\n'); + if (p) { + len = p - s; + tmpstr = dc_malloc(len + 1); + strncpy(tmpstr, s, len); + tmpstr[len] = '\0'; + system(tmpstr); + free(tmpstr); + return p + 1; + } + system(s); + return s + strlen(s); +} + + +/* print out the indicated value */ +void +dc_print DC_DECLARG((value, obase, newline_p, discard_p)) + dc_data value DC_DECLSEP + int obase DC_DECLSEP + dc_newline newline_p DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + if (value.dc_type == DC_NUMBER) { + dc_out_num(value.v.number, obase, newline_p, discard_p); + } else if (value.dc_type == DC_STRING) { + dc_out_str(value.v.string, newline_p, discard_p); + } else { + dc_garbage("in data being printed", -1); + } +} + +/* return a duplicate of the passed value, regardless of type */ +dc_data +dc_dup DC_DECLARG((value)) + dc_data value DC_DECLEND +{ + if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING) + dc_garbage("in value being duplicated", -1); + if (value.dc_type == DC_NUMBER) + return dc_dup_num(value.v.number); + /*else*/ + return dc_dup_str(value.v.string); +} diff --git a/dc/numeric.c b/dc/numeric.c new file mode 100644 index 0000000..78b7eec --- /dev/null +++ b/dc/numeric.c @@ -0,0 +1,600 @@ +/* + * interface dc to the bc numeric routines + * + * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* This should be the only module that knows the internals of type dc_num */ +/* In this particular implementation we just slather out some glue and + * make use of bc's numeric routines. + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_LIMITS_H +# include +#else +# define UCHAR_MAX ((unsigned char)~0) +#endif +#include +#include "number.h" +#include "dc.h" +#include "dc-proto.h" + +#ifdef __GNUC__ +# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7) +# define ATTRIB(x) __attribute__(x) +# endif +#endif +#ifndef ATTRIB +# define ATTRIB(x) +#endif + +/* Forward prototype */ +static void out_char (int); + +/* there is no POSIX standard for dc, so we'll take the GNU definitions */ +int std_only = FALSE; + +/* convert an opaque dc_num into a real bc_num */ +#define CastNum(x) ((bc_num)(x)) + +/* add two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_add DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale ATTRIB((unused)) DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0); + return DC_SUCCESS; +} + +/* subtract two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_sub DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale ATTRIB((unused)) DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0); + return DC_SUCCESS; +} + +/* multiply two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_mul DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale); + return DC_SUCCESS; +} + +/* divide two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_div DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){ + fprintf(stderr, "%s: divide by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +/* divide two dc_nums, place quotient into *quotient and remainder + * into *remainder; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *quotient DC_DECLSEP + dc_num *remainder DC_DECLEND +{ + bc_init_num((bc_num *)quotient); + bc_init_num((bc_num *)remainder); + if (bc_divmod(CastNum(a), CastNum(b), + (bc_num *)quotient, (bc_num *)remainder, kscale)){ + fprintf(stderr, "%s: divide by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +/* place the reminder of dividing a by b into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_rem DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){ + fprintf(stderr, "%s: remainder by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +int +dc_modexp DC_DECLARG((base, expo, mod, kscale, result)) + dc_num base DC_DECLSEP + dc_num expo DC_DECLSEP + dc_num mod DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod), + (bc_num *)result, kscale)){ + if (bc_is_zero(CastNum(mod))) + fprintf(stderr, "%s: remainder by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +/* place the result of exponentiationg a by b into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_exp DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_init_num((bc_num *)result); + bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale); + return DC_SUCCESS; +} + +/* take the square root of the value, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_sqrt DC_DECLARG((value, kscale, result)) + dc_num value DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_num tmp; + + tmp = bc_copy_num(CastNum(value)); + if (!bc_sqrt(&tmp, kscale)){ + fprintf(stderr, "%s: square root of negative number\n", progname); + bc_free_num(&tmp); + return DC_DOMAIN_ERROR; + } + *((bc_num *)result) = tmp; + return DC_SUCCESS; +} + +/* compare dc_nums a and b; + * return a negative value if a < b; + * return a positive value if a > b; + * return zero value if a == b + */ +int +dc_compare DC_DECLARG((a, b)) + dc_num a DC_DECLSEP + dc_num b DC_DECLEND +{ + return bc_compare(CastNum(a), CastNum(b)); +} + +/* attempt to convert a dc_num to its corresponding int value + * If discard_p is DC_TOSS then deallocate the value after use. + */ +int +dc_num2int DC_DECLARG((value, discard_p)) + dc_num value DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + long result; + + result = bc_num2long(CastNum(value)); + if (discard_p == DC_TOSS) + dc_free_num(&value); + return (int)result; +} + +/* convert a C integer value into a dc_num */ +/* For convenience of the caller, package the dc_num + * into a dc_data result. + */ +dc_data +dc_int2data DC_DECLARG((value)) + int value DC_DECLEND +{ + dc_data result; + + bc_init_num(&result.v.number); + bc_int2num(&result.v.number, value); + result.dc_type = DC_NUMBER; + return result; +} + +/* get a dc_num from some input stream; + * input is a function which knows how to read the desired input stream + * ibase is the input base (2<=ibase<=DC_IBASE_MAX) + * *readahead will be set to the readahead character consumed while + * looking for the end-of-number + */ +/* For convenience of the caller, package the dc_num + * into a dc_data result. + */ +dc_data +dc_getnum DC_DECLARG((input, ibase, readahead)) + int (*input) DC_PROTO((void)) DC_DECLSEP + int ibase DC_DECLSEP + int *readahead DC_DECLEND +{ + bc_num base; + bc_num result; + bc_num build; + bc_num tmp; + bc_num divisor; + dc_data full_result; + int negative = 0; + int digit; + int decimal; + int c; + + bc_init_num(&tmp); + bc_init_num(&build); + bc_init_num(&base); + result = bc_copy_num(_zero_); + bc_int2num(&base, ibase); + c = (*input)(); + while (isspace(c)) + c = (*input)(); + if (c == '_' || c == '-'){ + negative = c; + c = (*input)(); + }else if (c == '+'){ + c = (*input)(); + } + while (isspace(c)) + c = (*input)(); + for (;;){ + if (isdigit(c)) + digit = c - '0'; + else if ('A' <= c && c <= 'F') + digit = 10 + c - 'A'; + else + break; + c = (*input)(); + bc_int2num(&tmp, digit); + bc_multiply(result, base, &result, 0); + bc_add(result, tmp, &result, 0); + } + if (c == '.'){ + bc_free_num(&build); + bc_free_num(&tmp); + divisor = bc_copy_num(_one_); + build = bc_copy_num(_zero_); + decimal = 0; + for (;;){ + c = (*input)(); + if (isdigit(c)) + digit = c - '0'; + else if ('A' <= c && c <= 'F') + digit = 10 + c - 'A'; + else + break; + bc_int2num(&tmp, digit); + bc_multiply(build, base, &build, 0); + bc_add(build, tmp, &build, 0); + bc_multiply(divisor, base, &divisor, 0); + ++decimal; + } + bc_divide(build, divisor, &build, decimal); + bc_add(result, build, &result, 0); + } + /* Final work. */ + if (negative) + bc_sub(_zero_, result, &result, 0); + + bc_free_num(&tmp); + bc_free_num(&build); + bc_free_num(&base); + if (readahead) + *readahead = c; + full_result.v.number = (dc_num)result; + full_result.dc_type = DC_NUMBER; + return full_result; +} + + +/* return the "length" of the number */ +int +dc_numlen DC_DECLARG((value)) + dc_num value DC_DECLEND +{ + bc_num num = CastNum(value); + + /* is this right??? */ + return num->n_len + num->n_scale - (*num->n_value == '\0'); +} + +/* return the scale factor of the passed dc_num + * If discard_p is DC_TOSS then deallocate the value after use. + */ +int +dc_tell_scale DC_DECLARG((value, discard_p)) + dc_num value DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + int kscale; + + kscale = CastNum(value)->n_scale; + if (discard_p == DC_TOSS) + dc_free_num(&value); + return kscale; +} + + +/* initialize the math subsystem */ +void +dc_math_init DC_DECLVOID() +{ + bc_init_numbers(); +} + +/* print out a dc_num in output base obase to stdout; + * if newline_p is DC_WITHNL, terminate output with a '\n'; + * if discard_p is DC_TOSS then deallocate the value after use + */ +void +dc_out_num DC_DECLARG((value, obase, newline_p, discard_p)) + dc_num value DC_DECLSEP + int obase DC_DECLSEP + dc_newline newline_p DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + out_char('\0'); /* clear the column counter */ + bc_out_num(CastNum(value), obase, out_char, 0); + if (newline_p == DC_WITHNL) + putchar ('\n'); + if (discard_p == DC_TOSS) + dc_free_num(&value); +} + +/* dump out the absolute value of the integer part of a + * dc_num as a byte stream, without any line wrapping; + * if discard_p is DC_TOSS then deallocate the value after use + */ +void +dc_dump_num DC_DECLARG((dcvalue, discard_p)) + dc_num dcvalue DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + struct digit_stack { int digit; struct digit_stack *link;}; + struct digit_stack *top_of_stack = NULL; + struct digit_stack *cur; + struct digit_stack *next; + bc_num value; + bc_num obase; + bc_num digit; + + bc_init_num(&value); + bc_init_num(&obase); + bc_init_num(&digit); + + /* we only handle the integer portion: */ + bc_divide(CastNum(dcvalue), _one_, &value, 0); + /* we only handle the absolute value: */ + value->n_sign = PLUS; + /* we're done with the dcvalue parameter: */ + if (discard_p == DC_TOSS) + dc_free_num(&dcvalue); + + bc_int2num(&obase, 1+UCHAR_MAX); + do { + (void) bc_divmod(value, obase, &value, &digit, 0); + cur = dc_malloc(sizeof *cur); + cur->digit = (int)bc_num2long(digit); + cur->link = top_of_stack; + top_of_stack = cur; + } while (!bc_is_zero(value)); + + for (cur=top_of_stack; cur; cur=next) { + putchar(cur->digit); + next = cur->link; + free(cur); + } + + bc_free_num(&digit); + bc_free_num(&obase); + bc_free_num(&value); +} + +/* deallocate an instance of a dc_num */ +void +dc_free_num DC_DECLARG((value)) + dc_num *value DC_DECLEND +{ + bc_free_num((bc_num *)value); +} + +/* return a duplicate of the number in the passed value */ +/* The mismatched data types forces the caller to deal with + * bad dc_type'd dc_data values, and makes it more convenient + * for the caller to not have to do the grunge work of setting + * up a dc_type result. + */ +dc_data +dc_dup_num DC_DECLARG((value)) + dc_num value DC_DECLEND +{ + dc_data result; + + ++CastNum(value)->n_refs; + result.v.number = value; + result.dc_type = DC_NUMBER; + return result; +} + + + +/*---------------------------------------------------------------------------\ +| The rest of this file consists of stubs for bc routines called by numeric.c| +| so as to minimize the amount of bc code needed to build dc. | +| The bulk of the code was just lifted straight out of the bc source. | +\---------------------------------------------------------------------------*/ + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_STDARG_H +# include +#else +# include +#endif + + +int out_col = 0; + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\". */ + +static void +out_char (ch) + int ch; +{ + + if (ch == '\0') + { + out_col = 0; + } + else + { + out_col++; + if (out_col == 70) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + putchar (ch); + } +} + +/* Malloc could not get enough memory. */ + +void +out_of_memory() +{ + dc_memfail(); +} + +/* Runtime error will print a message and stop the machine. */ + +#ifdef HAVE_STDARG_H +#ifdef __STDC__ +void +rt_error (char *mesg, ...) +#else +void +rt_error (mesg) + char *mesg; +#endif +#else +void +rt_error (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + + fprintf (stderr, "Runtime error: "); +#ifdef HAVE_STDARG_H + va_start (args, mesg); +#else + va_start (args); +#endif + vfprintf (stderr, mesg, args); + va_end (args); + fprintf (stderr, "\n"); +} + + +/* A runtime warning tells of some action taken by the processor that + may change the program execution but was not enough of a problem + to stop the execution. */ + +#ifdef HAVE_STDARG_H +#ifdef __STDC__ +void +rt_warn (char *mesg, ...) +#else +void +rt_warn (mesg) + char *mesg; +#endif +#else +void +rt_warn (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + + fprintf (stderr, "Runtime warning: "); +#ifdef HAVE_STDARG_H + va_start (args, mesg); +#else + va_start (args); +#endif + vfprintf (stderr, mesg, args); + va_end (args); + fprintf (stderr, "\n"); +} diff --git a/dc/stack.c b/dc/stack.c new file mode 100644 index 0000000..1d8a9bf --- /dev/null +++ b/dc/stack.c @@ -0,0 +1,494 @@ +/* + * implement stack functions for dc + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* This module is the only one that knows what stacks (both the + * regular evaluation stack and the named register stacks) + * look like. + */ + +#include "config.h" + +#include +#ifdef HAVE_STDLIB_H +# include +#endif +#include "dc.h" +#include "dc-proto.h" +#include "dc-regdef.h" + +/* an oft-used error message: */ +#define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname) + + +/* simple linked-list implementaion suffices: */ +struct dc_list { + dc_data value; + struct dc_array *array; /* opaque */ + struct dc_list *link; +}; +typedef struct dc_list dc_list; + +/* the anonymous evaluation stack */ +static dc_list *dc_stack=NULL; + +/* the named register stacks */ +static dc_list *dc_register[DC_REGCOUNT]; + + +/* allocate a new dc_list item */ +static dc_list * +dc_alloc DC_DECLVOID() +{ + dc_list *result; + + result = dc_malloc(sizeof *result); + result->value.dc_type = DC_UNINITIALIZED; + result->array = NULL; + result->link = NULL; + return result; +} + + +/* check that there are two numbers on top of the stack, + * then call op with the popped numbers. Construct a dc_data + * value from the dc_num returned by op and push it + * on the stack. + * If the op call doesn't return DC_SUCCESS, then leave the stack + * unmodified. + */ +void +dc_binop DC_DECLARG((op, kscale)) + int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP + int kscale DC_DECLEND +{ + dc_data a; + dc_data b; + dc_data r; + + if (!dc_stack || !dc_stack->link){ + Empty_Stack; + return; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return; + } + (void)dc_pop(&b); + (void)dc_pop(&a); + if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){ + r.dc_type = DC_NUMBER; + dc_push(r); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + }else{ + /* op failed; restore the stack */ + dc_push(a); + dc_push(b); + } +} + +/* check that there are two numbers on top of the stack, + * then call op with the popped numbers. Construct two dc_data + * values from the dc_num's returned by op and push them + * on the stack. + * If the op call doesn't return DC_SUCCESS, then leave the stack + * unmodified. + */ +void +dc_binop2 DC_DECLARG((op, kscale)) + int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP + int kscale DC_DECLEND +{ + dc_data a; + dc_data b; + dc_data r1; + dc_data r2; + + if (!dc_stack || !dc_stack->link){ + Empty_Stack; + return; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return; + } + (void)dc_pop(&b); + (void)dc_pop(&a); + if ((*op)(a.v.number, b.v.number, kscale, + &r1.v.number, &r2.v.number) == DC_SUCCESS){ + r1.dc_type = DC_NUMBER; + dc_push(r1); + r2.dc_type = DC_NUMBER; + dc_push(r2); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + }else{ + /* op failed; restore the stack */ + dc_push(a); + dc_push(b); + } +} + +/* check that there are two numbers on top of the stack, + * then call dc_compare with the popped numbers. + * Return negative, zero, or positive based on the ordering + * of the two numbers. + */ +int +dc_cmpop DC_DECLVOID() +{ + int result; + dc_data a; + dc_data b; + + if (!dc_stack || !dc_stack->link){ + Empty_Stack; + return 0; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return 0; + } + (void)dc_pop(&b); + (void)dc_pop(&a); + result = dc_compare(b.v.number, a.v.number); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + return result; +} + +/* check that there are three numbers on top of the stack, + * then call op with the popped numbers. Construct a dc_data + * value from the dc_num returned by op and push it + * on the stack. + * If the op call doesn't return DC_SUCCESS, then leave the stack + * unmodified. + */ +void +dc_triop DC_DECLARG((op, kscale)) + int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP + int kscale DC_DECLEND +{ + dc_data a; + dc_data b; + dc_data c; + dc_data r; + + if (!dc_stack || !dc_stack->link || !dc_stack->link->link){ + Empty_Stack; + return; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER + || dc_stack->link->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return; + } + (void)dc_pop(&c); + (void)dc_pop(&b); + (void)dc_pop(&a); + if ((*op)(a.v.number, b.v.number, c.v.number, + kscale, &r.v.number) == DC_SUCCESS){ + r.dc_type = DC_NUMBER; + dc_push(r); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + dc_free_num(&c.v.number); + }else{ + /* op failed; restore the stack */ + dc_push(a); + dc_push(b); + dc_push(c); + } +} + + +/* initialize the register stacks to their initial values */ +void +dc_register_init DC_DECLVOID() +{ + int i; + + for (i=0; ilink; + if (n->value.dc_type == DC_NUMBER) + dc_free_num(&n->value.v.number); + else if (n->value.dc_type == DC_STRING) + dc_free_str(&n->value.v.string); + else + dc_garbage("in stack", -1); + dc_array_free(n->array); + free(n); + } + dc_stack = NULL; +} + +/* push a value onto the evaluation stack */ +void +dc_push DC_DECLARG((value)) + dc_data value DC_DECLEND +{ + dc_list *n = dc_alloc(); + + if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING) + dc_garbage("in data being pushed", -1); + n->value = value; + n->link = dc_stack; + dc_stack = n; +} + +/* push a value onto the named register stack */ +void +dc_register_push DC_DECLARG((stackid, value)) + int stackid DC_DECLSEP + dc_data value DC_DECLEND +{ + dc_list *n = dc_alloc(); + + stackid = regmap(stackid); + n->value = value; + n->link = dc_register[stackid]; + dc_register[stackid] = n; +} + +/* set *result to the value on the top of the evaluation stack */ +/* The caller is responsible for duplicating the value if it + * is to be maintained as anything more than a transient identity. + * + * DC_FAIL is returned if the stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_top_of_stack DC_DECLARG((result)) + dc_data *result DC_DECLEND +{ + if (!dc_stack){ + Empty_Stack; + return DC_FAIL; + } + if (dc_stack->value.dc_type!=DC_NUMBER + && dc_stack->value.dc_type!=DC_STRING) + dc_garbage("at top of stack", -1); + *result = dc_stack->value; + return DC_SUCCESS; +} + +/* set *result to a dup of the value on the top of the named register stack */ +/* + * DC_FAIL is returned if the named stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_register_get DC_DECLARG((regid, result)) + int regid DC_DECLSEP + dc_data *result DC_DECLEND +{ + dc_list *r; + + regid = regmap(regid); + r = dc_register[regid]; + if ( ! r ){ + fprintf(stderr, "%s: register ", progname); + dc_show_id(stderr, regid, " is empty\n"); + return DC_FAIL; + } + *result = dc_dup(r->value); + return DC_SUCCESS; +} + +/* set the top of the named register stack to the indicated value */ +/* If the named stack is empty, craft a stack entry to enter the + * value into. + */ +void +dc_register_set DC_DECLARG((regid, value)) + int regid DC_DECLSEP + dc_data value DC_DECLEND +{ + dc_list *r; + + regid = regmap(regid); + r = dc_register[regid]; + if ( ! r ) + dc_register[regid] = dc_alloc(); + else if (r->value.dc_type == DC_NUMBER) + dc_free_num(&r->value.v.number); + else if (r->value.dc_type == DC_STRING) + dc_free_str(&r->value.v.string); + else if (r->value.dc_type == DC_UNINITIALIZED) + ; + else + dc_garbage("", regid); + dc_register[regid]->value = value; +} + +/* pop from the evaluation stack + * + * DC_FAIL is returned if the stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_pop DC_DECLARG((result)) + dc_data *result DC_DECLEND +{ + dc_list *r; + + r = dc_stack; + if (!r){ + Empty_Stack; + return DC_FAIL; + } + if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING) + dc_garbage("at top of stack", -1); + *result = r->value; + dc_stack = r->link; + dc_array_free(r->array); + free(r); + return DC_SUCCESS; +} + +/* pop from the named register stack + * + * DC_FAIL is returned if the named stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_register_pop DC_DECLARG((stackid, result)) + int stackid DC_DECLSEP + dc_data *result DC_DECLEND +{ + dc_list *r; + + stackid = regmap(stackid); + r = dc_register[stackid]; + if (!r){ + fprintf(stderr, "%s: stack register ", progname); + dc_show_id(stderr, stackid, " is empty\n"); + return DC_FAIL; + } + if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING) + dc_garbage(" stack", stackid); + *result = r->value; + dc_register[stackid] = r->link; + dc_array_free(r->array); + free(r); + return DC_SUCCESS; +} + + +/* tell how many entries are currently on the evaluation stack */ +int +dc_tell_stackdepth DC_DECLVOID() +{ + dc_list *n; + int depth=0; + + for (n=dc_stack; n; n=n->link) + ++depth; + return depth; +} + + +/* return the length of the indicated data value; + * if discard_p is DC_TOSS, the deallocate the value when done + * + * The definition of a datum's length is deligated to the + * appropriate module. + */ +int +dc_tell_length DC_DECLARG((value, discard_p)) + dc_data value DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + int length; + + if (value.dc_type == DC_NUMBER){ + length = dc_numlen(value.v.number); + if (discard_p == DC_TOSS) + dc_free_num(&value.v.number); + } else if (value.dc_type == DC_STRING) { + length = dc_strlen(value.v.string); + if (discard_p == DC_TOSS) + dc_free_str(&value.v.string); + } else { + dc_garbage("in tell_length", -1); + /*NOTREACHED*/ + length = 0; /*just to suppress spurious compiler warnings*/ + } + return length; +} + + + +/* print out all of the values on the evaluation stack */ +void +dc_printall DC_DECLARG((obase)) + int obase DC_DECLEND +{ + dc_list *n; + + for (n=dc_stack; n; n=n->link) + dc_print(n->value, obase, DC_WITHNL, DC_KEEP); +} + + + + +/* get the current array head for the named array */ +struct dc_array * +dc_get_stacked_array DC_DECLARG((array_id)) + int array_id DC_DECLEND +{ + dc_list *r = dc_register[regmap(array_id)]; + return r ? r->array : NULL; +} + +/* set the current array head for the named array */ +void +dc_set_stacked_array DC_DECLARG((array_id, new_head)) + int array_id DC_DECLSEP + struct dc_array *new_head DC_DECLEND +{ + dc_list *r; + + array_id = regmap(array_id); + r = dc_register[array_id]; + if ( ! r ) + r = dc_register[array_id] = dc_alloc(); + r->array = new_head; +} diff --git a/dc/string.c b/dc/string.c new file mode 100644 index 0000000..a7f79a4 --- /dev/null +++ b/dc/string.c @@ -0,0 +1,211 @@ +/* + * implement string functions for dc + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: + * + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111 USA + */ + +/* This should be the only module that knows the internals of type dc_string */ + +#include "config.h" + +#include +#ifdef HAVE_STDDEF_H +# include /* ptrdiff_t */ +#else +# define ptrdiff_t size_t +#endif +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_STRING_H +# include /* memcpy */ +#else +# ifdef HAVE_MEMORY_H +# include /* memcpy, maybe */ +# else +# ifdef HAVE_STRINGS_H +# include /* memcpy, maybe */ +# endif +# endif +#endif +#include "dc.h" +#include "dc-proto.h" + +/* here is the completion of the dc_string type: */ +struct dc_string { + char *s_ptr; /* pointer to base of string */ + size_t s_len; /* length of counted string */ + int s_refs; /* reference count to cut down on memory use by duplicates */ +}; + + +/* return a duplicate of the string in the passed value */ +/* The mismatched data types forces the caller to deal with + * bad dc_type'd dc_data values, and makes it more convenient + * for the caller to not have to do the grunge work of setting + * up a dc_type result. + */ +dc_data +dc_dup_str DC_DECLARG((value)) + dc_str value DC_DECLEND +{ + dc_data result; + + ++value->s_refs; + result.v.string = value; + result.dc_type = DC_STRING; + return result; +} + +/* free an instance of a dc_str value */ +void +dc_free_str DC_DECLARG((value)) + dc_str *value DC_DECLEND +{ + struct dc_string *string = *value; + + if (--string->s_refs < 1){ + free(string->s_ptr); + free(string); + } +} + +/* Output a dc_str value. + * Add a trailing newline if "newline" is set. + * Free the value after use if discard_flag is set. + */ +void +dc_out_str DC_DECLARG((value, newline, discard_flag)) + dc_str value DC_DECLSEP + dc_newline newline DC_DECLSEP + dc_discard discard_flag DC_DECLEND +{ + fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout); + if (newline == DC_WITHNL) + putchar('\n'); + if (discard_flag == DC_TOSS) + dc_free_str(&value); +} + +/* make a copy of a string (base s, length len) + * into a dc_str value; return a dc_data result + * with this value + */ +dc_data +dc_makestring DC_DECLARG((s, len)) + const char *s DC_DECLSEP + size_t len DC_DECLEND +{ + dc_data result; + struct dc_string *string; + + string = dc_malloc(sizeof *string); + string->s_ptr = dc_malloc(len+1); + memcpy(string->s_ptr, s, len); + string->s_ptr[len] = '\0'; /* nul terminated for those who need it */ + string->s_len = len; + string->s_refs = 1; + result.v.string = string; + result.dc_type = DC_STRING; + return result; +} + +/* read a dc_str value from FILE *fp; + * if ldelim == rdelim, then read until a ldelim char or EOF is reached; + * if ldelim != rdelim, then read until a matching rdelim for the + * (already eaten) first ldelim is read. + * Return a dc_data result with the dc_str value as its contents. + */ +dc_data +dc_readstring DC_DECLARG((fp, ldelim, rdelim)) + FILE *fp DC_DECLSEP + int ldelim DC_DECLSEP + int rdelim DC_DECLEND +{ + static char *line_buf = NULL; /* a buffer to build the string in */ + static size_t buflen = 0; /* the current size of line_buf */ + int depth=1; + int c; + char *p; + const char *end; + + if (!line_buf){ + /* initial buflen should be large enough to handle most cases */ + buflen = 2016; + line_buf = dc_malloc(buflen); + } + p = line_buf; + end = line_buf + buflen; + for (;;){ + c = getc(fp); + if (c == EOF) + break; + else if (c == rdelim && --depth < 1) + break; + else if (c == ldelim) + ++depth; + if (p >= end){ + ptrdiff_t offset = p - line_buf; + /* buflen increment should be big enough + * to avoid execessive reallocs: + */ + buflen += 2048; + line_buf = realloc(line_buf, buflen); + if (!line_buf) + dc_memfail(); + p = line_buf + offset; + end = line_buf + buflen; + } + *p++ = c; + } + return dc_makestring(line_buf, (size_t)(p-line_buf)); +} + +/* return the base pointer of the dc_str value; + * This function is needed because no one else knows what dc_str + * looks like. + */ +const char * +dc_str2charp DC_DECLARG((value)) + dc_str value DC_DECLEND +{ + return value->s_ptr; +} + +/* return the length of the dc_str value; + * This function is needed because no one else knows what dc_str + * looks like, and strlen(dc_str2charp(value)) won't work + * if there's an embedded '\0'. + */ +size_t +dc_strlen DC_DECLARG((value)) + dc_str value DC_DECLEND +{ + return value->s_len; +} + + +/* initialize the strings subsystem */ +void +dc_string_init DC_DECLVOID() +{ + /* nothing to do for this implementation */ +} diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..a729cee --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,12 @@ +## Process this file with automake to produce Makefile.in + +info_TEXINFOS = bc.texi dc.texi +MAKEINFO = makeinfo --no-split + +MAINTAINERCLEANFILES = Makefile.in + +# FIXME: remove this when automake has been fixed to include these +# files automatically +EXTRA_DIST = bc.1 dc.1 + +man_MANS = bc.1 dc.1 diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..840d007 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,355 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +info_TEXINFOS = bc.texi dc.texi +MAKEINFO = makeinfo --no-split + +MAINTAINERCLEANFILES = Makefile.in + +# FIXME: remove this when automake has been fixed to include these +# files automatically +EXTRA_DIST = bc.1 dc.1 + +man_MANS = bc.1 dc.1 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +TEXI2DVI = texi2dvi +INFO_DEPS = bc.info dc.info +DVIS = bc.dvi dc.dvi +TEXINFOS = bc.texi dc.texi +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in texinfo.tex + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +.SUFFIXES: .dvi .info .ps .texi .texinfo .txi +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +bc.info: bc.texi +bc.dvi: bc.texi + + +dc.info: dc.texi +dc.dvi: dc.texi + + +DVIPS = dvips + +.texi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texi.dvi: + TEXINPUTS=.:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.texi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texinfo.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texinfo: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texinfo.dvi: + TEXINPUTS=.:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.txi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.txi.dvi: + TEXINPUTS=.:$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.txi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` +.dvi.ps: + $(DVIPS) $< -o $@ + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(infodir) + @list='$(INFO_DEPS)'; \ + for file in $$list; do \ + d=$(srcdir); \ + for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \ + if test -f $$d/$$ifile; then \ + echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \ + $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \ + else : ; fi; \ + done; \ + done + @$(POST_INSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\ + install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\ + done; \ + else : ; fi + +uninstall-info: + $(PRE_UNINSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + ii=yes; \ + else ii=; fi; \ + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + test -z "$ii" \ + || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \ + done + @$(NORMAL_UNINSTALL) + list='$(INFO_DEPS)'; \ + for file in $$list; do \ + (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \ + done + +dist-info: $(INFO_DEPS) + list='$(INFO_DEPS)'; \ + for base in $$list; do \ + d=$(srcdir); \ + for file in `cd $$d && eval echo $$base*`; do \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done; \ + done + +mostlyclean-aminfo: + -rm -f bc.aux bc.cp bc.cps bc.dvi bc.fn bc.fns bc.ky bc.kys bc.ps \ + bc.log bc.pg bc.toc bc.tp bc.tps bc.vr bc.vrs bc.op bc.tr \ + bc.cv bc.cn dc.aux dc.cp dc.cps dc.dvi dc.fn dc.fns dc.ky \ + dc.kys dc.ps dc.log dc.pg dc.toc dc.tp dc.tps dc.vr dc.vrs \ + dc.op dc.tr dc.cv dc.cn + +clean-aminfo: + +distclean-aminfo: + +maintainer-clean-aminfo: + cd $(srcdir) && for i in $(INFO_DEPS); do \ + rm -f $$i; \ + if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \ + rm -f $$i-[0-9]*; \ + fi; \ + done + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man1 +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = doc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info +info-am: $(INFO_DEPS) +info: info-am +dvi-am: $(DVIS) +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: install-info-am install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-info uninstall-man +uninstall: uninstall-am +all-am: Makefile $(INFO_DEPS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(mandir)/man1 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-aminfo mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-aminfo clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-aminfo distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-aminfo maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: install-info-am uninstall-info mostlyclean-aminfo \ +distclean-aminfo clean-aminfo maintainer-clean-aminfo install-man1 \ +uninstall-man1 install-man uninstall-man tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/bc.1 b/doc/bc.1 new file mode 100644 index 0000000..c0b03f7 --- /dev/null +++ b/doc/bc.1 @@ -0,0 +1,792 @@ +.\" +.\" bc.1 - the *roff document processor source for the bc manual +.\" +.\" This file is part of GNU bc. +.\" Copyright (C) 1991-1994, 1997, 2000 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, Inc. +.\" 59 Temple Place, Suite 330 +.\" Boston, MA 02111 USA +.\" +.\" You may contact the author by: +.\" e-mail: philnelson@acm.org +.\" us-mail: Philip A. Nelson +.\" Computer Science Department, 9062 +.\" Western Washington University +.\" Bellingham, WA 98226-9062 +.\" +.\" +.TH bc 1 .\" "Command Manual" v1.06 "Sept 12, 2000" +.SH NAME +bc - An arbitrary precision calculator language +.SH SYNTAX +\fBbc\fR [ \fB-hlwsqv\fR ] [long-options] [ \fI file ...\fR ] +.SH VERSION +This man page documents GNU bc version 1.06. +.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 "-h, --help" +Print the usage and exit. +.IP "-i, --interactive" +Force interactive mode. +.IP "-l, --mathlib" +Define the standard math library. +.IP "-w, --warn" +Give warnings for extensions to POSIX \fBbc\fR. +.IP "-s, --standard" +Process exactly the POSIX \fBbc\fR language. +.IP "-q, --quiet" +Do not print the normal GNU bc welcome. +.IP "-v, --version" +Print the version number and copyright and quit. +.SS NUMBERS +The most basic element in \fBbc\fR is the number. Numbers are +arbitrary precision numbers. This precision is both in the integer +part and the fractional part. All numbers are represented internally +in decimal and all computation is done in decimal. (This version +truncates results from divide and multiply operations.) There are two +attributes of numbers, the length and the scale. The length is the +total number of significant decimal digits in a number and the scale +is the total number of decimal digits after the decimal point. For +example: +.nf +.RS + .000001 has a length of 6 and scale of 6. + 1935.000 has a length of 7 and a scale of 3. +.RE +.fi +.SS VARIABLES +Numbers are stored in two types of variables, simple variables and +arrays. Both simple variables and array variables are named. Names +begin with a letter followed by any number of letters, digits and +underscores. All letters must be lower case. (Full alpha-numeric +names are an extension. In POSIX \fBbc\fR all names are a single +lower case letter.) The type of variable is clear by the context +because all array variable names will be followed by brackets ([]). +.PP +There are four special variables, \fBscale, ibase, obase,\fR and +\fBlast\fR. \fBscale\fR defines how some operations use digits after the +decimal point. The default value of \fBscale\fR is 0. \fBibase\fR +and \fBobase\fR define the conversion base for input and output +numbers. The default for both input and output is base 10. +\fBlast\fR (an extension) is a variable that has the value of the last +printed number. These will be discussed in further detail where +appropriate. All of these variables may have values assigned to them +as well as used in expressions. +.SS COMMENTS +Comments in \fBbc\fR start with the characters \fB/*\fR and end with +the characters \fB*/\fR. Comments may start anywhere and appear as a +single space in the input. (This causes comments to delimit other +input items. For example, a comment can not be found in the middle of +a variable name.) Comments include any newlines (end of line) between +the start and the end of the comment. +.PP +To support the use of scripts for \fBbc\fR, a single line comment has been +added as an extension. A single line comment starts at a \fB#\fR +character and continues to the next end of the line. The end of line +character is not part of the comment and is processed normally. +.SS EXPRESSIONS +The numbers are manipulated by expressions and statements. Since +the language was designed to be interactive, statements and expressions +are executed as soon as possible. There is no "main" program. Instead, +code is executed as it is encountered. (Functions, discussed in +detail later, are defined when encountered.) +.PP +A simple expression is just a constant. \fBbc\fR converts constants +into internal decimal numbers using the current input base, specified +by the variable \fBibase\fR. (There is an exception in functions.) +The legal values of \fBibase\fR are 2 through 16. Assigning a +value outside this range to \fBibase\fR will result in a value of 2 +or 16. Input numbers may contain the characters 0-9 and A-F. (Note: +They must be capitals. Lower case letters are variable names.) +Single digit numbers always have the value of the digit regardless of +the value of \fBibase\fR. (i.e. A = 10.) For multi-digit numbers, +\fBbc\fR changes all input digits greater or equal to ibase to the +value of \fBibase\fR-1. This makes the number \fBFFF\fR always be +the largest 3 digit number of the input base. +.PP +Full expressions are similar to many other high level languages. +Since there is only one kind of number, there are no rules for mixing +types. Instead, there are rules on the scale of expressions. Every +expression has a scale. This is derived from the scale of original +numbers, the operation performed and in many cases, the value of the +variable \fBscale\fR. Legal values of the variable \fBscale\fR are +0 to the maximum number representable by a C integer. +.PP +In the following descriptions of legal expressions, "expr" refers to a +complete expression and "var" refers to a simple or an array variable. +A simple variable is just a +.RS +\fIname\fR +.RE +and an array variable is specified as +.RS +\fIname\fR[\fIexpr\fR] +.RE +Unless specifically +mentioned the scale of the result is the maximum scale of the +expressions involved. +.IP "- expr" +The result is the negation of the expression. +.IP "++ var" +The variable is incremented by one and the new value is the result of +the expression. +.IP "-- var" +The variable +is decremented by one and the new value is the result of the +expression. +.IP "var ++" + The result of the expression is the value of +the variable and then the variable is incremented by one. +.IP "var --" +The result of the expression is the value of the variable and then +the variable is decremented by one. +.IP "expr + expr" +The result of the expression is the sum of the two expressions. +.IP "expr - expr" +The result of the expression is the difference of the two expressions. +.IP "expr * expr" +The result of the expression is the product of the two expressions. +.IP "expr / expr" +The result of the expression is the quotient of the two expressions. +The scale of the result is the value of the variable \fBscale\fR. +.IP "expr % expr" +The result of the expression is the "remainder" and it is computed in the +following way. To compute a%b, first a/b is computed to \fBscale\fR +digits. That result is used to compute a-(a/b)*b to the scale of the +maximum of \fBscale\fR+scale(b) and scale(a). If \fBscale\fR is set +to zero and both expressions are integers this expression is the +integer remainder function. +.IP "expr ^ expr" +The result of the expression is the value of the first raised to the +second. The second expression must be an integer. (If the second +expression is not an integer, a warning is generated and the +expression is truncated to get an integer value.) The scale of the +result is \fBscale\fR if the exponent is negative. If the exponent +is positive the scale of the result is the minimum of the scale of the +first expression times the value of the exponent and the maximum of +\fBscale\fR and the scale of the first expression. (e.g. scale(a^b) += min(scale(a)*b, max( \fBscale,\fR scale(a))).) It should be noted +that expr^0 will always return the value of 1. +.IP "( expr )" +This alters the standard precedence to force the evaluation of the +expression. +.IP "var = expr" +The variable is assigned the value of the expression. +.IP "var = expr" +This is equivalent to "var = var 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", where 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 +" ...", 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 causes the side effect of assigning the printed value to the +special variable \fBlast\fR. This allows the user to recover the +last value printed without having to retype the expression that +printed the number. Assigning to \fBlast\fR is legal and will +overwrite the last printed value with the assigned value. The newly +assigned value will remain until the next number is printed or another +value is assigned to \fBlast\fR. (Some installations may allow the +use of a single period (.) which is not part of a number as a short +hand notation for for \fBlast\fR.) +.IP "string" +The string is printed to the output. Strings start with a double quote +character and contain all characters until the next double quote character. +All characters are take literally, including any newline. No newline +character is printed after the string. +.IP "\fBprint\fR list" +The print statement (an extension) provides another method of output. +The "list" is a list of strings and expressions separated by commas. +Each string or expression is printed in the order of the list. No +terminating newline is printed. Expressions are evaluated and their +value is printed and assigned to the variable \fBlast\fR. Strings +in the print statement are printed to the output and may contain +special characters. Special characters start with the backslash +character (\e). The special characters recognized by \fBbc\fR are +"a" (alert or bell), "b" (backspace), "f" (form feed), "n" (newline), +"r" (carriage return), "q" (double quote), "t" (tab), and "\e" (backslash). +Any other character following the backslash will be ignored. +.IP "{ statement_list }" +This is the compound statement. It allows multiple statements to be +grouped together for execution. +.IP "\fBif\fR ( expression ) statement1 [\fBelse\fR statement2]" +The if statement evaluates the expression and executes statement1 or +statement2 depending on the value of the expression. If the expression +is non-zero, statement1 is executed. If statement2 is present and +the value of the expression is 0, then statement2 is executed. (The +else clause is an extension.) +.IP "\fBwhile\fR ( expression ) statement" +The while statement will execute the statement while the expression +is non-zero. It evaluates the expression before each execution of +the statement. Termination of the loop is caused by a zero +expression value or the execution of a break statement. +.IP "\fBfor\fR ( [expression1] ; [expression2] ; [expression3] ) statement" +The for statement controls repeated execution of the statement. +Expression1 is evaluated before the loop. Expression2 is evaluated +before each execution of the statement. If it is non-zero, the statement +is evaluated. If it is zero, the loop is terminated. After each +execution of the statement, expression3 is evaluated before the reevaluation +of expression2. If expression1 or expression3 are missing, nothing is +evaluated at the point they would be evaluated. +If expression2 is missing, it is the same as substituting +the value 1 for expression2. (The optional expressions are an +extension. POSIX \fBbc\fR requires all three expressions.) +The following is equivalent code for the for statement: +.nf +.RS +expression1; +while (expression2) { + statement; + expression3; +} +.RE +.fi +.IP "\fBbreak\fR" +This statement causes a forced exit of the most recent enclosing while +statement or for statement. +.IP "\fBcontinue\fR" +The continue statement (an extension) causes the most recent enclosing +for statement to start the next iteration. +.IP "\fBhalt\fR" +The halt statement (an extension) is an executed statement that causes +the \fBbc\fR processor to quit only when it is executed. For example, +"if (0 == 1) halt" will not cause \fBbc\fR to terminate because the halt is +not executed. +.IP "\fBreturn\fR" +Return the value 0 from a function. (See the section on functions.) +.IP "\fBreturn\fR ( expression )" +Return the value of the expression from a function. (See the section on +functions.) As an extension, the parenthesis are not required. +.SS PSEUDO STATEMENTS +These statements are not statements in the traditional sense. They are +not executed statements. Their function is performed at "compile" time. +.IP "\fBlimits\fR" +Print the local limits enforced by the local version of \fBbc\fR. This +is an extension. +.IP "\fBquit\fR" +When the quit statement is read, the \fBbc\fR processor +is terminated, regardless of where the quit statement is found. For +example, "if (0 == 1) quit" will cause \fBbc\fR to terminate. +.IP "\fBwarranty\fR" +Print a longer warranty notice. This is an extension. +.SS FUNCTIONS +Functions provide a method of defining a computation that can be executed +later. Functions in +.B bc +always compute a value and return it to the caller. Function definitions +are "dynamic" in the sense that a function is undefined until a definition +is encountered in the input. That definition is then used until another +definition function for the same name is encountered. The new definition +then replaces the older definition. A function is defined as follows: +.nf +.RS +\fBdefine \fIname \fB( \fIparameters \fB) { \fInewline +\fI auto_list statement_list \fB}\fR +.RE +.fi +A function call is just an expression of the form +"\fIname\fB(\fIparameters\fB)\fR". +.PP +Parameters are numbers or arrays (an extension). In the function definition, +zero or more parameters are defined by listing their names separated by +commas. Numbers are only call by value parameters. Arrays are only +call by variable. Arrays are specified in the parameter definition by +the notation "\fIname\fB[]\fR". In the function call, actual parameters +are full expressions for number parameters. The same notation is used +for passing arrays as for defining array parameters. The named array is +passed by variable to the function. Since function definitions are dynamic, +parameter numbers and types are checked when a function is called. Any +mismatch in number or types of parameters will cause a runtime error. +A runtime error will also occur for the call to an undefined function. +.PP +The \fIauto_list\fR is an optional list of variables that are for +"local" use. The syntax of the auto list (if present) is "\fBauto +\fIname\fR, ... ;". (The semicolon is optional.) Each \fIname\fR is +the name of an auto variable. Arrays may be specified by using the +same notation as used in parameters. These variables have their +values pushed onto a stack at the start of the function. The +variables are then initialized to zero and used throughout the +execution of the function. At function exit, these variables are +popped so that the original value (at the time of the function call) +of these variables are restored. The parameters are really auto +variables that are initialized to a value provided in the function +call. Auto variables are different than traditional local variables +because 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. +.PP +As an extension, the format of the definition has been slightly relaxed. +The standard requires the opening brace be on the same line as the +\fBdefine\fR keyword and all other parts must be on following lines. +This version of \fBbc\fR will allow any number of newlines before and +after the opening brace of the function. For example, the following +definitions are legal. +.nf +.RS +\f(CW +define d (n) { return (2*n); } +define d (n) + { return (2*n); } +\fR +.RE +.fi +.SS MATH LIBRARY +If \fBbc\fR is invoked with the \fB-l\fR option, a math library is preloaded +and the default scale is set to 20. The math functions will calculate their +results to the scale set at the time of their call. +The math library defines the following functions: +.IP "s (\fIx\fR)" +The sine of x, x is in radians. +.IP "c (\fIx\fR)" +The cosine of x, x is in radians. +.IP "a (\fIx\fR)" +The arctangent of x, arctangent returns radians. +.IP "l (\fIx\fR)" +The natural logarithm of x. +.IP "e (\fIx\fR)" +The exponential function of raising e to the value x. +.IP "j (\fIn,x\fR)" +The bessel function of integer order n of x. +.SS EXAMPLES +In /bin/sh, the following will assign the value of "pi" to the shell +variable \fBpi\fR. +.RS +\f(CW +pi=$(echo "scale=10; 4*a(1)" | bc -l) +\fR +.RE +.PP +The following is the definition of the exponential function used in the +math library. This function is written in POSIX \fBbc\fR. +.nf +.RS +\f(CW +scale = 20 + +/* Uses the fact that e^x = (e^(x/2))^2 + When x is small enough, we use the series: + e^x = 1 + x + x^2/2! + x^3/3! + ... +*/ + +define e(x) { + auto a, d, e, f, i, m, v, z + + /* Check the sign of x. */ + if (x<0) { + m = 1 + x = -x + } + + /* Precondition x. */ + z = scale; + scale = 4 + z + .44*x; + while (x > 1) { + f += 1; + x /= 2; + } + + /* Initialize the variables. */ + v = 1+x + a = x + d = 1 + + for (i=2; 1; i++) { + e = (a *= x) / (d *= i) + if (e == 0) { + if (f>0) while (f--) v = v*v; + scale = z + if (m) return (1/v); + return (v/1); + } + v += e + } +} +\fR +.RE +.fi +.PP +The following is code that uses the extended features of \fBbc\fR to +implement a simple program for calculating checkbook balances. This +program is best kept in a file so that it can be used many times +without having to retype it at every use. +.nf +.RS +\f(CW +scale=2 +print "\enCheck book program!\en" +print " Remember, deposits are negative transactions.\en" +print " Exit by a 0 transaction.\en\en" + +print "Initial balance? "; bal = read() +bal /= 1 +print "\en" +while (1) { + "current balance = "; bal + "transaction? "; trans = read() + if (trans == 0) break; + bal -= trans + bal /= 1 +} +quit +\fR +.RE +.fi +.PP +The following is the definition of the recursive factorial function. +.nf +.RS +\f(CW +define f (x) { + if (x <= 1) return (1); + return (f(x-1) * x); +} +\fR +.RE +.fi +.SS READLINE AND LIBEDIT OPTIONS +GNU \fBbc\fR can be compiled (via a configure option) to use the GNU +\fBreadline\fR input editor library or the BSD \fBlibedit\fR library. +This allows the user to do editing of lines before sending them +to \fBbc\fR. It also allows for a history of previous lines typed. +When this option is selected, \fBbc\fR has one more special variable. +This special variable, \fBhistory\fR is the number of lines of history +retained. For \fBreadline\fR, a value of -1 means that an unlimited +number of history lines are retained. Setting the value of +\fBhistory\fR to a positive number restricts the number of history +lines to the number given. The value of 0 disables the history +feature. The default value is 100. For more information, read the +user manuals for the GNU \fBreadline\fR, \fBhistory\fR and BSD \fBlibedit\fR +libraries. One can not enable both \fBreadline\fR and \fBlibedit\fR +at the same time. +.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 "return statement" +POSIX \fBbc\fR requires parentheses around the return expression. +.IP "array parameters" +POSIX \fBbc\fR does not (currently) support array parameters in full. +The POSIX grammar allows for arrays in function definitions, but does +not provide a method to specify an array as an actual parameter. (This +is most likely an oversight in the grammar.) Traditional implementations +of \fBbc\fR have only call by value array parameters. +.IP "function format" +POSIX \fBbc\fR requires the opening brace on the same line as the +\fBdefine\fR key word and the \fBauto\fR statement on the next line. +.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 "variable names" +The current limit on the number of unique names is 32767 for each of +simple variables, arrays and functions. +.SH ENVIRONMENT VARIABLES +The following environment variables are processed by \fBbc\fR: +.IP "POSIXLY_CORRECT" +This is the same as the \fB-s\fR option. +.IP "BC_ENV_ARGS" +This is another mechanism to get arguments to \fBbc\fR. The +format is the same as the command line arguments. These arguments +are processed first, so any files listed in the environent arguments +are processed before any command line argument files. This allows +the user to set up "standard" options and files to be processed +at every invocation of \fBbc\fR. The files in the environment +variables would typically contain function definitions for functions +the user wants defined every time \fBbc\fR is run. +.IP "BC_LINE_LENGTH" +This should be an integer specifing the number of characters in an +output line for numbers. This includes the backslash and newline characters +for long numbers. +.SH DIAGNOSTICS +If any file on the command line can not be opened, \fBbc\fR will report +that the file is unavailable and terminate. Also, there are compile +and run time diagnostics that should be self-explanatory. +.SH BUGS +Error recovery is not very good yet. +.PP +Email bug reports to +.BR bug-bc@gnu.org . +Be sure to include the word ``bc'' somewhere in the ``Subject:'' field. +.SH AUTHOR +.nf +Philip A. Nelson +philnelson@acm.org +.fi +.SH ACKNOWLEDGEMENTS +The author would like to thank Steve Sommars (Steve.Sommars@att.com) for +his extensive help in testing the implementation. Many great suggestions +were given. This is a much better product due to his involvement. diff --git a/doc/bc.info b/doc/bc.info new file mode 100644 index 0000000..2e6648b --- /dev/null +++ b/doc/bc.info @@ -0,0 +1,1004 @@ +This is bc.info, produced by makeinfo version 4.0 from bc.texi. + +START-INFO-DIR-ENTRY +* bc: (bc). An arbritrary precision calculator language +END-INFO-DIR-ENTRY + + + +File: bc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +* Menu: + +* Introduction:: +* Basic Elements:: +* Expressions:: +* Statements:: +* Functions:: +* Examples:: +* Readline and Libedit Options:: +* GNU `bc' and Other Implementations:: +* Limits:: +* Environment Variables:: + + +File: bc.info, Node: Introduction, Next: Basic Elements, Prev: Top, Up: Top + +Introduction +************ + +* Menu: + +* Description:: +* Command Line Options:: + + +File: bc.info, Node: Description, Next: Command Line Options, Prev: Introduction, Up: Introduction + +Description +=========== + + `bc' [ -hlwsqv ] [long-options] [ FILE ... ] + + `bc' 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. `bc' starts by processing code +from all the files listed on the command line in the order listed. +After all files have been processed, `bc' reads from the standard +input. All code is executed as it is read. (If a file contains a +command to halt the processor, `bc' will never read from the standard +input.) + + This version of `bc' contains several extensions beyond traditional +`bc' 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. + + The author would like to thank Steve Sommars +() for his extensive help in testing the +implementation. Many great suggestions were given. This is a much +better product due to his involvement. + + Email bug reports to . Be sure to include the word +"bc" somewhere in the "Subject:" field. + + +File: bc.info, Node: Command Line Options, Next: Numbers, Prev: Description, Up: Introduction + +Command Line Options +==================== + + `bc' takes the following options from the command line: +`-h, --help' + Print the usage and exit. + +`-l, --mathlib' + Define the standard math library. + +`-w, --warn' + Give warnings for extensions to POSIX `bc'. + +`-s, --standard' + Process exactly the POSIX `bc' language. + +`-q, --quiet' + Do not print the normal GNU `bc' welcome. + +`-v, --version' + Print the version number and copyright and quit. + + +File: bc.info, Node: Basic Elements, Next: Expressions, Prev: Introduction, Up: Top + +Basic Elements +************** + +* Menu: + +* Numbers:: +* Variables:: +* Comments:: + + +File: bc.info, Node: Numbers, Next: Variables, Prev: Command Line Options, Up: Basic Elements + +Numbers +======= + + The most basic element in `bc' 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, .000001 has a +length of 6 and scale of 6, while 1935.000 has a length of 7 and a scale +of 3. + + +File: bc.info, Node: Variables, Next: Comments, Prev: Numbers, Up: Basic Elements + +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 alphanumeric names +are an extension. In POSIX `bc' 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 ( [ ] ). + + There are four special variables, SCALE, IBASE, OBASE, and LAST. +SCALE defines how some operations use digits after the decimal point. +The default value of SCALE is 0. IBASE and OBASE define the conversion +base for input and output numbers. The default for both input and +output is base 10. LAST (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. + + +File: bc.info, Node: Comments, Prev: Variables, Up: Basic Elements + +Comments +======== + + Comments in `bc' start with the characters `/*' and end with the +characters `*/'. 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. + + To support the use of scripts for `bc', a single line comment has +been added as an extension. A single line comment starts at a `#' +character and continues to the next end of the line. The end of line +character is not part of the comment and is processed normally. + + +File: bc.info, Node: Expressions, Next: Statements, Prev: Basic Elements, Up: Top + +Expressions +*********** + +* Menu: + +* About Expressions and Special Variables:: +* Basic Expressions:: +* Relational Expressions:: +* Boolean Expressions:: +* Precedence:: +* Special Expressions:: + + +File: bc.info, Node: About Expressions and Special Variables, Next: Basic Expressions, Prev: Expressions, Up: Expressions + +About Expressions and Special Variables +======================================= + + 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.) + + A simple expression is just a constant. `bc' converts constants into +internal decimal numbers using the current input base, specified by the +variable IBASE. (There is an exception in functions.) The legal values +of IBASE are 2 through 16. Assigning a value outside this range to +IBASE 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 IBASE. (i.e. A = 10.) +For multi-digit numbers, `bc' changes all input digits greater or equal +to IBASE to the value of IBASE-1. This makes the number `FFF' always +be the largest 3 digit number of the input base. + + 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 SCALE. Legal values of the variable SCALE are 0 to the maximum +number representable by a C integer. + + +File: bc.info, Node: Basic Expressions, Next: Relational Expressions, Prev: About Expressions and Special Variables, Up: Expressions + +Basic Expressions +================= + + 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 + + NAME + + and an array variable is specified as + + NAME[EXPR] + + Unless specifically mentioned the scale of the result is the maximum +scale of the expressions involved. + +`- expr' + The result is the negation of the expression. + +`++ VAR' + The variable is incremented by one and the new value is the result + of the expression. + +`-- VAR' + The variable is decremented by one and the new value is the result + of the expression. + +`VAR ++' + The result of the expression is the value of the variable and then + the variable is incremented by one. + +`VAR --' + The result of the expression is the value of the variable and then + the variable is decremented by one. + +`expr + expr' + The result of the expression is the sum of the two expressions. + +`expr - expr' + The result of the expression is the difference of the two + expressions. + +`expr * expr' + The result of the expression is the product of the two expressions. + +`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 + `scale' + +`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 + SCALE digits. That result is used to compute a-(a/b)*b to the + scale of the maximum of SCALE+scale(b) and scale(a). If SCALE is + set to zero and both expressions are integers this expression is + the integer remainder function. + +`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 SCALE 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 + SCALE and the scale of the first expression. (e.g. scale(a^b) = + min(scale(a)*b, max(SCALE, scale(a))).) It should be noted that + expr^0 will always return the value of 1. + +`( expr )' + This alters the standard precedence to force the evaluation of the + expression. + +`VAR = expr' + The variable is assigned the value of the expression. + +`VAR = expr' + This is equivalent to "VAR = VAR expr" with the exception + that the "VAR" part is evaluated only once. This can make a + difference if "VAR" is an array. + + +File: bc.info, Node: Relational Expressions, Next: Boolean Expressions, Prev: Basic Expressions, Up: Expressions + +Relational Expressions +====================== + + 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 + +`expr1 < expr2' + The result is 1 if expr1 is strictly less than expr2. + +`expr1 <= expr2' + The result is 1 if expr1 is less than or equal to expr2. + +`expr1 > expr2' + The result is 1 if expr1 is strictly greater than expr2. + +`expr1 >= expr2' + The result is 1 if expr1 is greater than or equal to expr2. + +`expr1 == expr2' + The result is 1 if expr1 is equal to expr2. + +`expr1 != expr2' + The result is 1 if expr1 is not equal to expr2. + + +File: bc.info, Node: Boolean Expressions, Next: Precedence, Prev: Relational Expressions, Up: Expressions + +Boolean Expressions +=================== + + Boolean operations are also legal. (POSIX `bc' 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: + +`!expr' + The result is 1 if expr is 0. + +`expr && expr' + The result is 1 if both expressions are non-zero. + +`expr || expr' + The result is 1 if either expression is non-zero. + + +File: bc.info, Node: Precedence, Next: Special Expressions, Prev: Boolean Expressions, Up: Expressions + +Precedence +========== + + The expression precedence is as follows: (lowest to highest) + + || 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 + + This precedence was chosen so that POSIX compliant `bc' 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: + + a = 3 < 5 + + Most C programmers would assume this would assign the result of "3 < +5" (the value 1) to the variable "a". What this does in `bc' is assign +the value 3 to the variable "a" and then compare 3 to 5. It is best to +use parentheses when using relational and logical operators with the +assignment operators. + + +File: bc.info, Node: Special Expressions, Prev: Precedence, Up: Expressions + +Special Expressions +=================== + + There are a few more special expressions that are provided in `bc'. +These have to do with user-defined functions and standard functions. +They all appear as "NAME`('PARAMETERS`)'". *Note Functions::, for +user-defined functions. The standard functions are: + +`length ( expression )' + The value of the length function is the number of significant + digits in the expression. + +`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 IBASE for the conversion base. + +`scale ( expression )' + The value of the `scale' function is the number of digits after the + decimal point in the expression. + +`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. + + +File: bc.info, Node: Statements, Next: Functions, Prev: Expressions, Up: Top + +Statements +********** + +* Menu: + +* Pseudo Statements:: + + Statements (as in most algebraic languages) provide the sequencing of +expression evaluation. In `bc' 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 `bc'. 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 "\", where is the newline appears to `bc' 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 `bc' statements and what they do: (Things enclosed in brackets +( [ ] ) are optional parts of the statement.) + +EXPRESSION + This statement does one of two things. If the expression starts + with " ...", 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 OBASE. The legal + values for OBASE are 2 through BC_BASE_MAX (*note Environment + Variables::). For bases 2 through 16, the usual method of writing + numbers is used. For bases greater than 16, `bc' 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 "\" + as the last character on a line. The maximum number of characters + printed per line is 70. Due to the interactive nature of `bc', + printing a number causes the side effect of assigning the printed + value to the special variable LAST. This allows the user to + recover the last value printed without having to retype the + expression that printed the number. Assigning to LAST 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 LAST. (Some installations + may allow the use of a single period (.) which is not part of a + number as a short hand notation for for LAST.) + +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 taken literally, including + any newline. No newline character is printed after the string. + +`PRINT' 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 to the variable + `last'. 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 `bc' are "a" (alert or bell), "b" (backspace), "f" (form feed), + "n" (newline), "r" (carriage return), "q" (double quote), "t" + (tab), and "\e" (backslash). Any other character following the + backslash will be ignored. + +{ STATEMENT_LIST } + This is the compound statement. It allows multiple statements to + be grouped together for execution. + +`IF' ( EXPRESSION ) STATEMENT1 [`ELSE' 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.) + +`WHILE' ( 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. + +`FOR' ( [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 `bc' requires all three + expressions.) The following is equivalent code for the `for' + statement: + + expression1; + while (expression2) { + statement; + expression3; + } + +`BREAK' + This statement causes a forced exit of the most recent enclosing + `while' statement or `for' statement. + +`CONTINUE' + The `continue' statement (an extension) causes the most recent + enclosing `for' statement to start the next iteration. + +`HALT' + The `halt' statement (an extension) is an executed statement that + causes the `bc' processor to quit only when it is executed. For + example, "if (0 == 1) halt" will not cause `bc' to terminate + because the `halt' is not executed. + +`RETURN' + Return the value 0 from a function. (*Note Functions::.) + +`RETURN' ( EXPRESSION ) + Return the value of the expression from a function. (*Note + Functions::.) As an extension, the parenthesis are not required. + + +File: bc.info, Node: Pseudo Statements, Prev: Statements, Up: Statements + +Pseudo Statements +================= + + These statements are not statements in the traditional sense. They +are not executed statements. Their function is performed at "compile" +time. + +`limits' + Print the local limits enforced by the local version of `bc'. This + is an extension. + +`quit' + When the `quit' statement is read, the `bc' processor is + terminated, regardless of where the `quit' statement is found. For + example, "if (0 == 1) quit" will cause `bc' to terminate. + +`warranty' + Print a longer warranty notice. This is an extension. + + +File: bc.info, Node: Functions, Next: Examples, Prev: Statements, Up: Top + +Functions +********* + +* Menu: + +* Math Library Functions:: + + Functions provide a method of defining a computation that can be +executed later. Functions in `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: + + `define' NAME `(' PARAMETERS `)' `{' NEWLINE + AUTO_LIST STATEMENT_LIST `}' + + A function call is just an expression of the form "`name' +`('PARAMETERS`)'". + + 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 "NAME`[ ]'". 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. + + The AUTO_LIST is an optional list of variables that are for "local" +use. The syntax of the auto list (if present) is "`auto' NAME, ... ;". +(The semicolon is optional.) Each NAME 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 because 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, `bc' supports +recursive functions. + + The function body is a list of `bc' 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, "`return'", returns +the value 0 to the calling expression. The second form, "`return' ( +EXPRESSION )", computes the value of the expression and returns that +value to the calling expression. There is an implied "`return' (0)" at +the end of every function. This allows a function to terminate and +return 0 without an explicit `return' statement. + + Functions also change the usage of the variable IBASE. All +constants in the function body will be converted using the value of +IBASE at the time of the function call. Changes of IBASE will be +ignored during the execution of the function except for the standard +function `read', which will always use the current value of IBASE for +conversion of numbers. + + As an extension, the format of the definition has been slightly +relaxed. The standard requires the opening brace be on the same line +as the `define' keyword and all other parts must be on following lines. +This version of `bc' will allow any number of newlines before and after +the opening brace of the function. For example, the following +definitions are legal. + + define d (n) { return (2*n); } + define d (n) + { return (2*n); } + + +File: bc.info, Node: Math Library Functions, Prev: Functions, Up: Functions + +Math Library Functions +====================== + + If `bc' is invoked with the `-l' 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: + +`s (X)' + The sine of X, X is in radians. + +`c (X)' + The cosine of X, X is in radians. + +`a (X)' + The arctangent of X, arctangent returns radians. + +`l (X)' + The natural logarithm of X. + +`E (X)' + The exponential function of raising E to the value X. + +`J (N,X)' + The bessel function of integer order N of X. + + +File: bc.info, Node: Examples, Next: Readline and Libedit Options, Prev: Functions, Up: Top + +Examples +******** + + In /bin/sh, the following will assign the value of "pi" to the shell +variable PI. + + pi=$(echo "scale=10; 4*a(1)" | bc -l) + + The following is the definition of the exponential function used in +the math library. This function is written in POSIX `bc'. + + + 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 + } + } + + The following is code that uses the extended features of `bc' 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. + + + scale=2 + print "\nCheck book program\n!" + print " Remember, deposits are negative transactions.\n" + print " Exit by a 0 transaction.\n\n" + + print "Initial balance? "; bal = read() + bal /= 1 + print "\n" + while (1) { + "current balance = "; bal + "transaction? "; trans = read() + if (trans == 0) break; + bal -= trans + bal /= 1 + } + quit + + The following is the definition of the recursive factorial function. + + + define f (x) { + if (x <= 1) return (1); + return (f(x-1) * x); + } + + +File: bc.info, Node: Readline and Libedit Options, Next: GNU `bc' and Other Implementations, Prev: Examples, Up: Top + +Readline and Libedit Options +**************************** + + GNU `bc' can be compiled (via a configure option) to use the GNU +`readline' input editor library or the BSD `libedit' library. This +allows the user to do more editing of lines before sending them to +`bc'. It also allows for a history of previous lines typed. When this +option is selected, `bc' has one more special variable. This special +variable, HISTORY is the number of lines of history retained. A value +of -1 means that an unlimited number of history lines are retained. +This is the default value. Setting the value of HISTORY to a positive +number restricts the number of history lines to the number given. The +value of 0 disables the history feature. For more information, read +the user manuals for the GNU `readline', `history' and BSD `libedit' +libraries. One can not enable both `readline' and `libedit' at the +same time. + + +File: bc.info, Node: GNU `bc' and Other Implementations, Next: Limits, Prev: Readline and Libedit Options, Up: Top + +GNU `bc' and Other Implementations +********************************** + + This version of `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 `dc'. 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. + + 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. + +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_. + +NAMES + Traditional and POSIX `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. + +STRINGS + Strings are not allowed to contain NUL characters. POSIX says all + characters must be included in strings. + +LAST + POSIX `bc' does not have a \fBlast variable. Some implementations + of `bc' use the period (.) in a similar way. + +COMPARISONS + POSIX `bc' 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. + +IF STATEMENT, ELSE CLAUSE + POSIX `bc' does not have an `else' clause. + +FOR STATEMENT + POSIX `bc' requires all expressions to be present in the `for' + statement. + +&&, ||, ! + POSIX `bc' does not have the logical operators. + +READ FUNCTION + POSIX `bc' does not have a `read' function. + +PRINT STATEMENT + POSIX `bc' does not have a `print' statement. + +CONTINUE STATEMENT + POSIX `bc' does not have a continue statement. + +ARRAY PARAMETERS + POSIX `bc' does not (currently) support array parameters in full. + The POSIX grammar allows for arrays in function definitions, but + does not provide a method to specify an array as an actual + parameter. (This is most likely an oversight in the grammar.) + Traditional implementations of `bc' have only call by value array + parameters. + +FUNCTION FORMAT + POSIX `bc' requires the opening brace on the same line as the + `define' key word and the `auto' statement on the next line. + +=+, =-, =*, =/, =%, =^ + POSIX `bc' 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 `a' by + 1 instead of setting `a' to the value -1. + +SPACES IN NUMBERS + Other implementations of `bc' 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 `bc'. + +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, + + a = 1 + b = 2 + + has two execution blocks and + + { a = 1 + b = 2 } + + 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. + +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 `bc' 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 `bc'. + + +File: bc.info, Node: Limits, Next: Environment Variables, Prev: GNU `bc' and Other Implementations, Up: Top + +Limits +****** + + The following are the limits currently in place for this `bc' +processor. Some of them may have been changed by an installation. Use +the `limits' statement to see the actual values. + +`BC_BASE_MAX' + The maximum output base is currently set at 999. The maximum + input base is 16. + +`BC_DIM_MAX' + This is currently an arbitrary limit of 65535 as distributed. Your + installation may be different. + +`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. + +`BC_STRING_MAX' + The limit on the number of characters in a string is INT_MAX + characters. + +`exponent' + The value of the exponent in the raise operation (^) is limited to + LONG_MAX. + +`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. + +`variable names' + The current limit on the number of unique names is 32767 for each + of simple variables, arrays and functions. + + +File: bc.info, Node: Environment Variables, Prev: Limits, Up: Top + +Environment Variables +********************* + + The following environment variables are processed by `bc': + +`POSIXLY_CORRECT' + This is the same as the -s option (*note Command Line Options::). + +`BC_ENV_ARGS' + This is another mechanism to get arguments to `bc'. The format is + the same as the command line arguments. These arguments are + processed first, so any files listed in the environent arguments + are processed before any command line argument files. This allows + the user to set up "standard" options and files to be processed at + every invocation of `bc'. The files in the environment variables + would typically contain function definitions for functions the user + wants defined every time `bc' is run. + +`BC_LINE_LENGTH' + This should be an integer specifing the number of characters in an + output line for numbers. This includes the backslash and newline + characters for long numbers. + + + +Tag Table: +Node: Top65 +Node: Introduction354 +Node: Description515 +Node: Command Line Options1969 +Node: Basic Elements2533 +Node: Numbers2704 +Node: Variables3467 +Node: Comments4576 +Node: Expressions5317 +Node: About Expressions and Special Variables5597 +Node: Basic Expressions7333 +Node: Relational Expressions10274 +Node: Boolean Expressions11279 +Node: Precedence11834 +Node: Special Expressions12994 +Node: Statements14376 +Node: Pseudo Statements21001 +Node: Functions21649 +Node: Math Library Functions25703 +Node: Examples26413 +Node: Readline and Libedit Options28431 +Node: GNU `bc' and Other Implementations29458 +Node: Limits34700 +Node: Environment Variables35953 + +End Tag Table diff --git a/doc/bc.texi b/doc/bc.texi new file mode 100644 index 0000000..a7cb9f6 --- /dev/null +++ b/doc/bc.texi @@ -0,0 +1,1014 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename bc.info +@settitle bc Command Manual +@c %**end of header + +@c This file has the new style title page commands. +@c Run `makeinfo' rather than `texinfo-format-buffer'. + +@smallbook + +@c tex +@c \overfullrule=0pt +@c end tex + +@titlepage +@title @command{bc} +@subtitle an arbitrary precision calculator language +@subtitle version 1.06 + +@author Philip A. Nelson +@page + +This manual documents @command{bc}, an arbitrary precision calculator language. + +This manual is part of GNU @command{bc}.@* +@sp4 +Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@iftex +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end iftex + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. + +You may contact the author by: +e-mail: @email{phil@@cs.wwu.edu}@* +us-mail: Philip A. Nelson@* +Computer Science Department, 9062@* +Western Washington University@* +Bellingham, WA 98226-9062 + +@end titlepage + +@node Top, Introduction, (dir), (dir) + +@menu +* Introduction:: +* Basic Elements:: +* Expressions:: +* Statements:: +* Functions:: +* Examples:: +* Readline and Libedit Options:: +* GNU @command{bc} and Other Implementations:: +* Limits:: +* Environment Variables:: +@end menu + +@node Introduction, Basic Elements, Top, Top +@chapter Introduction +@menu +* Description:: +* Command Line Options:: +@end menu + +@node Description, Command Line Options, Introduction, Introduction +@section Description + +@command{bc} [ -hlwsqv ] [long-options] [ @var{ file ...} ] + +@command{bc} 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. +@command{bc} starts by processing code from all the files listed +on the command line in the order listed. After all files have been +processed, @command{bc} reads from the standard input. All code is +executed as it is read. (If a file contains a command to halt the +processor, @command{bc} will never read from the standard input.) + +This version of @command{bc} contains several extensions beyond +traditional @command{bc} 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. + +The author would like to thank Steve Sommars +(@email{Steve.Sommars@@att.com}) for his extensive help in testing the +implementation. Many great suggestions were given. This is a much +better product due to his involvement. + +Email bug reports to @email{bug-bc@@gnu.org}. Be sure to include +the word ``bc'' somewhere in the ``Subject:'' field. + +@node Command Line Options, Numbers, Description, Introduction +@section Command Line Options + +@command{bc} takes the following options from the command line: +@table @code + +@item -h, --help +Print the usage and exit. + +@item -l, --mathlib +Define the standard math library. + +@item -w, --warn +Give warnings for extensions to POSIX @command{bc}. + +@item -s, --standard +Process exactly the POSIX @command{bc} language. + +@item -q, --quiet +Do not print the normal GNU @command{bc} welcome. + +@item -v, --version +Print the version number and copyright and quit. + +@end table + + +@node Basic Elements, Expressions, Introduction, Top +@chapter Basic Elements +@menu +* Numbers:: +* Variables:: +* Comments:: +@end menu + +@node Numbers, Variables, Command Line Options, Basic Elements +@section Numbers + +The most basic element in @command{bc} 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, .000001 has a +length of 6 and scale of 6, while 1935.000 has a length of 7 and a scale +of 3. + +@node Variables, Comments, Numbers, Basic Elements +@section 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 alphanumeric +names are an extension. In POSIX @command{bc} 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 ( [ ] ). + +There are four special variables, @var{scale}, @var{ibase}, @var{obase}, and +@var{last}. @var{scale} defines how some operations use digits after the +decimal point. The default value of @var{scale} is 0. @var{ibase} +and @var{obase} define the conversion base for input and output +numbers. The default for both input and output is base 10. +@var{last} (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. + +@node Comments, , Variables, Basic Elements +@section Comments + +Comments in @command{bc} start with the characters @code{/*} and end with +the characters @code{*/}. 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. + +To support the use of scripts for @command{bc}, a single line comment has been +added as an extension. A single line comment starts at a @code{#} +character and continues to the next end of the line. The end of line +character is not part of the comment and is processed normally. + +@node Expressions, Statements, Basic Elements, Top +@chapter Expressions + +@menu +* About Expressions and Special Variables:: +* Basic Expressions:: +* Relational Expressions:: +* Boolean Expressions:: +* Precedence:: +* Special Expressions:: +@end menu + +@node About Expressions and Special Variables, Basic Expressions, Expressions, Expressions +@section About Expressions and Special Variables + +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.) + +A simple expression is just a constant. @command{bc} converts constants +into internal decimal numbers using the current input base, specified by +the variable @var{ibase}. (There is an exception in functions.) The +legal values of @var{ibase} are 2 through 16. Assigning a value outside +this range to @var{ibase} 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 +@var{ibase}. (i.e. A = 10.) For multi-digit numbers, @command{bc} +changes all input digits greater or equal to @var{ibase} to the value of +@var{ibase}-1. This makes the number @code{FFF} always be the largest +3 digit number of the input base. + +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 @var{scale}. Legal values of the variable @var{scale} are +0 to the maximum number representable by a C integer. + +@node Basic Expressions, Relational Expressions, About Expressions and Special Variables, Expressions +@section Basic Expressions + +In the following descriptions of legal expressions, "expr" refers to a +complete expression and "@var{var}" refers to a simple or an array variable. +A simple variable is just a + +@var{name} + +and an array variable is specified as + +@var{name}[@var{expr}] + +Unless specifically mentioned the scale of the result is the maximum +scale of the expressions involved. + +@table @code +@item - expr +The result is the negation of the expression. + +@item ++ @var{var} +The variable is incremented by one and the new value is the result of +the expression. + +@item -- @var{var} +The variable +is decremented by one and the new value is the result of the +expression. + +@item @var{var} ++ + The result of the expression is the value of +the variable and then the variable is incremented by one. + +@item @var{var} -- +The result of the expression is the value of the variable and then +the variable is decremented by one. + +@item expr + expr +The result of the expression is the sum of the two expressions. + +@item expr - expr +The result of the expression is the difference of the two expressions. + +@item expr * expr +The result of the expression is the product of the two expressions. + +@item 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 @code{scale} + +@item 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 @var{scale} +digits. That result is used to compute a-(a/b)*b to the scale of the +maximum of @var{scale}+scale(b) and scale(a). If @var{scale} is set +to zero and both expressions are integers this expression is the +integer remainder function. + +@item 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 @var{scale} 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 +@var{scale} and the scale of the first expression. (e.g. scale(a^b) += min(scale(a)*b, max(@var{scale}, scale(a))).) It should be noted +that expr^0 will always return the value of 1. + +@item ( expr ) +This alters the standard precedence to force the evaluation of the +expression. + +@item @var{var} = expr +The variable is assigned the value of the expression. + +@item @var{var} = expr +This is equivalent to "@var{var} = @var{var} expr" with the +exception that the "@var{var}" part is evaluated only once. This can +make a difference if "@var{var}" is an array. +@end table + +@node Relational Expressions, Boolean Expressions, Basic Expressions, Expressions +@section Relational Expressions + +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 @command{bc} +requires that relational expressions are used only in @code{if}, +@code{while}, and @code{for} statements and that only one relational +test may be done in them.) The relational operators are + +@table @code +@item expr1 < expr2 +The result is 1 if expr1 is strictly less than expr2. + +@item expr1 <= expr2 +The result is 1 if expr1 is less than or equal to expr2. + +@item expr1 > expr2 +The result is 1 if expr1 is strictly greater than expr2. + +@item expr1 >= expr2 +The result is 1 if expr1 is greater than or equal to expr2. + +@item expr1 == expr2 +The result is 1 if expr1 is equal to expr2. + +@item expr1 != expr2 +The result is 1 if expr1 is not equal to expr2. +@end table + +@node Boolean Expressions, Precedence, Relational Expressions, Expressions +@section Boolean Expressions + +Boolean operations are also legal. (POSIX @command{bc} 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: + +@table @code +@item !expr +The result is 1 if expr is 0. + +@item expr && expr +The result is 1 if both expressions are non-zero. + +@item expr || expr +The result is 1 if either expression is non-zero. +@end table + +@node Precedence, Special Expressions, Boolean Expressions, Expressions +@section Precedence + +The expression precedence is as follows: (lowest to highest) + +@example +|| 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 +@end example + +This precedence was chosen so that POSIX compliant @command{bc} 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: + +@example +a = 3 < 5 +@end example + +Most C programmers would assume this would assign the result of "3 < +5" (the value 1) to the variable "a". What this does in @command{bc} is +assign the value 3 to the variable "a" and then compare 3 to 5. It is +best to use parentheses when using relational and logical operators +with the assignment operators. + +@node Special Expressions, , Precedence, Expressions +@section Special Expressions + +There are a few more special expressions that are provided in +@command{bc}. These have to do with user-defined functions and standard +functions. They all appear as +"@var{name}@code{(}@var{parameters}@code{)}". @xref{Functions}, for +user-defined functions. The standard functions are: + +@table @code +@item length ( expression ) +The value of the length function is the number of significant digits in the +expression. + +@item read ( ) +The @code{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 @code{read} function is the +number read from the standard input using the current value of the +variable @var{ibase} for the conversion base. + +@item scale ( expression ) +The value of the @code{scale} function is the number of digits after the +decimal point in the expression. + +@item sqrt ( expression ) +The value of the @code{sqrt} function is the square root of the +expression. If the expression is negative, a run time error is +generated. +@end table + +@node Statements, Functions, Expressions, Top +@chapter Statements + +@menu +* Pseudo Statements:: +@end menu + +Statements (as in most algebraic languages) provide the sequencing of +expression evaluation. In @command{bc} 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 @command{bc}. 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 "\", where is the newline appears to +@command{bc} 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 @command{bc} statements and what they do: (Things +enclosed in brackets ( [ ] ) are optional parts of the statement.) + +@table @var +@item expression +This statement does one of two things. If the expression starts with +" ...", 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 @var{obase}. The legal values for @var{obase} are 2 through +BC_BASE_MAX (@pxref{Environment Variables}). For bases 2 through 16, +the usual method of writing numbers is used. For bases greater than 16, +@command{bc} 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 +"@var{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 "\" as the last character +on a line. The maximum number of characters printed per line is 70. +Due to the interactive nature of @command{bc}, printing a number causes +the side effect of assigning the printed value to the special variable +@var{last}. This allows the user to recover the last value printed +without having to retype the expression that printed the number. +Assigning to @var{last} 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 +@var{last}. (Some installations may allow the use of a single period +(.) which is not part of a number as a short hand notation for for +@var{last}.) + +@item 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 taken literally, including any newline. No newline +character is printed after the string. + +@item @code{print} @var{list} +The @code{print} statement (an extension) provides another method of +output. The @var{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 to the variable @code{last}. 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 @command{bc} are "a" (alert or +bell), "b" (backspace), "f" (form feed), "n" (newline), "r" (carriage +return), "q" (double quote), "t" (tab), and "\e" (backslash). Any other +character following the backslash will be ignored. + +@item @{ statement_list @} +This is the compound statement. It allows multiple statements to be +grouped together for execution. + +@item @code{if} ( expression ) statement1 [@code{else} 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 +@code{else} clause is an extension.) + +@item @code{while} ( 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 @code{break} statement. + +@item @code{for} ( [expression1] ; [expression2] ; [expression3] ) statement +The @code{for} statement controls repeated execution of the statement. +@var{Expression1} is evaluated before the loop. @var{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, @var{expression3} is evaluated +before the reevaluation of expression2. If @var{expression1} or +@var{expression3} are missing, nothing is evaluated at the point they +would be evaluated. If @var{expression2} is missing, it is the same as +substituting the value 1 for @var{expression2}. (The optional +expressions are an extension. POSIX @command{bc} requires all three +expressions.) The following is equivalent code for the @code{for} +statement: + +@example +expression1; +while (expression2) @{ + statement; + expression3; +@} +@end example + +@item @code{break} +This statement causes a forced exit of the most recent enclosing @code{while} +statement or @code{for} statement. + +@item @code{continue} +The @code{continue} statement (an extension) causes the most recent enclosing +@code{for} statement to start the next iteration. + +@item @code{halt} +The @code{halt} statement (an extension) is an executed statement that +causes the @command{bc} processor to quit only when it is executed. For +example, "if (0 == 1) halt" will not cause @command{bc} to terminate +because the @code{halt} is not executed. + +@item @code{return} +Return the value 0 from a function. (@xref{Functions}.) + +@item @code{return} ( expression ) +Return the value of the expression from a function. (@xref{Functions}.) +As an extension, the parenthesis are not required. +@end table + +@node Pseudo Statements, , Statements, Statements +@section Pseudo Statements + +These statements are not statements in the traditional sense. They are +not executed statements. Their function is performed at "compile" time. + +@table @code +@item limits +Print the local limits enforced by the local version of @command{bc}. This +is an extension. + +@item quit +When the @code{quit} statement is read, the @command{bc} processor +is terminated, regardless of where the @code{quit} statement is found. For +example, "if (0 == 1) quit" will cause @command{bc} to terminate. + +@item warranty +Print a longer warranty notice. This is an extension. +@end table + +@node Functions, Examples, Statements, Top +@chapter Functions + +@menu +* Math Library Functions:: +@end menu + +Functions provide a method of defining a computation that can be +executed later. Functions in @command{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: + +@example +@code{define} @var{name} @code{(} @var{parameters} @code{)} @code{@{} @var{newline} + @var{auto_list statement_list} @code{@}} +@end example + +A function call is just an expression of the form +"@code{name} @code{(}@var{parameters}@code{)}". + +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 "@var{name}@code{[ ]}". 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. + +The @var{auto_list} is an optional list of variables that are for +"local" use. The syntax of the auto list (if present) is "@code{auto} +@var{name}, ... ;". (The semicolon is optional.) Each @var{name} 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 +because 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, @command{bc} supports recursive functions. + +The function body is a list of @command{bc} 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, "@code{return}", returns +the value 0 to the calling expression. The second form, +"@code{return} ( @var{expression} )", computes the value of the expression +and returns that value to the calling expression. There is an implied +"@code{return} (0)" at the end of every function. This allows a function +to terminate and return 0 without an explicit @code{return} statement. + +Functions also change the usage of the variable @var{ibase}. All +constants in the function body will be converted using the value of +@var{ibase} at the time of the function call. Changes of @var{ibase} +will be ignored during the execution of the function except for the +standard function @code{read}, which will always use the current value +of @var{ibase} for conversion of numbers. + +As an extension, the format of the definition has been slightly relaxed. +The standard requires the opening brace be on the same line as the +@code{define} keyword and all other parts must be on following lines. +This version of @command{bc} will allow any number of newlines before and +after the opening brace of the function. For example, the following +definitions are legal. + +@example + define d (n) @{ return (2*n); @} + define d (n) + @{ return (2*n); @} +@end example + + +@node Math Library Functions, , Functions, Functions +@section Math Library Functions + +If @command{bc} is invoked with the @code{-l} option, a math library is +preloaded and the default @var{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: + +@table @code +@item s (@var{x}) +The sine of @var{x}, @var{x} is in radians. + +@item c (@var{x}) +The cosine of @var{x}, @var{x} is in radians. + +@item a (@var{x}) +The arctangent of @var{x}, arctangent returns radians. + +@item l (@var{x}) +The natural logarithm of @var{x}. + +@item @var{e} (@var{x}) +The exponential function of raising @var{e} to the value @var{x}. + +@item @var{j} (@var{n,x}) +The bessel function of integer order @var{n} of @var{x}. +@end table + +@node Examples, Readline and Libedit Options, Functions, Top +@chapter Examples + +In /bin/sh, the following will assign the value of "pi" to the shell +variable @var{pi}. +@example + +pi=$(echo "scale=10; 4*a(1)" | bc -l) + +@end example + +The following is the definition of the exponential function used in the +math library. This function is written in POSIX @command{bc}. + +@example + +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 + @} +@} + +@end example + +The following is code that uses the extended features of @command{bc} 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. + +@example + +scale=2 +print "\nCheck book program\n!" +print " Remember, deposits are negative transactions.\n" +print " Exit by a 0 transaction.\n\n" + +print "Initial balance? "; bal = read() +bal /= 1 +print "\n" +while (1) @{ + "current balance = "; bal + "transaction? "; trans = read() + if (trans == 0) break; + bal -= trans + bal /= 1 +@} +quit + +@end example + + +The following is the definition of the recursive factorial function. + +@example + +define f (x) @{ + if (x <= 1) return (1); + return (f(x-1) * x); +@} + +@end example + +@node Readline and Libedit Options, GNU @command{bc} and Other Implementations, Examples, Top +@chapter Readline and Libedit Options + +GNU @command{bc} can be compiled (via a configure option) to use the GNU +@command{readline} input editor library or the BSD @command{libedit} +library. This allows the user to do +more editing of lines before sending them to @command{bc}. It also +allows for a history of previous lines typed. When this option is +selected, @command{bc} has one more special variable. This special +variable, @var{history} is the number of lines of history retained. A +value of -1 means that an unlimited number of history lines are +retained. This is the default value. Setting the value of +@var{history} to a positive number restricts the number of history lines +to the number given. The value of 0 disables the history feature. For +more information, read the user manuals for the GNU @command{readline}, +@command{history} and BSD @command{libedit} libraries. One can not +enable both @command{readline} and @command{libedit} at the same time. + +@node GNU @command{bc} and Other Implementations, Limits, Readline and Libedit Options, Top +@chapter GNU @command{bc} and Other Implementations + +This version of @command{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 @command{dc}. 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. + +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. + +@table @var + +@item 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_. + +@item names +Traditional and POSIX @command{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. + +@item Strings +Strings are not allowed to contain NUL characters. POSIX says all characters +must be included in strings. + +@item last +POSIX @command{bc} does not have a \fBlast variable. Some implementations +of @command{bc} use the period (.) in a similar way. + +@item comparisons +POSIX @command{bc} allows comparisons only in the @code{if} statement, +the @code{while} statement, and the second expression of the @code{for} +statement. Also, only one relational operation is allowed in each of +those statements. + +@item if statement, else clause +POSIX @command{bc} does not have an @code{else} clause. + +@item for statement +POSIX @command{bc} requires all expressions to be present in the +@code{for} statement. + +@item &&, ||, ! +POSIX @command{bc} does not have the logical operators. + +@item read function +POSIX @command{bc} does not have a @code{read} function. + +@item print statement +POSIX @command{bc} does not have a @code{print} statement. + +@item continue statement +POSIX @command{bc} does not have a continue statement. + +@item array parameters +POSIX @command{bc} does not (currently) support array parameters in full. +The POSIX grammar allows for arrays in function definitions, but does +not provide a method to specify an array as an actual parameter. (This +is most likely an oversight in the grammar.) Traditional implementations +of @command{bc} have only call by value array parameters. + +@item function format +POSIX @command{bc} requires the opening brace on the same line as the +@code{define} key word and the @code{auto} statement on the next line. + +@item =+, =-, =*, =/, =%, =^ +POSIX @command{bc} does not require these "old style" assignment +operators to be defined. This version may allow these "old style" +assignments. Use the @code{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 @code{a} by 1 instead +of setting @code{a} to the value -1. + +@item spaces in numbers +Other implementations of @command{bc} 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 @command{bc}. + +@item 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, + +@example +a = 1 +b = 2 +@end example + +has two execution blocks and + +@example +@{ a = 1 + b = 2 @} +@end example + +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. + +@item 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 @command{bc} 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 @command{bc}. +@end table + +@node Limits, Environment Variables, GNU @command{bc} and Other Implementations, Top +@chapter Limits + +The following are the limits currently in place for this @command{bc} +processor. Some of them may have been changed by an installation. Use +the @code{limits} statement to see the actual values. + +@table @code + +@item BC_BASE_MAX +The maximum output base is currently set at 999. The maximum input base +is 16. + +@item BC_DIM_MAX +This is currently an arbitrary limit of 65535 as distributed. Your +installation may be different. + +@item 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. + +@item BC_STRING_MAX +The limit on the number of characters in a string is INT_MAX characters. + +@item exponent +The value of the exponent in the raise operation (^) is limited to LONG_MAX. + +@item 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. + +@item variable names +The current limit on the number of unique names is 32767 for each of +simple variables, arrays and functions. +@end table + +@node Environment Variables, , Limits, Top +@chapter Environment Variables + +The following environment variables are processed by @command{bc}: + +@table @code + + +@item POSIXLY_CORRECT +This is the same as the -s option (@pxref{Command Line Options}). + +@item BC_ENV_ARGS +This is another mechanism to get arguments to @command{bc}. The format +is the same as the command line arguments. These arguments are +processed first, so any files listed in the environent arguments are +processed before any command line argument files. This allows the user +to set up "standard" options and files to be processed at every +invocation of @command{bc}. The files in the environment variables +would typically contain function definitions for functions the user +wants defined every time @command{bc} is run. + +@item BC_LINE_LENGTH +This should be an integer specifing the number of characters in an +output line for numbers. This includes the backslash and newline +characters for long numbers. +@end table + +@contents +@bye + + diff --git a/doc/dc.1 b/doc/dc.1 new file mode 100644 index 0000000..7a136a7 --- /dev/null +++ b/doc/dc.1 @@ -0,0 +1,488 @@ +.\" +.\" dc.1 - the *roff document processor source for the dc manual +.\" +.\" This file is part of GNU dc. +.\" Copyright (C) 1994, 1997, 1998, 2000 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, Inc. +.\" 59 Temple Place, Suite 330 +.\" Boston, MA 02111 USA +.\" +.TH DC 1 "1997-03-25" "GNU Project" +.ds dc \fIdc\fP +.ds Dc \fIDc\fP +.SH NAME +dc \- an arbitrary precision calculator +.SH SYNOPSIS +dc [-V] [--version] [-h] [--help] + [-e scriptexpression] [--expression=scriptexpression] + [-f scriptfile] [--file=scriptfile] + [file ...] +.SH DESCRIPTION +.PP +\*(Dc is a reverse-polish desk calculator which supports +unlimited precision arithmetic. +It also allows you to define and call macros. +Normally \*(dc reads from the standard input; +if any command arguments are given to it, they are filenames, +and \*(dc reads and executes the contents of the files before reading +from standard input. +All normal output is to standard output; +all error output is to standard error. +.PP +A reverse-polish calculator stores numbers on a stack. +Entering a number pushes it on the stack. +Arithmetic operations pop arguments off the stack and push the results. +.PP +To enter a number in +.IR dc , +type the digits with an optional decimal point. +Exponential notation is not supported. +To enter a negative number, +begin the number with ``_''. +``-'' cannot be used for this, +as it is a binary operator for subtraction instead. +To enter two numbers in succession, +separate them with spaces or newlines. +These have no meaning as commands. +.SH OPTIONS +\*(Dc may be invoked with the following command-line options: +.TP +.B -V +.TP +.B --version +Print out the version of \*(dc that is being run and a copyright notice, +then exit. +.TP +.B -h +.TP +.B --help +Print a usage message briefly summarizing these command-line options +and the bug-reporting address, +then exit. +.TP +.B -e \fIscript\fP +.TP +.BI --expression= script +Add the commands in +.I script +to the set of commands to be run while processing the input. +.TP +.B -f \fIscript-file\fP +.TP +.BI --file= script-file +Add the commands contained in the file +.I script-file +to the set of commands to be run while processing the input. +.PP +If any command-line parameters remain after processing the above, +these parameters are interpreted as the names of input files to +be processed. +A file name of +.B - +refers to the standard input stream. +The standard input will processed if no file names are specified. +.PD +.SH +Printing Commands +.TP +.B p +Prints the value on the top of the stack, +without altering the stack. +A newline is printed after the value. +.TP +.B n +Prints the value on the top of the stack, popping it off, +and does not print a newline after. +.TP +.B P +Pops off the value on top of the stack. +If it it a string, it is simply printed without a trailing newline. +Otherwise it is a number, and the integer portion of its absolute +value is printed out as a "base (UCHAR_MAX+1)" byte stream. +Assuming that (UCHAR_MAX+1) is 256 +(as it is on most machines with 8-bit bytes), +the sequence \fBKSK 0k1/ [_1*]sx d0>x [256~aPd0 r +Pops two values off the stack and compares them +assuming they are numbers, +executing the contents of register +.I r +as a macro if the original top-of-stack +is greater. +Thus, +.B 1 2>a +will invoke register +.BR a 's +contents and +.B 2 1>a +will not. +.TP +.BI !> r +Similar but invokes the macro if the original top-of-stack is +not greater than (less than or equal to) what was the second-to-top. +.TP +.BI < r +Similar but invokes the macro if the original top-of-stack is less. +.TP +.BI !< r +Similar but invokes the macro if the original top-of-stack is +not less than (greater than or equal to) what was the second-to-top. +.TP +.BI = r +Similar but invokes the macro if the two numbers popped are equal. +.TP +.BI != r +Similar but invokes the macro if the two numbers popped are not equal. +.ig +This can also be validly used to compare two strings for equality. +.. +.TP +.B ? +Reads a line from the terminal and executes it. +This command allows a macro to request input from the user. +.TP +.B q +exits from a macro and also from the macro which invoked it. +If called from the top level, +or from a macro which was called directly from the top level, +the +.B q +command will cause \*(dc to exit. +.TP +.B Q +Pops a value off the stack and uses it as a count +of levels of macro execution to be exited. +Thus, +.B 3Q +exits three levels. +The +.B Q +command will never cause \*(dc to exit. +.SH +Status Inquiry +.TP +.B Z +Pops a value off the stack, +calculates the number of digits it has +(or number of characters, if it is a string) +and pushes that number. +.TP +.B X +Pops a value off the stack, +calculates the number of fraction digits it has, +and pushes that number. +For a string, +the value pushed is +.\" -1. +0. +.TP +.B z +Pushes the current stack depth: +the number of objects on the stack before the execution of the +.B z +command. +.SH +Miscellaneous +.TP +.B ! +Will run the rest of the line as a system command. +Note that parsing of the !<, !=, and !> commands take precedence, +so if you want to run a command starting with <, =, or > you will +need to add a space after the !. +.TP +.B # +Will interpret the rest of the line as a comment. +.TP +.BI : r +Will pop the top two values off of the stack. +The old second-to-top value will be stored in the array +.IR r , +indexed by the old top-of-stack value. +.TP +.BI ; r +Pops the top-of-stack and uses it as an index into +the array +.IR r . +The selected value is then pushed onto the stack. +.P +Note that each stacked instance of a register has its own +array associated with it. +Thus \fB1 0:a 0Sa 2 0:a La 0;ap\fP will print 1, +because the 2 was stored in an instance of 0:a that +was later popped. +.SH +BUGS +.PP +Email bug reports to +.BR bug-dc@gnu.org . diff --git a/doc/dc.info b/doc/dc.info new file mode 100644 index 0000000..050a6b3 --- /dev/null +++ b/doc/dc.info @@ -0,0 +1,441 @@ +This is dc.info, produced by makeinfo version 4.0 from dc.texi. + +START-INFO-DIR-ENTRY +* dc: (dc). Arbritrary precision RPN "Desktop Calculator". +END-INFO-DIR-ENTRY + This file documents DC, an arbitrary precision calculator. + + Published by the Free Software Foundation, Inc. 59 Temple Place, +Suite 330 Boston, MA 02111 USA + + Copyright (C) 1984, 1994, 1997, 1998, 2000 Free Software Foundation, +Inc. + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the Foundation. + + +File: dc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +* Menu: + +* Introduction:: Introduction +* Invocation:: Invocation +* Printing Commands:: Printing Commands +* Arithmetic:: Arithmetic +* Stack Control:: Stack Control +* Registers:: Registers +* Parameters:: Parameters +* Strings:: Strings +* Status Inquiry:: Status Inquiry +* Miscellaneous:: Other commands +* Reporting bugs:: Reporting bugs + + +File: dc.info, Node: Introduction, Next: Invocation, Prev: Top, Up: Top + +Introduction +************ + + DC is a reverse-polish desk calculator which supports unlimited +precision arithmetic. It also allows you to define and call macros. +Normally DC reads from the standard input; if any command arguments are +given to it, they are filenames, and DC reads and executes the contents +of the files instead of reading from standard input. All normal output +is to standard output; all error messages are written to standard error. + + To exit, use `q'. `C-c' does not exit; it is used to abort macros +that are looping, etc. (Currently this is not true; `C-c' does exit.) + + A reverse-polish calculator stores numbers on a stack. Entering a +number pushes it on the stack. Arithmetic operations pop arguments off +the stack and push the results. + + To enter a number in DC, type the digits, with an optional decimal +point. Exponential notation is not supported. To enter a negative +number, begin the number with `_'. `-' cannot be used for this, as it +is a binary operator for subtraction instead. To enter two numbers in +succession, separate them with spaces or newlines. These have no +meaning as commands. + + +File: dc.info, Node: Invocation, Next: Printing Commands, Prev: Introduction, Up: Top + +Invocation +********** + + DC may be invoked with the following command-line options: +`-e EXPR' + +`--expression=EXPR' + Evaluate EXPR as DC commands. + +`-f FILE' + +`--file=FILE' + Read and evaluate DC commands from FILE. + +`-h' + +`--help' + Print a usage message summarizing the command-line options, then + exit. + +`-V' + +`--version' + Print the version information for this program, then exit. + + If any command-line parameters remain after processing the options, +these parameters are interpreted as additional FILEs whose contents are +read and evaluated. A file name of `-' refers to the standard input +stream. If no `-e' option was specified, and no files were specified, +then the standard input will be read for commands to evaluate. + + +File: dc.info, Node: Printing Commands, Next: Arithmetic, Prev: Invocation, Up: Top + +Printing Commands +***************** + +`p' + Prints the value on the top of the stack, without altering the + stack. A newline is printed after the value. + +`n' + Prints the value on the top of the stack, popping it off, and does + not print a newline after. (This command is a GNU extension.) + +`P' + Pops off the value on top of the stack. If it it a string, it is + simply printed without a trailing newline. Otherwise it is a + number, and the integer portion of its absolute value is printed + out as a "base (UCHAR_MAX+1)" byte stream. Assuming that + (UCHAR_MAX+1) is 256 (as it is on most machines with 8-bit bytes), + the sequence `KSK 0k1/ [_1*]sx d0>x [256~aPd0R' + Pops two values off the stack and compares them assuming they are + numbers, executing the contents of register R as a macro if the + original top-of-stack is greater. Thus, `1 2>a' will invoke + register `a''s contents and `2 1>a' will not. + +`!>R' + Similar but invokes the macro if the original top-of-stack is not + greater (is less than or equal to) what was the second-to-top. + +` commands take precidence, so if you + want to run a command starting with <, =, or > you will need to + add a space after the !. + +`#' + Will interpret the rest of the line as a comment. (This command + is a GNU extension.) + +`:R' + Will pop the top two values off of the stack. The old + second-to-top value will be stored in the array R, indexed by the + old top-of-stack value. + +`;R' + Pops the top-of-stack and uses it as an index into the array R. + The selected value is then pushed onto the stack. + + Note that each stacked instance of a register has its own array +associated with it. Thus `1 0:A 0SA 2 0:A LA 0;Ap' will print 1, +because the 2 was stored in an instance of 0:A that was later popped. + + +File: dc.info, Node: Reporting bugs, Prev: Miscellaneous, Up: Top + +Reporting bugs +************** + + Email bug reports to . + + + +Tag Table: +Node: Top1084 +Node: Introduction1663 +Node: Invocation2880 +Node: Printing Commands3724 +Node: Arithmetic4902 +Node: Stack Control7815 +Node: Registers8228 +Node: Parameters9154 +Node: Strings10415 +Node: Status Inquiry13385 +Node: Miscellaneous13942 +Node: Reporting bugs14909 + +End Tag Table diff --git a/doc/dc.texi b/doc/dc.texi new file mode 100644 index 0000000..0a4d973 --- /dev/null +++ b/doc/dc.texi @@ -0,0 +1,526 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename dc.info +@settitle dc, an arbitrary precision calculator +@c %**end of header + +@c This file has the new style title page commands. +@c Run `makeinfo' rather than `texinfo-format-buffer'. + +@c smallbook + +@c tex +@c \overfullrule=0pt +@c end tex + +@c Combine indices. +@synindex cp fn +@syncodeindex vr fn +@syncodeindex ky fn +@syncodeindex pg fn +@syncodeindex tp fn + +@ifinfo +@direntry +* dc: (dc). Arbritrary precision RPN ``Desktop Calculator''. +@end direntry +This file documents @sc{dc}, an arbitrary precision calculator. + +Published by the Free Software Foundation, Inc. +59 Temple Place, Suite 330 +Boston, MA 02111 USA + +Copyright (C) 1984, 1994, 1997, 1998, 2000 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@setchapternewpage off + +@titlepage +@title dc, an arbitrary precision calculator + +@author by Ken Pizzini +@author original manual by Richard Stallman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1994, 1997, 1998 Free Software Foundation, Inc. + +@sp 2 +Published by the Free Software Foundation, @* +59 Temple Place, Suite 330 @* +Boston, MA 02111 USA + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. + +@end titlepage +@page + +@node Top, Introduction, (dir), (dir) + +@menu +* Introduction:: Introduction +* Invocation:: Invocation +* Printing Commands:: Printing Commands +* Arithmetic:: Arithmetic +* Stack Control:: Stack Control +* Registers:: Registers +* Parameters:: Parameters +* Strings:: Strings +* Status Inquiry:: Status Inquiry +* Miscellaneous:: Other commands +* Reporting bugs:: Reporting bugs +@end menu + +@node Introduction, Invocation, Top, Top +@comment node-name, next, previous, up +@chapter Introduction + +@sc{dc} is a reverse-polish desk calculator +which supports unlimited precision arithmetic. +It also allows you to define and call macros. +Normally @sc{dc} reads from the standard input; +if any command arguments are given to it, they are filenames, +and @sc{dc} reads and executes the contents of the files +instead of reading from standard input. +All normal output is to standard output; +all error messages are written to standard error. + +To exit, use @samp{q}. +@kbd{C-c} does not exit; +it is used to abort macros that are looping, etc. +(Currently this is not true; @kbd{C-c} does exit.) + +A reverse-polish calculator stores numbers on a stack. +Entering a number pushes it on the stack. +Arithmetic operations pop arguments off the stack and push the results. + +To enter a number in @sc{dc}, type the digits, +with an optional decimal point. +Exponential notation is not supported. +To enter a negative number, begin the number with @samp{_}. +@samp{-} cannot be used for this, as it is a binary operator +for subtraction instead. +To enter two numbers in succession, +separate them with spaces or newlines. +These have no meaning as commands. + +@node Invocation, Printing Commands, Introduction, Top +@chapter Invocation + +@sc{dc} may be invoked with the following command-line options: +@table @samp + +@item -e @var{expr} +@item --expression=@var{expr} +Evaluate @var{expr} as @sc{dc} commands. + +@item -f @var{file} +@item --file=@var{file} +Read and evaluate @sc{dc} commands from @var{file}. + +@item -h +@item --help +Print a usage message summarizing the command-line options, then exit. + +@item -V +@item --version +Print the version information for this program, then exit. +@end table + +If any command-line parameters remain after processing the options, +these parameters are interpreted as additional @var{file}s whose +contents are read and evaluated. +A file name of @code{-} refers to the standard input stream. +If no @code{-e} option was specified, and no files were specified, +then the standard input will be read for commands to evaluate. + +@node Printing Commands, Arithmetic, Invocation, Top +@chapter Printing Commands + +@table @samp +@item p +Prints the value on the top of the stack, +without altering the stack. +A newline is printed after the value. + +@item n +Prints the value on the top of the stack, popping it off, +and does not print a newline after. +(This command is a GNU extension.) + +@item P +Pops off the value on top of the stack. +If it it a string, it is simply printed without a trailing newline. +Otherwise it is a number, and the integer portion of its absolute +value is printed out as a "base (UCHAR_MAX+1)" byte stream. +Assuming that (UCHAR_MAX+1) is 256 +(as it is on most machines with 8-bit bytes), +the sequence +@code{KSK 0k1/ [_1*]sx d0>x [256~aPd0@var{r} +Pops two values off the stack and compares them +assuming they are numbers, +executing the contents of register @var{r} as a macro +if the original top-of-stack is greater. +Thus, @samp{1 2>a} will invoke register @samp{a}'s contents +and @samp{2 1>a} will not. + +@item !>@var{r} +Similar but invokes the macro if the original top-of-stack is not greater +(is less than or equal to) what was the second-to-top. + +@item <@var{r} +Similar but invokes the macro if the original top-of-stack is less. + +@item !<@var{r} +Similar but invokes the macro if the original top-of-stack is not less +(is greater than or equal to) what was the second-to-top. + +@item =@var{r} +Similar but invokes the macro if the two numbers popped are equal. +@c This can also be validly used to compare two strings for equality. + +@item !=@var{r} +Similar but invokes the macro if the two numbers popped are not equal. +@c This can also be validly used to compare two strings for equality. + +@item ? +Reads a line from the terminal and executes it. +This command allows a macro to request input from the user. + +@item q +During the execution of a macro, +this command exits from the macro and also from the macro which invoked it. +If called from the top level, +or from a macro which was called directly from the top level, +the @samp{q} command will cause @sc{dc} to exit. + +@item Q +Pops a value off the stack and uses it as a count +of levels of macro execution to be exited. +Thus, @samp{3Q} exits three levels. +@end table + +@node Status Inquiry, Miscellaneous, Strings, Top +@chapter Status Inquiry + +@table @samp +@item Z +Pops a value off the stack, +calculates the number of digits it has +(or number of characters, if it is a string) +and pushes that number. + +@item X +Pops a value off the stack, +calculates the number of fraction digits it has, +and pushes that number. +For a string, the value pushed is +@c -1. +0. + +@item z +Pushes the current stack depth: +the number of objects on the stack +before the execution of the @samp{z} command. +@end table + +@node Miscellaneous, Reporting bugs, Status Inquiry, Top +@chapter Miscellaneous + +@table @samp +@item ! +Will run the rest of the line as a system command. +Note that parsing of the !<, !=, and !> commands take precidence, +so if you want to run a command starting with <, =, or > you will +need to add a space after the !. + +@item # +Will interpret the rest of the line as a comment. +(This command is a GNU extension.) + +@item :@var{r} +Will pop the top two values off of the stack. +The old second-to-top value will be stored in the array @var{r}, +indexed by the old top-of-stack value. + +@item ;@var{r} +Pops the top-of-stack and uses it as an index into +the array @var{r}. +The selected value is then pushed onto the stack. +@end table + +Note that each stacked instance of a register has its own +array associated with it. +Thus @samp{1 @var{0:a} 0S@var{a} 2 @var{0:a} L@var{a} @var{0;a}p} +will print 1, because the 2 was stored in an instance of @var{0:a} +that was later popped. + +@node Reporting bugs, , Miscellaneous, Top +@chapter Reporting bugs + +Email bug reports to @email{bug-dc@@gnu.org}. +@contents +@bye diff --git a/doc/texinfo.tex b/doc/texinfo.tex new file mode 100644 index 0000000..c49af9f --- /dev/null +++ b/doc/texinfo.tex @@ -0,0 +1,5992 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{1999-09-25.10} +% +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +% Free Software Foundation, Inc. +% +% This texinfo.tex file is free software; you can redistribute it and/or +% modify it under the terms of the GNU General Public License as +% published by the Free Software Foundation; either version 2, or (at +% your option) any later version. +% +% This texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write +% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +% In other words, you are welcome to use, share and improve this program. +% You are forbidden to forbid anyone else to use, share and improve +% what you give them. Help stamp out software-hoarding! +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% ftp://ftp.gnu.org/gnu/texinfo.tex +% (and all GNU mirrors, see http://www.gnu.org/order/ftp.html) +% ftp://texinfo.org/tex/texinfo.tex +% ftp://us.ctan.org/macros/texinfo/texinfo.tex +% (and all CTAN mirrors, finger ctan@us.ctan.org for a list). +% /home/gd/gnu/doc/texinfo.tex on the GNU machines. +% The texinfo.tex in any given Texinfo distribution could well be out +% of date, so if that's what you're using, please check. +% Texinfo has a small home page at http://texinfo.org/. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever, to process the dvi file; this makes foo.ps. +% The extra runs of TeX get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages. You can get +% the existing language-specific files from ftp://ftp.gnu.org/gnu/texinfo/. + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% We never want plain's outer \+ definition in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeftypevar\undefined\gdef\putwordDeftypevar{Variable}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi +\ifx\putwordDeftypefun\undefined\gdef\putwordDeftypefun{Function}\fi + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\ifx\eTeXversion\undefined +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\else +\def\loggingall{\tracingcommands3 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \tracingscantokens1 \tracingassigns1 \tracingifs1 + \tracinggroups1 \tracingnesting2 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\fi + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifpdfmakepagedest \pdfmkdest{\the\pageno} \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment; press RETURN to continue} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Press RETURN to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Ensure vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % If the @need value is less than one line space, it's useless. + \dimen0 = #1\mil + \dimen2 = \ht\strutbox + \advance\dimen2 by \dp\strutbox + \ifdim\dimen0 > \dimen2 + % + % Do a \strut just to make the height of this box be normal, so the + % normal leading is inserted relative to the preceding line. + % And a page break here is fine. + \vtop to #1\mil{\strut\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + \fi +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in a typewriter +% font as three actual period characters. +% +\def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \leavevmode + \hbox to 2em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + \spacefactor=3000 +} + + +% @page forces the start of a new page +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% We cannot implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\def\paragraphindent{\parsearg\doparagraphindent} +\def\doparagraphindent#1{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\def\exampleindent{\parsearg\doexampleindent} +\def\doexampleindent#1{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \iflinks + \readauxfile + \fi % \openindices needs to do some work in any case. + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +\ifx\pdfoutput\undefined + \pdffalse + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\linkcolor = \relax + \let\pdfmakeoutlines = \relax +\else + \pdftrue + \pdfoutput = 1 + \input pdfcolor + \def\dopdfimage#1#2#3{% + \def\imagewidth{#2}% + \def\imageheight{#3}% + \ifnum\pdftexversion < 14 + \pdfimage + \else + \pdfximage + \fi + \ifx\empty\imagewidth\else width \imagewidth \fi + \ifx\empty\imageheight\else height \imageheight \fi + {#1.pdf}% + \ifnum\pdftexversion < 14 \else + \pdfrefximage \pdflastximage + \fi} + \def\pdfmkdest#1{\pdfdest name{#1@} xyz} + \def\pdfmkpgn#1{#1@} + \let\linkcolor = \Cyan + \def\endlink{\Black\pdfendlink} + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + \def\pdfmakeoutlines{{% + \openin 1 \jobname.toc + \ifeof 1\else\bgroup + \closein 1 + \indexnofonts + \def\tt{} + % thanh's hack / proper braces in bookmarks + \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace + \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace + % + \def\chapentry ##1##2##3{} + \def\unnumbchapentry ##1##2{} + \def\secentry ##1##2##3##4{\advancenumber{chap##2}} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{\advancenumber{sec##2.##3}} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{\advancenumber{subsec##2.##3.##4}} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \def\chapentry ##1##2##3{% + \pdfoutline goto name{\pdfmkpgn{##3}}count-\expnumber{chap##2}{##1}} + \def\unnumbchapentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \def\secentry ##1##2##3##4{% + \pdfoutline goto name{\pdfmkpgn{##4}}count-\expnumber{sec##2.##3}{##1}} + \def\unnumbsecentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \def\subsecentry ##1##2##3##4##5{% + \pdfoutline goto name{\pdfmkpgn{##5}}count-\expnumber{subsec##2.##3.##4}{##1}} + \def\unnumbsubsecentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \def\subsubsecentry ##1##2##3##4##5##6{% + \pdfoutline goto name{\pdfmkpgn{##6}}{##1}} + \def\unnumbsubsubsecentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \input \jobname.toc + \egroup\fi + }} + \def\makelinks #1,{% + \def\params{#1}\def\E{END}% + \ifx\params\E + \let\nextmakelinks=\relax + \else + \let\nextmakelinks=\makelinks + \ifnum\lnkcount>0,\fi + \picknum{#1}% + \startlink attr{/Border [0 0 0]} + goto name{\pdfmkpgn{\the\pgn}}% + \linkcolor #1% + \advance\lnkcount by 1% + \endlink + \fi + \nextmakelinks + } + \def\picknum#1{\expandafter\pn#1} + \def\pn#1{% + \def\p{#1}% + \ifx\p\lbrace + \let\nextpn=\ppn + \else + \let\nextpn=\ppnn + \def\first{#1} + \fi + \nextpn + } + \def\ppn#1{\pgn=#1\gobble} + \def\ppnn{\pgn=\first} + \def\pdfmklnk#1{\lnkcount=0\makelinks #1,END,} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \ifx\p\space\else\addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \fi + \nextsp} + \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + \def\pdfurl#1{% + \begingroup + \normalturnoffactive\def\@{@}% + \leavevmode\Red + \startlink attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + % #1 + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS| + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\mkpgn{#1}} + \linkcolor #1\endlink} + \def\mkpgn#1{#1@} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\fi % \ifx\pdfoutput + + +\message{fonts,} +% Font-change commands. + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\setfont\smallrm\rmshape{9}{1000} +\setfont\smalltt\ttshape{9}{1000} +\setfont\smallbf\bfshape{10}{900} +\setfont\smallit\itshape{9}{1000} +\setfont\smallsl\slshape{9}{1000} +\setfont\smallsf\sfshape{9}{1000} +\setfont\smallsc\scshape{10}{900} +\setfont\smallttsl\ttslshape{10}{900} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\smallfonts{% + \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl + \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc + \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy + \let\tenttsl=\smallttsl + \resetmathfonts \setleading{11pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic +\let\cite=\smartslanted + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp#1{`\tclose{#1}'\null} +\setfont\keyrm\rmshape{8}{1000} +\font\keysy=cmsy9 +\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \let-\codedash + \catcode`\_=\active \let_\codeunder + \codex + } + % + % If we end up with any active - characters when handling the index, + % just treat them as a normal -. + \global\def\indexbreaks{\catcode`\-=\active \let-\realdash} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @url, @env, @command quotes seem unnecessary, so use \code. +\let\url=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{\begingroup + \unsepspaces + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \ifpdf + \unhbox0 % PDF: 2nd arg given, show only it + \else + \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url + \fi + \else + \code{#1}% only url given, so show it + \fi + \fi + \endlink +\endgroup} + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} +\else + \let\email=\uref +\fi + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym downcases the argument and prints in smallcaps. +\def\acronym#1{{\smallcaps \lowercase{#1}}} + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi + % + \ifpdf \pdfmakepagedesttrue \fi + % + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +% Contains a kludge to get @end[description] to work. +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +% @table, @ftable, @vtable. +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the part of the @columnfraction before the decimal point, which +% is presumably either 0 or the empty string (but we don't check, we +% just throw it away). #2 is the decimal part, which we use as the +% percent of \hsize for this column. +\def\pickupwholefraction#1.#2 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% This used to have \hskip1sp. But then the space in a template line is +% not enough. That is bad. So let's go back to just & until we +% encounter the problem it was intended to solve again. +% --karl, nathan@acm.org, 20apr99. +\def\tab{&} + +% @multitable ... @end multitable definitions: +% +\def\multitable{\parsearg\dotable} +\def\dotable#1{\bgroup + \vskip\parskip + \let\item\crcr + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}% + % + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. + \everycr{\noalign{% + % + % \filbreak%% keeps underfull box messages off when table breaks over pages. + % Maybe so, but it also creates really weird page breaks when the table + % breaks over pages. Wouldn't \vfil be better? Wait until the problem + % manifests itself, so it can be fixed for real --karl. + \global\colcount=0\relax}}% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup&\global\advance\colcount by 1\relax + \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip +\global\advance\multitablelinespace by-\ht0 +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +\else +%% FIXME: what is \box0 supposed to be? +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% + \let\chapter=\relax + \let\unnumbered=\relax + \let\top=\relax + \let\unnumberedsec=\relax + \let\unnumberedsection=\relax + \let\unnumberedsubsec=\relax + \let\unnumberedsubsection=\relax + \let\unnumberedsubsubsec=\relax + \let\unnumberedsubsubsection=\relax + \let\section=\relax + \let\subsec=\relax + \let\subsubsec=\relax + \let\subsection=\relax + \let\subsubsection=\relax + \let\appendix=\relax + \let\appendixsec=\relax + \let\appendixsection=\relax + \let\appendixsubsec=\relax + \let\appendixsubsection=\relax + \let\appendixsubsubsec=\relax + \let\appendixsubsubsection=\relax + \let\contents=\relax + \let\smallbook=\relax + \let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypeivar = \relax + \let\deftypeop = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + % This @ is a catcode 12 token (that is the normal catcode of @ in + % this texinfo.tex file). We change the catcode of @ below to match. + \long\def\doignoretext##1@end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % We must not have @c interpreted as a control sequence. + \catcode`\@ = 12 + % + % Make the letter c a comment character so that the rest of the line + % will be ignored. This way, the document can have (for example) + % @c @end ifinfo + % and the @end ifinfo will be properly ignored. + % (We've just changed @ to catcode 12.) + \catcode`\c = 14 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{WARNING: for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm=\nullfont \let\tenit=\nullfont \let\tensl=\nullfont + \let\tenbf=\nullfont \let\tentt=\nullfont \let\smallcaps=\nullfont + \let\tensf=\nullfont + % Similarly for index fonts (mostly for their use in smallexample). + \let\smallrm=\nullfont \let\smallit=\nullfont \let\smallsl=\nullfont + \let\smallbf=\nullfont \let\smalltt=\nullfont \let\smallsc=\nullfont + \let\smallsf=\nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% + % Do not execute macro definitions. + % `c' is a comment character, so the word `macro' will get cut off. + \def\macro{\doignore{ma}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +{ + \catcode`\_ = \active + % + % We might end up with active _ or - characters in the argument if + % we're called from @code, as @code{@value{foo-bar_}}. So \let any + % such active characters to their normal equivalents. + \gdef\value{\begingroup + \catcode`\-=12 \catcode`\_=12 + \indexbreaks \let_\normalunderscore + \valuexxx} +} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we \let\value to this in \indexdummies). Ones +% whose names contain - or _ still won't work, but we can't do anything +% about that. The command has to be fully expandable, since the result +% winds up in the index file. This means that if the variable's value +% contains other Texinfo commands, it's almost certain it will fail +% (although perhaps we could fix that with sufficient work to do a +% one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% The \closeout helps reduce unnecessary open files; the limit on the +% Acorn RISC OS is a mere 16 files. +\def\synindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\doindex{#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\docodeindex{#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\ { }% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +% Need these in case \tex is in effect and \{ is a \delimiter again. +% But can't use \lbracecmd and \rbracecmd because texindex assumes +% braces and backslashes are used only as delimiters. +\let\{ = \mylbrace +\let\} = \myrbrace +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\uref##1{\realbackslash uref {##1}}% +\def\url##1{\realbackslash url {##1}}% +\def\env##1{\realbackslash env {##1}}% +\def\command##1{\realbackslash command {##1}}% +\def\option##1{\realbackslash option {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\acronym##1{\realbackslash acronym {##1}}% +% +% Handle some cases of @value -- where the variable name does not +% contain - or _, and the value does not contain any +% (non-fully-expandable) commands. +\let\value = \expandablevalue +% +\unsepspaces +% Turn off macro expansion +\turnoffmacros +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\url=\indexdummyfont +\let\uref=\indexdummyfont +\let\env=\indexdummyfont +\let\acronym=\indexdummyfont +\let\command=\indexdummyfont +\let\option=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other + @gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% For \ifx comparisons. +\def\emptymacro{\empty} + +% Most index entries go through here, but \dosubind is the general case. +% +\def\doind#1#2{\dosubind{#1}{#2}\empty} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% \empty if called from \doind, as we usually are. The main exception +% is with defuns, which call us directly. +% +\def\dosubind#1#2#3{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio = 0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + \def\thirdarg{#3}% + % + % If third arg is present, precede it with space in sort key. + \ifx\thirdarg\emptymacro + \let\subentry = \empty + \else + \def\subentry{ #3}% + \fi + % + % First process the index entry with all font commands turned + % off to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2\subentry}}% + % + % Now the real index entry with the fonts. + \toks0 = {#2}% + % + % If third (subentry) arg is present, add it to the index + % string. And include a space. + \ifx\thirdarg\emptymacro \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + % Set up the complete index entry, with both the sort key + % and the original text, including any font commands. We write + % three arguments to \entry to the .?? file, texindex reduces to + % two when writing the .??s sorted result. + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + % + % If a skip is the last thing on the list now, preserve it + % by backing up by \lastskip, doing the \write, then inserting + % the skip again. Otherwise, the whatsit generated by the + % \write will make \lastskip zero. The result is that sequences + % like this: + % @end defun + % @tindex whatever + % @defun ... + % will have extra space inserted, because the \medbreak in the + % start of the @defun won't see the skip inserted by the @end of + % the previous defun. + % + % But don't do any of this if we're not in vertical mode. We + % don't want to do a \vskip and prematurely end a paragraph. + % + % Avoid page breaks due to these extra skips, too. + % + \iflinks + \ifvmode + \skip0 = \lastskip + \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi + \fi + % + \temp % do the write + % + % + \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi + \fi + }% + }% + \penalty\count255 + }% +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \smallfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \penalty -300 + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + \vskip .33\baselineskip plus .1\baselineskip + % + % Do our best not to break after the initial. + \nobreak +}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry#1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing columns. + \vskip 0pt plus1pt + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + \ #2% The page number ends the paragraph. + \fi + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \advance\vsize by -\ht\partialpage + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split, in box0 and box2. + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +% \def\appendixletter{\char\the\appendixno} +% We do the following for the sake of pdftex, which needs the actual +% letter in the expansion, not just typeset. +\def\appendixletter{% + \ifnum\appendixno=`A A% + \else\ifnum\appendixno=`B B% + \else\ifnum\appendixno=`C C% + \else\ifnum\appendixno=`D D% + \else\ifnum\appendixno=`E E% + \else\ifnum\appendixno=`F F% + \else\ifnum\appendixno=`G G% + \else\ifnum\appendixno=`H H% + \else\ifnum\appendixno=`I I% + \else\ifnum\appendixno=`J J% + \else\ifnum\appendixno=`K K% + \else\ifnum\appendixno=`L L% + \else\ifnum\appendixno=`M M% + \else\ifnum\appendixno=`N N% + \else\ifnum\appendixno=`O O% + \else\ifnum\appendixno=`P P% + \else\ifnum\appendixno=`Q Q% + \else\ifnum\appendixno=`R R% + \else\ifnum\appendixno=`S S% + \else\ifnum\appendixno=`T T% + \else\ifnum\appendixno=`U U% + \else\ifnum\appendixno=`V V% + \else\ifnum\appendixno=`W W% + \else\ifnum\appendixno=`X X% + \else\ifnum\appendixno=`Y Y% + \else\ifnum\appendixno=`Z Z% + % The \the is necessary, despite appearances, because \appendixletter is + % expanded while writing the .toc file. \char\appendixno is not + % expandable, thus it is written literally, thus all appendixes come out + % with the same letter (or @) in the toc without it. + \else\char\the\appendixno + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + +% @chapter, @appendix, @unnumbered. +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\the\chapno}}}% +\temp +\donoderef +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 +\message{\putwordAppendix\space \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}}}% +\temp +\appendixnoderef +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +% @top is like @unnumbered. +\outer\def\top{\parsearg\unnumberedyyy} + +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the to achieve this: TeX expands \the only once, +% simply yielding the contents of . (We also do this for +% the toc entries.) +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}% +\temp +\unnumbnoderef +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +} + +% Sections. +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\the\chapno}{\the\secno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\appendixletter}{\the\secno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{% +\plainsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsections. +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{% +\plainsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsubsections. +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. We supply {\folio} at the end of the +% argument, which will end up as the last argument to the \...entry macro. +% +% We open the .toc file here instead of at @setfilename or any other +% given time so that @contents can be put in the document anywhere. +% +\newif\iftocfileopened +\def\writetocentry#1{% + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + \iflinks \write\tocfile{#1{\folio}}\fi +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Finish up the main text and prepare to read what we've written +% to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \pdfmakeoutlines + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} +\let\shortcontents = \summarycontents + +\ifpdf + \pdfcatalog{/PageMode /UseOutlines}% +\fi + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#3\egroup}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +% +\newdimen\shortappendixwidth +% +\def\shortchaplabel#1{% + % Compute width of word "Appendix", may change with language. + \setbox0 = \hbox{\shortcontrm \putwordAppendix}% + \shortappendixwidth = \wd0 + % + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno\bgroup#2\egroup}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + % Do not use \turnoffactive in these arguments. Since the toc is + % typeset in cmr, so characters such as _ would come out wrong; we + % have to do the usual translation tricks. + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} +% @foo ... @end foo. + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie + \catcode `\%=14 + \catcode 43=12 % plus + \catcode`\"=12 + \catcode`\==12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\*=\ptexstar + \let\t=\ptext + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% Define the \E... control sequence only if we are inside the particular +% environment, so the error checking in \end will work. +% +% To end an @example-like environment, we first end the paragraph (via +% \afterenvbreak's vertical glue), and then the group. That way we keep +% the zero \parskip that the environments set -- \parskip glue will be +% inserted at the beginning of the next paragraph in the document, after +% the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup} + +% @lisp: indented, narrowed, typewriter font. +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} + +% @example: Same as @lisp. +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} + +% @small... is usually equivalent to the non-small (@smallbook +% redefines). We must call \example (or whatever) last in the +% definition, since it reads the return following the @example (or +% whatever) command. +% +% This actually allows (for example) @end display inside an +% @smalldisplay. Too bad, but makeinfo will catch the error anyway. +% +\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display} +\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format} +\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts. +% Originally contributed by Pavel@xerox. +\def\smalllispx{\begingroup + \def\Esmalllisp{\nonfillfinish\endgroup}% + \def\Esmallexample{\nonfillfinish\endgroup}% + \smallfonts + \lisp +} + +% @display: same as @lisp except keep current font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% @smalldisplay (when @smallbook): @display plus smaller fonts. +% +\def\smalldisplayx{\begingroup + \def\Esmalldisplay{\nonfillfinish\endgroup}% + \smallfonts \rm + \display +} + +% @format: same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @smallformat (when @smallbook): @format plus smaller fonts. +% +\def\smallformatx{\begingroup + \def\Esmallformat{\nonfillfinish\endgroup}% + \smallfonts \rm + \format +} + +% @flushleft (same as @format). +% +\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format} + +% @flushright. +% +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble +} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + + +\message{defuns,} +% @defun etc. + +% Allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\let\ampnr = \& +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% Active &'s sneak into the index arguments, so make sure it's defined. +{ + \catcode`& = 13 + \global\let& = \ampnr +} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\noindent +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 +\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% +\def\defmethparsebody#1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +% Used for @deftypemethod and @deftypeivar. +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by a space, is the class name. +% #5 is the method's return type. +% +\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV + \medbreak + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}} + +% Used for @deftypeop. The change from \deftypemethparsebody is an +% extra argument at the beginning which is the `category', instead of it +% being the hardwired string `Method' or `Instance Variable'. We have +% to account for this both in the \...x definition and in parsing the +% input at hand. Thus also need a control sequence (passed as #5) for +% the \E... definition to assign the category name to. +% +\def\deftypeopparsebody#1#2#3#4#5 #6 {\begingroup\inENV + \medbreak + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 ##3 {% + \def#4{##1}% + \begingroup\obeylines\activeparens\spacesplit{#3{##2}{##3}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#5}{#6}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs#1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Set the font temporarily and use \font in case \setfont made \tensl a macro. +{\tensl\hyphenchar\font=0}% +#1% +{\tensl\hyphenchar\font=45}% +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDeffunc}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefmac}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefspec}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defop CATEGORY CLASS OPERATION ARG... +% +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} +% +\def\defopheader#1#2#3{% +\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype\ \putwordon\ #1}% +\defunargs {#3}\endgroup % +} + +% @deftypeop CATEGORY CLASS TYPE OPERATION ARG... +% +\def\deftypeop #1 {\def\deftypeopcategory{#1}% + \deftypeopparsebody\Edeftypeop\deftypeopx\deftypeopheader + \deftypeopcategory} +% +% #1 is the class name, #2 the data type, #3 the operation name, #4 the args. +\def\deftypeopheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3} + {\deftypeopcategory\ \putwordon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @deftypemethod CLASS TYPE METHOD ARG... +% +\def\deftypemethod{% + \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @deftypeivar CLASS TYPE VARNAME +% +\def\deftypeivar{% + \deftypemethparsebody\Edeftypeivar\deftypeivarx\deftypeivarheader} +% +% #1 is the class name, #2 the data type, #3 the variable name. +\def\deftypeivarheader#1#2#3{% + \dosubind{vr}{\code{#3}}{\putwordof\ \code{#1}}% entry in variable index + \begingroup + \defname{#3}{\putwordInstanceVariableof\ \code{#1}}% + \defvarargs{#3}% + \endgroup +} + +% @defmethod == @defop Method +% +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} +% +% #1 is the class name, #2 the method name, #3 the args. +\def\defmethodheader#1#2#3{% + \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{#2}{\putwordMethodon\ \code{#1}}% + \defunargs{#3}% + \endgroup +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar CLASS VARNAME == @defcv {Instance Variable} CLASS VARNAME +% +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} +% +\def\defivarheader#1#2#3{% + \dosubind {vr}{\code{#2}}{\putwordof\ #1}% entry in var index + \begingroup + \defname{#2}{\putwordInstanceVariableof\ #1}% + \defvarargs{#3}% + \endgroup +} + +% @defvar +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefvar}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefopt}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% These definitions are used if you use @defunx (etc.) +% anywhere other than immediately after a @defun or @defunx. +% +\def\defcvx#1 {\errmessage{@defcvx in invalid context}} +\def\deffnx#1 {\errmessage{@deffnx in invalid context}} +\def\defivarx#1 {\errmessage{@defivarx in invalid context}} +\def\defmacx#1 {\errmessage{@defmacx in invalid context}} +\def\defmethodx#1 {\errmessage{@defmethodx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\defopx#1 {\errmessage{@defopx in invalid context}} +\def\defspecx#1 {\errmessage{@defspecx in invalid context}} +\def\deftpx#1 {\errmessage{@deftpx in invalid context}} +\def\deftypefnx#1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypefunx#1 {\errmessage{@deftypefunx in invalid context}} +\def\deftypeivarx#1 {\errmessage{@deftypeivarx in invalid context}} +\def\deftypemethodx#1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypeopx#1 {\errmessage{@deftypeopx in invalid context}} +\def\deftypevarx#1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx#1 {\errmessage{@deftypevrx in invalid context}} +\def\defunx#1 {\errmessage{@defunx in invalid context}} +\def\defvarx#1 {\errmessage{@defvarx in invalid context}} +\def\defvrx#1 {\errmessage{@defvrx in invalid context}} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + % Undo catcode changes of \startcontents and \doprintindex + \catcode`\@=0 \catcode`\\=12 \escapechar=`\@ + % Append \endinput to make sure that TeX does not see the ending newline. + \toks0={#1\endinput}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \let\xeatspaces\eatspaces + \input \jobname.tmp + \endgroup +} +\else +\def\scanmacro#1{% +\begingroup \newlinechar`\^^M +% Undo catcode changes of \startcontents and \doprintindex +\catcode`\@=0 \catcode`\\=12 \escapechar=`\@ +\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup} +\fi + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? +\def\macrolist{} % List of all defined macros in the form + % \do\macro1\do\macro2... + +% Utility routines. +% Thisdoes \let #1 = #2, except with \csnames. +\def\cslet#1#2{% +\expandafter\expandafter +\expandafter\let +\expandafter\expandafter +\csname#1\endcsname +\csname#2\endcsname} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=12\catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\macrobodyctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\@=12 + \catcode`\^^M=12 + \usembodybackslash} + +\def\macroargctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\@=12 + \catcode`\\=12} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{The name \the\macname\space is reserved}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + % Add the macroname to \macrolist + \toks0 = \expandafter{\macrolist\do}% + \xdef\macrolist{\the\toks0 + \expandafter\noexpand\csname\the\macname\endcsname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\def\unmacro{\parsearg\unmacroxxx} +\def\unmacroxxx#1{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist + \begingroup + \edef\tempa{\expandafter\noexpand\csname#1\endcsname}% + \def\do##1{% + \def\tempb{##1}% + \ifx\tempa\tempb + % remove this + \else + \toks0 = \expandafter{\newmacrolist\do}% + \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}% + \fi}% + \def\newmacrolist{}% + % Execute macro list to define \newmacrolist + \macrolist + \global\let\macrolist\newmacrolist + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + +% We mant to disable all macros during \shipout so that they are not +% expanded by \write. +\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}% + \edef\next{\macrolist}\expandafter\endgroup\next} + + +% @alias. +% We need some trickery to remove the optional spaces around the equal +% sign. Just make them active and then expand them all to nothing. +\def\alias{\begingroup\obeyspaces\parsearg\aliasxxx} +\def\aliasxxx #1{\aliasyyy#1\relax} +\def\aliasyyy #1=#2\relax{\ignoreactivespaces +\edef\next{\global\let\expandafter\noexpand\csname#1\endcsname=% + \expandafter\noexpand\csname#2\endcsname}% +\expandafter\endgroup\next} + + +\message{cross references,} +% @xref etc. + +\newwrite\auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's job is to define \lastnode. +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +% The sectioning commands (@chapter, etc.) call these. +\def\donoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Ysectionnumberandtype}% + \global\let\lastnode=\relax + \fi +} +\def\unnumbnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}% + \global\let\lastnode=\relax + \fi +} +\def\appendixnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Yappendixletterandtype}% + \global\let\lastnode=\relax + \fi +} + + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\newcount\savesfregister +\gdef\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} +\gdef\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} +\gdef\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} + +% \setref{NAME}{SNT} defines a cross-reference point NAME, namely +% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have +% to set \indexdummies so commands such as @code in a section title +% aren't expanded. It would be nicer not to expand the titles in the +% first place, but there's so many layers that that is hard to do. +% +\def\setref#1#2{{% + \indexdummies + \pdfmkdest{#1}% + \dosetq{#1-title}{Ytitle}% + \dosetq{#1-pg}{Ypagenumber}% + \dosetq{#1-snt}{#2}% +}} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \unsepspaces + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifpdf + \leavevmode + \getfilename{#4}% + \ifnum\filenamelength>0 + \startlink attr{/Border [0 0 0]}% + goto file{\the\filename.pdf} name{#1@}% + \else + \startlink attr{/Border [0 0 0]}% + goto name{#1@}% + \fi + \linkcolor + \fi + % + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' \putwordin{} \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\normalturnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % [mynode], + [\printednodename],\space + % page 3 + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \endlink +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \normalturnoffactive so that punctuation chars such as underscore +% and backslash work in node names. (\turnoffactive doesn't do \.) +\def\dosetq#1#2{% + {\let\folio=0% + \normalturnoffactive + \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}% + \iflinks + \next + \fi + }% +} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +% +\def\xrdef#1{\begingroup + % Reenable \ as an escape while reading the second argument. + \catcode`\\ = 0 + \afterassignment\endgroup + \expandafter\gdef\csname X#1\endcsname +} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + \smallfonts \rm + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\par\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + \closein 1 + % Do not bother showing banner with post-v2.7 epsf.tex (available in + % doc/epsf.tex until it shows up on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + \ifpdf + \centerline{\dopdfimage{#1}{#2}{#3}}% + \else + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \begingroup + \catcode`\^^M = 5 % in case we're inside an example + % If the image is by itself, center it. + \ifvmode + \nobreak\bigskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \centerline{\epsfbox{#1.eps}}% + \bigbreak + \else + % In the middle of a paragraph, no extra space. + \epsfbox{#1.eps}% + \fi + \endgroup + \fi +} + + +\message{localization,} +% and i18n. + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language abbreviation. +% It would be nice if we could set up a hyphenation file here. +% +\def\documentlanguage{\parsearg\dodocumentlanguage} +\def\dodocumentlanguage#1{% + \tex % read txi-??.tex file in plain TeX. + % Read the file if it exists. + \openin 1 txi-#1.tex + \ifeof1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \let\temp = \relax + \else + \def\temp{\input txi-#1.tex }% + \fi + \temp + \endgroup +} +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + + +% @documentencoding should change something in TeX eventually, most +% likely, but for now just recognize it. +\let\documentencoding = \comment + + +% Page size parameters. +% +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; 3) voffset; +% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can +% set \parskip and call \setleading for \baselineskip. +% +\def\internalpagesizes#1#2#3#4#5#6{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}% +}} + +% Use @smallbook to reset parameters for 7x9.5 (or so) format. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \setleading{12pt}% + % + \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \deftypemargin = 0pt + \defbodyindent = .5cm + % + \let\smalldisplay = \smalldisplayx + \let\smallexample = \smalllispx + \let\smallformat = \smallformatx + \let\smalllisp = \smalllispx +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \setleading{12pt}% + \parskip = 3pt plus 2pt minus 1pt + % + \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}% + % + \tolerance = 700 + \hfuzz = 1pt +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex{{\globaldefs = 1 + \setleading{13.6pt}% + % + \afourpaper + \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}% + % + \globaldefs = 0 +}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{% + \afourpaper + \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}% + % + \globaldefs = 0 +} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\def\pagesizes{\parsearg\pagesizesxxx} +\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\catcode`\$=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} +\def\normaldollar{$} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +\catcode`\$=\active +\def${\ifusingit{{\sl\$}}\normaldollar} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus +@let$=@normaldollar} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus +@let$=@normaldollar} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active + @catcode`@_=@active +} + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These look ok in all fonts, so just make them not special. +@catcode`@& = @other +@catcode`@# = @other +@catcode`@% = @other + +@c Set initial fonts. +@textfonts +@rm + + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: diff --git a/h/getopt.h b/h/getopt.h new file mode 100644 index 0000000..f3696d9 --- /dev/null +++ b/h/getopt.h @@ -0,0 +1,133 @@ +/* Declarations for getopt. + Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/h/number.h b/h/number.h new file mode 100644 index 0000000..8d78120 --- /dev/null +++ b/h/number.h @@ -0,0 +1,153 @@ +/* number.h: Arbitrary precision numbers header file. */ +/* + Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111-1307 USA. + + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#ifndef _NUMBER_H_ +#define _NUMBER_H_ + +typedef enum {PLUS, MINUS} sign; + +typedef struct bc_struct *bc_num; + +typedef struct bc_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. */ + bc_num n_next; /* Linked list for available list. */ + char *n_ptr; /* The pointer to the actual storage. + If NULL, n_value points to the inside of + another number (bc_multiply...) and should + not be "freed." */ + char *n_value; /* The number. Not zero char terminated. + May not point to the same place as n_ptr as + in the case of leading zeros generated. */ + } bc_struct; + + +/* The base used in storing the numbers in n_value above. + Currently this MUST be 10. */ + +#define BASE 10 + +/* Some useful macros and constants. */ + +#define CH_VAL(c) (c - '0') +#define BCD_CHAR(d) (d + '0') + +#ifdef MIN +#undef MIN +#undef MAX +#endif +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)>(b)?(b):(a)) +#define ODD(a) ((a)&1) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 0x7ffffff +#endif + + +/* Global numbers. */ +extern bc_num _zero_; +extern bc_num _one_; +extern bc_num _two_; + + +/* Function Prototypes */ + +/* 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 + +_PROTOTYPE(void bc_init_numbers, (void)); + +_PROTOTYPE(bc_num bc_new_num, (int length, int scale)); + +_PROTOTYPE(void bc_free_num, (bc_num *num)); + +_PROTOTYPE(bc_num bc_copy_num, (bc_num num)); + +_PROTOTYPE(void bc_init_num, (bc_num *num)); + +_PROTOTYPE(void bc_str2num, (bc_num *num, char *str, int scale)); + +_PROTOTYPE(char *bc_num2str, (bc_num num)); + +_PROTOTYPE(void bc_int2num, (bc_num *num, int val)); + +_PROTOTYPE(long bc_num2long, (bc_num num)); + +_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2)); + +_PROTOTYPE(char bc_is_zero, (bc_num num)); + +_PROTOTYPE(char bc_is_near_zero, (bc_num num, int scale)); + +_PROTOTYPE(char bc_is_neg, (bc_num num)); + +_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result, int scale_min)); + +_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result, int scale_min)); + +_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale)); + +_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale)); + +_PROTOTYPE(int bc_modulo, (bc_num num1, bc_num num2, bc_num *result, + int scale)); + +_PROTOTYPE(int bc_divmod, (bc_num num1, bc_num num2, bc_num *quot, + bc_num *rem, int scale)); + +_PROTOTYPE(int bc_raisemod, (bc_num base, bc_num expo, bc_num mod, + bc_num *result, int scale)); + +_PROTOTYPE(void bc_raise, (bc_num num1, bc_num num2, bc_num *result, + int scale)); + +_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale)); + +_PROTOTYPE(void bc_out_num, (bc_num num, int o_base, void (* out_char)(int), + int leading_zero)); + +#endif diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..ab74c88 --- /dev/null +++ b/install-sh @@ -0,0 +1,238 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 0000000..6f74b4d --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in +noinst_LIBRARIES = libbc.a + +INCLUDES = -I. -I.. -I$(srcdir)/../h + +libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c + +DEFS = @DEFS@ $(DEFSADD) + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +MAINTAINERCLEANFILES = Makefile.in number.c + +newnumber.o: number.c muldigits.h + $(CC) $(CFLAGS) $(INCLUDES) -c -DMULDIGITS -o newnumber.o $(srcdir)/number.c + +muldigits.h: testmul + @echo "The following may take up to 10 minutes." + testmul > muldigits.h + +testmul: testmul.o number.o + $(CC) $(CFLAGS) -o testmul testmul.o number.o + +specialnumber: newnumber.o + cp newnumber.o number.o + diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 0000000..5ffa593 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,283 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +noinst_LIBRARIES = libbc.a + +INCLUDES = -I. -I.. -I$(srcdir)/../h + +libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c + +DEFS = @DEFS@ $(DEFSADD) + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +MAINTAINERCLEANFILES = Makefile.in number.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libbc_a_LIBADD = +libbc_a_OBJECTS = getopt.o getopt1.o vfprintf.o number.o +AR = ar +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(libbc_a_SOURCES) +OBJECTS = $(libbc_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libbc.a: $(libbc_a_OBJECTS) $(libbc_a_DEPENDENCIES) + -rm -f libbc.a + $(AR) cru libbc.a $(libbc_a_OBJECTS) $(libbc_a_LIBADD) + $(RANLIB) libbc.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +getopt.o: getopt.c ../config.h ../h/getopt.h +getopt1.o: getopt1.c ../config.h ../h/getopt.h +number.o: number.c ../config.h ../h/number.h +vfprintf.o: vfprintf.c ../config.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +newnumber.o: number.c muldigits.h + $(CC) $(CFLAGS) $(INCLUDES) -c -DMULDIGITS -o newnumber.o $(srcdir)/number.c + +muldigits.h: testmul + @echo "The following may take up to 10 minutes." + testmul > muldigits.h + +testmul: testmul.o number.o + $(CC) $(CFLAGS) -o testmul testmul.o number.o + +specialnumber: newnumber.o + cp newnumber.o number.o + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/getopt.c b/lib/getopt.c new file mode 100644 index 0000000..23ce064 --- /dev/null +++ b/lib/getopt.c @@ -0,0 +1,752 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 + Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#endif /* GNU C library. */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + optstring = _getopt_initialize (optstring); + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if (nameend - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); + else + fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/getopt1.c b/lib/getopt1.c new file mode 100644 index 0000000..de8e2ad --- /dev/null +++ b/lib/getopt1.c @@ -0,0 +1,184 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#else +char *getenv (); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/number.c b/lib/number.c new file mode 100644 index 0000000..240f653 --- /dev/null +++ b/lib/number.c @@ -0,0 +1,1794 @@ +/* number.c: Implements arbitrary precision numbers. */ +/* + Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 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, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111-1307 USA. + + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include +#include +#include +#include +#include +#include /* Prototypes needed for external utility routines. */ +#include + +#define bc_rt_warn rt_warn +#define bc_rt_error rt_error +#define bc_out_of_memory out_of_memory + +_PROTOTYPE(void rt_warn, (char *mesg ,...)); +_PROTOTYPE(void rt_error, (char *mesg ,...)); +_PROTOTYPE(void out_of_memory, (void)); + +/* Storage used for special numbers. */ +bc_num _zero_; +bc_num _one_; +bc_num _two_; + +static bc_num _bc_Free_list = NULL; + +/* new_num allocates a number and sets fields to known values. */ + +bc_num +bc_new_num (length, scale) + int length, scale; +{ + bc_num temp; + + if (_bc_Free_list != NULL) { + temp = _bc_Free_list; + _bc_Free_list = temp->n_next; + } else { + temp = (bc_num) malloc (sizeof(bc_struct)); + if (temp == NULL) bc_out_of_memory (); + } + temp->n_sign = PLUS; + temp->n_len = length; + temp->n_scale = scale; + temp->n_refs = 1; + temp->n_ptr = (char *) malloc (length+scale); + if (temp->n_ptr == NULL) bc_out_of_memory(); + temp->n_value = temp->n_ptr; + memset (temp->n_ptr, 0, length+scale); + return temp; +} + +/* "Frees" a bc_num NUM. Actually decreases reference count and only + frees the storage if reference count is zero. */ + +void +bc_free_num (num) + bc_num *num; +{ + if (*num == NULL) return; + (*num)->n_refs--; + if ((*num)->n_refs == 0) { + if ((*num)->n_ptr) + free ((*num)->n_ptr); + (*num)->n_next = _bc_Free_list; + _bc_Free_list = *num; + } + *num = NULL; +} + + +/* Intitialize the number package! */ + +void +bc_init_numbers () +{ + _zero_ = bc_new_num (1,0); + _one_ = bc_new_num (1,0); + _one_->n_value[0] = 1; + _two_ = bc_new_num (1,0); + _two_->n_value[0] = 2; +} + + +/* Make a copy of a number! Just increments the reference count! */ + +bc_num +bc_copy_num (num) + bc_num num; +{ + num->n_refs++; + return num; +} + + +/* Initialize a number NUM by making it a copy of zero. */ + +void +bc_init_num (num) + bc_num *num; +{ + *num = bc_copy_num (_zero_); +} + +/* For many things, we may have leading zeros in a number NUM. + _bc_rm_leading_zeros just moves the data "value" pointer to the + correct place and adjusts the length. */ + +static void +_bc_rm_leading_zeros (num) + bc_num num; +{ + /* We can move n_value to point to the first non zero digit! */ + while (*num->n_value == 0 && num->n_len > 1) { + num->n_value++; + num->n_len--; + } +} + + +/* 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 +_bc_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 _bc_do_compare (n1, n2, TRUE, FALSE); +} + +/* In some places we need to check if the number is negative. */ + +char +bc_is_neg (num) + bc_num num; +{ + return num->n_sign == MINUS; +} + +/* In some places we need to check if the number NUM is zero. */ + +char +bc_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 NUM is almost zero. + Specifically, all but the last digit is 0 and the last digit is 1. + Last digit is defined by scale. */ + +char +bc_is_near_zero (num, scale) + bc_num num; + int scale; +{ + int count; + char *nptr; + + /* Error checking */ + if (scale > num->n_scale) + scale = num->n_scale; + + /* Initialize */ + count = num->n_len + scale; + nptr = num->n_value; + + /* The check */ + while ((count > 0) && (*nptr++ == 0)) count--; + + if (count != 0 && (count != 1 || *--nptr != 1)) + return FALSE; + else + return TRUE; +} + + +/* Perform addition: N1 is added to N2 and the value is + returned. The signs of N1 and N2 are ignored. + SCALE_MIN is to set the minimum scale of the result. */ + +static bc_num +_bc_do_add (n1, n2, scale_min) + bc_num n1, n2; + int scale_min; +{ + bc_num sum; + int sum_scale, sum_digits; + char *n1ptr, *n2ptr, *sumptr; + int carry, n1bytes, n2bytes; + int count; + + /* Prepare sum. */ + sum_scale = MAX (n1->n_scale, n2->n_scale); + sum_digits = MAX (n1->n_len, n2->n_len) + 1; + sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min)); + + /* Zero extra digits made by scale_min. */ + if (scale_min > sum_scale) + { + sumptr = (char *) (sum->n_value + sum_scale + sum_digits); + for (count = scale_min - sum_scale; count > 0; count--) + *sumptr++ = 0; + } + + /* 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 > (BASE-1)) + { + carry = 1; + *sumptr -= BASE; + } + 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 > (BASE-1)) + { + carry = 1; + *sumptr -= BASE; + } + else + carry = 0; + sumptr--; + } + + /* Set final carry. */ + if (carry == 1) + *sumptr += 1; + + /* Adjust sum and return. */ + _bc_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. SCALE_MIN is the minimum scale + of the result. */ + +static bc_num +_bc_do_sub (n1, n2, scale_min) + bc_num n1, n2; + int scale_min; +{ + 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 = bc_new_num (diff_len, MAX(diff_scale, scale_min)); + + /* Zero extra digits made by scale_min. */ + if (scale_min > diff_scale) + { + diffptr = (char *) (diff->n_value + diff_len + diff_scale); + for (count = scale_min - diff_scale; count > 0; count--) + *diffptr++ = 0; + } + + /* 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 += BASE; + 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 += BASE; + 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 += BASE; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + } + + /* Clean up and return. */ + _bc_rm_leading_zeros (diff); + return diff; +} + + +/* Here is the full subtract routine that takes care of negative numbers. + N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN + is the minimum scale for the result. */ + +void +bc_sub (n1, n2, result, scale_min) + bc_num n1, n2, *result; + int scale_min; +{ + bc_num diff = NULL; + int cmp_res; + int res_scale; + + if (n1->n_sign != n2->n_sign) + { + diff = _bc_do_add (n1, n2, scale_min); + diff->n_sign = n1->n_sign; + } + else + { + /* subtraction must be done. */ + /* Compare magnitudes. */ + cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); + switch (cmp_res) + { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + diff = _bc_do_sub (n2, n1, scale_min); + diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS); + break; + case 0: + /* They are equal! return zero! */ + res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); + diff = bc_new_num (1, res_scale); + memset (diff->n_value, 0, res_scale+1); + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + diff = _bc_do_sub (n1, n2, scale_min); + diff->n_sign = n1->n_sign; + break; + } + } + + /* Clean up and return. */ + bc_free_num (result); + *result = diff; +} + + +/* Here is the full add routine that takes care of negative numbers. + N1 is added to N2 and the result placed into RESULT. SCALE_MIN + is the minimum scale for the result. */ + +void +bc_add (n1, n2, result, scale_min) + bc_num n1, n2, *result; + int scale_min; +{ + bc_num sum = NULL; + int cmp_res; + int res_scale; + + if (n1->n_sign == n2->n_sign) + { + sum = _bc_do_add (n1, n2, scale_min); + sum->n_sign = n1->n_sign; + } + else + { + /* subtraction must be done. */ + cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */ + switch (cmp_res) + { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + sum = _bc_do_sub (n2, n1, scale_min); + sum->n_sign = n2->n_sign; + break; + case 0: + /* They are equal! return zero with the correct scale! */ + res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); + sum = bc_new_num (1, res_scale); + memset (sum->n_value, 0, res_scale+1); + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + sum = _bc_do_sub (n1, n2, scale_min); + sum->n_sign = n1->n_sign; + } + } + + /* Clean up and return. */ + bc_free_num (result); + *result = sum; +} + +/* Recursive vs non-recursive multiply crossover ranges. */ +#if defined(MULDIGITS) +#include "muldigits.h" +#else +#define MUL_BASE_DIGITS 80 +#endif + +int mul_base_digits = MUL_BASE_DIGITS; +#define MUL_SMALL_DIGITS mul_base_digits/4 + +/* Multiply utility routines */ + +static bc_num +new_sub_num (length, scale, value) + int length, scale; + char *value; +{ + bc_num temp; + + if (_bc_Free_list != NULL) { + temp = _bc_Free_list; + _bc_Free_list = temp->n_next; + } else { + temp = (bc_num) malloc (sizeof(bc_struct)); + if (temp == NULL) bc_out_of_memory (); + } + temp->n_sign = PLUS; + temp->n_len = length; + temp->n_scale = scale; + temp->n_refs = 1; + temp->n_ptr = NULL; + temp->n_value = value; + return temp; +} + +static void +_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod, + int full_scale) +{ + char *n1ptr, *n2ptr, *pvptr; + char *n1end, *n2end; /* To the end of n1 and n2. */ + int indx, sum, prodlen; + + prodlen = n1len+n2len+1; + + *prod = bc_new_num (prodlen, 0); + + n1end = (char *) (n1->n_value + n1len - 1); + n2end = (char *) (n2->n_value + n2len - 1); + pvptr = (char *) ((*prod)->n_value + prodlen - 1); + sum = 0; + + /* Here is the loop... */ + for (indx = 0; indx < prodlen-1; indx++) + { + n1ptr = (char *) (n1end - MAX(0, indx-n2len+1)); + n2ptr = (char *) (n2end - MIN(indx, n2len-1)); + while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) + sum += *n1ptr-- * *n2ptr++; + *pvptr-- = sum % BASE; + sum = sum / BASE; + } + *pvptr = sum; +} + + +/* A special adder/subtractor for the recursive divide and conquer + multiply algorithm. Note: if sub is called, accum must + be larger that what is being subtracted. Also, accum and val + must have n_scale = 0. (e.g. they must look like integers. *) */ +static void +_bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub) +{ + signed char *accp, *valp; + int count, carry; + + count = val->n_len; + if (val->n_value[0] == 0) + count--; + assert (accum->n_len+accum->n_scale >= shift+count); + + /* Set up pointers and others */ + accp = (signed char *)(accum->n_value + + accum->n_len + accum->n_scale - shift - 1); + valp = (signed char *)(val->n_value + val->n_len - 1); + carry = 0; + + if (sub) { + /* Subtraction, carry is really borrow. */ + while (count--) { + *accp -= *valp-- + carry; + if (*accp < 0) { + carry = 1; + *accp-- += BASE; + } else { + carry = 0; + accp--; + } + } + while (carry) { + *accp -= carry; + if (*accp < 0) + *accp-- += BASE; + else + carry = 0; + } + } else { + /* Addition */ + while (count--) { + *accp += *valp-- + carry; + if (*accp > (BASE-1)) { + carry = 1; + *accp-- -= BASE; + } else { + carry = 0; + accp--; + } + } + while (carry) { + *accp += carry; + if (*accp > (BASE-1)) + *accp-- -= BASE; + else + carry = 0; + } + } +} + +/* Recursive divide and conquer multiply algorithm. + Based on + Let u = u0 + u1*(b^n) + Let v = v0 + v1*(b^n) + Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0 + + B is the base of storage, number of digits in u1,u0 close to equal. +*/ +static void +_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod, + int full_scale) +{ + bc_num u0, u1, v0, v1; + int u0len, v0len; + bc_num m1, m2, m3, d1, d2; + int n, prodlen, m1zero; + int d1len, d2len; + + /* Base case? */ + if ((ulen+vlen) < mul_base_digits + || ulen < MUL_SMALL_DIGITS + || vlen < MUL_SMALL_DIGITS ) { + _bc_simp_mul (u, ulen, v, vlen, prod, full_scale); + return; + } + + /* Calculate n -- the u and v split point in digits. */ + n = (MAX(ulen, vlen)+1) / 2; + + /* Split u and v. */ + if (ulen < n) { + u1 = bc_copy_num (_zero_); + u0 = new_sub_num (ulen,0, u->n_value); + } else { + u1 = new_sub_num (ulen-n, 0, u->n_value); + u0 = new_sub_num (n, 0, u->n_value+ulen-n); + } + if (vlen < n) { + v1 = bc_copy_num (_zero_); + v0 = new_sub_num (vlen,0, v->n_value); + } else { + v1 = new_sub_num (vlen-n, 0, v->n_value); + v0 = new_sub_num (n, 0, v->n_value+vlen-n); + } + _bc_rm_leading_zeros (u1); + _bc_rm_leading_zeros (u0); + u0len = u0->n_len; + _bc_rm_leading_zeros (v1); + _bc_rm_leading_zeros (v0); + v0len = v0->n_len; + + m1zero = bc_is_zero(u1) || bc_is_zero(v1); + + /* Calculate sub results ... */ + + bc_init_num(&d1); + bc_init_num(&d2); + bc_sub (u1, u0, &d1, 0); + d1len = d1->n_len; + bc_sub (v0, v1, &d2, 0); + d2len = d2->n_len; + + + /* Do recursive multiplies and shifted adds. */ + if (m1zero) + m1 = bc_copy_num (_zero_); + else + _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0); + + if (bc_is_zero(d1) || bc_is_zero(d2)) + m2 = bc_copy_num (_zero_); + else + _bc_rec_mul (d1, d1len, d2, d2len, &m2, 0); + + if (bc_is_zero(u0) || bc_is_zero(v0)) + m3 = bc_copy_num (_zero_); + else + _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0); + + /* Initialize product */ + prodlen = ulen+vlen+1; + *prod = bc_new_num(prodlen, 0); + + if (!m1zero) { + _bc_shift_addsub (*prod, m1, 2*n, 0); + _bc_shift_addsub (*prod, m1, n, 0); + } + _bc_shift_addsub (*prod, m3, n, 0); + _bc_shift_addsub (*prod, m3, 0, 0); + _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign); + + /* Now clean up! */ + bc_free_num (&u1); + bc_free_num (&u0); + bc_free_num (&v1); + bc_free_num (&m1); + bc_free_num (&v0); + bc_free_num (&m2); + bc_free_num (&m3); + bc_free_num (&d1); + bc_free_num (&d2); +} + +/* The multiply routine. N2 times 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; + int len1, len2; + int full_scale, prod_scale; + + /* Initialize things. */ + len1 = n1->n_len + n1->n_scale; + len2 = n2->n_len + n2->n_scale; + full_scale = n1->n_scale + n2->n_scale; + prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale))); + + /* Do the multiply */ + _bc_rec_mul (n1, len1, n2, len2, &pval, full_scale); + + /* Assign to prod and clean up the number. */ + pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + pval->n_value = pval->n_ptr; + pval->n_len = len2 + len1 + 1 - full_scale; + pval->n_scale = prod_scale; + _bc_rm_leading_zeros (pval); + if (bc_is_zero (pval)) + pval->n_sign = PLUS; + bc_free_num (prod); + *prod = pval; +} + +/* 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 % BASE; + carry = value / BASE; + } + + 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 (bc_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 = bc_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)); + bc_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) bc_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) bc_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 = bc_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) bc_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 (bc_is_zero (qval)) qval->n_sign = PLUS; + _bc_rm_leading_zeros (qval); + bc_free_num (quot); + *quot = qval; + + /* Clean up temporary storage. */ + free (mval); + free (num1); + free (num2); + + return 0; /* Everything is OK. */ +} + + +/* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and + NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT + is NULL then that store will be omitted. + */ + +int +bc_divmod (num1, num2, quot, rem, scale) + bc_num num1, num2, *quot, *rem; + int scale; +{ + bc_num quotient = NULL; + bc_num temp; + int rscale; + + /* Check for correct numbers. */ + if (bc_is_zero (num2)) return -1; + + /* Calculate final scale. */ + rscale = MAX (num1->n_scale, num2->n_scale+scale); + bc_init_num(&temp); + + /* Calculate it. */ + bc_divide (num1, num2, &temp, scale); + if (quot) + quotient = bc_copy_num (temp); + bc_multiply (temp, num2, &temp, rscale); + bc_sub (num1, temp, rem, rscale); + bc_free_num (&temp); + + if (quot) + { + bc_free_num (quot); + *quot = quotient; + } + + 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; +{ + return bc_divmod (num1, num2, NULL, result, scale); +} + +/* Raise BASE to the EXPO power, reduced modulo MOD. The result is + placed in RESULT. If a EXPO is not an integer, + only the integer part is used. */ + +int +bc_raisemod (base, expo, mod, result, scale) + bc_num base, expo, mod, *result; + int scale; +{ + bc_num power, exponent, parity, temp; + int rscale; + + /* Check for correct numbers. */ + if (bc_is_zero(mod)) return -1; + if (bc_is_neg(expo)) return -1; + + /* Set initial values. */ + power = bc_copy_num (base); + exponent = bc_copy_num (expo); + temp = bc_copy_num (_one_); + bc_init_num(&parity); + + /* Check the base for scale digits. */ + if (base->n_scale != 0) + bc_rt_warn ("non-zero scale in base"); + + /* Check the exponent for scale digits. */ + if (exponent->n_scale != 0) + { + bc_rt_warn ("non-zero scale in exponent"); + bc_divide (exponent, _one_, &exponent, 0); /*truncate */ + } + + /* Check the modulus for scale digits. */ + if (mod->n_scale != 0) + bc_rt_warn ("non-zero scale in modulus"); + + /* Do the calculation. */ + rscale = MAX(scale, base->n_scale); + while ( !bc_is_zero(exponent) ) + { + (void) bc_divmod (exponent, _two_, &exponent, &parity, 0); + if ( !bc_is_zero(parity) ) + { + bc_multiply (temp, power, &temp, rscale); + (void) bc_modulo (temp, mod, &temp, scale); + } + + bc_multiply (power, power, &power, rscale); + (void) bc_modulo (power, mod, &power, scale); + } + + /* Assign the value. */ + bc_free_num (&power); + bc_free_num (&exponent); + bc_free_num (result); + *result = 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; + int pwrscale; + int calcscale; + char neg; + + /* Check the exponent for scale digits and convert to a long. */ + if (num2->n_scale != 0) + bc_rt_warn ("non-zero scale in exponent"); + exponent = bc_num2long (num2); + if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0)) + bc_rt_error ("exponent too large in raise"); + + /* Special case if exponent is a zero. */ + if (exponent == 0) + { + bc_free_num (result); + *result = bc_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)); + } + + /* Set initial value of temp. */ + power = bc_copy_num (num1); + pwrscale = num1->n_scale; + while ((exponent & 1) == 0) + { + pwrscale = 2*pwrscale; + bc_multiply (power, power, &power, pwrscale); + exponent = exponent >> 1; + } + temp = bc_copy_num (power); + calcscale = pwrscale; + exponent = exponent >> 1; + + /* Do the calculation. */ + while (exponent > 0) + { + pwrscale = 2*pwrscale; + bc_multiply (power, power, &power, pwrscale); + if ((exponent & 1) == 1) { + calcscale = pwrscale + calcscale; + bc_multiply (temp, power, &temp, calcscale); + } + exponent = exponent >> 1; + } + + /* Assign the value. */ + if (neg) + { + bc_divide (_one_, temp, result, rscale); + bc_free_num (&temp); + } + else + { + bc_free_num (result); + *result = temp; + if ((*result)->n_scale > rscale) + (*result)->n_scale = rscale; + } + bc_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, diff; + + /* Initial checks. */ + cmp_res = bc_compare (*num, _zero_); + if (cmp_res < 0) + return 0; /* error */ + else + { + if (cmp_res == 0) + { + bc_free_num (num); + *num = bc_copy_num (_zero_); + return 1; + } + } + cmp_res = bc_compare (*num, _one_); + if (cmp_res == 0) + { + bc_free_num (num); + *num = bc_copy_num (_one_); + return 1; + } + + /* Initialize the variables. */ + rscale = MAX (scale, (*num)->n_scale); + bc_init_num(&guess); + bc_init_num(&guess1); + bc_init_num(&diff); + point5 = bc_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 = bc_copy_num (_one_); + cscale = (*num)->n_scale; + } + else + { + /* The number is greater than 1. Guess should start at 10^(exp/2). */ + bc_int2num (&guess,10); + + bc_int2num (&guess1,(*num)->n_len); + bc_multiply (guess1, point5, &guess1, 0); + guess1->n_scale = 0; + bc_raise (guess, guess1, &guess, 0); + bc_free_num (&guess1); + cscale = 3; + } + + /* Find the square root using Newton's algorithm. */ + done = FALSE; + while (!done) + { + bc_free_num (&guess1); + guess1 = bc_copy_num (guess); + bc_divide (*num, guess, &guess, cscale); + bc_add (guess, guess1, &guess, 0); + bc_multiply (guess, point5, &guess, cscale); + bc_sub (guess, guess1, &diff, cscale+1); + if (bc_is_near_zero (diff, cscale)) + { + if (cscale < rscale+1) + cscale = MIN (cscale*3, rscale+1); + else + done = TRUE; + } + } + + /* Assign the number and clean up. */ + bc_free_num (num); + bc_divide (guess,_one_,num,rscale); + bc_free_num (&guess); + bc_free_num (&guess1); + bc_free_num (&point5); + bc_free_num (&diff); + 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. */ +static 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 +bc_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 +bc_out_num (num, o_base, out_char, leading_zero) + bc_num num; + int o_base; +#ifdef __STDC__ + void (*out_char)(int); +#else + void (*out_char)(); +#endif + int leading_zero; +{ + 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 (bc_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++; + + if (leading_zero && bc_is_zero (num)) + (*out_char) ('0'); + + /* Now the fraction. */ + if (num->n_scale > 0) + { + (*out_char) ('.'); + for (index=0; indexn_scale; index++) + (*out_char) (BCD_CHAR(*nptr++)); + } + } + else + { + /* special case ... */ + if (leading_zero && bc_is_zero (num)) + (*out_char) ('0'); + + /* The number is some other base. */ + digits = NULL; + bc_init_num (&int_part); + bc_divide (num, _one_, &int_part, 0); + bc_init_num (&frac_part); + bc_init_num (&cur_dig); + bc_init_num (&base); + bc_sub (num, int_part, &frac_part, 0); + /* Make the INT_PART and FRAC_PART positive. */ + int_part->n_sign = PLUS; + frac_part->n_sign = PLUS; + bc_int2num (&base, o_base); + bc_init_num (&max_o_digit); + bc_int2num (&max_o_digit, o_base-1); + + + /* Get the digits of the integer part and push them on a stack. */ + while (!bc_is_zero (int_part)) + { + bc_modulo (int_part, base, &cur_dig, 0); + temp = (stk_rec *) malloc (sizeof(stk_rec)); + if (temp == NULL) bc_out_of_memory(); + temp->digit = bc_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 + bc_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 = bc_copy_num (_one_); + while (t_num->n_len <= num->n_scale) { + bc_multiply (frac_part, base, &frac_part, num->n_scale); + fdigit = bc_num2long (frac_part); + bc_int2num (&int_part, fdigit); + bc_sub (frac_part, int_part, &frac_part, 0); + if (o_base <= 16) + (*out_char) (ref_str[fdigit]); + else { + bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char); + pre_space = 1; + } + bc_multiply (t_num, base, &t_num, 0); + } + bc_free_num (&t_num); + } + + /* Clean up. */ + bc_free_num (&int_part); + bc_free_num (&frac_part); + bc_free_num (&base); + bc_free_num (&cur_dig); + bc_free_num (&max_o_digit); + } +} +/* 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 +bc_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/BASE)); index--) + val = val*BASE + *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); +} + + +/* Convert an integer VAL to a bc number NUM. */ + +void +bc_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 % BASE; + val = val / BASE; + + /* Extract remaining digits. */ + while (val != 0) + { + *bptr++ = val % BASE; + val = val / BASE; + ix++; /* Count the digits. */ + } + + /* Make the number. */ + bc_free_num (num); + *num = bc_new_num (ix, 0); + if (neg) (*num)->n_sign = MINUS; + + /* Assign the digits. */ + vptr = (*num)->n_value; + while (ix-- > 0) + *vptr++ = *--bptr; +} + +/* 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) bc_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; indexn_scale; index++) + *sptr++ = BCD_CHAR(*nptr++); + } + + /* Terminate the string and return it! */ + *sptr = '\0'; + return (str); +} +/* Convert strings to bc numbers. Base 10 only.*/ + +void +bc_str2num (num, str, scale) + bc_num *num; + char *str; + int scale; +{ + int digits, strscale; + char *ptr, *nptr; + char zero_int; + + /* Prepare num. */ + bc_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((int)*ptr)) ptr++, digits++; /* digits */ + if (*ptr == '.') ptr++; /* decimal point */ + while (isdigit((int)*ptr)) ptr++, strscale++; /* digits */ + if ((*ptr != '\0') || (digits+strscale == 0)) + { + *num = bc_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 = bc_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++); + } +} + +/* pn prints the number NUM in base 10. */ + +static void +out_char (int c) +{ + putchar(c); +} + + +void +pn (num) + bc_num num; +{ + bc_out_num (num, 10, out_char, 0); + out_char ('\n'); +} + + +/* pv prints a character array as if it was a string of bcd digits. */ +void +pv (name, num, len) + char *name; + unsigned char *num; + int len; +{ + int i; + printf ("%s=", name); + for (i=0; i +#include +#include "number.h" +#ifndef VARARGS +#include +#else +#include +#endif + +/* from number.c ... */ +extern int mul_base_digits; +/* extern int mul_small_digits; */ +extern bc_num _one_; + +/* global variables */ +int test_n = 1000; +int test_time = 30 * CLOCKS_PER_SEC; /* 30 seconds */ + +/* Other things for number.c. */ +int std_only; + +void +out_of_memory() +{ + fprintf (stderr, "Fatal error: Out of memory for malloc.\n"); + exit (1); +} + +/* 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: %s\n", error_mesg); +} + +/* A runtime warning tells of some action taken by the processor that + may change the program execution but was not enough of a problem + to stop the execution. */ + +#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: %s\n", error_mesg); +} + +void +out_char (int ch) +{ + putchar (ch); +} + +/* Time stuff !!! */ + +int +timeit ( bc_num a, bc_num b, int *n) +{ + clock_t first; + int i, res; + bc_num c; + + bc_init_num (&c); + first = clock(); + *n = 0; + do { + for (i=0; i 1) + if (strcmp (argv[1], "-d") == 0) + debug = 1; + + bc_init_numbers(); + bc_init_num (&ten); + bc_init_num (&num); + bc_init_num (&expo); + bc_init_num (&big); + bc_int2num (&ten, 10); + + if (debug) + fprintf (stderr, "Timings are for %d multiplies\n" + "Minimum time is %d seconds\n", test_n, + test_time/CLOCKS_PER_SEC); + + /* Two of the same size */ + min = 10; + max = 500; + + if (debug) + fprintf (stderr, "Testing numbers of the same length.\n"); + + while (min < max) { + mid = (min+max)/2; + if (debug) fprintf (stderr,"Checking %d...\n", mid); + + bc_int2num (&expo, mid); + bc_raise (ten, expo, &num, 0); + bc_sub (num, _one_, &num, 0); + + mul_base_digits = 2*mid+1; + t1 = timeit (num, num, &n1); + permul1 = (float)t1/(float)n1; + + mul_base_digits = 2*mid-1; + t2 = timeit (num, num, &n2); + permul2 = (float)t2/(float)n2; + + if (permul1 < permul2) + min = mid+1; + else + max = mid-1; + + if (debug) { + fprintf (stderr, "n1 = %d :: n2 = %d\n", n1, n2); + fprintf (stderr, "p1 = %f :: p2 = %f\n", permul1, permul2); + } + } + + if (debug) + fprintf (stderr, "Base digits crossover at %d digits\n", min); + printf ("#define MUL_BASE_DIGITS %d\n", 2*min); + + +#if 0 + mul_base_digits = min; + + /* Small one times a big one. */ + + smallsize = min/2; + bc_int2num (&expo, smallsize); + bc_raise (ten, expo, &big, 0); + bc_sub (num, _one_, &big, 0); + + min = min / 2; + max = 500; + + if (debug) + fprintf (stderr, "Testing numbers of the different length.\n"); + + while (min < max) { + mid = (min+max)/2; + if (debug) fprintf (stderr, "Checking %d...\n", mid); + + bc_int2num (&expo, mid-smallsize); + bc_raise (ten, expo, &num, 0); + bc_sub (num, _one_, &num, 0); + + mul_small_digits = mid+1; + t1 = timeit (big, num, &n1); + permul1 = (float)t1/(float)n1; + + mul_small_digits = mid-1; + t2 = timeit (big, num, &n2); + permul2 = (float)t2/(float)n2; + + if (permul1 < permul2) + min = mid+1; + else + max = mid-1; + + if (debug) { + fprintf (stderr, "n1 = %d :: n2 = %d\n", n1, n2); + fprintf (stderr, "p1 = %f :: p2 = %f\n", permul1, permul2); + } + } + + if (debug) + fprintf (stderr, "Non equal digits crossover at %d total digits\n", min); + printf ("#define MUL_SMALL_DIGITS = %d\n", min); + +#endif + + return 0; +} diff --git a/lib/vfprintf.c b/lib/vfprintf.c new file mode 100644 index 0000000..ad53d0c --- /dev/null +++ b/lib/vfprintf.c @@ -0,0 +1,31 @@ +/* vfprintf.c -- this was provided for minix. It may not + work on any other system. */ + +#include "config.h" +#ifndef HAVE_VPRINTF +#ifndef HAVE_DOPRINT + #error need vfprintf() or doprint() +#else + +#ifdef HAVE_LIB_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif + +int vfprintf(file, format, argp) +FILE *file; +_CONST char *format; +va_list argp; +{ + _doprintf(file, format, argp); + if (testflag(file, PERPRINTF)) fflush(file); + return 0; +} + +#endif /* HAVE_DOPRINT */ +#endif /* !HAVE_VFPRINTF */ diff --git a/missing b/missing new file mode 100755 index 0000000..e4b838c --- /dev/null +++ b/missing @@ -0,0 +1,134 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison touch file \`y.tab.c' + makeinfo touch the output file + yacc touch file \`y.tab.c'" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + touch config.h.in + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + your modified any \`.y' file. For being effective, your + modifications might require the \`Bison' package. Grab it from + any GNU archive site." + touch y.tab.c + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..cc8783e --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,36 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? + fi + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/packaging/bc.changes b/packaging/bc.changes new file mode 100644 index 0000000..30ae771 --- /dev/null +++ b/packaging/bc.changes @@ -0,0 +1,2 @@ +* Mon Mar 10 2014 Patrick McCarty c5ce1cd +- Minor cleanups for the spec file. diff --git a/packaging/bc.manifest b/packaging/bc.manifest new file mode 100644 index 0000000..017d22d --- /dev/null +++ b/packaging/bc.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/bc.spec b/packaging/bc.spec new file mode 100644 index 0000000..1149c67 --- /dev/null +++ b/packaging/bc.spec @@ -0,0 +1,59 @@ +Name: bc + +BuildRequires: automake +BuildRequires: bison +BuildRequires: ed +BuildRequires: flex +BuildRequires: readline-devel + +Url: ftp://ftp.gnu.org/pub/gnu/bc +License: GPL-2.0+ +Group: Base/Utilities +Version: 1.06 +Release: 0 +Summary: GNU Command Line Calculator +Source: %{name}-%{version}.tar.bz2 +Source1001: bc.manifest + +%description +bc is an interpreter that supports numbers of arbitrary precision and +the interactive execution of statements. The syntax has some +similarities to the C programming language. A standard math library is +available through command line options. When used, the math library is +read in before any other input files. bc then reads in all other files +from the command line, evaluating their contents. Then bc reads from +standard input (usually the keyboard). + +The dc program is also included. dc is a calculator that supports +reverse-polish notation and allows unlimited precision arithmetic. +Macros can also be defined. Normally, dc reads from standard input but +can also read in files specified on the command line. A calculator with +reverse-polish notation saves numbers to a stack. Arguments to +mathematical operations (operands) are "pushed" onto the stack until +the next operator is read in, which "pops" its arguments off the stack +and "pushes" its results back onto the stack. + +%prep +%setup -q +cp %{SOURCE1001} . + +%build +%reconfigure --with-readline + +rm bc/libmath.h +sed -i 's|\(^_PR.*readline.*$\)|/* \1 */|' bc/scan.l +make + +%install +make install DESTDIR=$RPM_BUILD_ROOT + +%files +%manifest %{name}.manifest +%defattr(-,root,root) +%doc COPYING +%{_bindir}/bc +%{_bindir}/dc +%{_infodir}/*.info* +%{_mandir}/man1/* + +%changelog diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp