- Remove GNU bc/dc bits. There has not been any regressions seen after

BSD bc/dc import. It has been tested with make universe that this code
  is not used by anything any more.

Approved by:	delphij (mentor)
This commit is contained in:
Gabor Kovesdan 2010-02-21 14:28:03 +00:00
parent 62399df2c9
commit 5e72825fcd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=204171
88 changed files with 0 additions and 20901 deletions

View file

@ -1,4 +0,0 @@
Phil Nelson <philnelson@acm.org> wrote bc, including the number.c
source in the "lib" directory.
Ken Pizzini wrote dc.

File diff suppressed because it is too large Load diff

View file

@ -1,16 +0,0 @@
scale=2
print "\nCheck book program!\n"
print " Remember, deposits are negative transactions.\n"
print " Exit by a 0 transaction.\n\n"
print "Initial balance? "; bal = read()
bal /= 1
print "\n"
while (1) {
"current balance = "; bal
"transaction? "; trans = read()
if (trans == 0) break;
bal -= trans
bal /= 1
}
quit

View file

@ -1,53 +0,0 @@
/*
This is a program to determine the distribution of digits in the
fraction part of PI. It will look at the first scale digits.
The results are left in the global variable digits.
digits[0] is the number of 0's in PI.
This program requires the math library.
*/
define pi () {
auto ix, pi, save_scale, work;
save_scale = scale;
scale += 5;
print "\n\nCalculating PI to ",scale," digits. Please wait . . .";
pi = 4*a(1);
scale -= 5;
work = pi;
print "\nCounting digits. . .";
for (ix = 0; ix < 10; ix++) digits[ix] = 0;
/* Extract the One's digit from pi. */
scale = 0;
one_digit = work / 1;
for (ix = save_scale; ix > 0; ix--) {
/* Remove the One's digit and multiply by 10. */
scale = ix;
work = (work - one_digit) / 1 * 10;
/* Extract the One's digit. */
scale = 0;
one_digit = work / 1;
digits[one_digit] += 1;
}
/* Restore the scale. */
scale = save_scale;
/* Report. */
print "\n\n"
print "PI to ", scale, " digits is:\n", pi/1, "\n\n"
print "The frequency of the digits are:\n"
for (ix = 0; ix < 10; ix++) {
print " ", ix, " - ", digits[ix], " times\n"
}
print "\n\n"
}

View file

@ -1,32 +0,0 @@
/* An example that finds all primes between 2 and limit. */
define primes (limit) {
auto num, p, root, i
prime[1] = 2;
prime[2] = 3;
num = 2;
if (limit >= 2) print "prime 1 = 2\n"
if (limit >= 3) print "prime 2 = 3\n";
scale = 0;
for ( p=5; p <= limit; p += 2) {
root = sqrt(p);
isprime = 1;
for ( i = 1; i < num && prime[i] <= root; i++ ) {
if ( p % prime[i] == 0 ) {
isprime = 0;
break;
}
}
if (isprime) {
num += 1;
prime [num] = p;
print "prime ", num, " = ", p, "\n"
}
}
}
print "\ntyping 'primes (10)' will print all primes less than 10.\n"

View file

@ -1,40 +0,0 @@
/* An example that finds all primes between 2 and limit. */
define primes (limit) {
auto num, p, root, i
prime[1] = 2;
prime[2] = 3;
num = 2;
scale = 0;
for ( p=5; p <= limit; p += 2) {
root = sqrt(p);
isprime = 1;
for ( i = 1; i < num && prime[i] <= root; i++ ) {
if ( p % prime[i] == 0 ) {
isprime = 0;
break;
}
}
if (isprime) {
num += 1;
prime [num] = p;
}
}
}
print "\ntyping 'twins (10)' will print all twin primes less than 10.\n"
define twins (limit) {
auto i;
i = primes(limit+2);
for (i=1; prime[i] > 0; i++) {
if ((prime[i]+2) == prime[i+1]) \
print "twins are ", prime[i], " and ", prime[i+1], "\n"
}
}

View file

@ -1,17 +0,0 @@
Because of frequent questions ....... here is the BC FAQ
1) Why does BC have its own arbitrary precision number routines
(found in lib/number.c) rather than using GMP?
GMP has "integers" (no digits after a decimal), "rational numbers"
(stored as 2 integers) and "floats". None of these will correctly
represent a POSIX BC number. Floats are the closest, but will not
behave correctly for many computations. For example, BC numbers have
a "scale" that represent the number of digits to represent after the
decimal point. The multiplying two of these numbers requires one to
calculate an exact number of digits after the decimal point regardless
of the number of digits in the integer part. GMP floats have a
"fixed, but arbitrary" mantissa and so multiplying two floats will end
up dropping digits BC must calculate.

View file

@ -1,14 +0,0 @@
$FreeBSD$
bc 1.0.5a
originals can be found at: ftp://prep.ai.mit.edu/pub/gnu/
removed no subdirectories
removed bc/scan.c bc/bc.c bc/bc.h doc/texinfo.tex doc/dc.info
removed */getopt*
obrien@FreeBSD.ORG
Imported with the commands:
tar xvzf bc-1.0.5a.tar.gz
cd bc-1.0.5
cvs import src/contrib/bc BC bc_1_0_5a

View file

