bc: use the outsourced build.
* remove in-tree bc.
This commit is contained in:
@@ -23,7 +23,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
# Include required packages:
|
# Include required packages:
|
||||||
# primary architecture
|
# primary architecture
|
||||||
AddHaikuImagePackages [ FFilterByBuildFeatures
|
AddHaikuImagePackages [ FFilterByBuildFeatures
|
||||||
bash coreutils curl freetype icu libsolv zlib
|
bash bc coreutils curl freetype icu libsolv zlib
|
||||||
|
|
||||||
regular_image @{
|
regular_image @{
|
||||||
bzip2 ctags diffutils expat ffmpeg findutils gawk glu grep gutenprint
|
bzip2 ctags diffutils expat ffmpeg findutils gawk glu grep gutenprint
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
SYSTEM_BIN = [ FFilterByBuildFeatures
|
SYSTEM_BIN = [ FFilterByBuildFeatures
|
||||||
addattr alert arp autologin
|
addattr alert arp autologin
|
||||||
bc beep bfsinfo
|
beep bfsinfo
|
||||||
catattr checkfs checkitout chop clear collectcatkeys compress copyattr
|
catattr checkfs checkitout chop clear collectcatkeys compress copyattr
|
||||||
dc desklink df diskimage draggers
|
desklink df diskimage draggers
|
||||||
driveinfo dstcheck dumpcatalog
|
driveinfo dstcheck dumpcatalog
|
||||||
eject error
|
eject error
|
||||||
fdinfo ffm filepanel finddir findpaths fortune fstrim
|
fdinfo ffm filepanel finddir findpaths fortune fstrim
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ DoCatalogs filepanel
|
|||||||
;
|
;
|
||||||
|
|
||||||
SubInclude HAIKU_TOP src bin addattr ;
|
SubInclude HAIKU_TOP src bin addattr ;
|
||||||
SubInclude HAIKU_TOP src bin bc ;
|
|
||||||
SubInclude HAIKU_TOP src bin bfs_tools ;
|
SubInclude HAIKU_TOP src bin bfs_tools ;
|
||||||
SubInclude HAIKU_TOP src bin cddb_lookup ;
|
SubInclude HAIKU_TOP src bin cddb_lookup ;
|
||||||
SubInclude HAIKU_TOP src bin compress ;
|
SubInclude HAIKU_TOP src bin compress ;
|
||||||
|
|||||||
@@ -1,340 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 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.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Library General
|
|
||||||
Public License instead of this License.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src bin bc ;
|
|
||||||
|
|
||||||
SubInclude HAIKU_TOP src bin bc lib ;
|
|
||||||
SubInclude HAIKU_TOP src bin bc bc ;
|
|
||||||
SubInclude HAIKU_TOP src bin bc dc ;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src bin bc bc ;
|
|
||||||
|
|
||||||
SubDirCcFlags -DHAVE_CONFIG_H ;
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) lib ] ;
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) h ] ;
|
|
||||||
|
|
||||||
BinCommand bc :
|
|
||||||
main.c bc.c scan.c execute.c load.c storage.c util.c global.c
|
|
||||||
: libbc.a
|
|
||||||
: bc.rdef ;
|
|
||||||
|
|
||||||
-1886
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
resource app_version
|
|
||||||
{
|
|
||||||
major = 1,
|
|
||||||
middle = 0,
|
|
||||||
minor = 6,
|
|
||||||
variety = 5,
|
|
||||||
internal = 0,
|
|
||||||
short_info = "1.06",
|
|
||||||
long_info = "1.06 ©2000 The Free Software Foundation"
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,654 +0,0 @@
|
|||||||
%{
|
|
||||||
/* 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: [email protected]
|
|
||||||
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 <i_value> ENDOFLINE AND OR NOT
|
|
||||||
%token <s_value> STRING NAME NUMBER
|
|
||||||
/* '-', '+' are tokens themselves */
|
|
||||||
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
|
|
||||||
%token <c_value> ASSIGN_OP
|
|
||||||
/* '==', '<=', '>=', '!=', '<', '>' */
|
|
||||||
%token <s_value> REL_OP
|
|
||||||
/* '++', '--' */
|
|
||||||
%token <c_value> INCR_DECR
|
|
||||||
/* 'define', 'break', 'quit', 'length' */
|
|
||||||
%token <i_value> Define Break Quit Length
|
|
||||||
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
|
|
||||||
%token <i_value> Return For If While Sqrt Else
|
|
||||||
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
|
|
||||||
%token <i_value> Scale Ibase Obase Auto Read
|
|
||||||
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
|
|
||||||
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
|
|
||||||
/* 'history' */
|
|
||||||
%token <i_value> UNARY_MINUS HistoryVar
|
|
||||||
|
|
||||||
/* Types of all other things. */
|
|
||||||
%type <i_value> expression return_expression named_expression opt_expression
|
|
||||||
%type <c_value> '+' '-' '*' '/' '%'
|
|
||||||
%type <a_value> opt_parameter_list opt_auto_define_list define_list
|
|
||||||
%type <a_value> opt_argument_list argument_list
|
|
||||||
%type <i_value> program input_item semicolon_list statement_list
|
|
||||||
%type <i_value> 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 >= 0)
|
|
||||||
generate ("p");
|
|
||||||
$4 = next_label++;
|
|
||||||
sprintf (genstr, "N%1d:", $4);
|
|
||||||
generate (genstr);
|
|
||||||
}
|
|
||||||
opt_expression ';'
|
|
||||||
{
|
|
||||||
if ($7 < 0) generate ("1");
|
|
||||||
$7 = next_label++;
|
|
||||||
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
|
|
||||||
generate (genstr);
|
|
||||||
$<i_value>$ = 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 = $<i_value>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"); }
|
|
||||||
;
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
/* 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: [email protected]
|
|
||||||
us-mail: Philip A. Nelson
|
|
||||||
Computer Science Department, 9062
|
|
||||||
Western Washington University
|
|
||||||
Bellingham, WA 98226-9062
|
|
||||||
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
/* Include the configuration file. */
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
/* Standard includes for all files. */
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#ifdef HAVE_STRINGS_H
|
|
||||||
#include <strings.h>
|
|
||||||
#else
|
|
||||||
#include <string.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIMITS_H
|
|
||||||
#include <limits.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(LIBEDIT)
|
|
||||||
#include <histedit.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(READLINE)
|
|
||||||
#include <readline/readline.h>
|
|
||||||
#include <readline/history.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Include the other definitions. */
|
|
||||||
#include "const.h"
|
|
||||||
#include "number.h"
|
|
||||||
|
|
||||||
/* These definitions define all the structures used in
|
|
||||||
code and data storage. This includes the representation of
|
|
||||||
labels. The "guiding" principle is to make structures that
|
|
||||||
take a minimum of space when unused but can be built to contain
|
|
||||||
the full structures. */
|
|
||||||
|
|
||||||
/* Labels are first. Labels are generated sequentially in functions
|
|
||||||
and full code. They just "point" to a single bye in the code. The
|
|
||||||
"address" is the byte number. The byte number is used to get an
|
|
||||||
actual character pointer. */
|
|
||||||
|
|
||||||
typedef struct bc_label_group
|
|
||||||
{
|
|
||||||
long l_adrs [ BC_LABEL_GROUP ];
|
|
||||||
struct bc_label_group *l_next;
|
|
||||||
} bc_label_group;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/* 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: [email protected]
|
|
||||||
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
|
|
||||||
/* <limits.h> 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
|
|
||||||
@@ -1,788 +0,0 @@
|
|||||||
/* 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: [email protected]
|
|
||||||
us-mail: Philip A. Nelson
|
|
||||||
Computer Science Department, 9062
|
|
||||||
Western Washington University
|
|
||||||
Bellingham, WA 98226-9062
|
|
||||||
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
#include "bcdefs.h"
|
|
||||||
#include <signal.h>
|
|
||||||
#include "global.h"
|
|
||||||
#include "proto.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* The SIGINT interrupt handling routine. */
|
|
||||||
|
|
||||||
int had_sigint;
|
|
||||||
|
|
||||||
void
|
|
||||||
stop_execution (sig)
|
|
||||||
int sig;
|
|
||||||
{
|
|
||||||
had_sigint = TRUE;
|
|
||||||
printf ("\n");
|
|
||||||
rt_error ("interrupted execution");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Get the current byte and advance the PC counter. */
|
|
||||||
|
|
||||||
unsigned char
|
|
||||||
byte (pc)
|
|
||||||
program_counter *pc;
|
|
||||||
{
|
|
||||||
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_);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
ed libmath.h <<EOS-EOS
|
|
||||||
1,1s/^/{"/
|
|
||||||
1,\$s/\$/",/
|
|
||||||
2,\$s/^/"/
|
|
||||||
\$,\$d
|
|
||||||
\$,\$s/,\$/,0}/
|
|
||||||
w
|
|
||||||
q
|
|
||||||
EOS-EOS
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/* global.c: This defines the global variables. */
|
|
||||||
|
|
||||||
/* 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: [email protected]
|
|
||||||
us-mail: Philip A. Nelson
|
|
||||||
Computer Science Department, 9062
|
|
||||||
Western Washington University
|
|
||||||
Bellingham, WA 98226-9062
|
|
||||||
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
#include "bcdefs.h"
|
|
||||||
|
|
||||||
/* Since we want to define them here, we use the following define. */
|
|
||||||
#undef EXTERN
|
|
||||||
#define EXTERN
|
|
||||||
|
|
||||||
/* Define all the global variables for bc. */
|
|
||||||
#include "global.h"
|
|
||||||
|
|
||||||
CONST char *libmath[] =
|
|
||||||
#include "libmath.h"
|
|
||||||
;
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
/* global.h: The global variables 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: [email protected]
|
|
||||||
us-mail: Philip A. Nelson
|
|
||||||
Computer Science Department, 9062
|
|
||||||
Western Washington University
|
|
||||||
Bellingham, WA 98226-9062
|
|
||||||
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/* The current break level's lable. */
|
|
||||||
EXTERN int break_label;
|
|
||||||
|
|
||||||
/* The current if statement's else label or label after else. */
|
|
||||||
EXTERN int if_label;
|
|
||||||
|
|
||||||
/* The current for statement label for continuing the loop. */
|
|
||||||
EXTERN int continue_label;
|
|
||||||
|
|
||||||
/* Next available label number. */
|
|
||||||
EXTERN int next_label;
|
|
||||||
|
|
||||||
/* Byte code character storage. Used in many places for generation of code. */
|
|
||||||
EXTERN char genstr[80];
|
|
||||||
|
|
||||||
/* Count of characters printed to the output in compile_only mode. */
|
|
||||||
EXTERN int out_count;
|
|
||||||
|
|
||||||
/* Have we generated any code since the last initialization of the code
|
|
||||||
generator. */
|
|
||||||
EXTERN char did_gen;
|
|
||||||
|
|
||||||
/* Is this run an interactive execution. (Is stdin a terminal?) */
|
|
||||||
EXTERN char interactive;
|
|
||||||
|
|
||||||
/* Just generate the byte code. -c flag. */
|
|
||||||
EXTERN int compile_only;
|
|
||||||
|
|
||||||
/* Load the standard math functions. -l flag. */
|
|
||||||
EXTERN int use_math;
|
|
||||||
|
|
||||||
/* Give a warning on use of any non-standard feature (non-POSIX). -w flag. */
|
|
||||||
EXTERN int warn_not_std;
|
|
||||||
|
|
||||||
/* Accept POSIX bc only! -s flag. */
|
|
||||||
EXTERN int std_only;
|
|
||||||
|
|
||||||
/* Don't print the banner at start up. -q flag. */
|
|
||||||
EXTERN int quiet;
|
|
||||||
|
|
||||||
/* The list of file names to process. */
|
|
||||||
EXTERN file_node *file_names;
|
|
||||||
|
|
||||||
/* The name of the current file being processed. */
|
|
||||||
EXTERN char *file_name;
|
|
||||||
|
|
||||||
/* Is the current file a named file or standard input? */
|
|
||||||
EXTERN char is_std_in;
|
|
||||||
|
|
||||||
/* global variables for the bc machine. All will be dynamic in size.*/
|
|
||||||
/* Function storage. main is (0) and functions (1-f_count) */
|
|
||||||
|
|
||||||
EXTERN bc_function *functions;
|
|
||||||
EXTERN char **f_names;
|
|
||||||
EXTERN int f_count;
|
|
||||||
|
|
||||||
/* Variable stoarge and reverse names. */
|
|
||||||
|
|
||||||
EXTERN bc_var **variables;
|
|
||||||
EXTERN char **v_names;
|
|
||||||
EXTERN int v_count;
|
|
||||||
|
|
||||||
/* Array Variable storage and reverse names. */
|
|
||||||
|
|
||||||
EXTERN bc_var_array **arrays;
|
|
||||||
EXTERN char **a_names;
|
|
||||||
EXTERN int a_count;
|
|
||||||
|
|
||||||
/* Execution stack. */
|
|
||||||
EXTERN estack_rec *ex_stack;
|
|
||||||
|
|
||||||
/* Function return stack. */
|
|
||||||
EXTERN fstack_rec *fn_stack;
|
|
||||||
|
|
||||||
/* Current ibase, obase, scale, and n_history (if needed). */
|
|
||||||
EXTERN int i_base;
|
|
||||||
EXTERN int o_base;
|
|
||||||
EXTERN int scale;
|
|
||||||
#if defined(READLINE) || defined(LIBEDIT)
|
|
||||||
EXTERN int n_history;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(LIBEDIT)
|
|
||||||
/* LIBEDIT data */
|
|
||||||
EditLine *edit;
|
|
||||||
History *hist;
|
|
||||||
HistEvent histev;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* "Condition code" -- false (0) or true (1) */
|
|
||||||
EXTERN char c_code;
|
|
||||||
|
|
||||||
/* Records the number of the runtime error. */
|
|
||||||
EXTERN char runtime_error;
|
|
||||||
|
|
||||||
/* Holds the current location of execution. */
|
|
||||||
EXTERN program_counter pc;
|
|
||||||
|
|
||||||
/* For POSIX bc, this is just for number output, not strings. */
|
|
||||||
EXTERN int out_col;
|
|
||||||
|
|
||||||
/* Keeps track of the current number of characters per output line.
|
|
||||||
This includes the \n at the end of the line. */
|
|
||||||
EXTERN int line_size;
|
|
||||||
|
|
||||||
/* Input Line numbers and other error information. */
|
|
||||||
EXTERN int line_no;
|
|
||||||
EXTERN int had_error;
|
|
||||||
|
|
||||||
/* For larger identifiers, a tree, and how many "storage" locations
|
|
||||||
have been allocated. */
|
|
||||||
|
|
||||||
EXTERN int next_array;
|
|
||||||
EXTERN int next_func;
|
|
||||||
EXTERN int next_var;
|
|
||||||
|
|
||||||
EXTERN id_rec *name_tree;
|
|
||||||
|
|
||||||
/* For use with getopt. Do not declare them here.*/
|
|
||||||
extern int optind;
|
|
||||||
|
|
||||||
/* Access to the yy input file. Defined in scan.c. */
|
|
||||||
extern FILE *yyin;
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
/* libmath.b for GNU bc. */
|
|
||||||
|
|
||||||
/* This file is part of GNU bc.
|
|
||||||
Copyright (C) 1991, 1992, 1993, 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
|
|
||||||
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
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, n, v, z
|
|
||||||
|
|
||||||
/* a - holds x^y of x^y/y! */
|
|
||||||
/* d - holds y! */
|
|
||||||
/* e - is the value x^y/y! */
|
|
||||||
/* v - is the sum of the e's */
|
|
||||||
/* f - number of times x was divided by 2. */
|
|
||||||
/* m - is 1 if x was minus. */
|
|
||||||
/* i - iteration count. */
|
|
||||||
/* n - the scale to compute the sum. */
|
|
||||||
/* z - orignal scale. */
|
|
||||||
|
|
||||||
/* Check the sign of x. */
|
|
||||||
if (x<0) {
|
|
||||||
m = 1
|
|
||||||
x = -x
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Precondition x. */
|
|
||||||
z = scale;
|
|
||||||
n = 6 + z + .44*x;
|
|
||||||
scale = scale(x)+1;
|
|
||||||
while (x > 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{"@iK20:s2:p@r",
|
|
||||||
"@iF1,5.6,7,8,9,10,11,12,13,14[l5:0<Z1:1s11:pl5:ns5:pN1:l2:s14:",
|
|
||||||
"pK6:l14:+K.44:l5:*+s12:pl5:cS1+s2:pN2:l5:1>Z3:l9:1+s9:pl5:K2:",
|
|
||||||
"/s5:pl2:1+s2:pJ2:N3:l12:s2:p1l5:+s13:pl5:s6:p1s7:pK2:s10:pN5:",
|
|
||||||
"1B6:J4:N7:l10:i10:pJ5:N6:l6:l5:*s6:l7:l10:*s7:/s8:pl8:0=Z8:l9:",
|
|
||||||
"0>Z9:N10:l9:d9:Z11:l13:l13:*s13:pJ10:N11:N9:l14:s2:pl11:Z12:1",
|
|
||||||
"l13:/RN12:l13:1/RN8:l13:l8:+s13:pJ7:N4:0R]@r",
|
|
||||||
"@iF2,5.8,9,10,11,12,13,14[l5:0{Z1:1K10:l2:^-1/RN1:l2:s14:pK6:",
|
|
||||||
"l2:+s2:pK2:s9:p0s10:pN2:l5:K2:}Z3:l9:K2:*s9:pl5:cRs5:pJ2:N3:N4:",
|
|
||||||
"l5:K.5:{Z5:l9:K2:*s9:pl5:cRs5:pJ4:N5:l5:1-l5:1+/s12:s13:pl12:",
|
|
||||||
"l12:*s11:pK3:s10:pN7:1B8:J6:N9:l10:K2:+s10:pJ7:N8:l12:l11:*s12:",
|
|
||||||
"l10:/s8:pl8:0=Z10:l9:l13:*s13:pl14:s2:pl13:1/RN10:l13:l8:+s13:",
|
|
||||||
"pJ9:N6:0R]@r",
|
|
||||||
"@iF3,5.8,10,11,12,15,13,14[l2:s14:pK1.1:l14:*K2:+s2:p1C4,0:s13:",
|
|
||||||
"pl5:0<Z1:1s11:pl5:ns5:pN1:0s2:pl5:l13:/K2:+K4:/s12:pl5:K4:l12:",
|
|
||||||
"*l13:*-s5:pl12:K2:%Z2:l5:ns5:pN2:l14:K2:+s2:pl5:s8:s13:pl5:nl5:",
|
|
||||||
"*s15:pK3:s10:pN4:1B5:J3:N6:l10:K2:+s10:pJ4:N5:l8:l15:l10:l10:",
|
|
||||||
"1-*/*s8:pl8:0=Z7:l14:s2:pl11:Z8:l13:n1/RN8:l13:1/RN7:l13:l8:+",
|
|
||||||
"s13:pJ6:N3:0R]@r",
|
|
||||||
"@iF5,5.13,14[l2:s14:pl2:K1.2:*s2:pl5:1C4,0:K2:*+C3,0:s13:pl14:",
|
|
||||||
"s2:pl13:1/R0R]@r",
|
|
||||||
"@iF4,5.6,8,9,10,11,12,15,13,14[1s11:pl5:0<Z1:1ns11:pl5:ns5:pN1:",
|
|
||||||
"l5:1=Z2:l2:K25:{Z3:K.7853981633974483096156608:l11:/RN3:l2:K40",
|
|
||||||
":{Z4:K.7853981633974483096156608458198757210492:l11:/RN4:l2:K",
|
|
||||||
"60:{Z5:K.785398163397448309615660845819875721049292349843776455243736",
|
|
||||||
":l11:/RN5:N2:l5:K.2:=Z6:l2:K25:{Z7:K.1973955598498807583700497",
|
|
||||||
":l11:/RN7:l2:K40:{Z8:K.1973955598498807583700497651947902934475",
|
|
||||||
":l11:/RN8:l2:K60:{Z9:K.197395559849880758370049765194790293447585103787852101517688",
|
|
||||||
":l11:/RN9:N6:l2:s14:pl5:K.2:>Z10:l14:K5:+s2:pK.2:C4,0:s6:pN10:",
|
|
||||||
"l14:K3:+s2:pN11:l5:K.2:>Z12:l9:1+s9:pl5:K.2:-1l5:K.2:*+/s5:pJ11:N12:",
|
|
||||||
"l5:s12:s13:pl5:nl5:*s15:pK3:s10:pN14:1B15:J13:N16:l10:K2:+s10:",
|
|
||||||
"pJ14:N15:l12:l15:*s12:l10:/s8:pl8:0=Z17:l14:s2:pl9:l6:*l13:+l11:",
|
|
||||||
"/RN17:l13:l8:+s13:pJ16:N13:0R]@r",
|
|
||||||
"@iF6,12,5.6,16,7,8,9,10,11,15,13,14[l2:s14:p0s2:pl12:1/s12:pl12:",
|
|
||||||
"0<Z1:l12:ns12:pl12:K2:%1=Z2:1s11:pN2:N1:l0:s16:pKA:s0:p1s9:pK",
|
|
||||||
"2:s10:pN4:l10:l12:{B5:J3:N6:l10:i10:pJ4:N5:l9:l10:*s9:pJ6:N3:",
|
|
||||||
"K1.5:l14:*s2:pl5:l12:^K2:l12:^/l9:/s9:p1s8:s13:pl5:nl5:*K4:/s15:",
|
|
||||||
"pK1.5:l14:*l9:cL+l9:cS-s2:p1s10:pN8:1B9:J7:N10:l10:i10:pJ8:N9:",
|
|
||||||
"l8:l15:*l10:/l12:l10:+/s8:pl8:0=Z11:l16:s0:pl14:s2:pl11:Z12:l9:",
|
|
||||||
"nl13:*1/RN12:l9:l13:*1/RN11:l13:l8:+s13:pJ10:N7:0R]@r",0}
|
|
||||||
@@ -1,351 +0,0 @@
|
|||||||
/* 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: [email protected]
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,352 +0,0 @@
|
|||||||
/* 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: [email protected]
|
|
||||||
us-mail: Philip A. Nelson
|
|
||||||
Computer Science Department, 9062
|
|
||||||
Western Washington University
|
|
||||||
Bellingham, WA 98226-9062
|
|
||||||
|
|
||||||
*************************************************************************/
|
|
||||||
|
|
||||||
#include "bcdefs.h"
|
|
||||||
#include <signal.h>
|
|
||||||
#include "global.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#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 '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);
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
/* 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: [email protected]
|
|
||||||
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 <unistd.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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
|
|
||||||
@@ -1,448 +0,0 @@
|
|||||||
%{
|
|
||||||
/* 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: [email protected]
|
|
||||||
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 <i_value> ENDOFLINE AND OR NOT
|
|
||||||
%token <s_value> STRING NAME NUMBER
|
|
||||||
/* '-', '+' are tokens themselves */
|
|
||||||
%token <c_value> ASSIGN_OP
|
|
||||||
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
|
|
||||||
%token <s_value> REL_OP
|
|
||||||
/* '==', '<=', '>=', '!=', '<', '>' */
|
|
||||||
%token <c_value> INCR_DECR
|
|
||||||
/* '++', '--' */
|
|
||||||
%token <i_value> Define Break Quit Length
|
|
||||||
/* 'define', 'break', 'quit', 'length' */
|
|
||||||
%token <i_value> Return For If While Sqrt Else
|
|
||||||
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
|
|
||||||
%token <i_value> Scale Ibase Obase Auto Read
|
|
||||||
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
|
|
||||||
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
|
|
||||||
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
|
|
||||||
|
|
||||||
/* The types of all other non-terminals. */
|
|
||||||
%type <i_value> expression named_expression return_expression
|
|
||||||
%type <a_value> opt_parameter_list parameter_list opt_auto_define_list
|
|
||||||
%type <a_value> define_list opt_argument_list argument_list
|
|
||||||
%type <i_value> program input_item semicolon_list statement_list
|
|
||||||
%type <i_value> 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);
|
|
||||||
$<i_value>$ = next_label++;
|
|
||||||
sprintf (genstr, "N%1d:", $<i_value>$);
|
|
||||||
generate (genstr);
|
|
||||||
}
|
|
||||||
expression ')'
|
|
||||||
{
|
|
||||||
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
|
|
||||||
generate (genstr);
|
|
||||||
}
|
|
||||||
statement
|
|
||||||
{
|
|
||||||
sprintf (genstr, "J%1d:N%1d:", $<i_value>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; }
|
|
||||||
;
|
|
||||||
|
|
||||||
%%
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,374 +0,0 @@
|
|||||||
%{
|
|
||||||
/* 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: [email protected]
|
|
||||||
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 <errno.h>
|
|
||||||
|
|
||||||
/* Using flex, we can ask for a smaller input buffer. With lex, this
|
|
||||||
does nothing! */
|
|
||||||
|
|
||||||
#ifdef SMALL_BUF
|
|
||||||
#undef YY_READ_BUF_SIZE
|
|
||||||
#define YY_READ_BUF_SIZE 512
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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 <histedit.h>
|
|
||||||
|
|
||||||
/* 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: #");
|
|
||||||
}
|
|
||||||
<slcomment>[^\n]* { BEGIN(INITIAL); }
|
|
||||||
<slcomment>"\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 =<op>");
|
|
||||||
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. */
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,873 +0,0 @@
|
|||||||
/* 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 <stdarg.h>
|
|
||||||
#else
|
|
||||||
#include <varargs.h>
|
|
||||||
#endif
|
|
||||||
#include "global.h"
|
|
||||||
#include "proto.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* strcopyof mallocs new memory and copies a string to to the new
|
|
||||||
memory. */
|
|
||||||
|
|
||||||
char *
|
|
||||||
strcopyof (str)
|
|
||||||
char *str;
|
|
||||||
{
|
|
||||||
char *temp;
|
|
||||||
|
|
||||||
temp = (char *) bc_malloc (strlen (str)+1);
|
|
||||||
return (strcpy (temp,str));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* nextarg adds another value to the list of arguments. */
|
|
||||||
|
|
||||||
arg_list *
|
|
||||||
nextarg (args, val, 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 "\<cr>". 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 "\<cr>". 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 (FALSE);
|
|
||||||
case -2: /* we need to do a rebalancing act. */
|
|
||||||
A = *root;
|
|
||||||
B = (*root)->left;
|
|
||||||
if (B->balance <= 0)
|
|
||||||
{
|
|
||||||
/* Single Rotate. */
|
|
||||||
A->left = B->right;
|
|
||||||
B->right = A;
|
|
||||||
*root = B;
|
|
||||||
A->balance = 0;
|
|
||||||
B->balance = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Double Rotate. */
|
|
||||||
*root = B->right;
|
|
||||||
B->right = (*root)->left;
|
|
||||||
A->left = (*root)->right;
|
|
||||||
(*root)->left = B;
|
|
||||||
(*root)->right = A;
|
|
||||||
switch ((*root)->balance)
|
|
||||||
{
|
|
||||||
case -1:
|
|
||||||
A->balance = 1;
|
|
||||||
B->balance = 0;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
A->balance = 0;
|
|
||||||
B->balance = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
A->balance = 0;
|
|
||||||
B->balance = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(*root)->balance = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Insert it on the right. */
|
|
||||||
if (insert_id_rec (&((*root)->right), new_id))
|
|
||||||
{
|
|
||||||
/* The height increased. */
|
|
||||||
(*root)->balance ++;
|
|
||||||
switch ((*root)->balance)
|
|
||||||
{
|
|
||||||
case 0: /* no height increase. */
|
|
||||||
return (FALSE);
|
|
||||||
case 1: /* height increase. */
|
|
||||||
return (FALSE);
|
|
||||||
case 2: /* we need to do a rebalancing act. */
|
|
||||||
A = *root;
|
|
||||||
B = (*root)->right;
|
|
||||||
if (B->balance >= 0)
|
|
||||||
{
|
|
||||||
/* Single Rotate. */
|
|
||||||
A->right = B->left;
|
|
||||||
B->left = A;
|
|
||||||
*root = B;
|
|
||||||
A->balance = 0;
|
|
||||||
B->balance = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Double Rotate. */
|
|
||||||
*root = B->left;
|
|
||||||
B->left = (*root)->right;
|
|
||||||
A->right = (*root)->left;
|
|
||||||
(*root)->left = A;
|
|
||||||
(*root)->right = B;
|
|
||||||
switch ((*root)->balance)
|
|
||||||
{
|
|
||||||
case -1:
|
|
||||||
A->balance = 0;
|
|
||||||
B->balance = 1;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
A->balance = 0;
|
|
||||||
B->balance = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
A->balance = -1;
|
|
||||||
B->balance = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(*root)->balance = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we fall through to here, the tree did not grow in height. */
|
|
||||||
return (FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize variables for the symbol table tree. */
|
|
||||||
|
|
||||||
void
|
|
||||||
init_tree()
|
|
||||||
{
|
|
||||||
name_tree = NULL;
|
|
||||||
next_array = 1;
|
|
||||||
next_func = 1;
|
|
||||||
/* 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");
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
/* config.h. Generated automatically by configure. */
|
|
||||||
/* 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. */
|
|
||||||
#define HAVE_VPRINTF 1
|
|
||||||
|
|
||||||
/* 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 <sys/types.h> doesn't define. */
|
|
||||||
/* #undef size_t */
|
|
||||||
|
|
||||||
/* Define if you have the ANSI C header files. */
|
|
||||||
#define STDC_HEADERS 1
|
|
||||||
|
|
||||||
/* Define if lex declares yytext as a char * by default, not a char[]. */
|
|
||||||
#define YYTEXT_POINTER 1
|
|
||||||
|
|
||||||
/* VERSION number for DC target*/
|
|
||||||
#define DC_VERSION "1.3"
|
|
||||||
|
|
||||||
/* COPYRIGHT notice for DC target */
|
|
||||||
#define DC_COPYRIGHT "Copyright 1994, 1997, 1998, 2000 Free Software Foundation, Inc."
|
|
||||||
|
|
||||||
/* COPYRIGHT notice for BC target */
|
|
||||||
#define BC_COPYRIGHT "Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc."
|
|
||||||
|
|
||||||
/* Define to use the readline library. */
|
|
||||||
/* #undef READLINE */
|
|
||||||
|
|
||||||
/* Define to use the BSD libedit library. */
|
|
||||||
/* #undef LIBEDIT */
|
|
||||||
|
|
||||||
/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
|
|
||||||
/* #undef ptrdiff_t */
|
|
||||||
|
|
||||||
/* Define if you have the isgraph function. */
|
|
||||||
#define HAVE_ISGRAPH 1
|
|
||||||
|
|
||||||
/* Define if you have the setvbuf function. */
|
|
||||||
#define HAVE_SETVBUF 1
|
|
||||||
|
|
||||||
/* Define if you have the <lib.h> header file. */
|
|
||||||
/* #undef HAVE_LIB_H */
|
|
||||||
|
|
||||||
/* Define if you have the <limits.h> header file. */
|
|
||||||
#define HAVE_LIMITS_H 1
|
|
||||||
|
|
||||||
/* Define if you have the <stdarg.h> header file. */
|
|
||||||
#define HAVE_STDARG_H 1
|
|
||||||
|
|
||||||
/* Define if you have the <stddef.h> header file. */
|
|
||||||
#define HAVE_STDDEF_H 1
|
|
||||||
|
|
||||||
/* Define if you have the <stdlib.h> header file. */
|
|
||||||
#define HAVE_STDLIB_H 1
|
|
||||||
|
|
||||||
/* Define if you have the <string.h> header file. */
|
|
||||||
#define HAVE_STRING_H 1
|
|
||||||
|
|
||||||
/* Define if you have the <unistd.h> header file. */
|
|
||||||
#define HAVE_UNISTD_H 1
|
|
||||||
|
|
||||||
/* Name of package */
|
|
||||||
#define PACKAGE "bc"
|
|
||||||
|
|
||||||
/* Version number of package */
|
|
||||||
#define VERSION "1.06"
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src bin bc dc ;
|
|
||||||
|
|
||||||
SubDirCcFlags -DHAVE_CONFIG_H ;
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) lib ] ;
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) h ] ;
|
|
||||||
|
|
||||||
BinCommand dc :
|
|
||||||
dc.c misc.c eval.c stack.c array.c numeric.c string.c
|
|
||||||
: libbc.a
|
|
||||||
: dc.rdef ;
|
|
||||||
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h> /* "dc-proto.h" wants this */
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
/* get size_t definition from "almost ANSI" compiling environments. */
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 *));
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <limits.h> /* 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
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
# include <stdlib.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STRING_H
|
|
||||||
# include <string.h>
|
|
||||||
#else
|
|
||||||
# ifdef HAVE_STRINGS_H
|
|
||||||
# include <strings.h>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#include <getopt.h>
|
|
||||||
#include "dc.h"
|
|
||||||
#include "dc-proto.h"
|
|
||||||
|
|
||||||
#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */
|
|
||||||
# define EXIT_SUCCESS 0
|
|
||||||
#endif
|
|
||||||
#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
|
|
||||||
# define EXIT_FAILURE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *progname; /* basename of program invocation */
|
|
||||||
|
|
||||||
static void
|
|
||||||
bug_report_info DC_DECLVOID()
|
|
||||||
{
|
|
||||||
printf("Email bug reports to: [email protected] .\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;
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 */
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
resource app_version
|
|
||||||
{
|
|
||||||
major = 1,
|
|
||||||
middle = 3,
|
|
||||||
minor = 0,
|
|
||||||
variety = 5,
|
|
||||||
internal = 0,
|
|
||||||
short_info = "1.3",
|
|
||||||
long_info = "1.3 ©2000 The Free Software Foundation"
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,682 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#ifdef HAVE_STRING_H
|
|
||||||
# include <string.h> /* memchr */
|
|
||||||
#else
|
|
||||||
# ifdef HAVE_MEMORY_H
|
|
||||||
# include <memory.h> /* memchr, maybe */
|
|
||||||
# else
|
|
||||||
# ifdef HAVE_STRINGS_H
|
|
||||||
# include <strings.h> /* 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; p<end && count>0; ++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;
|
|
||||||
}
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
# include <stdlib.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STRING_H
|
|
||||||
# include <string.h>
|
|
||||||
#else
|
|
||||||
# ifdef HAVE_STRINGS_H
|
|
||||||
# include <strings.h>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#include <ctype.h>
|
|
||||||
#ifndef isgraph
|
|
||||||
# ifndef HAVE_ISGRAPH
|
|
||||||
# define isgraph isprint
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#include <getopt.h>
|
|
||||||
#include "dc.h"
|
|
||||||
#include "dc-proto.h"
|
|
||||||
|
|
||||||
#ifndef EXIT_FAILURE /* C89 <stdlib.h> */
|
|
||||||
# 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);
|
|
||||||
}
|
|
||||||
@@ -1,600 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#ifdef HAVE_LIMITS_H
|
|
||||||
# include <limits.h>
|
|
||||||
#else
|
|
||||||
# define UCHAR_MAX ((unsigned char)~0)
|
|
||||||
#endif
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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((bc_num *)&result.v.number);
|
|
||||||
bc_int2num((bc_num *)&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 <stdlib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_STDARG_H
|
|
||||||
# include <stdarg.h>
|
|
||||||
#else
|
|
||||||
# include <varargs.h>
|
|
||||||
#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 "\<cr>". */
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
@@ -1,494 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
# include <stdlib.h>
|
|
||||||
#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; i<DC_REGCOUNT; ++i)
|
|
||||||
dc_register[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear the evaluation stack */
|
|
||||||
void
|
|
||||||
dc_clear_stack DC_DECLVOID()
|
|
||||||
{
|
|
||||||
dc_list *n;
|
|
||||||
dc_list *t;
|
|
||||||
|
|
||||||
for (n=dc_stack; n; n=t){
|
|
||||||
t = n->link;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#ifdef HAVE_STDDEF_H
|
|
||||||
# include <stddef.h> /* ptrdiff_t */
|
|
||||||
#else
|
|
||||||
# define ptrdiff_t size_t
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
# include <stdlib.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STRING_H
|
|
||||||
# include <string.h> /* memcpy */
|
|
||||||
#else
|
|
||||||
# ifdef HAVE_MEMORY_H
|
|
||||||
# include <memory.h> /* memcpy, maybe */
|
|
||||||
# else
|
|
||||||
# ifdef HAVE_STRINGS_H
|
|
||||||
# include <strings.h> /* 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 */
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
/* 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 */
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
/* 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
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src bin bc lib ;
|
|
||||||
|
|
||||||
SubDirCcFlags -DHAVE_CONFIG_H ;
|
|
||||||
|
|
||||||
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
|
||||||
SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) h ] ;
|
|
||||||
|
|
||||||
StaticLibrary libbc.a :
|
|
||||||
getopt.c getopt1.c vfprintf.c number.c
|
|
||||||
;
|
|
||||||
@@ -1,752 +0,0 @@
|
|||||||
/* 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 <stdio.h>.
|
|
||||||
Ditto for AIX 3.2 and <stdlib.h>. */
|
|
||||||
#ifndef _NO_PROTO
|
|
||||||
#define _NO_PROTO
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined (__STDC__) || !__STDC__
|
|
||||||
/* This is a separate conditional since some stdc systems
|
|
||||||
reject `defined (const)'. */
|
|
||||||
#ifndef const
|
|
||||||
#define const
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* 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 <stdlib.h>
|
|
||||||
#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 <string.h>
|
|
||||||
#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 */
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
/* 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 <config.h>
|
|
||||||
#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 <stdio.h>
|
|
||||||
|
|
||||||
/* 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 <stdlib.h>
|
|
||||||
#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 <stdio.h>
|
|
||||||
|
|
||||||
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 */
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,244 +0,0 @@
|
|||||||
/* compute the crossover for recursive and simple multiplication */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "number.h"
|
|
||||||
#ifndef VARARGS
|
|
||||||
#include <stdarg.h>
|
|
||||||
#else
|
|
||||||
#include <varargs.h>
|
|
||||||
#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<test_n; i++)
|
|
||||||
bc_multiply(a,b,&c,0);
|
|
||||||
*n += test_n;
|
|
||||||
res = (int) (clock() - first);
|
|
||||||
} while (res < test_time);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int debug = 0; /* Print debugging messages? */
|
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
bc_num ten, num, expo, big;
|
|
||||||
|
|
||||||
int min, max, mid;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
int smallsize;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int n1, n2;
|
|
||||||
clock_t t1, t2;
|
|
||||||
float permul1, permul2;
|
|
||||||
|
|
||||||
/* args? */
|
|
||||||
if (argc > 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;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/* 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 <lib.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STDARG_H
|
|
||||||
#include <stdarg.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STDIO_H
|
|
||||||
#include <stdio.h>
|
|
||||||
#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 */
|
|
||||||
Reference in New Issue
Block a user