@ -1,176 +0,0 @@
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes a while. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have to compile the package for one architecture at a time
in the source code directory. After you have installed the package for
one architecture, use `make distclean' before reconfiguring for another
architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made.
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

View file

@ -1,18 +0,0 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = lib bc dc doc
MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in \
$(distdir).tar.gz h/number.h
dist-hook:
mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test
cp -p $(srcdir)/h/*.h $(distdir)/h
cp -p $(srcdir)/Examples/*.b $(distdir)/Examples
cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test
cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test
cp -p $(srcdir)/lib/testmul.c $(distdir)/lib
cp -p $(srcdir)/FAQ $(distdir)
timetest:
(cd lib; $(MAKE) specialnumber)

View file

@ -1,368 +0,0 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = .
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
CC = @CC@
LEX = @LEX@
MAKEINFO = @MAKEINFO@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
READLINELIB = @READLINELIB@
VERSION = @VERSION@
YACC = @YACC@
SUBDIRS = lib bc dc doc
MAINTAINERCLEANFILES = aclocal.m4 config.h.in configure Makefile.in $(distdir).tar.gz h/number.h
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
DIST_COMMON = README ./stamp-h.in AUTHORS COPYING COPYING.LIB ChangeLog \
INSTALL Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 config.h.in \
configure configure.in install-sh missing mkinstalldirs
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
all: all-redirect
.SUFFIXES:
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
$(ACLOCAL_M4): configure.in
cd $(srcdir) && $(ACLOCAL)
config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
cd $(srcdir) && $(AUTOCONF)
config.h: stamp-h
@if test ! -f $@; then \
rm -f stamp-h; \
$(MAKE) stamp-h; \
else :; fi
stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES= CONFIG_HEADERS=config.h \
$(SHELL) ./config.status
@echo timestamp > stamp-h 2> /dev/null
$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
@if test ! -f $@; then \
rm -f $(srcdir)/stamp-h.in; \
$(MAKE) $(srcdir)/stamp-h.in; \
else :; fi
$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
cd $(top_srcdir) && $(AUTOHEADER)
@echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
mostlyclean-hdr:
clean-hdr:
distclean-hdr:
-rm -f config.h
maintainer-clean-hdr:
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
# (1) if the variable is set in `config.status', edit `config.status'
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
@SET_MAKE@
all-recursive install-data-recursive install-exec-recursive \
installdirs-recursive install-recursive uninstall-recursive \
check-recursive installcheck-recursive info-recursive dvi-recursive:
@set fnord $(MAKEFLAGS); amf=$$2; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
mostlyclean-recursive clean-recursive distclean-recursive \
maintainer-clean-recursive:
@set fnord $(MAKEFLAGS); amf=$$2; \
dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \
test "$$subdir" = "." && dot_seen=yes; \
done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \
for subdir in $$rev; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
done && test -z "$$fail"
tags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
done
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
fi; \
done; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
-rm -rf $(distdir)
GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
mkdir $(distdir)/=build
mkdir $(distdir)/=inst
dc_install_base=`cd $(distdir)/=inst && pwd`; \
cd $(distdir)/=build \
&& ../configure --srcdir=.. --prefix=$$dc_install_base \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) dist
-rm -rf $(distdir)
@banner="$(distdir).tar.gz is ready for distribution"; \
dashes=`echo "$$banner" | sed s/./=/g`; \
echo "$$dashes"; \
echo "$$banner"; \
echo "$$dashes"
dist: distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
dist-all: distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
-rm -rf $(distdir)
distdir: $(DISTFILES)
-rm -rf $(distdir)
mkdir $(distdir)
-chmod 777 $(distdir)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
for subdir in $(SUBDIRS); do \
if test "$$subdir" = .; then :; else \
test -d $(distdir)/$$subdir \
|| mkdir $(distdir)/$$subdir \
|| exit 1; \
chmod 777 $(distdir)/$$subdir; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
|| exit 1; \
fi; \
done
$(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
info-am:
info: info-recursive
dvi-am:
dvi: dvi-recursive
check-am: all-am
check: check-recursive
installcheck-am:
installcheck: installcheck-recursive
all-recursive-am: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
install-exec-am:
install-exec: install-exec-recursive
install-data-am:
install-data: install-data-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-recursive
uninstall-am:
uninstall: uninstall-recursive
all-am: Makefile config.h
all-redirect: all-recursive-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs: installdirs-recursive
installdirs-am:
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
mostlyclean: mostlyclean-recursive
clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
clean: clean-recursive
distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
distclean: distclean-recursive
-rm -f config.status
maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-recursive
-rm -f config.status
.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
install-data-recursive uninstall-data-recursive install-exec-recursive \
uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
all-recursive check-recursive installcheck-recursive info-recursive \
dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
install-exec-am install-exec install-data-am install-data install-am \
install uninstall-am uninstall all-redirect all-am all installdirs-am \
installdirs mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
dist-hook:
mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test
cp -p $(srcdir)/h/*.h $(distdir)/h
cp -p $(srcdir)/Examples/*.b $(distdir)/Examples
cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test
cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test
cp -p $(srcdir)/lib/testmul.c $(distdir)/lib
cp -p $(srcdir)/FAQ $(distdir)
timetest:
(cd lib; $(MAKE) specialnumber)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -1,68 +0,0 @@
This is GNU bc version 1.06. (And dc version 1.2)
Changes in dc from 1.2 to 1.3:
Minor bug fixes.
New multiply algorithm of bc.
Changes in bc from 1.05 to 1.06:
New multiply algoirthm and many other changes in lib/number.c
Function size now done dynamically.
Function syntax in non-posix mode allows newlines in more places.
Bug fixes:
improved computation of j(n,x).
enables readline only if interactive.
for statment bug fixed.
use int instead of char for readline char counts.
improved cosine accuracy.
Changes in dc from 1.1 to 1.2:
added !< != !> commands
arrays now stack
output is now line buffered, provided setvbuf() is available
fixed known bugs in 'q', 'Q', 'a' commands, '-f' command-line option,
and documentation
changed the 'P' command's behavior on a numeric argument:
due to popular demand it now does the equivalent of 'aP'
(for small values)
added new 'n' command to do what the old 'P' command did
Changes in bc from 1.04 to 1.05:
Solaris makes work better.
bug fixes
stdout now always does line buffering.
sqrt bug fixed for small numbers.
readline (if support is compiled in) is enabled only for
interactive executions of bc.
This is GNU bc version 1.04. (And dc version 1.1)
Changes from 1.03
reorganization of source tree
use of automake
new commands for dc (|, ~, r, a)
new command line options for dc
fixed infinite loop in sqrt in bc
fixed an I/O bug in bc
made bc conform to POSIX for array parameters
added long option support for bc
new commandline options for bc (-q)
added support for readline to bc (use configure --with-readline)
command line argumens can now be taken from an environment variable
Changes from 1.02
minor bug fixes in bc.
addition of Ken Pizzini's dc program that uses the GNU bc
arbitrary precision arithmetic routines.
Changes from 1.01
minor bug fixes.

View file

@ -1,86 +0,0 @@
GNU bc version 1.06:
Extra configuration options:
--with-readline tells bc to use the readline package that allows
for editing input lines when run interactive.
--with-editline tells bc to use the BSD editline package that
allows for editing input lines when run interactive.
Extra make steps:
The simple make compiles a version of bc with fixed parameters
for the recursive multiplication algorithm. The fixed parameter
is the number of digits where a sequential algorithm is used
instead of the recursive algorithm. It is set to a value that
is known good on a couple of machines. (Sparc Ultra 10, Pentium
II, 450.) I'm calling this point the crossover point.
To make a version of bc with a custom crossover point for your
machine, do the following steps:
make timetest
make
The timetest step takes a minimum of 10 minutes to complete.
-------- Original comp.sources.reviewed README --------
Program: GNU bc
Author: Philip A. Nelson
E-mail: phil@cs.wwu.edu
OS: UNIX (BSD, System V, MINIX, POSIX)
Copying: GNU GPL version 2
Copyright holder: Free Software Foundation, Inc.
Version: bc version 1.01
Required: vsprintf and vfprintf routines.
Machines: It has been compiled and run on the following environments:
BSD4.3 (VAX 11)
MINIX 1.5 (IBM PC, both K&R and ANSI compilers)
MINIX 1.5 (pc532)
SUN-OS 4.1 (SUN 3 and SUN 4)
SVR3V5 (Motorola 68K)
SVR3.2 (3B2)
SVR4.0.2 (a 386 box)
ULTRIX 4.1 (DEC 5000)
UTS (Amdahl)
bc is an arbitrary precision numeric processing language. Syntax is
similar to C, but differs in many substantial areas. It supports
interactive execution of statements. bc is a utility included in the
POSIX P1003.2/D11 draft standard.
This version was written to be a POSIX compliant bc processor with
several extensions to the draft standard. Option flags are available
to cause warning or rejection of the extensions to the POSIX standard.
For those who want only POSIX bc with no extensions, a grammar is
provided for exactly the language described in the POSIX document.
The grammar (sbc.y) comes from the POSIX document. The Makefile
contains rules to make sbc. (for Standard BC)
Since the POSIX document does not specify how bc must be implemented,
this version does not use the historical method of having bc be a
compiler for the dc calculator. This version has a single executable
that both compiles the language and runs the a resulting "byte code".
The "byte code" is NOT the dc language.
Also, included in the initial distribution is the library file
vfprintf.c for MINIX systems. My minix 1.5 did not have this file.
Also, you should verify that vsprintf.c works correctly on your
system.
The extensions add some features I think are missing. The major
changes and additions for bc are (a) names are allowed to be full
identifiers ([a-z][a-z0-9_]*), (b) addition of the &&, ||, and !
operators, (c) allowing comparison and boolean operations in any
expression, (d) addition of an else clause to the if statement, (e)
addition of a new standard function "read()" that reads a number from
the standard input under program control, (f) passing of arrays as
parameters by variable, (g) addition of the "halt" statement that is
an executable statement unlike the quit (i.e. "if (1 == 0) quit" will
halt bc but "if (1 == 0) halt" will not halt bc.), and (h) the
addition of the special variable "last" that is assigned the value of
each print as the number is printed.
-----------------------------------------------------------------------

View file

@ -1,40 +0,0 @@
/* <--- bug.bc ---><--- bug.bc ---><--- bug.bc ---><--- bug.bc ---> */
/*
* See the file "signum" for a description and reference for this
* program.
*
* THIS BUG IS *NOT* IN GNU BC!!!
*
*/
obase=16
ibase=16
x=1A8F5C99605AE52 /* dividend */
y=BB0B404 /* divisor */
q=245A07AD /* (correct) quotient */
r=147EB9E /* (correct) remainder */
"Base 16
"
"x = "; x /* output numbers just to be sure... */
"y = "; y
"quo = "; q
"rem = "; r
"x/y = "; x/y /* watch this result! */
"x%y = "; x%y /* watch this result! */
"y*q+r= "; y*q+r /* check quotient & remainder */
/*
* Do the same thing in base 10:
*/
"
Base 10
"
ibase=A
obase=10
"x = "; x /* output numbers just to be sure... */
"y = "; y
"q = "; q
"r = "; r
"x/y = "; x/y /* watch this result! */
"x%y = "; x%y /* watch this result! */
"y*q+r= "; y*q+r /* check quotient & remainder */

View file

@ -1,14 +0,0 @@
"This tests arrays!
"
define p(x,y) {
auto i;
for (i=x; i<y; i++) a[i];
}
for (i=0; i<10; i++) a[i] = i;
j = p(0,10);
for (i=1000; i<1030; i++) a[i] = i;
j = p(1000,1030);
j = p(0,10);

View file

@ -1,30 +0,0 @@
"This tests arrays!
"
define p(a[],x,y) {
auto i;
for (i=x; i<y; i++) a[i];
}
define m(a[],x,y) {
auto i;
for (i=x; i<y; i++) a[i] = i;
}
define m1(*a[],x,y) {
auto i;
print "m1\n"
for (i=x; i<y; i++) a[i] = i;
}
for (i=0; i<10; i++) a[i] = i;
j = p(a[],0,10);
j = m(b[],0,10);
j = p(b[],0,10);
print "---\n";
j = m1(b[],0,10);
j = p(b[],0,10);
quit

View file

@ -1,16 +0,0 @@
define p ( x[] ) {
auto i;
for (i=0; i<10; i++) x[i];
}
define m ( x[] ) {
auto i;
for (i=0; i<10; i++) x[i] *= 2;
}
scale = 20;
for (i=0; i<10; i++) a[i] = sqrt(i);
p(a[]);
m(a[]);
p(a[]);

View file

@ -1,5 +0,0 @@
for (a=0; a<1000; a+=2) x=a(a)
x
for (a=0; a<2; a+=.01) x=a(a)
x
quit

View file

@ -1,109 +0,0 @@
define t (x,y,d,s,t) {
auto u, v, w, i, b, c;
if (s >= t) {
"Bad Scales. Try again.
"; return;
}
for (i = x; i < y; i += d) {
scale = s;
u = f(i);
scale = t;
v = f(i);
scale = s;
w = v / 1;
b += 1;
if (u != w) {
c += 1;
"
Failed:
"
" index = "; i;
" val1 = "; u;
" val2 = "; v;
"
"
}
}
"
Total tests: "; b;
"
Total failures: "; c;
"
Percent failed: "; scale = 2; c*100/b;
}
/*
b = begining scale value,
l = limit scale value,
i = increment scale value.
if b is set to a non-zero value before this file is executed,
b, l and i are not reset.
*/
if (b == 0) { b = 10; l = 61; i = 10; }
"
Checking e(x)"
define f(x) {
return (e(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(0,200,1,s,s+4)
}
"
Checking l(x)"
define f(x) {
return (l(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(1,10000,25,s,s+4)
}
"
Checking s(x)"
define f(x) {
return (s(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(0,8*a(1),.01,s,s+4)
}
"
Checking a(x)"
define f(x) {
return (a(x))
}
for (s=10; s<l; s=s+i) {
"
scale = "; s
j = t(-1000,1000,10,s,s+4)
}
"
Checking j(n,x)"
define f(x) {
return (j(n,x))
}
for (s=10; s<l; s=s+i) {
"
n=0, scale = "; s
n=0
j = t(0,30,.1,s,s+4)
"
n=1, scale = "; s
n=1
j = t(0,30,.1,s,s+4)
}

View file

@ -1,8 +0,0 @@
scale = 20
a=2/3
for (i=0; i<1000; i++) {
for (j=1; j<100; j++) b=a/j
}
b
quit

View file

@ -1,3 +0,0 @@
for (a=0; a<180; a+=.4) x=e(a)
x
quit

View file

@ -1,12 +0,0 @@
define f (x) {
if (x<=1) return(1)
return (f(x-1)*x)
}
for (a=1; a<600; a++) b=f(a)
"
"
"b=";b
quit

View file

@ -1,6 +0,0 @@
scale = 50
for (a=0; a<=100; a += 20) {
for (b=0; b<=300; b += 20) x=j(a,b)
x
}
quit

View file

@ -1,4 +0,0 @@
scale = 60
for (a=1; a<100000000000000000000000000000000000000; a = a*2) x=l(a)
x
quit

View file

@ -1,13 +0,0 @@
scale = 20
for (i=0; i<10000; i++) {
for (j=1; j<100; j++) b=i*j
}
b
for (i=0; i<10000; i++) {
for (j=1000000000000000000000000000000000000000000000000000000000000000000; \
j<1000000000000000000000000000000000000000000000000000000000000000100; \
j++) b=i*j
}
b
quit

View file

@ -1,7 +0,0 @@
for (i=0; i<1000; i++) a = 2^i;
a
for (i=3000; i<3100; i++) a = 3^i;
a
for (i=200; i<220; i++) a = (4^100)^i;
a
quit

View file

@ -1,87 +0,0 @@
/* From gnu@cygnus.com Wed Jul 14 13:46:44 1993
Return-Path: <gnu@cygnus.com>
To: phil@cs.wwu.edu, gnu@cygnus.com
Subject: bc/dc - no rest for the wicked
Date: Tue, 06 Jul 93 19:12:40 -0700
From: gnu@cygnus.com
GNU bc 1.02 passes all these tests. Can you add the test to the distribution?
Putting it into a DejaGnu test case for GNU bc would be a great thing, too.
(I haven't seen the Signum paper, maybe you can dig it out.)
John Gilmore
Cygnus Support
------- Forwarded Message
Date: Tue, 6 Jul 93 08:45:48 PDT
From: uunet!Eng.Sun.COM!David.Hough@uunet.UU.NET (David Hough)
Message-Id: <9307061545.AA14477@dgh.Eng.Sun.COM>
To: numeric-interest@validgh.com
Subject: bc/dc - no rest for the wicked
Steve Sommars sent me a bc script which reproduces ALL the test cases from
Dittmer's paper. Neither SunOS 5.2 on SPARC nor 5.1 on x86 come out clean.
Anybody else who has fixed all the bugs would be justified in
bragging about it here. */
/*Ingo Dittmer, ACM Signum, April 1993, page 8-11*/
define g(x,y,z){
auto a
a=x%y
if(a!=z){
"
x=";x
"y=";y
"Should be ";z
"was ";a
}
}
/*Table 1*/
g=g(53894380494284,9980035577,2188378484)
g=g(47907874973121,9980035577,3704203521)
g=g(76850276401922,9980035577,4002459022)
g=g(85830854846664,9980035577,2548884464)
g=g(43915353970066,9980035577,3197431266)
g=g(35930746212825,9980035577,2618135625)
g=g(51900604524715,9980035577,4419524315)
g=g(87827018005068,9980035577,2704927468)
g=g(57887902441764,9980035577,3696095164)
g=g(96810941031110,9980035577,4595934210)
/*Table 2*/
g=g(86833646827370,9980035577,7337307470)
g=g(77850880592435,9980035577,6603091835)
g=g(84836601050323,9980035577,6298645823)
g=g(85835110016211,9980035577,6804054011)
g=g(94817143459192,9980035577,6805477692)
g=g(94818870293481,9980035577,8532311981)
g=g(91823235571154,9980035577,6908262754)
g=g(59885451951796,9980035577,5238489796)
g=g(80844460893239,9980035577,6172719539)
g=g(67869195894693,9980035577,4953971093)
g=g(95813990985202,9980035577,5649446002)
/*Skip Table 3, duplicate of line 1, table 1*/
/*Table 4*/
g=g(28420950579078013018256253301,17987947258,16619542243)
g=g(12015118977201790601658257234,16687885701,8697335297)
g=g(14349070374946789715188912007,13712994561,3605141129)
g=g(61984050238512905451986475027,13337935089,5296182558)
g=g(86189707791214681859449918641,17837971389,14435206830)
g=g(66747908181102582528134773954,19462997965,8615839889)
/*Table 6*/
g=g(4999253,9998,253)
g=g(8996373,9995,873)
/* Added by Phil Nelson..... */
"end of tests
"

View file

@ -1,5 +0,0 @@
for (i=0; i<8*a(1); i=i+.01) x=s(i)
x
for (i=i; i<16*a(1); i=i+.01) x=s(i+.1234123412341234)
x
quit

View file

@ -1,13 +0,0 @@
scale = 5
for (a=1; a<500; a++) r=sqrt(a)
r
scale = 10
for (a=1; a<500; a++) r=sqrt(a)
r
scale = 25
for (a=1; a<500; a++) r=sqrt(a)
r
scale = 40
for (a=1; a<500; a++) r=sqrt(a)
r
quit

View file

@ -1,13 +0,0 @@
for (j=0; j<10; j++) {
a = .9;
b = .9+j;
scale = 2;
for (i=0; i<90; i++) {
scale += 1;
a /= 10;
b += a;
x = sqrt(b);
}
x;
}
quit

View file

@ -1,10 +0,0 @@
scale = 20
for (a=1; a<5000; a += 1) r=sqrt(a)
r
for (a=1; a<50000; a += 100) r=sqrt(a)
r
for (a=1; a<500000; a+=1000) r=sqrt(a)
r
for (a=1; a<5000000; a+=10000) r=sqrt(a)
r
quit

View file

@ -1,47 +0,0 @@
/* This function "t" tests the function "f" to see if computing at
two different scales has much effect on the accuracy.
test from f(x) to f(y) incrementing the index by d. f(i) is
computed at two scales, scale s and then scale t, where t>s.
the result from scale t is divided by 1 at scale s and the
results are compared. If they are different, the function is
said to have failed. It will then print out the value of i
(called index) and the two original values val1 (scale s) and
val2 (scale t) */
define t (x,y,d,s,t) {
auto u, v, w, i, b, c;
if (s >= t) {
"Bad Scales. Try again.
"; return;
}
for (i = x; i < y; i += d) {
scale = s;
u = f(i);
scale = t;
v = f(i);
scale = s;
w = v / 1;
b += 1;
if (u != w) {
c += 1;
"
Failed:
"
" index = "; i;
" val1 = "; u;
" val2 = "; v;
"
"
}
}
"
Total tests: "; b;
"
Total failures: "; c;
"
Percent failed: "; scale = 2; c*100/b;
}

View file

@ -1,16 +0,0 @@
#!/bin/sh
#
# Time the functions.
#
SYSBC=/usr/bin/bc
if [ x$BC = x ] ; then
BC=../bc/bc
fi
for file in exp.b ln.b sine.b atan.b jn.b mul.b div.b raise.b sqrt.b
do
for prog in $BC $SYSBC $OTHERBC
do
echo Timing $file with $prog
time $prog -l $file
done
done

View file

@ -1,24 +0,0 @@
/* PACKAGE name */
#undef PACKAGE
/* Package VERSION number */
#undef VERSION
/* VERSION number for DC target*/
#undef DC_VERSION
/* COPYRIGHT notice for DC target */
#undef DC_COPYRIGHT
/* COPYRIGHT notice for BC target */
#undef BC_COPYRIGHT
/* Define to use the readline library. */
#undef READLINE
/* Define to use the BSD libedit library. */
#undef LIBEDIT
/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
#undef ptrdiff_t

136
contrib/bc/aclocal.m4 vendored
View file

@ -1,136 +0,0 @@
dnl aclocal.m4 generated automatically by aclocal 1.4
dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
dnl PARTICULAR PURPOSE.
# Do all the work for Automake. This macro actually does too much --
# some checks are only needed if your package does certain things.
# But this isn't really a big deal.
# serial 1
dnl Usage:
dnl AM_INIT_AUTOMAKE(package,version, [no-define])
AC_DEFUN(AM_INIT_AUTOMAKE,
[AC_REQUIRE([AC_PROG_INSTALL])
PACKAGE=[$1]
AC_SUBST(PACKAGE)
VERSION=[$2]
AC_SUBST(VERSION)
dnl test to see if srcdir already configured
if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
fi
ifelse([$3],,
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
AC_REQUIRE([AM_SANITY_CHECK])
AC_REQUIRE([AC_ARG_PROGRAM])
dnl FIXME This is truly gross.
missing_dir=`cd $ac_aux_dir && pwd`
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
AC_REQUIRE([AC_PROG_MAKE_SET])])
#
# Check to make sure that the build environment is sane.
#
AC_DEFUN(AM_SANITY_CHECK,
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftestfile
# Do `set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
if test "[$]*" = "X"; then
# -L didn't work.
set X `ls -t $srcdir/configure conftestfile`
fi
if test "[$]*" != "X $srcdir/configure conftestfile" \
&& test "[$]*" != "X conftestfile $srcdir/configure"; then
# If neither matched, then we have a broken ls. This can happen
# if, for instance, CONFIG_SHELL is bash and it inherits a
# broken ls alias from the environment. This has actually
# happened. Such a system could not be considered "sane".
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
alias in your environment])
fi
test "[$]2" = conftestfile
)
then
# Ok.
:
else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
rm -f conftest*
AC_MSG_RESULT(yes)])
dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
dnl The program must properly implement --version.
AC_DEFUN(AM_MISSING_PROG,
[AC_MSG_CHECKING(for working $2)
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
# Redirect stdin to placate older versions of autoconf. Sigh.
if ($2 --version) < /dev/null > /dev/null 2>&1; then
$1=$2
AC_MSG_RESULT(found)
else
$1="$3/missing $2"
AC_MSG_RESULT(missing)
fi
AC_SUBST($1)])
# Like AC_CONFIG_HEADER, but automatically create stamp file.
AC_DEFUN(AM_CONFIG_HEADER,
[AC_PREREQ([2.12])
AC_CONFIG_HEADER([$1])
dnl When config.status generates a header, we must update the stamp-h file.
dnl This file resides in the same directory as the config header
dnl that is generated. We must strip everything past the first ":",
dnl and everything past the last "/".
AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
<<am_indx=1
for am_file in <<$1>>; do
case " <<$>>CONFIG_HEADERS " in
*" <<$>>am_file "*<<)>>
echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
;;
esac
am_indx=`expr "<<$>>am_indx" + 1`
done<<>>dnl>>)
changequote([,]))])
dnl AM_PROG_LEX
dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT
AC_DEFUN(AM_PROG_LEX,
[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1)
AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex")
AC_PROG_LEX
AC_DECL_YYTEXT])

View file

@ -1,42 +0,0 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = bc
bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c
EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h \
sbc.y
noinst_HEADERS = libmath.h
DISTCLEANFILES = sbc sbc.c sbc.h
MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c
INCLUDES = -I$(srcdir) -I$(srcdir)/../h
LIBBC = ../lib/libbc.a
LIBL = @LEXLIB@
LDADD = $(LIBBC) $(LIBL) @READLINELIB@
YFLAGS = -d
CFLAGS = @CFLAGS@ -Wall -funsigned-char
$(PROGRAMS): $(LIBBC)
scan.o: bc.h
global.o: libmath.h
libmath.h: libmath.b
echo '{0}' > libmath.h
$(MAKE) fbc
./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h
$(srcdir)/fix-libmath_h
rm -f ./fbc
fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o
fbc: $(fbcOBJ)
$(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o
sbc.o: sbc.c
sbc: $(sbcOBJ)
$(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)

View file

@ -1,345 +0,0 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
CC = @CC@
LEX = @LEX@
MAKEINFO = @MAKEINFO@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
READLINELIB = @READLINELIB@
VERSION = @VERSION@
YACC = @YACC@
bin_PROGRAMS = bc
bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c
EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h sbc.y
noinst_HEADERS = libmath.h
DISTCLEANFILES = sbc sbc.c sbc.h
MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c
INCLUDES = -I$(srcdir) -I$(srcdir)/../h
LIBBC = ../lib/libbc.a
LIBL = @LEXLIB@
LDADD = $(LIBBC) $(LIBL) @READLINELIB@
YFLAGS = -d
CFLAGS = @CFLAGS@ -Wall -funsigned-char
fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o
sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(bin_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
bc_OBJECTS = main.o bc.o scan.o execute.o load.o storage.o util.o \
global.o
bc_LDADD = $(LDADD)
bc_DEPENDENCIES = ../lib/libbc.a
bc_LDFLAGS =
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LEXLIB = @LEXLIB@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
HEADERS = $(noinst_HEADERS)
DIST_COMMON = Makefile.am Makefile.in bc.c scan.c
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
SOURCES = $(bc_SOURCES)
OBJECTS = $(bc_OBJECTS)
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .l .o .s .y
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps bc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-binPROGRAMS:
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
distclean-binPROGRAMS:
maintainer-clean-binPROGRAMS:
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
list='$(bin_PROGRAMS)'; for p in $$list; do \
rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
done
.c.o:
$(COMPILE) -c $<
.s.o:
$(COMPILE) -c $<
.S.o:
$(COMPILE) -c $<
mostlyclean-compile:
-rm -f *.o core *.core
clean-compile:
distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
bc: $(bc_OBJECTS) $(bc_DEPENDENCIES)
@rm -f bc
$(LINK) $(bc_LDFLAGS) $(bc_OBJECTS) $(bc_LDADD) $(LIBS)
.l.c:
$(LEX) $(AM_LFLAGS) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@
.y.c:
$(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c
if test -f y.tab.h; then \
if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
else :; fi
bc.h: bc.c
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = bc
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
bc.o: bc.c bcdefs.h ../config.h const.h ../h/number.h global.h proto.h
execute.o: execute.c bcdefs.h ../config.h const.h ../h/number.h global.h \
proto.h
global.o: global.c bcdefs.h ../config.h const.h ../h/number.h global.h \
libmath.h
load.o: load.c bcdefs.h ../config.h const.h ../h/number.h global.h \
proto.h
main.o: main.c bcdefs.h ../config.h const.h ../h/number.h global.h \
proto.h ../h/getopt.h
scan.o: scan.c bcdefs.h ../config.h const.h ../h/number.h bc.h global.h \
proto.h
storage.o: storage.c bcdefs.h ../config.h const.h ../h/number.h global.h \
proto.h
util.o: util.c bcdefs.h ../config.h const.h ../h/number.h global.h \
proto.h
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am: install-binPROGRAMS
install-exec: install-exec-am
install-data-am:
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-binPROGRAMS
uninstall: uninstall-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(bindir)
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
maintainer-clean-generic:
-test -z "scanlbchbcc$(MAINTAINERCLEANFILES)" || rm -f scanl bch bcc $(MAINTAINERCLEANFILES)
mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \
mostlyclean-am
clean: clean-am
distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
distclean-generic clean-am
distclean: distclean-am
maintainer-clean-am: maintainer-clean-binPROGRAMS \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
check-am installcheck-am installcheck install-exec-am install-exec \
install-data-am install-data install-am install uninstall-am uninstall \
all-redirect all-am all installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
$(PROGRAMS): $(LIBBC)
scan.o: bc.h
global.o: libmath.h
libmath.h: libmath.b
echo '{0}' > libmath.h
$(MAKE) fbc
./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h
$(srcdir)/fix-libmath_h
rm -f ./fbc
fbc: $(fbcOBJ)
$(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
sbc.o: sbc.c
sbc: $(sbcOBJ)
$(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
%}
%start program
%union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
}
/* Extensions over POSIX bc.
a) NAME was LETTER. This grammar allows longer names.
Single letter names will still work.
b) Relational_expression allowed only one comparison.
This grammar has added boolean expressions with
&& (and) || (or) and ! (not) and allowed all of them in
full expressions.
c) Added an else to the if.
d) Call by variable array parameters
e) read() procedure that reads a number under program control from stdin.
f) halt statement that halts the the program under program control. It
is an executed statement.
g) continue statement for for loops.
h) optional expressions in the for loop.
i) print statement to print multiple numbers per line.
j) warranty statement to print an extended warranty notice.
j) limits statement to print the processor's limits.
*/
%token <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"); }
;
%%

View file

@ -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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Include the configuration file. */
#include "config.h"
/* Standard includes for all files. */
#include <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

View file

@ -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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */
#ifndef INT_MAX
#define INT_MAX 0x7FFFFFFF
#endif
#ifndef LONG_MAX
#define LONG_MAX 0x7FFFFFFF
#endif
/* Define constants in some reasonable size. The next 4 constants are
POSIX constants. */
#ifdef BC_BASE_MAX
/* <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

View file

@ -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: philnelson@acm.org
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_);
}

View file

@ -1,9 +0,0 @@
ed libmath.h <<EOS-EOS
1,1s/^/{"/
1,\$s/\$/",/
2,\$s/^/"/
\$,\$d
\$,\$s/,\$/,0}/
w
q
EOS-EOS

View file

@ -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: philnelson@acm.org
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"
;

View file

@ -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: philnelson@acm.org
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;

View file

@ -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;
}
}

View file

@ -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}

View file

@ -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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
/* Load variables. */
program_counter load_adr;
char load_str;
char load_const;
/* Initialize the load sequence. */
void
init_load ()
{
clear_func(0);
load_adr.pc_func = 0;
load_adr.pc_addr = 0;
load_str = FALSE;
load_const = FALSE;
}
/* addbyte adds one BYTE to the current code segment. */
void
addbyte (byte)
char byte;
{
int pc;
bc_function *f;
char *new_body;
/* If there was an error, don't continue. */
if (had_error) return;
/* Calculate the segment and offset. */
pc = load_adr.pc_addr++;
f = &functions[load_adr.pc_func];
if (pc >= f->f_body_size)
{
f->f_body_size *= 2;
new_body = (char *) bc_malloc (f->f_body_size);
memcpy(new_body, f->f_body, f->f_body_size/2);
free (f->f_body);
f->f_body = new_body;
}
/* Store the byte. */
f->f_body[pc] = byte;
f->f_code_size++;
}
/* Define a label LAB to be the current program counter. */
void
def_label (lab)
long lab;
{
bc_label_group *temp;
int group, offset, func;
/* Get things ready. */
group = lab >> BC_LABEL_LOG;
offset = lab % BC_LABEL_GROUP;
func = load_adr.pc_func;
/* Make sure there is at least one label group. */
if (functions[func].f_label == NULL)
{
functions[func].f_label =
(bc_label_group *) bc_malloc (sizeof(bc_label_group));
functions[func].f_label->l_next = NULL;
}
/* Add the label group. */
temp = functions[func].f_label;
while (group > 0)
{
if (temp->l_next == NULL)
{
temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
temp->l_next->l_next = NULL;
}
temp = temp->l_next;
group --;
}
/* Define it! */
temp->l_adrs [offset] = load_adr.pc_addr;
}
/* Several instructions have integers in the code. They
are all known to be legal longs. So, no error code
is added. STR is the pointer to the load string and
must be moved to the last non-digit character. */
long
long_val (str)
char **str;
{ int val = 0;
char neg = FALSE;
if (**str == '-')
{
neg = TRUE;
(*str)++;
}
while (isdigit((int)(**str)))
val = val*10 + *(*str)++ - '0';
if (neg)
return -val;
else
return val;
}
/* load_code loads the CODE into the machine. */
void
load_code (code)
char *code;
{
char *str;
long ap_name; /* auto or parameter name. */
long label_no;
long vaf_name; /* variable, array or function number. */
long func;
static 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++;
}
}
}

View file

@ -1,358 +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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
$FreeBSD$
*************************************************************************/
#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 predefined math routines\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;
case 0:
/* long options */
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);
}

View file

@ -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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* For the pc version using k&r ACK. (minix1.5 and earlier.) */
#ifdef SHORTNAMES
#define init_numbers i_numbers
#define push_constant push__constant
#define load_const in_load_const
#define yy_get_next_buffer yyget_next_buffer
#define yy_init_buffer yyinit_buffer
#define yy_last_accepting_state yylast_accepting_state
#define arglist1 arg1list
#endif
/* Include the standard library header files. */
#ifdef HAVE_UNISTD_H
#include <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

View file

@ -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: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "global.h" /* To get the global variables. */
#include "proto.h"
%}
%start program
%union {
char *s_value;
char c_value;
int i_value;
arg_list *a_value;
}
%token <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; }
;
%%

View file

@ -1,374 +0,0 @@
%{
/* $FreeBSD$ */
/* scan.l: the (f)lex description file for the scanner. */
/* This file is part of GNU bc.
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
The Free Software Foundation, Inc.
59 Temple Place, Suite 330
Boston, MA 02111 USA
You may contact the author by:
e-mail: philnelson@acm.org
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
#include "bcdefs.h"
#include "bc.h"
#include "global.h"
#include "proto.h"
#include <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;
/* 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

View file

@ -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");
}

View file

@ -1,81 +0,0 @@
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define to empty if the keyword does not work. */
#undef const
/* Define if you don't have vprintf but do have _doprnt. */
#undef HAVE_DOPRNT
/* Define if you have the vprintf function. */
#undef HAVE_VPRINTF
/* Define if on MINIX. */
#undef _MINIX
/* Define if the system does not provide POSIX.1 features except
with this defined. */
#undef _POSIX_1_SOURCE
/* Define if you need to in order for stat and other things to work. */
#undef _POSIX_SOURCE
/* Define to `unsigned' if <sys/types.h> doesn't define. */
#undef size_t
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if lex declares yytext as a char * by default, not a char[]. */
#undef YYTEXT_POINTER
/* VERSION number for DC target*/
#undef DC_VERSION
/* COPYRIGHT notice for DC target */
#undef DC_COPYRIGHT
/* COPYRIGHT notice for BC target */
#undef BC_COPYRIGHT
/* Define to use the readline library. */
#undef READLINE
/* Define to use the BSD libedit library. */
#undef LIBEDIT
/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */
#undef ptrdiff_t
/* Define if you have the isgraph function. */
#undef HAVE_ISGRAPH
/* Define if you have the setvbuf function. */
#undef HAVE_SETVBUF
/* Define if you have the <lib.h> header file. */
#undef HAVE_LIB_H
/* Define if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Name of package */
#undef PACKAGE
/* Version number of package */
#undef VERSION

2656
contrib/bc/configure vendored

File diff suppressed because it is too large Load diff

View file

@ -1,89 +0,0 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(doc/bc.1)
AM_INIT_AUTOMAKE("bc", "1.06")
AM_CONFIG_HEADER(config.h)
AC_DEFINE(DC_VERSION,"1.3")
AC_DEFINE_UNQUOTED(BC_COPYRIGHT, dnl
["Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc."])
AC_DEFINE_UNQUOTED(DC_COPYRIGHT, dnl
["Copyright 1994, 1997, 1998, 2000 Free Software Foundation, Inc."])
AC_PROG_CC
AC_MINIX
dnl AC_ISC_POSIX
AM_PROG_LEX
AC_PROG_YACC
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_PROG_MAKE_SET
AC_CHECK_HEADERS(stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h)
AC_C_CONST
AC_TYPE_SIZE_T
AC_CHECK_TYPE(ptrdiff_t, size_t)
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(isgraph setvbuf)
AC_ARG_WITH(pkg,[ --with-pkg use software installed in /usr/pkg tree], [
CPPFLAGS="$CPPFLAGS -I/usr/pkg/include"
LDFLAGS="$LDFLAGS -L/usr/pkg/lib"
echo Using /usr/pkg/include and /usr/pkg/lib
])
bcle=n
AC_ARG_WITH(libedit,[ --with-libedit support fancy BSD command input
editing], [
AC_CHECK_LIB(termcap,tgetent,TERMLIB=-ltermcap)
LDSAVE=$LDFLAGS
LDFLAGS="$LDFLAGS $TERMLIB"
AC_CHECK_LIB(edit,el_gets,
[AC_CHECK_HEADER(histedit.h,
READLINELIB="-ledit $TERMLIB";bcle=y)],
READLINELIB="")
if test "$bcle" = "y"; then
echo Using the libedit library.
AC_DEFINE(LIBEDIT,1)
fi
LDFLAGS=$LDSAVE
])
bcrl=n
AC_ARG_WITH(readline,[ --with-readline support fancy command input editing], [
AC_CHECK_LIB(ncurses,tparm,TERMLIB=-lncurses,
AC_CHECK_LIB(termcap,tgetent,TERMLIB=-ltermcap))
LDSAVE=$LDFLAGS
LDFLAGS="$LDFLAGS $TERMLIB"
AC_CHECK_LIB(readline,readline,
[AC_CHECK_HEADER(readline/readline.h,
READLINELIB="-lreadline $TERMLIB";bcrl=y)],
READLINELIB="")
if test "$bcrl" = "y" ; then
echo Using the readline library.
AC_DEFINE(READLINE,1)
fi
LDFLAGS=$LDSAVE
])
if test "$LEX" = "flex" ; then
LEX="flex -I8"
else
if test "$bcrl" = "y" ; then
AC_MSG_WARN(readline works only with flex.)
fi
fi
if test "$bcrl" = "y" -a "$bcle" = "y" ; then
AC_MSG_ERROR(Can not use both readline and libedit. Aborting.)
fi
if test "$LEX" = "lex" -a `uname -s` = "SunOS" ; then
LEXLIB=""
echo "SunOS using lex does not have a -ll."
fi
AC_SUBST(READLINELIB)
AC_ARG_PROGRAM
AC_OUTPUT(Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile)

View file

@ -1,14 +0,0 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = dc
dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c
noinst_HEADERS = dc.h dc-proto.h dc-regdef.h
INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h
LDADD = ../lib/libbc.a
MAINTAINERCLEANFILES = Makefile.in
CFLAGS = @CFLAGS@ -Wall -funsigned-char
$(PROGRAMS): $(LDADD)

View file

@ -1,296 +0,0 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
CC = @CC@
LEX = @LEX@
MAKEINFO = @MAKEINFO@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
READLINELIB = @READLINELIB@
VERSION = @VERSION@
YACC = @YACC@
bin_PROGRAMS = dc
dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c
noinst_HEADERS = dc.h dc-proto.h dc-regdef.h
INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h
LDADD = ../lib/libbc.a
MAINTAINERCLEANFILES = Makefile.in
CFLAGS = @CFLAGS@ -Wall -funsigned-char
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(bin_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
dc_OBJECTS = dc.o misc.o eval.o stack.o array.o numeric.o string.o
dc_LDADD = $(LDADD)
dc_DEPENDENCIES = ../lib/libbc.a
dc_LDFLAGS =
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
HEADERS = $(noinst_HEADERS)
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
SOURCES = $(dc_SOURCES)
OBJECTS = $(dc_OBJECTS)
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .o .s
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps dc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-binPROGRAMS:
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
distclean-binPROGRAMS:
maintainer-clean-binPROGRAMS:
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
list='$(bin_PROGRAMS)'; for p in $$list; do \
rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
done
.c.o:
$(COMPILE) -c $<
.s.o:
$(COMPILE) -c $<
.S.o:
$(COMPILE) -c $<
mostlyclean-compile:
-rm -f *.o core *.core
clean-compile:
distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
dc: $(dc_OBJECTS) $(dc_DEPENDENCIES)
@rm -f dc
$(LINK) $(dc_LDFLAGS) $(dc_OBJECTS) $(dc_LDADD) $(LIBS)
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = dc
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
array.o: array.c ../config.h dc.h dc-proto.h dc-regdef.h
dc.o: dc.c ../config.h ../h/getopt.h dc.h dc-proto.h
eval.o: eval.c ../config.h dc.h dc-proto.h
misc.o: misc.c ../config.h ../h/getopt.h dc.h dc-proto.h
numeric.o: numeric.c ../config.h ../h/number.h dc.h dc-proto.h
stack.o: stack.c ../config.h dc.h dc-proto.h dc-regdef.h
string.o: string.c ../config.h dc.h dc-proto.h
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am: install-binPROGRAMS
install-exec: install-exec-am
install-data-am:
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-binPROGRAMS
uninstall: uninstall-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(bindir)
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \
mostlyclean-am
clean: clean-am
distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
distclean-generic clean-am
distclean: distclean-am
maintainer-clean-am: maintainer-clean-binPROGRAMS \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
check-am installcheck-am installcheck install-exec-am install-exec \
install-data-am install-data install-am install uninstall-am uninstall \
all-redirect all-am all installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
$(PROGRAMS): $(LDADD)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -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);
}
}

View file

@ -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 *));

View file

@ -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

View file

@ -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: bug-dc@gnu.org .\n");
}
static void
show_version DC_DECLVOID()
{
printf("dc (GNU %s %s) %s\n", PACKAGE, VERSION, DC_VERSION);
printf("\n%s\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\
to the extent permitted by law.\n", DC_COPYRIGHT);
}
/* your generic usage function */
static void
usage DC_DECLARG((f))
FILE *f DC_DECLEND
{
fprintf(f, "\
Usage: %s [OPTION] [file ...]\n\
-e, --expression=EXPR evaluate expression\n\
-f, --file=FILE evaluate contents of file\n\
-h, --help display this help and exit\n\
-V, --version output version information and exit\n\
\n\
", progname);
bug_report_info();
}
/* returns a pointer to one past the last occurance of c in s,
* or s if c does not occur in s.
*/
static char *
r1bindex DC_DECLARG((s, c))
char *s DC_DECLSEP
int c DC_DECLEND
{
char *p = strrchr(s, c);
if (!p)
return s;
return p + 1;
}
static void
try_file(const char *filename)
{
FILE *input;
if (strcmp(filename, "-") == 0) {
input = stdin;
} else if ( !(input=fopen(filename, "r")) ) {
fprintf(stderr, "Could not open file ");
perror(filename);
exit(EXIT_FAILURE);
}
if (dc_evalfile(input))
exit(EXIT_FAILURE);
if (input != stdin)
fclose(input);
}
int
main DC_DECLARG((argc, argv))
int argc DC_DECLSEP
char **argv DC_DECLEND
{
static struct option const long_opts[] = {
{"expression", required_argument, NULL, 'e'},
{"file", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
int did_eval = 0;
int c;
progname = r1bindex(*argv, '/');
#ifdef HAVE_SETVBUF
/* attempt to simplify interaction with applications such as emacs */
(void) setvbuf(stdout, NULL, _IOLBF, 0);
#endif
dc_math_init();
dc_string_init();
dc_register_init();
dc_array_init();
while ((c = getopt_long(argc, argv, "hVe:f:", long_opts, (int *)0)) != EOF) {
switch (c) {
case 'e':
{ dc_data string = dc_makestring(optarg, strlen(optarg));
if (dc_evalstr(string))
return EXIT_SUCCESS;
dc_free_str(&string.v.string);
did_eval = 1;
}
break;
case 'f':
try_file(optarg);
did_eval = 1;
break;
case 'h':
usage(stdout);
return EXIT_SUCCESS;
case 'V':
show_version();
return EXIT_SUCCESS;
default:
usage(stderr);
return EXIT_FAILURE;
}
}
for (; optind < argc; ++optind) {
try_file(argv[optind]);
did_eval = 1;
}
if (!did_eval) {
/* if no -e commands and no command files, then eval stdin */
if (dc_evalfile(stdin))
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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");
}

View file

@ -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;
}

View file

@ -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 */
}

View file

@ -1,12 +0,0 @@
## Process this file with automake to produce Makefile.in
info_TEXINFOS = bc.texi dc.texi
MAKEINFO = makeinfo --no-split
MAINTAINERCLEANFILES = Makefile.in
# FIXME: remove this when automake has been fixed to include these
# files automatically
EXTRA_DIST = bc.1 dc.1
man_MANS = bc.1 dc.1

View file

@ -1,355 +0,0 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
CC = @CC@
LEX = @LEX@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
READLINELIB = @READLINELIB@
VERSION = @VERSION@
YACC = @YACC@
info_TEXINFOS = bc.texi dc.texi
MAKEINFO = makeinfo --no-split
MAINTAINERCLEANFILES = Makefile.in
# FIXME: remove this when automake has been fixed to include these
# files automatically
EXTRA_DIST = bc.1 dc.1
man_MANS = bc.1 dc.1
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
TEXI2DVI = texi2dvi
INFO_DEPS = bc.info dc.info
DVIS = bc.dvi dc.dvi
TEXINFOS = bc.texi dc.texi
man1dir = $(mandir)/man1
MANS = $(man_MANS)
NROFF = nroff
DIST_COMMON = Makefile.am Makefile.in texinfo.tex
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
all: all-redirect
.SUFFIXES:
.SUFFIXES: .dvi .info .ps .texi .texinfo .txi
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
bc.info: bc.texi
bc.dvi: bc.texi
dc.info: dc.texi
dc.dvi: dc.texi
DVIPS = dvips
.texi.info:
@cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texi.dvi:
TEXINPUTS=.:$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
.texi:
@cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texinfo.info:
@cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texinfo:
@cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.texinfo.dvi:
TEXINPUTS=.:$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
.txi.info:
@cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.txi.dvi:
TEXINPUTS=.:$$TEXINPUTS \
MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
.txi:
@cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9]
cd $(srcdir) \
&& $(MAKEINFO) `echo $< | sed 's,.*/,,'`
.dvi.ps:
$(DVIPS) $< -o $@
install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(infodir)
@list='$(INFO_DEPS)'; \
for file in $$list; do \
d=$(srcdir); \
for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \
if test -f $$d/$$ifile; then \
echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \
$(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \
else : ; fi; \
done; \
done
@$(POST_INSTALL)
@if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
list='$(INFO_DEPS)'; \
for file in $$list; do \
echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\
install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\
done; \
else : ; fi
uninstall-info:
$(PRE_UNINSTALL)
@if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
ii=yes; \
else ii=; fi; \
list='$(INFO_DEPS)'; \
for file in $$list; do \
test -z "$ii" \
|| install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \
done
@$(NORMAL_UNINSTALL)
list='$(INFO_DEPS)'; \
for file in $$list; do \
(cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \
done
dist-info: $(INFO_DEPS)
list='$(INFO_DEPS)'; \
for base in $$list; do \
d=$(srcdir); \
for file in `cd $$d && eval echo $$base*`; do \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file; \
done; \
done
mostlyclean-aminfo:
-rm -f bc.aux bc.cp bc.cps bc.dvi bc.fn bc.fns bc.ky bc.kys bc.ps \
bc.log bc.pg bc.toc bc.tp bc.tps bc.vr bc.vrs bc.op bc.tr \
bc.cv bc.cn dc.aux dc.cp dc.cps dc.dvi dc.fn dc.fns dc.ky \
dc.kys dc.ps dc.log dc.pg dc.toc dc.tp dc.tps dc.vr dc.vrs \
dc.op dc.tr dc.cv dc.cn
clean-aminfo:
distclean-aminfo:
maintainer-clean-aminfo:
cd $(srcdir) && for i in $(INFO_DEPS); do \
rm -f $$i; \
if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \
rm -f $$i-[0-9]*; \
fi; \
done
install-man1:
$(mkinstalldirs) $(DESTDIR)$(man1dir)
@list='$(man1_MANS)'; \
l2='$(man_MANS)'; for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
done
uninstall-man1:
@list='$(man1_MANS)'; \
l2='$(man_MANS)'; for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
rm -f $(DESTDIR)$(man1dir)/$$inst; \
done
install-man: $(MANS)
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-man1
uninstall-man:
@$(NORMAL_UNINSTALL)
$(MAKE) $(AM_MAKEFLAGS) uninstall-man1
tags: TAGS
TAGS:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = doc
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
$(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info
info-am: $(INFO_DEPS)
info: info-am
dvi-am: $(DVIS)
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am:
install-exec: install-exec-am
install-data-am: install-info-am install-man
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-info uninstall-man
uninstall: uninstall-am
all-am: Makefile $(INFO_DEPS) $(MANS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(mandir)/man1
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
mostlyclean-am: mostlyclean-aminfo mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-aminfo clean-generic mostlyclean-am
clean: clean-am
distclean-am: distclean-aminfo distclean-generic clean-am
distclean: distclean-am
maintainer-clean-am: maintainer-clean-aminfo maintainer-clean-generic \
distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: install-info-am uninstall-info mostlyclean-aminfo \
distclean-aminfo clean-aminfo maintainer-clean-aminfo install-man1 \
uninstall-man1 install-man uninstall-man tags distdir info-am info \
dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
install-exec install-data-am install-data install-am install \
uninstall-am uninstall all-redirect all-am all installdirs \
mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -1,793 +0,0 @@
.\"
.\" bc.1 - the *roff document processor source for the bc manual
.\"
.\" This file is part of GNU bc.
.\" Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License , or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; see the file COPYING. If not, write to:
.\" The Free Software Foundation, Inc.
.\" 59 Temple Place, Suite 330
.\" Boston, MA 02111 USA
.\"
.\" You may contact the author by:
.\" e-mail: philnelson@acm.org
.\" us-mail: Philip A. Nelson
.\" Computer Science Department, 9062
.\" Western Washington University
.\" Bellingham, WA 98226-9062
.\"
.\" $FreeBSD$
.\"
.TH bc 1 .\" "Command Manual" v1.06 "Sept 12, 2000"
.SH NAME
bc - An arbitrary precision calculator language
.SH SYNTAX
\fBbc\fR [ \fB-hlwsqv\fR ] [long-options] [ \fI file ...\fR ]
.SH VERSION
This man page documents GNU bc version 1.06.
.SH DESCRIPTION
\fBbc\fR is a language that supports arbitrary precision numbers
with interactive execution of statements. There are some similarities
in the syntax to the C programming language.
A standard math library is available by command line option.
If requested, the math library is defined before processing any files.
\fBbc\fR starts by processing code from all the files listed
on the command line in the order listed. After all files have been
processed, \fBbc\fR reads from the standard input. All code is
executed as it is read. (If a file contains a command to halt the
processor, \fBbc\fR will never read from the standard input.)
.PP
This version of \fBbc\fR contains several extensions beyond
traditional \fBbc\fR implementations and the POSIX draft standard.
Command line options can cause these extensions to print a warning
or to be rejected. This
document describes the language accepted by this processor.
Extensions will be identified as such.
.SS OPTIONS
.IP "-h, --help"
Print the usage and exit.
.IP "-i, --interactive"
Force interactive mode.
.IP "-l, --mathlib"
Define the standard math library.
.IP "-w, --warn"
Give warnings for extensions to POSIX \fBbc\fR.
.IP "-s, --standard"
Process exactly the POSIX \fBbc\fR language.
.IP "-q, --quiet"
Do not print the normal GNU bc welcome.
.IP "-v, --version"
Print the version number and copyright and quit.
.SS NUMBERS
The most basic element in \fBbc\fR is the number. Numbers are
arbitrary precision numbers. This precision is both in the integer
part and the fractional part. All numbers are represented internally
in decimal and all computation is done in decimal. (This version
truncates results from divide and multiply operations.) There are two
attributes of numbers, the length and the scale. The length is the
total number of significant decimal digits in a number and the scale
is the total number of decimal digits after the decimal point. For
example:
.nf
.RS
.000001 has a length of 6 and scale of 6.
1935.000 has a length of 7 and a scale of 3.
.RE
.fi
.SS VARIABLES
Numbers are stored in two types of variables, simple variables and
arrays. Both simple variables and array variables are named. Names
begin with a letter followed by any number of letters, digits and
underscores. All letters must be lower case. (Full alpha-numeric
names are an extension. In POSIX \fBbc\fR all names are a single
lower case letter.) The type of variable is clear by the context
because all array variable names will be followed by brackets ([]).
.PP
There are four special variables, \fBscale, ibase, obase,\fR and
\fBlast\fR. \fBscale\fR defines how some operations use digits after the
decimal point. The default value of \fBscale\fR is 0. \fBibase\fR
and \fBobase\fR define the conversion base for input and output
numbers. The default for both input and output is base 10.
\fBlast\fR (an extension) is a variable that has the value of the last
printed number. These will be discussed in further detail where
appropriate. All of these variables may have values assigned to them
as well as used in expressions.
.SS COMMENTS
Comments in \fBbc\fR start with the characters \fB/*\fR and end with
the characters \fB*/\fR. Comments may start anywhere and appear as a
single space in the input. (This causes comments to delimit other
input items. For example, a comment can not be found in the middle of
a variable name.) Comments include any newlines (end of line) between
the start and the end of the comment.
.PP
To support the use of scripts for \fBbc\fR, a single line comment has been
added as an extension. A single line comment starts at a \fB#\fR
character and continues to the next end of the line. The end of line
character is not part of the comment and is processed normally.
.SS EXPRESSIONS
The numbers are manipulated by expressions and statements. Since
the language was designed to be interactive, statements and expressions
are executed as soon as possible. There is no "main" program. Instead,
code is executed as it is encountered. (Functions, discussed in
detail later, are defined when encountered.)
.PP
A simple expression is just a constant. \fBbc\fR converts constants
into internal decimal numbers using the current input base, specified
by the variable \fBibase\fR. (There is an exception in functions.)
The legal values of \fBibase\fR are 2 through 16. Assigning a
value outside this range to \fBibase\fR will result in a value of 2
or 16. Input numbers may contain the characters 0-9 and A-F. (Note:
They must be capitals. Lower case letters are variable names.)
Single digit numbers always have the value of the digit regardless of
the value of \fBibase\fR. (i.e. A = 10.) For multi-digit numbers,
\fBbc\fR changes all input digits greater or equal to ibase to the
value of \fBibase\fR-1. This makes the number \fBFFF\fR always be
the largest 3 digit number of the input base.
.PP
Full expressions are similar to many other high level languages.
Since there is only one kind of number, there are no rules for mixing
types. Instead, there are rules on the scale of expressions. Every
expression has a scale. This is derived from the scale of original
numbers, the operation performed and in many cases, the value of the
variable \fBscale\fR. Legal values of the variable \fBscale\fR are
0 to the maximum number representable by a C integer.
.PP
In the following descriptions of legal expressions, "expr" refers to a
complete expression and "var" refers to a simple or an array variable.
A simple variable is just a
.RS
\fIname\fR
.RE
and an array variable is specified as
.RS
\fIname\fR[\fIexpr\fR]
.RE
Unless specifically
mentioned the scale of the result is the maximum scale of the
expressions involved.
.IP "- expr"
The result is the negation of the expression.
.IP "++ var"
The variable is incremented by one and the new value is the result of
the expression.
.IP "-- var"
The variable
is decremented by one and the new value is the result of the
expression.
.IP "var ++"
The result of the expression is the value of
the variable and then the variable is incremented by one.
.IP "var --"
The result of the expression is the value of the variable and then
the variable is decremented by one.
.IP "expr + expr"
The result of the expression is the sum of the two expressions.
.IP "expr - expr"
The result of the expression is the difference of the two expressions.
.IP "expr * expr"
The result of the expression is the product of the two expressions.
.IP "expr / expr"
The result of the expression is the quotient of the two expressions.
The scale of the result is the value of the variable \fBscale\fR.
.IP "expr % expr"
The result of the expression is the "remainder" and it is computed in the
following way. To compute a%b, first a/b is computed to \fBscale\fR
digits. That result is used to compute a-(a/b)*b to the scale of the
maximum of \fBscale\fR+scale(b) and scale(a). If \fBscale\fR is set
to zero and both expressions are integers this expression is the
integer remainder function.
.IP "expr ^ expr"
The result of the expression is the value of the first raised to the
second. The second expression must be an integer. (If the second
expression is not an integer, a warning is generated and the
expression is truncated to get an integer value.) The scale of the
result is \fBscale\fR if the exponent is negative. If the exponent
is positive the scale of the result is the minimum of the scale of the
first expression times the value of the exponent and the maximum of
\fBscale\fR and the scale of the first expression. (e.g. scale(a^b)
= min(scale(a)*b, max( \fBscale,\fR scale(a))).) It should be noted
that expr^0 will always return the value of 1.
.IP "( expr )"
This alters the standard precedence to force the evaluation of the
expression.
.IP "var = expr"
The variable is assigned the value of the expression.
.IP "var <op>= expr"
This is equivalent to "var = var <op> expr" with the exception that
the "var" part is evaluated only once. This can make a difference if
"var" is an array.
.PP
Relational expressions are a special kind of expression
that always evaluate to 0 or 1, 0 if the relation is false and 1 if
the relation is true. These may appear in any legal expression.
(POSIX bc requires that relational expressions are used only in if,
while, and for statements and that only one relational test may be
done in them.) The relational operators are
.IP "expr1 < expr2"
The result is 1 if expr1 is strictly less than expr2.
.IP "expr1 <= expr2"
The result is 1 if expr1 is less than or equal to expr2.
.IP "expr1 > expr2"
The result is 1 if expr1 is strictly greater than expr2.
.IP "expr1 >= expr2"
The result is 1 if expr1 is greater than or equal to expr2.
.IP "expr1 == expr2"
The result is 1 if expr1 is equal to expr2.
.IP "expr1 != expr2"
The result is 1 if expr1 is not equal to expr2.
.PP
Boolean operations are also legal. (POSIX \fBbc\fR does NOT have
boolean operations). The result of all boolean operations are 0 and 1
(for false and true) as in relational expressions. The boolean
operators are:
.IP "!expr"
The result is 1 if expr is 0.
.IP "expr && expr"
The result is 1 if both expressions are non-zero.
.IP "expr || expr"
The result is 1 if either expression is non-zero.
.PP
The expression precedence is as follows: (lowest to highest)
.nf
.RS
|| operator, left associative
&& operator, left associative
! operator, nonassociative
Relational operators, left associative
Assignment operator, right associative
+ and - operators, left associative
*, / and % operators, left associative
^ operator, right associative
unary - operator, nonassociative
++ and -- operators, nonassociative
.RE
.fi
.PP
This precedence was chosen so that POSIX compliant \fBbc\fR programs
will run correctly. This will cause the use of the relational and
logical operators to have some unusual behavior when used with
assignment expressions. Consider the expression:
.RS
a = 3 < 5
.RE
.PP
Most C programmers would assume this would assign the result of "3 <
5" (the value 1) to the variable "a". What this does in \fBbc\fR is
assign the value 3 to the variable "a" and then compare 3 to 5. It is
best to use parenthesis when using relational and logical operators
with the assignment operators.
.PP
There are a few more special expressions that are provided in \fBbc\fR.
These have to do with user defined functions and standard
functions. They all appear as "\fIname\fB(\fIparameters\fB)\fR".
See the section on functions for user defined functions. The standard
functions are:
.IP "length ( expression )"
The value of the length function is the number of significant digits in the
expression.
.IP "read ( )"
The read function (an extension) will read a number from the standard
input, regardless of where the function occurs. Beware, this can
cause problems with the mixing of data and program in the standard input.
The best use for this function is in a previously written program that
needs input from the user, but never allows program code to be input
from the user. The value of the read function is the number read from
the standard input using the current value of the variable
\fBibase\fR for the conversion base.
.IP "scale ( expression )"
The value of the scale function is the number of digits after the decimal
point in the expression.
.IP "sqrt ( expression )"
The value of the sqrt function is the square root of the expression. If
the expression is negative, a run time error is generated.
.SS STATEMENTS
Statements (as in most algebraic languages) provide the sequencing of
expression evaluation. In \fBbc\fR statements are executed "as soon
as possible." Execution happens when a newline in encountered and
there is one or more complete statements. Due to this immediate
execution, newlines are very important in \fBbc\fR. In fact, both a
semicolon and a newline are used as statement separators. An
improperly placed newline will cause a syntax error. Because newlines
are statement separators, it is possible to hide a newline by using
the backslash character. The sequence "\e<nl>", where <nl> is the
newline appears to \fBbc\fR as whitespace instead of a newline. A
statement list is a series of statements separated by semicolons and
newlines. The following is a list of \fBbc\fR statements and what
they do: (Things enclosed in brackets ([]) are optional parts of the
statement.)
.IP "expression"
This statement does one of two things. If the expression starts with
"<variable> <assignment> ...", it is considered to be an assignment
statement. If the expression is not an assignment statement, the
expression is evaluated and printed to the output. After the number
is printed, a newline is printed. For example, "a=1" is an assignment
statement and "(a=1)" is an expression that has an embedded
assignment. All numbers that are printed are printed in the base
specified by the variable \fBobase\fR. The legal values for \fB
obase\fR are 2 through BC_BASE_MAX. (See the section LIMITS.) For
bases 2 through 16, the usual method of writing numbers is used. For
bases greater than 16, \fBbc\fR uses a multi-character digit method
of printing the numbers where each higher base digit is printed as a
base 10 number. The multi-character digits are separated by spaces.
Each digit contains the number of characters required to represent the
base ten value of "obase-1". Since numbers are of arbitrary
precision, some numbers may not be printable on a single output line.
These long numbers will be split across lines using the "\e" as the
last character on a line. The maximum number of characters printed
per line is 70. Due to the interactive nature of \fBbc\fR, printing
a number causes the side effect of assigning the printed value to the
special variable \fBlast\fR. This allows the user to recover the
last value printed without having to retype the expression that
printed the number. Assigning to \fBlast\fR is legal and will
overwrite the last printed value with the assigned value. The newly
assigned value will remain until the next number is printed or another
value is assigned to \fBlast\fR. (Some installations may allow the
use of a single period (.) which is not part of a number as a short
hand notation for for \fBlast\fR.)
.IP "string"
The string is printed to the output. Strings start with a double quote
character and contain all characters until the next double quote character.
All characters are take literally, including any newline. No newline
character is printed after the string.
.IP "\fBprint\fR list"
The print statement (an extension) provides another method of output.
The "list" is a list of strings and expressions separated by commas.
Each string or expression is printed in the order of the list. No
terminating newline is printed. Expressions are evaluated and their
value is printed and assigned to the variable \fBlast\fR. Strings
in the print statement are printed to the output and may contain
special characters. Special characters start with the backslash
character (\e). The special characters recognized by \fBbc\fR are
"a" (alert or bell), "b" (backspace), "f" (form feed), "n" (newline),
"r" (carriage return), "q" (double quote), "t" (tab), and "\e" (backslash).
Any other character following the backslash will be ignored.
.IP "{ statement_list }"
This is the compound statement. It allows multiple statements to be
grouped together for execution.
.IP "\fBif\fR ( expression ) statement1 [\fBelse\fR statement2]"
The if statement evaluates the expression and executes statement1 or
statement2 depending on the value of the expression. If the expression
is non-zero, statement1 is executed. If statement2 is present and
the value of the expression is 0, then statement2 is executed. (The
else clause is an extension.)
.IP "\fBwhile\fR ( expression ) statement"
The while statement will execute the statement while the expression
is non-zero. It evaluates the expression before each execution of
the statement. Termination of the loop is caused by a zero
expression value or the execution of a break statement.
.IP "\fBfor\fR ( [expression1] ; [expression2] ; [expression3] ) statement"
The for statement controls repeated execution of the statement.
Expression1 is evaluated before the loop. Expression2 is evaluated
before each execution of the statement. If it is non-zero, the statement
is evaluated. If it is zero, the loop is terminated. After each
execution of the statement, expression3 is evaluated before the reevaluation
of expression2. If expression1 or expression3 are missing, nothing is
evaluated at the point they would be evaluated.
If expression2 is missing, it is the same as substituting
the value 1 for expression2. (The optional expressions are an
extension. POSIX \fBbc\fR requires all three expressions.)
The following is equivalent code for the for statement:
.nf
.RS
expression1;
while (expression2) {
statement;
expression3;
}
.RE
.fi
.IP "\fBbreak\fR"
This statement causes a forced exit of the most recent enclosing while
statement or for statement.
.IP "\fBcontinue\fR"
The continue statement (an extension) causes the most recent enclosing
for statement to start the next iteration.
.IP "\fBhalt\fR"
The halt statement (an extension) is an executed statement that causes
the \fBbc\fR processor to quit only when it is executed. For example,
"if (0 == 1) halt" will not cause \fBbc\fR to terminate because the halt is
not executed.
.IP "\fBreturn\fR"
Return the value 0 from a function. (See the section on functions.)
.IP "\fBreturn\fR ( expression )"
Return the value of the expression from a function. (See the section on
functions.) As an extension, the parenthesis are not required.
.SS PSEUDO STATEMENTS
These statements are not statements in the traditional sense. They are
not executed statements. Their function is performed at "compile" time.
.IP "\fBlimits\fR"
Print the local limits enforced by the local version of \fBbc\fR. This
is an extension.
.IP "\fBquit\fR"
When the quit statement is read, the \fBbc\fR processor
is terminated, regardless of where the quit statement is found. For
example, "if (0 == 1) quit" will cause \fBbc\fR to terminate.
.IP "\fBwarranty\fR"
Print a longer warranty notice. This is an extension.
.SS FUNCTIONS
Functions provide a method of defining a computation that can be executed
later. Functions in
.B bc
always compute a value and return it to the caller. Function definitions
are "dynamic" in the sense that a function is undefined until a definition
is encountered in the input. That definition is then used until another
definition function for the same name is encountered. The new definition
then replaces the older definition. A function is defined as follows:
.nf
.RS
\fBdefine \fIname \fB( \fIparameters \fB) { \fInewline
\fI auto_list statement_list \fB}\fR
.RE
.fi
A function call is just an expression of the form
"\fIname\fB(\fIparameters\fB)\fR".
.PP
Parameters are numbers or arrays (an extension). In the function definition,
zero or more parameters are defined by listing their names separated by
commas. Numbers are only call by value parameters. Arrays are only
call by variable. Arrays are specified in the parameter definition by
the notation "\fIname\fB[]\fR". In the function call, actual parameters
are full expressions for number parameters. The same notation is used
for passing arrays as for defining array parameters. The named array is
passed by variable to the function. Since function definitions are dynamic,
parameter numbers and types are checked when a function is called. Any
mismatch in number or types of parameters will cause a runtime error.
A runtime error will also occur for the call to an undefined function.
.PP
The \fIauto_list\fR is an optional list of variables that are for
"local" use. The syntax of the auto list (if present) is "\fBauto
\fIname\fR, ... ;". (The semicolon is optional.) Each \fIname\fR is
the name of an auto variable. Arrays may be specified by using the
same notation as used in parameters. These variables have their
values pushed onto a stack at the start of the function. The
variables are then initialized to zero and used throughout the
execution of the function. At function exit, these variables are
popped so that the original value (at the time of the function call)
of these variables are restored. The parameters are really auto
variables that are initialized to a value provided in the function
call. Auto variables are different than traditional local variables
because if function A calls function B, B may access function
A's auto variables by just using the same name, unless function B has
called them auto variables. Due to the fact that auto variables and
parameters are pushed onto a stack, \fBbc\fR supports recursive functions.
.PP
The function body is a list of \fBbc\fR statements. Again, statements
are separated by semicolons or newlines. Return statements cause the
termination of a function and the return of a value. There are two
versions of the return statement. The first form, "\fBreturn\fR", returns
the value 0 to the calling expression. The second form,
"\fBreturn ( \fIexpression \fB)\fR", computes the value of the expression
and returns that value to the calling expression. There is an implied
"\fBreturn (0)\fR" at the end of every function. This allows a function
to terminate and return 0 without an explicit return statement.
.PP
Functions also change the usage of the variable \fBibase\fR. All
constants in the function body will be converted using the value of
\fBibase\fR at the time of the function call. Changes of \fBibase\fR
will be ignored during the execution of the function except for the
standard function \fBread\fR, which will always use the current value
of \fBibase\fR for conversion of numbers.
.PP
As an extension, the format of the definition has been slightly relaxed.
The standard requires the opening brace be on the same line as the
\fBdefine\fR keyword and all other parts must be on following lines.
This version of \fBbc\fR will allow any number of newlines before and
after the opening brace of the function. For example, the following
definitions are legal.
.nf
.RS
\f(CW
define d (n) { return (2*n); }
define d (n)
{ return (2*n); }
\fR
.RE
.fi
.SS MATH LIBRARY
If \fBbc\fR is invoked with the \fB-l\fR option, a math library is preloaded
and the default scale is set to 20. The math functions will calculate their
results to the scale set at the time of their call.
The math library defines the following functions:
.IP "s (\fIx\fR)"
The sine of x, x is in radians.
.IP "c (\fIx\fR)"
The cosine of x, x is in radians.
.IP "a (\fIx\fR)"
The arctangent of x, arctangent returns radians.
.IP "l (\fIx\fR)"
The natural logarithm of x.
.IP "e (\fIx\fR)"
The exponential function of raising e to the value x.
.IP "j (\fIn,x\fR)"
The bessel function of integer order n of x.
.SS EXAMPLES
In /bin/sh, the following will assign the value of "pi" to the shell
variable \fBpi\fR.
.RS
\f(CW
pi=$(echo "scale=10; 4*a(1)" | bc -l)
\fR
.RE
.PP
The following is the definition of the exponential function used in the
math library. This function is written in POSIX \fBbc\fR.
.nf
.RS
\f(CW
scale = 20
/* Uses the fact that e^x = (e^(x/2))^2
When x is small enough, we use the series:
e^x = 1 + x + x^2/2! + x^3/3! + ...
*/
define e(x) {
auto a, d, e, f, i, m, v, z
/* Check the sign of x. */
if (x<0) {
m = 1
x = -x
}
/* Precondition x. */
z = scale;
scale = 4 + z + .44*x;
while (x > 1) {
f += 1;
x /= 2;
}
/* Initialize the variables. */
v = 1+x
a = x
d = 1
for (i=2; 1; i++) {
e = (a *= x) / (d *= i)
if (e == 0) {
if (f>0) while (f--) v = v*v;
scale = z
if (m) return (1/v);
return (v/1);
}
v += e
}
}
\fR
.RE
.fi
.PP
The following is code that uses the extended features of \fBbc\fR to
implement a simple program for calculating checkbook balances. This
program is best kept in a file so that it can be used many times
without having to retype it at every use.
.nf
.RS
\f(CW
scale=2
print "\enCheck book program!\en"
print " Remember, deposits are negative transactions.\en"
print " Exit by a 0 transaction.\en\en"
print "Initial balance? "; bal = read()
bal /= 1
print "\en"
while (1) {
"current balance = "; bal
"transaction? "; trans = read()
if (trans == 0) break;
bal -= trans
bal /= 1
}
quit
\fR
.RE
.fi
.PP
The following is the definition of the recursive factorial function.
.nf
.RS
\f(CW
define f (x) {
if (x <= 1) return (1);
return (f(x-1) * x);
}
\fR
.RE
.fi
.SS READLINE AND LIBEDIT OPTIONS
GNU \fBbc\fR can be compiled (via a configure option) to use the GNU
\fBreadline\fR input editor library or the BSD \fBlibedit\fR library.
This allows the user to do editing of lines before sending them
to \fBbc\fR. It also allows for a history of previous lines typed.
When this option is selected, \fBbc\fR has one more special variable.
This special variable, \fBhistory\fR is the number of lines of history
retained. For \fBreadline\fR, a value of -1 means that an unlimited
number of history lines are retained. Setting the value of
\fBhistory\fR to a positive number restricts the number of history
lines to the number given. The value of 0 disables the history
feature. The default value is 100. For more information, read the
user manuals for the GNU \fBreadline\fR, \fBhistory\fR and BSD \fBlibedit\fR
libraries. One can not enable both \fBreadline\fR and \fBlibedit\fR
at the same time.
.SS DIFFERENCES
This version of
.B bc
was implemented from the POSIX P1003.2/D11 draft and contains
several differences and extensions relative to the draft and
traditional implementations.
It is not implemented in the traditional way using
.I dc(1).
This version is a single process which parses and runs a byte code
translation of the program. There is an "undocumented" option (-c)
that causes the program to output the byte code to
the standard output instead of running it. It was mainly used for
debugging the parser and preparing the math library.
.PP
A major source of differences is
extensions, where a feature is extended to add more functionality and
additions, where new features are added.
The following is the list of differences and extensions.
.IP "LANG environment"
This version does not conform to the POSIX standard in the processing
of the LANG environment variable and all environment variables starting
with LC_.
.IP names
Traditional and POSIX
.B bc
have single letter names for functions, variables and arrays. They have
been extended to be multi-character names that start with a letter and
may contain letters, numbers and the underscore character.
.IP Strings
Strings are not allowed to contain NUL characters. POSIX says all characters
must be included in strings.
.IP last
POSIX \fBbc\fR does not have a \fBlast\fR variable. Some implementations
of \fBbc\fR use the period (.) in a similar way.
.IP comparisons
POSIX \fBbc\fR allows comparisons only in the if statement, the while
statement, and the second expression of the for statement. Also, only
one relational operation is allowed in each of those statements.
.IP "if statement, else clause"
POSIX \fBbc\fR does not have an else clause.
.IP "for statement"
POSIX \fBbc\fR requires all expressions to be present in the for statement.
.IP "&&, ||, !"
POSIX \fBbc\fR does not have the logical operators.
.IP "read function"
POSIX \fBbc\fR does not have a read function.
.IP "print statement"
POSIX \fBbc\fR does not have a print statement .
.IP "continue statement"
POSIX \fBbc\fR does not have a continue statement.
.IP "return statement"
POSIX \fBbc\fR requires parentheses around the return expression.
.IP "array parameters"
POSIX \fBbc\fR does not (currently) support array parameters in full.
The POSIX grammar allows for arrays in function definitions, but does
not provide a method to specify an array as an actual parameter. (This
is most likely an oversight in the grammar.) Traditional implementations
of \fBbc\fR have only call by value array parameters.
.IP "function format"
POSIX \fBbc\fR requires the opening brace on the same line as the
\fBdefine\fR key word and the \fBauto\fR statement on the next line.
.IP "=+, =-, =*, =/, =%, =^"
POSIX \fBbc\fR does not require these "old style" assignment operators to
be defined. This version may allow these "old style" assignments. Use
the limits statement to see if the installed version supports them. If
it does support the "old style" assignment operators, the statement
"a =- 1" will decrement \fBa\fR by 1 instead of setting \fBa\fR to the
value -1.
.IP "spaces in numbers"
Other implementations of \fBbc\fR allow spaces in numbers. For example,
"x=1 3" would assign the value 13 to the variable x. The same statement
would cause a syntax error in this version of \fBbc\fR.
.IP "errors and execution"
This implementation varies from other implementations in terms of what
code will be executed when syntax and other errors are found in the
program. If a syntax error is found in a function definition, error
recovery tries to find the beginning of a statement and continue to
parse the function. Once a syntax error is found in the function, the
function will not be callable and becomes undefined.
Syntax errors in the interactive execution code will invalidate the
current execution block. The execution block is terminated by an
end of line that appears after a complete sequence of statements.
For example,
.nf
.RS
a = 1
b = 2
.RE
.fi
has two execution blocks and
.nf
.RS
{ a = 1
b = 2 }
.RE
.fi
has one execution block. Any runtime error will terminate the execution
of the current execution block. A runtime warning will not terminate the
current execution block.
.IP "Interrupts"
During an interactive session, the SIGINT signal (usually generated by
the control-C character from the terminal) will cause execution of the
current execution block to be interrupted. It will display a "runtime"
error indicating which function was interrupted. After all runtime
structures have been cleaned up, a message will be printed to notify the
user that \fBbc\fR is ready for more input. All previously defined functions
remain defined and the value of all non-auto variables are the value at
the point of interruption. All auto variables and function parameters
are removed during the
clean up process. During a non-interactive
session, the SIGINT signal will terminate the entire run of \fBbc\fR.
.SS LIMITS
The following are the limits currently in place for this
.B bc
processor. Some of them may have been changed by an installation.
Use the limits statement to see the actual values.
.IP BC_BASE_MAX
The maximum output base is currently set at 999. The maximum input base
is 16.
.IP BC_DIM_MAX
This is currently an arbitrary limit of 65535 as distributed. Your
installation may be different.
.IP BC_SCALE_MAX
The number of digits after the decimal point is limited to INT_MAX digits.
Also, the number of digits before the decimal point is limited to INT_MAX
digits.
.IP BC_STRING_MAX
The limit on the number of characters in a string is INT_MAX characters.
.IP exponent
The value of the exponent in the raise operation (^) is limited to LONG_MAX.
.IP "variable names"
The current limit on the number of unique names is 32767 for each of
simple variables, arrays and functions.
.SH ENVIRONMENT
The following environment variables are processed by \fBbc\fR:
.IP "POSIXLY_CORRECT"
This is the same as the \fB-s\fR option.
.IP "BC_ENV_ARGS"
This is another mechanism to get arguments to \fBbc\fR. The
format is the same as the command line arguments. These arguments
are processed first, so any files listed in the environment arguments
are processed before any command line argument files. This allows
the user to set up "standard" options and files to be processed
at every invocation of \fBbc\fR. The files in the environment
variables would typically contain function definitions for functions
the user wants defined every time \fBbc\fR is run.
.IP "BC_LINE_LENGTH"
This should be an integer specifying the number of characters in an
output line for numbers. This includes the backslash and newline characters
for long numbers.
.SH DIAGNOSTICS
If any file on the command line can not be opened, \fBbc\fR will report
that the file is unavailable and terminate. Also, there are compile
and run time diagnostics that should be self-explanatory.
.SH BUGS
Error recovery is not very good yet.
.PP
Email bug reports to
.BR bug-bc@gnu.org .
Be sure to include the word ``bc'' somewhere in the ``Subject:'' field.
.SH AUTHOR
.nf
Philip A. Nelson
philnelson@acm.org
.fi
.SH ACKNOWLEDGEMENTS
The author would like to thank Steve Sommars (Steve.Sommars@att.com) for
his extensive help in testing the implementation. Many great suggestions
were given. This is a much better product due to his involvement.

File diff suppressed because it is too large Load diff

View file

@ -1,490 +0,0 @@
.\"
.\" dc.1 - the *roff document processor source for the dc manual
.\"
.\" This file is part of GNU dc.
.\" Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation; either version 2 of the License , or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with this program; see the file COPYING. If not, write to:
.\" The Free Software Foundation, Inc.
.\" 59 Temple Place, Suite 330
.\" Boston, MA 02111 USA
.\"
.\" $FreeBSD$
.\"
.TH DC 1 "1997-03-25" "GNU Project"
.ds dc \fIdc\fP
.ds Dc \fIDc\fP
.SH NAME
dc \- an arbitrary precision calculator
.SH SYNOPSIS
dc [-V] [--version] [-h] [--help]
[-e scriptexpression] [--expression=scriptexpression]
[-f scriptfile] [--file=scriptfile]
[file ...]
.SH DESCRIPTION
.PP
\*(Dc is a reverse-polish desk calculator which supports
unlimited precision arithmetic.
It also allows you to define and call macros.
Normally \*(dc reads from the standard input;
if any command arguments are given to it, they are filenames,
and \*(dc reads and executes the contents of the files before reading
from standard input.
All normal output is to standard output;
all error output is to standard error.
.PP
A reverse-polish calculator stores numbers on a stack.
Entering a number pushes it on the stack.
Arithmetic operations pop arguments off the stack and push the results.
.PP
To enter a number in
.IR dc ,
type the digits with an optional decimal point.
Exponential notation is not supported.
To enter a negative number,
begin the number with ``_''.
``-'' cannot be used for this,
as it is a binary operator for subtraction instead.
To enter two numbers in succession,
separate them with spaces or newlines.
These have no meaning as commands.
.SH OPTIONS
\*(Dc may be invoked with the following command-line options:
.TP
.B -V
.TP
.B --version
Print out the version of \*(dc that is being run and a copyright notice,
then exit.
.TP
.B -h
.TP
.B --help
Print a usage message briefly summarizing these command-line options
and the bug-reporting address,
then exit.
.TP
.B -e \fIscript\fP
.TP
.BI --expression= script
Add the commands in
.I script
to the set of commands to be run while processing the input.
.TP
.B -f \fIscript-file\fP
.TP
.BI --file= script-file
Add the commands contained in the file
.I script-file
to the set of commands to be run while processing the input.
.PP
If any command-line parameters remain after processing the above,
these parameters are interpreted as the names of input files to
be processed.
A file name of
.B -
refers to the standard input stream.
The standard input will processed if no file names are specified.
.PD
.SH
Printing Commands
.TP
.B p
Prints the value on the top of the stack,
without altering the stack.
A newline is printed after the value.
.TP
.B n
Prints the value on the top of the stack, popping it off,
and does not print a newline after.
.TP
.B P
Pops off the value on top of the stack.
If it it a string, it is simply printed without a trailing newline.
Otherwise it is a number, and the integer portion of its absolute
value is printed out as a "base (UCHAR_MAX+1)" byte stream.
Assuming that (UCHAR_MAX+1) is 256
(as it is on most machines with 8-bit bytes),
the sequence \fBKSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk\fP
could also accomplish this function,
except for the side-effect of clobbering the x register.
.TP
.B f
Prints the entire contents of the stack
.ig
and the contents of all of the registers,
..
without altering anything.
This is a good command to use if you are lost or want
to figure out what the effect of some command has been.
.PD
.SH
Arithmetic
.TP
.B +
Pops two values off the stack, adds them,
and pushes the result.
The precision of the result is determined only
by the values of the arguments,
and is enough to be exact.
.TP
.B -
Pops two values,
subtracts the first one popped from the second one popped,
and pushes the result.
.TP
.B *
Pops two values, multiplies them, and pushes the result.
The number of fraction digits in the result depends on
the current precision value and the number of fraction
digits in the two arguments.
.TP
.B /
Pops two values,
divides the second one popped from the first one popped,
and pushes the result.
The number of fraction digits is specified by the precision value.
.TP
.B %
Pops two values,
computes the remainder of the division that the
.B /
command would do,
and pushes that.
The value computed is the same as that computed by
the sequence \fBSd dld/ Ld*-\fP .
.TP
.B ~
Pops two values,
divides the second one popped from the first one popped.
The quotient is pushed first, and the remainder is pushed next.
The number of fraction digits used in the division
is specified by the precision value.
(The sequence \fBSdSn lnld/ LnLd%\fP could also accomplish
this function, with slightly different error checking.)
.TP
.B ^
Pops two values and exponentiates,
using the first value popped as the exponent
and the second popped as the base.
The fraction part of the exponent is ignored.
The precision value specifies the number of fraction
digits in the result.
.TP
.B |
Pops three values and computes a modular exponentiation.
The first value popped is used as the reduction modulus;
this value must be a non-zero number,
and should be an integer.
The second popped is used as the exponent;
this value must be a non-negative number,
and any fractional part of this exponent will be ignored.
The third value popped is the base which gets exponentiated,
which should be an integer.
For small integers this is like the sequence \fBSm^Lm%\fP,
but, unlike \fB^\fP, this command will work with arbitrarily large exponents.
.TP
.B v
Pops one value,
computes its square root,
and pushes that.
The precision value specifies the number of fraction digits in the result.
.PP
Most arithmetic operations are affected by the ``precision value'',
which you can set with the
.B k
command.
The default precision value is zero,
which means that all arithmetic except for
addition and subtraction produces integer results.
.SH
Stack Control
.TP
.B c
Clears the stack, rendering it empty.
.TP
.B d
Duplicates the value on the top of the stack,
pushing another copy of it.
Thus, ``4d*p'' computes 4 squared and prints it.
.TP
.B r
Reverses the order of (swaps) the top two values on the stack.
.SH
Registers
.PP
\*(Dc provides at least 256 memory registers,
each named by a single character.
You can store a number or a string in a register and retrieve it later.
.TP
.BI s r
Pop the value off the top of the stack and store
it into register
.IR r .
.TP
.BI l r
Copy the value in register
.I r
and push it onto the stack.
This does not alter the contents of
.IR r .
.PP
Each register also contains its own stack.
The current register value is the top of the register's stack.
.TP
.BI S r
Pop the value off the top of the (main) stack and
push it onto the stack of register
.IR r .
The previous value of the register becomes inaccessible.
.TP
.BI L r
Pop the value off the top of register
.IR r 's
stack and push it onto the main stack.
The previous value
in register
.IR r 's
stack, if any,
is now accessible via the
.BI l r
command.
.ig
.PP
The
.B f
command prints a list of all registers that have contents stored in them,
together with their contents.
Only the current contents of each register
(the top of its stack)
is printed.
..
.SH
Parameters
.PP
\*(Dc has three parameters that control its operation:
the precision, the input radix, and the output radix.
The precision specifies the number
of fraction digits to keep in the result of most arithmetic operations.
The input radix controls the interpretation of numbers typed in;
all numbers typed in use this radix.
The output radix is used for printing numbers.
.PP
The input and output radices are separate parameters;
you can make them unequal,
which can be useful or confusing.
The input radix must be between 2 and 16 inclusive.
The output radix must be at least 2.
The precision must be zero or greater.
The precision is always measured in decimal digits,
regardless of the current input or output radix.
.TP
.B i
Pops the value off the top of the stack
and uses it to set the input radix.
.TP
.B o
Pops the value off the top of the stack
and uses it to set the output radix.
.TP
.B k
Pops the value off the top of the stack
and uses it to set the precision.
.TP
.B I
Pushes the current input radix on the stack.
.TP
.B O
Pushes the current output radix on the stack.
.TP
.B K
Pushes the current precision on the stack.
.SH
Strings
.PP
\*(Dc can operate on strings as well as on numbers.
The only things you can do with strings are
print them and execute them as macros
(which means that the contents of the string are processed as
\*(dc commands).
All registers and the stack can hold strings,
and \*(dc always knows whether any given object is a string or a number.
Some commands such as arithmetic operations demand numbers
as arguments and print errors if given strings.
Other commands can accept either a number or a string;
for example, the
.B p
command can accept either and prints the object
according to its type.
.TP
.BI [ characters ]
Makes a string containing
.I characters
(contained between balanced
.B [
and
.B ]
characters),
and pushes it on the stack.
For example,
.B [foo]P
prints the characters
.B foo
(with no newline).
.TP
.B a
The top-of-stack is popped.
If it was a number, then the low-order byte of this number
is converted into a string and pushed onto the stack.
Otherwise the top-of-stack was a string,
and the first character of that string is pushed back.
.TP
.B x
Pops a value off the stack and executes it as a macro.
Normally it should be a string;
if it is a number,
it is simply pushed back onto the stack.
For example,
.B [1p]x
executes the macro
.B 1p
which pushes
.B 1
on the stack and prints
.B 1
on a separate line.
.PP
Macros are most often stored in registers;
.B [1p]sa
stores a macro to print
.B 1
into register
.BR a ,
and
.B lax
invokes this macro.
.TP
.BI > r
Pops two values off the stack and compares them
assuming they are numbers,
executing the contents of register
.I r
as a macro if the original top-of-stack
is greater.
Thus,
.B 1 2>a
will invoke register
.BR a 's
contents and
.B 2 1>a
will not.
.TP
.BI !> r
Similar but invokes the macro if the original top-of-stack is
not greater than (less than or equal to) what was the second-to-top.
.TP
.BI < r
Similar but invokes the macro if the original top-of-stack is less.
.TP
.BI !< r
Similar but invokes the macro if the original top-of-stack is
not less than (greater than or equal to) what was the second-to-top.
.TP
.BI = r
Similar but invokes the macro if the two numbers popped are equal.
.TP
.BI != r
Similar but invokes the macro if the two numbers popped are not equal.
.ig
This can also be validly used to compare two strings for equality.
..
.TP
.B ?
Reads a line from the terminal and executes it.
This command allows a macro to request input from the user.
.TP
.B q
exits from a macro and also from the macro which invoked it.
If called from the top level,
or from a macro which was called directly from the top level,
the
.B q
command will cause \*(dc to exit.
.TP
.B Q
Pops a value off the stack and uses it as a count
of levels of macro execution to be exited.
Thus,
.B 3Q
exits three levels.
The
.B Q
command will never cause \*(dc to exit.
.SH
Status Inquiry
.TP
.B Z
Pops a value off the stack,
calculates the number of digits it has
(or number of characters, if it is a string)
and pushes that number.
.TP
.B X
Pops a value off the stack,
calculates the number of fraction digits it has,
and pushes that number.
For a string,
the value pushed is
.\" -1.
0.
.TP
.B z
Pushes the current stack depth:
the number of objects on the stack before the execution of the
.B z
command.
.SH
Miscellaneous
.TP
.B !
Will run the rest of the line as a system command.
Note that parsing of the !<, !=, and !> commands take precedence,
so if you want to run a command starting with <, =, or > you will
need to add a space after the !.
.TP
.B #
Will interpret the rest of the line as a comment.
.TP
.BI : r
Will pop the top two values off of the stack.
The old second-to-top value will be stored in the array
.IR r ,
indexed by the old top-of-stack value.
.TP
.BI ; r
Pops the top-of-stack and uses it as an index into
the array
.IR r .
The selected value is then pushed onto the stack.
.P
Note that each stacked instance of a register has its own
array associated with it.
Thus \fB1 0:a 0Sa 2 0:a La 0;ap\fP will print 1,
because the 2 was stored in an instance of 0:a that
was later popped.
.SH
BUGS
.PP
Email bug reports to
.BR bug-dc@gnu.org .

View file

@ -1,526 +0,0 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename dc.info
@settitle dc, an arbitrary precision calculator
@c %**end of header
@c This file has the new style title page commands.
@c Run `makeinfo' rather than `texinfo-format-buffer'.
@c smallbook
@c tex
@c \overfullrule=0pt
@c end tex
@c Combine indices.
@synindex cp fn
@syncodeindex vr fn
@syncodeindex ky fn
@syncodeindex pg fn
@syncodeindex tp fn
@ifinfo
@direntry
* dc: (dc). Arbritrary precision RPN ``Desktop Calculator''.
@end direntry
This file documents @sc{dc}, an arbitrary precision calculator.
Published by the Free Software Foundation, Inc.
59 Temple Place, Suite 330
Boston, MA 02111 USA
Copyright (C) 1984, 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Foundation.
@end ifinfo
@setchapternewpage off
@titlepage
@title dc, an arbitrary precision calculator
@author by Ken Pizzini
@author original manual by Richard Stallman
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1994, 1997, 1998 Free Software Foundation, Inc.
@sp 2
Published by the Free Software Foundation, @*
59 Temple Place, Suite 330 @*
Boston, MA 02111 USA
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be stated in a translation approved
by the Foundation.
@end titlepage
@page
@node Top, Introduction, (dir), (dir)
@menu
* Introduction:: Introduction
* Invocation:: Invocation
* Printing Commands:: Printing Commands
* Arithmetic:: Arithmetic
* Stack Control:: Stack Control
* Registers:: Registers
* Parameters:: Parameters
* Strings:: Strings
* Status Inquiry:: Status Inquiry
* Miscellaneous:: Other commands
* Reporting bugs:: Reporting bugs
@end menu
@node Introduction, Invocation, Top, Top
@comment node-name, next, previous, up
@chapter Introduction
@sc{dc} is a reverse-polish desk calculator
which supports unlimited precision arithmetic.
It also allows you to define and call macros.
Normally @sc{dc} reads from the standard input;
if any command arguments are given to it, they are filenames,
and @sc{dc} reads and executes the contents of the files
instead of reading from standard input.
All normal output is to standard output;
all error messages are written to standard error.
To exit, use @samp{q}.
@kbd{C-c} does not exit;
it is used to abort macros that are looping, etc.
(Currently this is not true; @kbd{C-c} does exit.)
A reverse-polish calculator stores numbers on a stack.
Entering a number pushes it on the stack.
Arithmetic operations pop arguments off the stack and push the results.
To enter a number in @sc{dc}, type the digits,
with an optional decimal point.
Exponential notation is not supported.
To enter a negative number, begin the number with @samp{_}.
@samp{-} cannot be used for this, as it is a binary operator
for subtraction instead.
To enter two numbers in succession,
separate them with spaces or newlines.
These have no meaning as commands.
@node Invocation, Printing Commands, Introduction, Top
@chapter Invocation
@sc{dc} may be invoked with the following command-line options:
@table @samp
@item -e @var{expr}
@item --expression=@var{expr}
Evaluate @var{expr} as @sc{dc} commands.
@item -f @var{file}
@item --file=@var{file}
Read and evaluate @sc{dc} commands from @var{file}.
@item -h
@item --help
Print a usage message summarizing the command-line options, then exit.
@item -V
@item --version
Print the version information for this program, then exit.
@end table
If any command-line parameters remain after processing the options,
these parameters are interpreted as additional @var{file}s whose
contents are read and evaluated.
A file name of @code{-} refers to the standard input stream.
If no @code{-e} option was specified, and no files were specified,
then the standard input will be read for commands to evaluate.
@node Printing Commands, Arithmetic, Invocation, Top
@chapter Printing Commands
@table @samp
@item p
Prints the value on the top of the stack,
without altering the stack.
A newline is printed after the value.
@item n
Prints the value on the top of the stack, popping it off,
and does not print a newline after.
(This command is a GNU extension.)
@item P
Pops off the value on top of the stack.
If it it a string, it is simply printed without a trailing newline.
Otherwise it is a number, and the integer portion of its absolute
value is printed out as a "base (UCHAR_MAX+1)" byte stream.
Assuming that (UCHAR_MAX+1) is 256
(as it is on most machines with 8-bit bytes),
the sequence
@code{KSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk}
could also accomplish this function,
except for the side-effect of clobbering the x register.
(Details of the behavior with a number are a GNU extension.)
@item f
Prints the entire contents of the stack
@c and the contents of all of the registers,
without altering anything.
This is a good command to use if you are lost or want
to figure out what the effect of some command has been.
@end table
@node Arithmetic, Stack Control, Printing Commands, Top
@chapter Arithmetic
@table @samp
@item +
Pops two values off the stack, adds them, and pushes the result.
The precision of the result is determined only
by the values of the arguments, and is enough to be exact.
@item -
Pops two values, subtracts the first one popped
from the second one popped, and pushes the result.
@item *
Pops two values, multiplies them, and pushes the result.
The number of fraction digits in the result is the largest of
the precision value,
the number of fraction digits in the multiplier,
or the number of fraction digits in the multiplicand;
but in no event exceeding the number of digits required for
an exact result.
@item /
Pops two values, divides the second one popped
from the first one popped, and pushes the result.
The number of fraction digits is specified by the precision value.
@item %
Pops two values,
computes the remainder of the division that
the @samp{/} command would do,
and pushes that.
The value computed is the same as that computed by
the sequence @code{Sd dld/ Ld*-} .
@item ~
Pops two values,
divides the second one popped from the first one popped.
The quotient is pushed first, and the remainder is pushed next.
The number of fraction digits used in the division
is specified by the precision value.
(The sequence @code{SdSn lnld/ LnLd%} could also accomplish
this function, with slightly different error checking.)
(This command is a GNU extension.)
@item ^
Pops two values and exponentiates,
using the first value popped as the exponent
and the second popped as the base.
The fraction part of the exponent is ignored.
The precision value specifies the number of fraction
digits in the result.
@item |
Pops three values and computes a modular exponentiation.
The first value popped is used as the reduction modulus;
this value must be a non-zero number,
and the result may not be accurate if the modulus
is not an integer.
The second popped is used as the exponent;
this value must be a non-negative number,
and any fractional part of this exponent will be ignored.
The third value popped is the base which gets exponentiated,
which should be an integer.
For small integers this is like the sequence @code{Sm^Lm%},
but, unlike @code{^}, this command will work with arbritrarily large exponents.
(This command is a GNU extension.)
@item v
Pops one value, computes its square root, and pushes that.
The precision value specifies the number of fraction digits
in the result.
@end table
Most arithmetic operations are affected by the @emph{precision value},
which you can set with the @samp{k} command.
The default precision value is zero,
which means that all arithmetic except for
addition and subtraction produces integer results.
@node Stack Control, Registers, Arithmetic, Top
@chapter Stack Control
@table @samp
@item c
Clears the stack, rendering it empty.
@item d
Duplicates the value on the top of the stack,
pushing another copy of it.
Thus, @samp{4d*p} computes 4 squared and prints it.
@item r
Reverses the order of (swaps) the top two values on the stack.
(This command is a GNU extension.)
@end table
@node Registers, Parameters, Stack Control, Top
@chapter Registers
@sc{dc} provides at least 256 memory registers,
each named by a single character.
You can store a number in a register and retrieve it later.
@table @samp
@item s@var{r}
Pop the value off the top of the stack and
store it into register @var{r}.
@item l@var{r}
Copy the value in register @var{r},
and push it onto the stack.
This does not alter the contents of @var{r}.
Each register also contains its own stack.
The current register value is the top of the register's stack.
@item S@var{r}
Pop the value off the top of the (main) stack and
push it onto the stack of register @var{r}.
The previous value of the register becomes inaccessible.
@item L@var{r}
Pop the value off the top of register @var{r}'s stack
and push it onto the main stack.
The previous value in register @var{r}'s stack, if any,
is now accessible via the @samp{l@var{r}} command.
@end table
@c
@c The @samp{f} command prints a list of all registers that have contents
@c stored in them, together with their contents.
@c Only the current contents of each register (the top of its stack)
@c is printed.
@node Parameters, Strings, Registers, Top
@chapter Parameters
@sc{dc} has three parameters that control its operation:
the precision, the input radix, and the output radix.
The precision specifies the number of fraction digits
to keep in the result of most arithmetic operations.
The input radix controls the interpretation of numbers typed in;
@emph{all} numbers typed in use this radix.
The output radix is used for printing numbers.
The input and output radices are separate parameters;
you can make them unequal, which can be useful or confusing.
The input radix must be between 2 and 16 inclusive.
The output radix must be at least 2.
The precision must be zero or greater.
The precision is always measured in decimal digits,
regardless of the current input or output radix.
@table @samp
@item i
Pops the value off the top of the stack
and uses it to set the input radix.
@item o
Pops the value off the top of the stack
and uses it to set the output radix.
@item k
Pops the value off the top of the stack
and uses it to set the precision.
@item I
Pushes the current input radix on the stack.
@item O
Pushes the current output radix on the stack.
@item K
Pushes the current precision on the stack.
@end table
@node Strings, Status Inquiry, Parameters, Top
@chapter Strings
@sc{dc} can operate on strings as well as on numbers.
The only things you can do with strings are print them
and execute them as macros
(which means that the contents of the string are processed as @sc{dc} commands).
Both registers and the stack can hold strings,
and @sc{dc} always knows whether any given object is a string or a number.
Some commands such as arithmetic operations demand numbers
as arguments and print errors if given strings.
Other commands can accept either a number or a string;
for example, the @samp{p} command can accept either and prints the object
according to its type.
@table @samp
@item [@var{characters}]
Makes a string containing @var{characters} and pushes it on the stack.
For example, @samp{[foo]P} prints the characters @samp{foo}
(with no newline).
@item a
The mnemonic for this is somewhat erroneous: asciify.
The top-of-stack is popped.
If it was a number, then the low-order byte of this number
is converted into a string and pushed onto the stack.
Otherwise the top-of-stack was a string,
and the first character of that string is pushed back.
(This command is a GNU extension.)
@item x
Pops a value off the stack and executes it as a macro.
Normally it should be a string;
if it is a number, it is simply pushed back onto the stack.
For example, @samp{[1p]x} executes the macro @samp{1p},
which pushes 1 on the stack and prints @samp{1} on a separate line.
Macros are most often stored in registers;
@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a},
and @samp{lax} invokes the macro.
@item >@var{r}
Pops two values off the stack and compares them
assuming they are numbers,
executing the contents of register @var{r} as a macro
if the original top-of-stack is greater.
Thus, @samp{1 2>a} will invoke register @samp{a}'s contents
and @samp{2 1>a} will not.
@item !>@var{r}
Similar but invokes the macro if the original top-of-stack is not greater
(is less than or equal to) what was the second-to-top.
@item <@var{r}
Similar but invokes the macro if the original top-of-stack is less.
@item !<@var{r}
Similar but invokes the macro if the original top-of-stack is not less
(is greater than or equal to) what was the second-to-top.
@item =@var{r}
Similar but invokes the macro if the two numbers popped are equal.
@c This can also be validly used to compare two strings for equality.
@item !=@var{r}
Similar but invokes the macro if the two numbers popped are not equal.
@c This can also be validly used to compare two strings for equality.
@item ?
Reads a line from the terminal and executes it.
This command allows a macro to request input from the user.
@item q
During the execution of a macro,
this command exits from the macro and also from the macro which invoked it.
If called from the top level,
or from a macro which was called directly from the top level,
the @samp{q} command will cause @sc{dc} to exit.
@item Q
Pops a value off the stack and uses it as a count
of levels of macro execution to be exited.
Thus, @samp{3Q} exits three levels.
@end table
@node Status Inquiry, Miscellaneous, Strings, Top
@chapter Status Inquiry
@table @samp
@item Z
Pops a value off the stack,
calculates the number of digits it has
(or number of characters, if it is a string)
and pushes that number.
@item X
Pops a value off the stack,
calculates the number of fraction digits it has,
and pushes that number.
For a string, the value pushed is
@c -1.
0.
@item z
Pushes the current stack depth:
the number of objects on the stack
before the execution of the @samp{z} command.
@end table
@node Miscellaneous, Reporting bugs, Status Inquiry, Top
@chapter Miscellaneous
@table @samp
@item !
Will run the rest of the line as a system command.
Note that parsing of the !<, !=, and !> commands take precidence,
so if you want to run a command starting with <, =, or > you will
need to add a space after the !.
@item #
Will interpret the rest of the line as a comment.
(This command is a GNU extension.)
@item :@var{r}
Will pop the top two values off of the stack.
The old second-to-top value will be stored in the array @var{r},
indexed by the old top-of-stack value.
@item ;@var{r}
Pops the top-of-stack and uses it as an index into
the array @var{r}.
The selected value is then pushed onto the stack.
@end table
Note that each stacked instance of a register has its own
array associated with it.
Thus @samp{1 @var{0:a} 0S@var{a} 2 @var{0:a} L@var{a} @var{0;a}p}
will print 1, because the 2 was stored in an instance of @var{0:a}
that was later popped.
@node Reporting bugs, , Miscellaneous, Top
@chapter Reporting bugs
Email bug reports to @email{bug-dc@@gnu.org}.
@contents
@bye

View file

@ -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

View file

@ -1,238 +0,0 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
tranformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View file

@ -1,26 +0,0 @@
## Process this file with automake to produce Makefile.in
noinst_LIBRARIES = libbc.a
INCLUDES = -I. -I.. -I$(srcdir)/../h
libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c
DEFS = @DEFS@ $(DEFSADD)
CFLAGS = @CFLAGS@ -Wall -funsigned-char
MAINTAINERCLEANFILES = Makefile.in number.c
newnumber.o: number.c muldigits.h
$(CC) $(CFLAGS) $(INCLUDES) -c -DMULDIGITS -o newnumber.o $(srcdir)/number.c
muldigits.h: testmul
@echo "The following may take up to 10 minutes."
testmul > muldigits.h
testmul: testmul.o number.o
$(CC) $(CFLAGS) -o testmul testmul.o number.o
specialnumber: newnumber.o
cp newnumber.o number.o

View file

@ -1,283 +0,0 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
CC = @CC@
LEX = @LEX@
MAKEINFO = @MAKEINFO@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
READLINELIB = @READLINELIB@
VERSION = @VERSION@
YACC = @YACC@
noinst_LIBRARIES = libbc.a
INCLUDES = -I. -I.. -I$(srcdir)/../h
libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c
DEFS = @DEFS@ $(DEFSADD)
CFLAGS = @CFLAGS@ -Wall -funsigned-char
MAINTAINERCLEANFILES = Makefile.in number.c
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
LIBRARIES = $(noinst_LIBRARIES)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
libbc_a_LIBADD =
libbc_a_OBJECTS = getopt.o getopt1.o vfprintf.o number.o
AR = ar
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
SOURCES = $(libbc_a_SOURCES)
OBJECTS = $(libbc_a_OBJECTS)
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .o .s
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-noinstLIBRARIES:
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
distclean-noinstLIBRARIES:
maintainer-clean-noinstLIBRARIES:
.c.o:
$(COMPILE) -c $<
.s.o:
$(COMPILE) -c $<
.S.o:
$(COMPILE) -c $<
mostlyclean-compile:
-rm -f *.o core *.core
clean-compile:
distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
libbc.a: $(libbc_a_OBJECTS) $(libbc_a_DEPENDENCIES)
-rm -f libbc.a
$(AR) cru libbc.a $(libbc_a_OBJECTS) $(libbc_a_LIBADD)
$(RANLIB) libbc.a
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = lib
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
getopt.o: getopt.c ../config.h ../h/getopt.h
getopt1.o: getopt1.c ../config.h ../h/getopt.h
number.o: number.c ../config.h ../h/number.h
vfprintf.o: vfprintf.c ../config.h
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am:
install-exec: install-exec-am
install-data-am:
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am:
uninstall: uninstall-am
all-am: Makefile $(LIBRARIES)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
mostlyclean-am
clean: clean-am
distclean-am: distclean-noinstLIBRARIES distclean-compile \
distclean-tags distclean-generic clean-am
distclean: distclean-am
maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
check-am installcheck-am installcheck install-exec-am install-exec \
install-data-am install-data install-am install uninstall-am uninstall \
all-redirect all-am all installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
newnumber.o: number.c muldigits.h
$(CC) $(CFLAGS) $(INCLUDES) -c -DMULDIGITS -o newnumber.o $(srcdir)/number.c
muldigits.h: testmul
@echo "The following may take up to 10 minutes."
testmul > muldigits.h
testmul: testmul.o number.o
$(CC) $(CFLAGS) -o testmul testmul.o number.o
specialnumber: newnumber.o
cp newnumber.o number.o
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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 */

View file

@ -1,134 +0,0 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
case "$1" in
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison touch file \`y.tab.c'
makeinfo touch the output file
yacc touch file \`y.tab.c'"
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing - GNU libit 0.0"
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
aclocal)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`acinclude.m4' or \`configure.in'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`configure.in'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`acconfig.h' or \`configure.in'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
touch config.h.in
;;
automake)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print \
| sed 's/^\(.*\).am$/touch \1.in/' \
| sh
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
your modified any \`.y' file. For being effective, your
modifications might require the \`Bison' package. Grab it from
any GNU archive site."
touch y.tab.c
;;
makeinfo)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. It should be needed only if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
fi
touch $file
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequirements for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0

View file

@ -1,36 +0,0 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-05-16
# Last modified: 1994-03-25
# Public domain
errstatus=0
for file in ${1+"$@"} ; do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d in ${1+"$@"} ; do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$?
fi
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here

View file

@ -1 +0,0 @@
timestamp

View file

@ -1,21 +0,0 @@
# $FreeBSD$
.include <bsd.own.mk>
BCDIR= ${.CURDIR}/../../../contrib/bc
.PATH: ${BCDIR}/bc ${BCDIR}/lib ${BCDIR}/doc ${BCDIR}/Examples
PROG= bc
SRCS= bc.y execute.c global.c load.c main.c scan.l storage.c util.c \
number.c
CFLAGS+=-I. -I${.CURDIR} -I${BCDIR}/h -I${BCDIR}/bc
CFLAGS+=-DHAVE_CONFIG_H
DPADD= ${LIBREADLINE} ${LIBTERMCAP}
LDADD= -lreadline -ltermcap
.if ${MK_EXAMPLES} != "no"
FILES= ckbook.b pi.b primes.b twins.b
FILESDIR= ${SHAREDIR}/examples/bc
.endif
.include <bsd.prog.mk>

View file

@ -1,84 +0,0 @@
/* $FreeBSD$ */
/* 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. */
#define READLINE 1
/* Define to use the BSD libedit library. */
/* #define LIBEDIT 1 */
/* 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"

View file

@ -1,15 +0,0 @@
# $FreeBSD$
BCDIR= ${.CURDIR}/../../../contrib/bc
.PATH: ${BCDIR}/dc ${BCDIR}/lib ${BCDIR}/doc
PROG= dc
SRCS= array.c dc.c eval.c misc.c numeric.c stack.c string.c \
number.c
CFLAGS+=-I${.CURDIR}/../bc -I${BCDIR}/h -DHAVE_CONFIG_H
DPADD= ${LIBM}
LDADD= -lm
SUBDIR= doc
.include <bsd.prog.mk>

View file

@ -1,11 +0,0 @@
# Makefile copyright Andreas Klemm <andreas@FreeBSD.ORG> 1998
#
# $FreeBSD$
.PATH: ${.CURDIR}/../../../../contrib/bc/doc
INFO = dc
INFOSECTION= "System Utilities"
INFOENTRY_dc= "* DC: (dc). The GNU Desktop Calculator."
.include <bsd.info.mk>