From 5439ab7459283bf61a0256c3a20df164c780ef6c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Wed, 15 Nov 2000 20:19:18 +0000 Subject: Imported from /home/lorry/working-area/delta_bc-tarball/bc-1.06.tar.gz. --- bc/Makefile.am | 42 + bc/Makefile.in | 345 +++++++++ bc/bc.c | 1886 +++++++++++++++++++++++++++++++++++++++++++++ bc/bc.h | 42 + bc/bc.y | 654 ++++++++++++++++ bc/bcdefs.h | 188 +++++ bc/const.h | 98 +++ bc/execute.c | 788 +++++++++++++++++++ bc/fix-libmath_h | 9 + bc/global.c | 42 + bc/global.h | 154 ++++ bc/libmath.b | 287 +++++++ bc/libmath.h | 40 + bc/load.c | 351 +++++++++ bc/main.c | 352 +++++++++ bc/proto.h | 148 ++++ bc/sbc.y | 448 +++++++++++ bc/scan.c | 2259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ bc/scan.l | 374 +++++++++ bc/storage.c | 1067 ++++++++++++++++++++++++++ bc/util.c | 873 +++++++++++++++++++++ 21 files changed, 10447 insertions(+) create mode 100644 bc/Makefile.am create mode 100644 bc/Makefile.in create mode 100644 bc/bc.c create mode 100644 bc/bc.h create mode 100644 bc/bc.y create mode 100644 bc/bcdefs.h create mode 100644 bc/const.h create mode 100644 bc/execute.c create mode 100755 bc/fix-libmath_h create mode 100644 bc/global.c create mode 100644 bc/global.h create mode 100644 bc/libmath.b create mode 100644 bc/libmath.h create mode 100644 bc/load.c create mode 100644 bc/main.c create mode 100644 bc/proto.h create mode 100644 bc/sbc.y create mode 100644 bc/scan.c create mode 100644 bc/scan.l create mode 100644 bc/storage.c create mode 100644 bc/util.c (limited to 'bc') diff --git a/bc/Makefile.am b/bc/Makefile.am new file mode 100644 index 0000000..9187339 --- /dev/null +++ b/bc/Makefile.am @@ -0,0 +1,42 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = bc + +bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c + +EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h \ + sbc.y +noinst_HEADERS = libmath.h + +DISTCLEANFILES = sbc sbc.c sbc.h + +MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h +LIBBC = ../lib/libbc.a +LIBL = @LEXLIB@ +LDADD = $(LIBBC) $(LIBL) @READLINELIB@ + +YFLAGS = -d + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +$(PROGRAMS): $(LIBBC) + +scan.o: bc.h +global.o: libmath.h + +libmath.h: libmath.b + echo '{0}' > libmath.h + $(MAKE) fbc + ./fbc -c $(srcdir)/libmath.b libmath.h + $(srcdir)/fix-libmath_h + rm -f ./fbc + +fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o +fbc: $(fbcOBJ) + $(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) + +sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o +sbc.o: sbc.c +sbc: $(sbcOBJ) + $(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) diff --git a/bc/Makefile.in b/bc/Makefile.in new file mode 100644 index 0000000..18ebce0 --- /dev/null +++ b/bc/Makefile.in @@ -0,0 +1,345 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +READLINELIB = @READLINELIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +bin_PROGRAMS = bc + +bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c + +EXTRA_DIST = bc.h bcdefs.h const.h fix-libmath_h global.h libmath.b proto.h sbc.y + +noinst_HEADERS = libmath.h + +DISTCLEANFILES = sbc sbc.c sbc.h + +MAINTAINERCLEANFILES = Makefile.in libmath.h bc.c bc.h scan.c + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h +LIBBC = ../lib/libbc.a +LIBL = @LEXLIB@ +LDADD = $(LIBBC) $(LIBL) @READLINELIB@ + +YFLAGS = -d + +CFLAGS = @CFLAGS@ -Wall -funsigned-char + +fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o + +sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +bc_OBJECTS = main.o bc.o scan.o execute.o load.o storage.o util.o \ +global.o +bc_LDADD = $(LDADD) +bc_DEPENDENCIES = ../lib/libbc.a +bc_LDFLAGS = +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LEXLIB = @LEXLIB@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = Makefile.am Makefile.in bc.c scan.c + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(bc_SOURCES) +OBJECTS = $(bc_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .l .o .s .y +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps bc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +bc: $(bc_OBJECTS) $(bc_DEPENDENCIES) + @rm -f bc + $(LINK) $(bc_LDFLAGS) $(bc_OBJECTS) $(bc_LDADD) $(LIBS) +.l.c: + $(LEX) $(AM_LFLAGS) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@ +.y.c: + $(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c + if test -f y.tab.h; then \ + if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \ + else :; fi +bc.h: bc.c + + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = bc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +bc.o: bc.c bcdefs.h ../config.h const.h ../h/number.h global.h proto.h +execute.o: execute.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h +global.o: global.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + libmath.h +load.o: load.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h +main.o: main.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h ../h/getopt.h +scan.o: scan.c bcdefs.h ../config.h const.h ../h/number.h bc.h global.h \ + proto.h +storage.o: storage.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h +util.o: util.c bcdefs.h ../config.h const.h ../h/number.h global.h \ + proto.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + -test -z "scanlbchbcc$(MAINTAINERCLEANFILES)" || rm -f scanl bch bcc $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LIBBC) + +scan.o: bc.h +global.o: libmath.h + +libmath.h: libmath.b + echo '{0}' > libmath.h + $(MAKE) fbc + ./fbc -c $(srcdir)/libmath.b libmath.h + $(srcdir)/fix-libmath_h + rm -f ./fbc +fbc: $(fbcOBJ) + $(LINK) $(fbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) +sbc.o: sbc.c +sbc: $(sbcOBJ) + $(LINK) $(sbcOBJ) $(LIBBC) $(LIBL) $(READLINELIB) $(LIBS) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bc/bc.c b/bc/bc.c new file mode 100644 index 0000000..6750bb6 --- /dev/null +++ b/bc/bc.c @@ -0,0 +1,1886 @@ + +/* A Bison parser, made from bc.y + by GNU Bison version 1.27 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define ENDOFLINE 257 +#define AND 258 +#define OR 259 +#define NOT 260 +#define STRING 261 +#define NAME 262 +#define NUMBER 263 +#define ASSIGN_OP 264 +#define REL_OP 265 +#define INCR_DECR 266 +#define Define 267 +#define Break 268 +#define Quit 269 +#define Length 270 +#define Return 271 +#define For 272 +#define If 273 +#define While 274 +#define Sqrt 275 +#define Else 276 +#define Scale 277 +#define Ibase 278 +#define Obase 279 +#define Auto 280 +#define Read 281 +#define Warranty 282 +#define Halt 283 +#define Last 284 +#define Continue 285 +#define Print 286 +#define Limits 287 +#define UNARY_MINUS 288 +#define HistoryVar 289 + +#line 1 "bc.y" + +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to: + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" + +#line 40 "bc.y" +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#include + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 185 +#define YYFLAG -32768 +#define YYNTBASE 50 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 289 ? yytranslate[x] : 84) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 40, 2, 2, 43, + 44, 38, 36, 47, 37, 2, 39, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 42, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 48, 2, 49, 41, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 45, 2, 46, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 1, 4, 7, 9, 12, 13, 15, 16, 18, + 22, 25, 26, 28, 31, 35, 38, 42, 44, 47, + 49, 51, 53, 55, 57, 59, 61, 63, 66, 67, + 68, 69, 70, 85, 86, 95, 96, 97, 106, 110, + 111, 115, 117, 121, 123, 125, 126, 127, 132, 133, + 146, 147, 149, 150, 154, 158, 160, 164, 169, 173, + 179, 186, 187, 189, 191, 195, 199, 205, 206, 208, + 209, 211, 212, 217, 218, 223, 224, 229, 232, 236, + 240, 244, 248, 252, 256, 260, 263, 265, 267, 271, + 276, 279, 282, 287, 292, 297, 301, 303, 308, 310, + 312, 314, 316, 318, 319, 321 +}; + +static const short yyrhs[] = { -1, + 50, 51, 0, 53, 3, 0, 69, 0, 1, 3, + 0, 0, 3, 0, 0, 55, 0, 53, 42, 55, + 0, 53, 42, 0, 0, 55, 0, 54, 3, 0, + 54, 3, 55, 0, 54, 42, 0, 54, 42, 56, + 0, 56, 0, 1, 56, 0, 28, 0, 33, 0, + 78, 0, 7, 0, 14, 0, 31, 0, 15, 0, + 29, 0, 17, 77, 0, 0, 0, 0, 0, 18, + 57, 43, 76, 42, 58, 76, 42, 59, 76, 44, + 60, 52, 56, 0, 0, 19, 43, 78, 44, 61, + 52, 56, 67, 0, 0, 0, 20, 62, 43, 78, + 63, 44, 52, 56, 0, 45, 54, 46, 0, 0, + 32, 64, 65, 0, 66, 0, 66, 47, 65, 0, + 7, 0, 78, 0, 0, 0, 22, 68, 52, 56, + 0, 0, 13, 8, 43, 71, 44, 52, 45, 83, + 72, 70, 54, 46, 0, 0, 73, 0, 0, 26, + 73, 3, 0, 26, 73, 42, 0, 8, 0, 8, + 48, 49, 0, 38, 8, 48, 49, 0, 73, 47, + 8, 0, 73, 47, 8, 48, 49, 0, 73, 47, + 38, 8, 48, 49, 0, 0, 75, 0, 78, 0, + 8, 48, 49, 0, 75, 47, 78, 0, 75, 47, + 8, 48, 49, 0, 0, 78, 0, 0, 78, 0, + 0, 82, 10, 79, 78, 0, 0, 78, 4, 80, + 78, 0, 0, 78, 5, 81, 78, 0, 6, 78, + 0, 78, 11, 78, 0, 78, 36, 78, 0, 78, + 37, 78, 0, 78, 38, 78, 0, 78, 39, 78, + 0, 78, 40, 78, 0, 78, 41, 78, 0, 37, + 78, 0, 82, 0, 9, 0, 43, 78, 44, 0, + 8, 43, 74, 44, 0, 12, 82, 0, 82, 12, + 0, 16, 43, 78, 44, 0, 21, 43, 78, 44, + 0, 23, 43, 78, 44, 0, 27, 43, 44, 0, + 8, 0, 8, 48, 78, 49, 0, 24, 0, 25, + 0, 23, 0, 35, 0, 30, 0, 0, 3, 0, + 83, 3, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 107, 116, 118, 120, 122, 128, 129, 132, 134, 135, + 136, 138, 140, 141, 142, 143, 144, 146, 147, 150, + 152, 154, 163, 170, 180, 191, 193, 195, 197, 202, + 212, 223, 233, 241, 248, 254, 260, 267, 273, 275, + 278, 279, 280, 282, 288, 291, 292, 300, 301, 315, + 321, 323, 325, 327, 329, 332, 334, 336, 338, 340, + 342, 345, 347, 349, 354, 360, 365, 381, 386, 388, + 393, 401, 413, 428, 436, 441, 449, 457, 463, 491, + 496, 501, 506, 511, 516, 521, 526, 535, 551, 553, + 569, 588, 611, 613, 615, 617, 623, 625, 630, 632, + 634, 636, 640, 647, 648, 649 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","ENDOFLINE", +"AND","OR","NOT","STRING","NAME","NUMBER","ASSIGN_OP","REL_OP","INCR_DECR","Define", +"Break","Quit","Length","Return","For","If","While","Sqrt","Else","Scale","Ibase", +"Obase","Auto","Read","Warranty","Halt","Last","Continue","Print","Limits","UNARY_MINUS", +"HistoryVar","'+'","'-'","'*'","'/'","'%'","'^'","';'","'('","')'","'{'","'}'", +"','","'['","']'","program","input_item","opt_newline","semicolon_list","statement_list", +"statement_or_error","statement","@1","@2","@3","@4","@5","@6","@7","@8","print_list", +"print_element","opt_else","@9","function","@10","opt_parameter_list","opt_auto_define_list", +"define_list","opt_argument_list","argument_list","opt_expression","return_expression", +"expression","@11","@12","@13","named_expression","required_eol", NULL +}; +#endif + +static const short yyr1[] = { 0, + 50, 50, 51, 51, 51, 52, 52, 53, 53, 53, + 53, 54, 54, 54, 54, 54, 54, 55, 55, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 57, 58, + 59, 60, 56, 61, 56, 62, 63, 56, 56, 64, + 56, 65, 65, 66, 66, 67, 68, 67, 70, 69, + 71, 71, 72, 72, 72, 73, 73, 73, 73, 73, + 73, 74, 74, 75, 75, 75, 75, 76, 76, 77, + 77, 79, 78, 80, 78, 81, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 82, 82, 82, 82, + 82, 82, 82, 83, 83, 83 +}; + +static const short yyr2[] = { 0, + 0, 2, 2, 1, 2, 0, 1, 0, 1, 3, + 2, 0, 1, 2, 3, 2, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, + 0, 0, 14, 0, 8, 0, 0, 8, 3, 0, + 3, 1, 3, 1, 1, 0, 0, 4, 0, 12, + 0, 1, 0, 3, 3, 1, 3, 4, 3, 5, + 6, 0, 1, 1, 3, 3, 5, 0, 1, 0, + 1, 0, 4, 0, 4, 0, 4, 2, 3, 3, + 3, 3, 3, 3, 3, 2, 1, 1, 3, 4, + 2, 2, 4, 4, 4, 3, 1, 4, 1, 1, + 1, 1, 1, 0, 1, 2 +}; + +static const short yydefact[] = { 1, + 0, 0, 0, 23, 97, 88, 0, 0, 24, 26, + 0, 70, 29, 0, 36, 0, 101, 99, 100, 0, + 20, 27, 103, 25, 40, 21, 102, 0, 0, 0, + 2, 0, 9, 18, 4, 22, 87, 5, 19, 78, + 62, 0, 97, 101, 91, 0, 0, 28, 71, 0, + 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, + 13, 3, 0, 74, 76, 0, 0, 0, 0, 0, + 0, 0, 72, 92, 97, 0, 63, 64, 0, 51, + 0, 68, 0, 0, 0, 0, 96, 44, 41, 42, + 45, 89, 0, 16, 39, 10, 0, 0, 79, 80, + 81, 82, 83, 84, 85, 0, 0, 90, 0, 98, + 56, 0, 0, 52, 93, 0, 69, 34, 37, 94, + 95, 0, 15, 17, 75, 77, 73, 65, 97, 66, + 0, 0, 6, 0, 30, 6, 0, 43, 0, 57, + 0, 7, 0, 59, 0, 68, 0, 6, 67, 58, + 104, 0, 0, 0, 46, 0, 105, 53, 60, 0, + 31, 47, 35, 38, 106, 0, 49, 61, 68, 6, + 0, 0, 0, 0, 54, 55, 0, 32, 48, 50, + 6, 0, 33, 0, 0 +}; + +static const short yydefgoto[] = { 1, + 31, 143, 32, 60, 61, 34, 50, 146, 169, 181, + 136, 52, 137, 56, 89, 90, 163, 170, 35, 172, + 113, 167, 114, 76, 77, 116, 48, 36, 106, 97, + 98, 37, 158 +}; + +static const short yypact[] = {-32768, + 170, 375, 567,-32768, -25,-32768, -3, 7,-32768,-32768, + -32, 567,-32768, -29,-32768, -26, -7,-32768,-32768, -5, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 567, 567, 213, +-32768, 16,-32768,-32768,-32768, 642, 14,-32768,-32768, 63, + 597, 567, -9,-32768,-32768, 18, 567,-32768, 642, 19, + 567, 20, 567, 567, 15, 537,-32768, 122, 505, 3, +-32768,-32768, 305,-32768,-32768, 567, 567, 567, 567, 567, + 567, 567,-32768,-32768, -18, 21, 26, 642, 39, -4, + 410, 567, 419, 567, 428, 466,-32768,-32768,-32768, 36, + 642,-32768, 259, 505,-32768,-32768, 567, 567, 404, 316, + 316, 44, 44, 44, 44, 567, 107,-32768, 627,-32768, + -8, 79, 45, 43,-32768, 49, 642,-32768, 642,-32768, +-32768, 537,-32768,-32768, 63, 652, 404,-32768, 38, 642, + 46, 48, 90, -1,-32768, 90, 61,-32768, 337,-32768, + 59,-32768, 65, 64, 103, 567, 505, 90,-32768,-32768, + 111, 68, 70, 78, 99, 505,-32768, 5,-32768, 75, +-32768,-32768,-32768,-32768,-32768, -4,-32768,-32768, 567, 90, + 13, 213, 81, 505,-32768,-32768, 6,-32768,-32768,-32768, + 90, 505,-32768, 129,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, -135,-32768, -37, 1, -2,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768, 25,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, -30,-32768,-32768, -136,-32768, 0,-32768,-32768, +-32768, 131,-32768 +}; + + +#define YYLAST 693 + + +static const short yytable[] = { 39, + 147, 33, 40, 111, 43, 93, 144, 165, 93, 154, + 47, 49, 156, 51, 46, 175, 53, 41, 62, 44, + 18, 19, 42, 73, 41, 74, 23, 57, 58, 107, + 166, 27, 173, 112, 174, 54, 145, 55, 42, 131, + 78, 79, 64, 65, 94, 182, 81, 94, 95, 66, + 83, 180, 85, 86, 176, 91, 39, 63, 87, 134, + 80, 82, 84, 96, 108, 99, 100, 101, 102, 103, + 104, 105, 109, 66, 67, 68, 69, 70, 71, 72, + 41, 117, 122, 119, 72, 139, 132, 110, 133, 134, + 135, 124, 142, 123, 140, 141, 125, 126, 67, 68, + 69, 70, 71, 72, 148, 127, 79, 150, 130, 151, + 153, 152, 3, 157, 5, 6, 159, 160, 7, 161, + 162, 91, 11, 168, 178, 64, 65, 16, 185, 17, + 18, 19, 66, 20, 177, 171, 23, 45, 79, 0, + 0, 27, 0, 28, 155, 117, 138, 0, 0, 29, + 0, 0, 0, 164, 0, 128, 0, 67, 68, 69, + 70, 71, 72, 0, 0, 92, 0, 0, 117, 184, + 2, 179, -8, 0, 0, 3, 4, 5, 6, 183, + 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 0, 17, 18, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 0, 27, 0, 28, 0, 0, 0, + 0, -8, 29, 59, 30, -12, 0, 0, 3, 4, + 5, 6, 0, 0, 7, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 0, 17, 18, 19, 0, 20, + 21, 22, 23, 24, 25, 26, 0, 27, 0, 28, + 0, 0, 0, 0, -12, 29, 0, 30, -12, 59, + 0, -14, 0, 0, 3, 4, 5, 6, 0, 0, + 7, 0, 9, 10, 11, 12, 13, 14, 15, 16, + 0, 17, 18, 19, 0, 20, 21, 22, 23, 24, + 25, 26, 0, 27, 0, 28, 0, 0, 0, 0, + -14, 29, 0, 30, -14, 59, 0, -11, 0, 0, + 3, 4, 5, 6, 0, 0, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 3, 0, 5, 6, -11, 29, 7, 30, + 0, 0, 11, 69, 70, 71, 72, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 0, 28, 0, 0, 0, 38, 0, 29, + 3, 4, 5, 6, 0, 149, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 0, 64, 65, 0, 0, 29, 0, 30, + 66, 0, 64, 65, 0, 0, 0, 0, 0, 66, + 0, 64, 65, 0, 0, 0, 0, 0, 66, 67, + 68, 69, 70, 71, 72, 67, 68, 69, 70, 71, + 72, 0, 0, 115, 67, 68, 69, 70, 71, 72, + 0, 0, 118, 67, 68, 69, 70, 71, 72, 64, + 65, 120, 0, 0, 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 67, 68, 69, 70, 71, 72, 0, 0, 121, + 3, 4, 5, 6, 0, 0, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 3, 88, 5, 6, 0, 29, 7, 30, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 5, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 75, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 129, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 64, 65, 16, 0, 17, + 18, 19, 66, 20, 0, 64, 23, 0, 0, 0, + 0, 27, 66, 28, 0, 0, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 0, 0, 67, 68, 69, + 70, 71, 72, 0, 0, 0, 0, 67, 68, 69, + 70, 71, 72 +}; + +static const short yycheck[] = { 2, + 136, 1, 3, 8, 8, 3, 8, 3, 3, 146, + 43, 12, 148, 43, 8, 3, 43, 43, 3, 23, + 24, 25, 48, 10, 43, 12, 30, 28, 29, 48, + 26, 35, 169, 38, 170, 43, 38, 43, 48, 48, + 41, 42, 4, 5, 42, 181, 47, 42, 46, 11, + 51, 46, 53, 54, 42, 56, 59, 42, 44, 47, + 43, 43, 43, 63, 44, 66, 67, 68, 69, 70, + 71, 72, 47, 11, 36, 37, 38, 39, 40, 41, + 43, 82, 47, 84, 41, 48, 8, 49, 44, 47, + 42, 94, 3, 93, 49, 48, 97, 98, 36, 37, + 38, 39, 40, 41, 44, 106, 107, 49, 109, 45, + 8, 48, 6, 3, 8, 9, 49, 48, 12, 42, + 22, 122, 16, 49, 44, 4, 5, 21, 0, 23, + 24, 25, 11, 27, 172, 166, 30, 7, 139, -1, + -1, 35, -1, 37, 147, 146, 122, -1, -1, 43, + -1, -1, -1, 156, -1, 49, -1, 36, 37, 38, + 39, 40, 41, -1, -1, 44, -1, -1, 169, 0, + 1, 174, 3, -1, -1, 6, 7, 8, 9, 182, + -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, -1, 23, 24, 25, -1, 27, 28, 29, 30, + 31, 32, 33, -1, 35, -1, 37, -1, -1, -1, + -1, 42, 43, 1, 45, 3, -1, -1, 6, 7, + 8, 9, -1, -1, 12, -1, 14, 15, 16, 17, + 18, 19, 20, 21, -1, 23, 24, 25, -1, 27, + 28, 29, 30, 31, 32, 33, -1, 35, -1, 37, + -1, -1, -1, -1, 42, 43, -1, 45, 46, 1, + -1, 3, -1, -1, 6, 7, 8, 9, -1, -1, + 12, -1, 14, 15, 16, 17, 18, 19, 20, 21, + -1, 23, 24, 25, -1, 27, 28, 29, 30, 31, + 32, 33, -1, 35, -1, 37, -1, -1, -1, -1, + 42, 43, -1, 45, 46, 1, -1, 3, -1, -1, + 6, 7, 8, 9, -1, -1, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, 6, -1, 8, 9, 42, 43, 12, 45, + -1, -1, 16, 38, 39, 40, 41, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, -1, 37, -1, -1, -1, 3, -1, 43, + 6, 7, 8, 9, -1, 49, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, -1, 4, 5, -1, -1, 43, -1, 45, + 11, -1, 4, 5, -1, -1, -1, -1, -1, 11, + -1, 4, 5, -1, -1, -1, -1, -1, 11, 36, + 37, 38, 39, 40, 41, 36, 37, 38, 39, 40, + 41, -1, -1, 44, 36, 37, 38, 39, 40, 41, + -1, -1, 44, 36, 37, 38, 39, 40, 41, 4, + 5, 44, -1, -1, -1, -1, 11, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 36, 37, 38, 39, 40, 41, -1, -1, 44, + 6, 7, 8, 9, -1, -1, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, 6, 7, 8, 9, -1, 43, 12, 45, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, 4, 5, 21, -1, 23, + 24, 25, 11, 27, -1, 4, 30, -1, -1, -1, + -1, 35, 11, 37, -1, -1, -1, -1, -1, 43, + -1, -1, -1, -1, -1, -1, -1, 36, 37, 38, + 39, 40, 41, -1, -1, -1, -1, 36, 37, 38, + 39, 40, 41 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/gnu/share/bison.simple" +/* This file comes from bison-1.27. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 216 "/usr/gnu/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 108 "bc.y" +{ + yyval.i_value = 0; + if (interactive && !quiet) + { + show_bc_version (); + welcome (); + } + ; + break;} +case 3: +#line 119 "bc.y" +{ run_code (); ; + break;} +case 4: +#line 121 "bc.y" +{ run_code (); ; + break;} +case 5: +#line 123 "bc.y" +{ + yyerrok; + init_gen (); + ; + break;} +case 7: +#line 130 "bc.y" +{ warn ("newline not allowed"); ; + break;} +case 8: +#line 133 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 12: +#line 139 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 19: +#line 148 "bc.y" +{ yyval.i_value = yyvsp[0].i_value; ; + break;} +case 20: +#line 151 "bc.y" +{ warranty (""); ; + break;} +case 21: +#line 153 "bc.y" +{ limits (); ; + break;} +case 22: +#line 155 "bc.y" +{ + if (yyvsp[0].i_value & 2) + warn ("comparison in expression"); + if (yyvsp[0].i_value & 1) + generate ("W"); + else + generate ("p"); + ; + break;} +case 23: +#line 164 "bc.y" +{ + yyval.i_value = 0; + generate ("w"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + ; + break;} +case 24: +#line 171 "bc.y" +{ + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + ; + break;} +case 25: +#line 181 "bc.y" +{ + warn ("Continue statement"); + if (continue_label == 0) + yyerror ("Continue outside a for"); + else + { + sprintf (genstr, "J%1d:", continue_label); + generate (genstr); + } + ; + break;} +case 26: +#line 192 "bc.y" +{ exit (0); ; + break;} +case 27: +#line 194 "bc.y" +{ generate ("h"); ; + break;} +case 28: +#line 196 "bc.y" +{ generate ("R"); ; + break;} +case 29: +#line 198 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + ; + break;} +case 30: +#line 203 "bc.y" +{ + if (yyvsp[-1].i_value & 2) + warn ("Comparison in first for expression"); + if (yyvsp[-1].i_value >= 0) + generate ("p"); + yyvsp[-1].i_value = next_label++; + sprintf (genstr, "N%1d:", yyvsp[-1].i_value); + generate (genstr); + ; + break;} +case 31: +#line 213 "bc.y" +{ + if (yyvsp[-1].i_value < 0) generate ("1"); + yyvsp[-1].i_value = next_label++; + sprintf (genstr, "B%1d:J%1d:", yyvsp[-1].i_value, break_label); + generate (genstr); + yyval.i_value = continue_label; + continue_label = next_label++; + sprintf (genstr, "N%1d:", continue_label); + generate (genstr); + ; + break;} +case 32: +#line 224 "bc.y" +{ + if (yyvsp[-1].i_value & 2 ) + warn ("Comparison in third for expression"); + if (yyvsp[-1].i_value & 16) + sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value); + else + sprintf (genstr, "pJ%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value); + generate (genstr); + ; + break;} +case 33: +#line 234 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = yyvsp[-13].i_value; + continue_label = yyvsp[-5].i_value; + ; + break;} +case 34: +#line 242 "bc.y" +{ + yyvsp[-1].i_value = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + ; + break;} +case 35: +#line 249 "bc.y" +{ + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = yyvsp[-5].i_value; + ; + break;} +case 36: +#line 255 "bc.y" +{ + yyvsp[0].i_value = next_label++; + sprintf (genstr, "N%1d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 37: +#line 261 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + ; + break;} +case 38: +#line 268 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, break_label); + generate (genstr); + break_label = yyvsp[-4].i_value; + ; + break;} +case 39: +#line 274 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 40: +#line 276 "bc.y" +{ warn ("print statement"); ; + break;} +case 44: +#line 283 "bc.y" +{ + generate ("O"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + ; + break;} +case 45: +#line 289 "bc.y" +{ generate ("P"); ; + break;} +case 47: +#line 293 "bc.y" +{ + warn ("else clause in if statement"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "J%d:N%1d:", yyvsp[0].i_value, if_label); + generate (genstr); + if_label = yyvsp[0].i_value; + ; + break;} +case 49: +#line 303 "bc.y" +{ + /* Check auto list against parameter list? */ + check_params (yyvsp[-5].a_value,yyvsp[0].a_value); + sprintf (genstr, "F%d,%s.%s[", + lookup(yyvsp[-7].s_value,FUNCTDEF), + arg_str (yyvsp[-5].a_value), arg_str (yyvsp[0].a_value)); + generate (genstr); + free_args (yyvsp[-5].a_value); + free_args (yyvsp[0].a_value); + yyvsp[-8].i_value = next_label; + next_label = 1; + ; + break;} +case 50: +#line 316 "bc.y" +{ + generate ("0R]"); + next_label = yyvsp[-11].i_value; + ; + break;} +case 51: +#line 322 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 53: +#line 326 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 54: +#line 328 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; ; + break;} +case 55: +#line 330 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; ; + break;} +case 56: +#line 333 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[0].s_value,SIMPLE), FALSE);; + break;} +case 57: +#line 335 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY), FALSE); ; + break;} +case 58: +#line 337 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY), TRUE); ; + break;} +case 59: +#line 339 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-2].a_value, lookup (yyvsp[0].s_value,SIMPLE), FALSE); ; + break;} +case 60: +#line 341 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-4].a_value, lookup (yyvsp[-2].s_value,ARRAY), FALSE); ; + break;} +case 61: +#line 343 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-5].a_value, lookup (yyvsp[-2].s_value,ARRAY), TRUE); ; + break;} +case 62: +#line 346 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 64: +#line 350 "bc.y" +{ + if (yyvsp[0].i_value & 2) warn ("comparison in argument"); + yyval.a_value = nextarg (NULL,0,FALSE); + ; + break;} +case 65: +#line 355 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (NULL,1,FALSE); + ; + break;} +case 66: +#line 361 "bc.y" +{ + if (yyvsp[0].i_value & 2) warn ("comparison in argument"); + yyval.a_value = nextarg (yyvsp[-2].a_value,0,FALSE); + ; + break;} +case 67: +#line 366 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (yyvsp[-4].a_value,1,FALSE); + ; + break;} +case 68: +#line 382 "bc.y" +{ + yyval.i_value = 16; + warn ("Missing expression in for statement"); + ; + break;} +case 70: +#line 389 "bc.y" +{ + yyval.i_value = 0; + generate ("0"); + ; + break;} +case 71: +#line 394 "bc.y" +{ + if (yyvsp[0].i_value & 2) + warn ("comparison in return expresion"); + if (!(yyvsp[0].i_value & 4)) + warn ("return expression requires parenthesis"); + ; + break;} +case 72: +#line 402 "bc.y" +{ + if (yyvsp[0].c_value != '=') + { + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "DL%d:", -yyvsp[-1].i_value); + else + sprintf (genstr, "l%d:", yyvsp[-1].i_value); + generate (genstr); + } + ; + break;} +case 73: +#line 413 "bc.y" +{ + if (yyvsp[0].i_value & 2) warn("comparison in assignment"); + if (yyvsp[-2].c_value != '=') + { + sprintf (genstr, "%c", yyvsp[-2].c_value); + generate (genstr); + } + if (yyvsp[-3].i_value < 0) + sprintf (genstr, "S%d:", -yyvsp[-3].i_value); + else + sprintf (genstr, "s%d:", yyvsp[-3].i_value); + generate (genstr); + yyval.i_value = 0; + ; + break;} +case 74: +#line 429 "bc.y" +{ + warn("&& operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "DZ%d:p", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 75: +#line 436 "bc.y" +{ + sprintf (genstr, "DZ%d:p1N%d:", yyvsp[-2].i_value, yyvsp[-2].i_value); + generate (genstr); + yyval.i_value = (yyvsp[-3].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 76: +#line 442 "bc.y" +{ + warn("|| operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "B%d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 77: +#line 449 "bc.y" +{ + int tmplab; + tmplab = next_label++; + sprintf (genstr, "B%d:0J%d:N%d:1N%d:", + yyvsp[-2].i_value, tmplab, yyvsp[-2].i_value, tmplab); + generate (genstr); + yyval.i_value = (yyvsp[-3].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 78: +#line 458 "bc.y" +{ + yyval.i_value = yyvsp[0].i_value & ~4; + warn("! operator"); + generate ("!"); + ; + break;} +case 79: +#line 464 "bc.y" +{ + yyval.i_value = 3; + switch (*(yyvsp[-1].s_value)) + { + case '=': + generate ("="); + break; + + case '!': + generate ("#"); + break; + + case '<': + if (yyvsp[-1].s_value[1] == '=') + generate ("{"); + else + generate ("<"); + break; + + case '>': + if (yyvsp[-1].s_value[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + ; + break;} +case 80: +#line 492 "bc.y" +{ + generate ("+"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 81: +#line 497 "bc.y" +{ + generate ("-"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 82: +#line 502 "bc.y" +{ + generate ("*"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 83: +#line 507 "bc.y" +{ + generate ("/"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 84: +#line 512 "bc.y" +{ + generate ("%"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 85: +#line 517 "bc.y" +{ + generate ("^"); + yyval.i_value = (yyvsp[-2].i_value | yyvsp[0].i_value) & ~4; + ; + break;} +case 86: +#line 522 "bc.y" +{ + generate ("n"); + yyval.i_value = yyvsp[0].i_value & ~4; + ; + break;} +case 87: +#line 527 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[0].i_value < 0) + sprintf (genstr, "L%d:", -yyvsp[0].i_value); + else + sprintf (genstr, "l%d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 88: +#line 536 "bc.y" +{ + int len = strlen(yyvsp[0].s_value); + yyval.i_value = 1; + if (len == 1 && *yyvsp[0].s_value == '0') + generate ("0"); + else if (len == 1 && *yyvsp[0].s_value == '1') + generate ("1"); + else + { + generate ("K"); + generate (yyvsp[0].s_value); + generate (":"); + } + free (yyvsp[0].s_value); + ; + break;} +case 89: +#line 552 "bc.y" +{ yyval.i_value = yyvsp[-1].i_value | 5; ; + break;} +case 90: +#line 554 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].a_value != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup (yyvsp[-3].s_value,FUNCT), + call_str (yyvsp[-1].a_value)); + free_args (yyvsp[-1].a_value); + } + else + { + sprintf (genstr, "C%d:", lookup (yyvsp[-3].s_value,FUNCT)); + } + generate (genstr); + ; + break;} +case 91: +#line 570 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[0].i_value < 0) + { + if (yyvsp[-1].c_value == '+') + sprintf (genstr, "DA%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value); + else + sprintf (genstr, "DM%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value); + } + else + { + if (yyvsp[-1].c_value == '+') + sprintf (genstr, "i%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value); + else + sprintf (genstr, "d%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value); + } + generate (genstr); + ; + break;} +case 92: +#line 589 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].i_value < 0) + { + sprintf (genstr, "DL%d:x", -yyvsp[-1].i_value); + generate (genstr); + if (yyvsp[0].c_value == '+') + sprintf (genstr, "A%d:", -yyvsp[-1].i_value); + else + sprintf (genstr, "M%d:", -yyvsp[-1].i_value); + } + else + { + sprintf (genstr, "l%d:", yyvsp[-1].i_value); + generate (genstr); + if (yyvsp[0].c_value == '+') + sprintf (genstr, "i%d:", yyvsp[-1].i_value); + else + sprintf (genstr, "d%d:", yyvsp[-1].i_value); + } + generate (genstr); + ; + break;} +case 93: +#line 612 "bc.y" +{ generate ("cL"); yyval.i_value = 1;; + break;} +case 94: +#line 614 "bc.y" +{ generate ("cR"); yyval.i_value = 1;; + break;} +case 95: +#line 616 "bc.y" +{ generate ("cS"); yyval.i_value = 1;; + break;} +case 96: +#line 618 "bc.y" +{ + warn ("read function"); + generate ("cI"); yyval.i_value = 1; + ; + break;} +case 97: +#line 624 "bc.y" +{ yyval.i_value = lookup(yyvsp[0].s_value,SIMPLE); ; + break;} +case 98: +#line 626 "bc.y" +{ + if (yyvsp[-1].i_value > 1) warn("comparison in subscript"); + yyval.i_value = lookup(yyvsp[-3].s_value,ARRAY); + ; + break;} +case 99: +#line 631 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 100: +#line 633 "bc.y" +{ yyval.i_value = 1; ; + break;} +case 101: +#line 635 "bc.y" +{ yyval.i_value = 2; ; + break;} +case 102: +#line 637 "bc.y" +{ yyval.i_value = 3; + warn ("History variable"); + ; + break;} +case 103: +#line 641 "bc.y" +{ yyval.i_value = 4; + warn ("Last variable"); + ; + break;} +case 104: +#line 647 "bc.y" +{ warn ("End of line required"); ; + break;} +case 106: +#line 650 "bc.y" +{ warn ("Too many end of lines"); ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 542 "/usr/gnu/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} +#line 653 "bc.y" + + diff --git a/bc/bc.h b/bc/bc.h new file mode 100644 index 0000000..4a1f59e --- /dev/null +++ b/bc/bc.h @@ -0,0 +1,42 @@ +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#define ENDOFLINE 257 +#define AND 258 +#define OR 259 +#define NOT 260 +#define STRING 261 +#define NAME 262 +#define NUMBER 263 +#define ASSIGN_OP 264 +#define REL_OP 265 +#define INCR_DECR 266 +#define Define 267 +#define Break 268 +#define Quit 269 +#define Length 270 +#define Return 271 +#define For 272 +#define If 273 +#define While 274 +#define Sqrt 275 +#define Else 276 +#define Scale 277 +#define Ibase 278 +#define Obase 279 +#define Auto 280 +#define Read 281 +#define Warranty 282 +#define Halt 283 +#define Last 284 +#define Continue 285 +#define Print 286 +#define Limits 287 +#define UNARY_MINUS 288 +#define HistoryVar 289 + + +extern YYSTYPE yylval; diff --git a/bc/bc.y b/bc/bc.y new file mode 100644 index 0000000..403e326 --- /dev/null +++ b/bc/bc.y @@ -0,0 +1,654 @@ +%{ +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to: + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" +%} + +%start program + +%union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } + +/* Extensions over POSIX bc. + a) NAME was LETTER. This grammar allows longer names. + Single letter names will still work. + b) Relational_expression allowed only one comparison. + This grammar has added boolean expressions with + && (and) || (or) and ! (not) and allowed all of them in + full expressions. + c) Added an else to the if. + d) Call by variable array parameters + e) read() procedure that reads a number under program control from stdin. + f) halt statement that halts the the program under program control. It + is an executed statement. + g) continue statement for for loops. + h) optional expressions in the for loop. + i) print statement to print multiple numbers per line. + j) warranty statement to print an extended warranty notice. + j) limits statement to print the processor's limits. +*/ + +%token ENDOFLINE AND OR NOT +%token STRING NAME NUMBER +/* '-', '+' are tokens themselves */ +/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */ +%token ASSIGN_OP +/* '==', '<=', '>=', '!=', '<', '>' */ +%token REL_OP +/* '++', '--' */ +%token INCR_DECR +/* 'define', 'break', 'quit', 'length' */ +%token Define Break Quit Length +/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */ +%token Return For If While Sqrt Else +/* 'scale', 'ibase', 'obase', 'auto', 'read' */ +%token Scale Ibase Obase Auto Read +/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */ +%token Warranty, Halt, Last, Continue, Print, Limits +/* 'history' */ +%token UNARY_MINUS HistoryVar + +/* Types of all other things. */ +%type expression return_expression named_expression opt_expression +%type '+' '-' '*' '/' '%' +%type opt_parameter_list opt_auto_define_list define_list +%type opt_argument_list argument_list +%type program input_item semicolon_list statement_list +%type statement function statement_or_error required_eol + +/* precedence */ +%left OR +%left AND +%nonassoc NOT +%left REL_OP +%right ASSIGN_OP +%left '+' '-' +%left '*' '/' '%' +%right '^' +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%% +program : /* empty */ + { + $$ = 0; + if (interactive && !quiet) + { + show_bc_version (); + welcome (); + } + } + | program input_item + ; +input_item : semicolon_list ENDOFLINE + { run_code (); } + | function + { run_code (); } + | error ENDOFLINE + { + yyerrok; + init_gen (); + } + ; +opt_newline : /* empty */ + | ENDOFLINE + { warn ("newline not allowed"); } + ; +semicolon_list : /* empty */ + { $$ = 0; } + | statement_or_error + | semicolon_list ';' statement_or_error + | semicolon_list ';' + ; +statement_list : /* empty */ + { $$ = 0; } + | statement_or_error + | statement_list ENDOFLINE + | statement_list ENDOFLINE statement_or_error + | statement_list ';' + | statement_list ';' statement + ; +statement_or_error : statement + | error statement + { $$ = $2; } + ; +statement : Warranty + { warranty (""); } + | Limits + { limits (); } + | expression + { + if ($1 & 2) + warn ("comparison in expression"); + if ($1 & 1) + generate ("W"); + else + generate ("p"); + } + | STRING + { + $$ = 0; + generate ("w"); + generate ($1); + free ($1); + } + | Break + { + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } + | Continue + { + warn ("Continue statement"); + if (continue_label == 0) + yyerror ("Continue outside a for"); + else + { + sprintf (genstr, "J%1d:", continue_label); + generate (genstr); + } + } + | Quit + { exit (0); } + | Halt + { generate ("h"); } + | Return return_expression + { generate ("R"); } + | For + { + $1 = break_label; + break_label = next_label++; + } + '(' opt_expression ';' + { + if ($4 & 2) + warn ("Comparison in first for expression"); + if ($4 >= 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); + $$ = continue_label; + continue_label = next_label++; + sprintf (genstr, "N%1d:", continue_label); + generate (genstr); + } + opt_expression ')' + { + if ($10 & 2 ) + warn ("Comparison in third for expression"); + if ($10 & 16) + sprintf (genstr, "J%1d:N%1d:", $4, $7); + else + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } + opt_newline statement + { + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = $1; + continue_label = $9; + } + | If '(' expression ')' + { + $3 = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + } + opt_newline statement opt_else + { + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = $3; + } + | While + { + $1 = next_label++; + sprintf (genstr, "N%1d:", $1); + generate (genstr); + } + '(' expression + { + $4 = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } + ')' opt_newline statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + break_label = $4; + } + | '{' statement_list '}' + { $$ = 0; } + | Print + { warn ("print statement"); } + print_list + ; +print_list : print_element + | print_element ',' print_list + ; +print_element : STRING + { + generate ("O"); + generate ($1); + free ($1); + } + | expression + { generate ("P"); } + ; +opt_else : /* nothing */ + | Else + { + warn ("else clause in if statement"); + $1 = next_label++; + sprintf (genstr, "J%d:N%1d:", $1, if_label); + generate (genstr); + if_label = $1; + } + opt_newline statement +function : Define NAME '(' opt_parameter_list ')' opt_newline + '{' required_eol opt_auto_define_list + { + /* Check auto list against parameter list? */ + check_params ($4,$9); + sprintf (genstr, "F%d,%s.%s[", + lookup($2,FUNCTDEF), + arg_str ($4), arg_str ($9)); + generate (genstr); + free_args ($4); + free_args ($9); + $1 = next_label; + next_label = 1; + } + statement_list /* ENDOFLINE */ '}' + { + generate ("0R]"); + next_label = $1; + } + ; +opt_parameter_list : /* empty */ + { $$ = NULL; } + | define_list + ; +opt_auto_define_list : /* empty */ + { $$ = NULL; } + | Auto define_list ENDOFLINE + { $$ = $2; } + | Auto define_list ';' + { $$ = $2; } + ; +define_list : NAME + { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);} + | NAME '[' ']' + { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); } + | '*' NAME '[' ']' + { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); } + | define_list ',' NAME '[' ']' + { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); } + | define_list ',' '*' NAME '[' ']' + { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); } + ; +opt_argument_list : /* empty */ + { $$ = NULL; } + | argument_list + ; +argument_list : expression + { + if ($1 & 2) warn ("comparison in argument"); + $$ = nextarg (NULL,0,FALSE); + } + | NAME '[' ']' + { + sprintf (genstr, "K%d:", -lookup ($1,ARRAY)); + generate (genstr); + $$ = nextarg (NULL,1,FALSE); + } + | argument_list ',' expression + { + if ($3 & 2) warn ("comparison in argument"); + $$ = nextarg ($1,0,FALSE); + } + | argument_list ',' NAME '[' ']' + { + sprintf (genstr, "K%d:", -lookup ($3,ARRAY)); + generate (genstr); + $$ = nextarg ($1,1,FALSE); + } + ; + +/* Expression lval meanings! (Bits mean something!) + * 0 => Top op is assignment. + * 1 => Top op is not assignment. + * 2 => Comparison is somewhere in expression. + * 4 => Expression is in parenthesis. + * 16 => Empty optional expression. + */ + +opt_expression : /* empty */ + { + $$ = 16; + warn ("Missing expression in for statement"); + } + | expression + ; +return_expression : /* empty */ + { + $$ = 0; + generate ("0"); + } + | expression + { + if ($1 & 2) + warn ("comparison in return expresion"); + if (!($1 & 4)) + warn ("return expression requires parenthesis"); + } + ; +expression : named_expression ASSIGN_OP + { + if ($2 != '=') + { + if ($1 < 0) + sprintf (genstr, "DL%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + } + expression + { + if ($4 & 2) warn("comparison in assignment"); + if ($2 != '=') + { + sprintf (genstr, "%c", $2); + generate (genstr); + } + if ($1 < 0) + sprintf (genstr, "S%d:", -$1); + else + sprintf (genstr, "s%d:", $1); + generate (genstr); + $$ = 0; + } + ; + | expression AND + { + warn("&& operator"); + $2 = next_label++; + sprintf (genstr, "DZ%d:p", $2); + generate (genstr); + } + expression + { + sprintf (genstr, "DZ%d:p1N%d:", $2, $2); + generate (genstr); + $$ = ($1 | $4) & ~4; + } + | expression OR + { + warn("|| operator"); + $2 = next_label++; + sprintf (genstr, "B%d:", $2); + generate (genstr); + } + expression + { + int tmplab; + tmplab = next_label++; + sprintf (genstr, "B%d:0J%d:N%d:1N%d:", + $2, tmplab, $2, tmplab); + generate (genstr); + $$ = ($1 | $4) & ~4; + } + | NOT expression + { + $$ = $2 & ~4; + warn("! operator"); + generate ("!"); + } + | expression REL_OP expression + { + $$ = 3; + switch (*($2)) + { + case '=': + generate ("="); + break; + + case '!': + generate ("#"); + break; + + case '<': + if ($2[1] == '=') + generate ("{"); + else + generate ("<"); + break; + + case '>': + if ($2[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } + | expression '+' expression + { + generate ("+"); + $$ = ($1 | $3) & ~4; + } + | expression '-' expression + { + generate ("-"); + $$ = ($1 | $3) & ~4; + } + | expression '*' expression + { + generate ("*"); + $$ = ($1 | $3) & ~4; + } + | expression '/' expression + { + generate ("/"); + $$ = ($1 | $3) & ~4; + } + | expression '%' expression + { + generate ("%"); + $$ = ($1 | $3) & ~4; + } + | expression '^' expression + { + generate ("^"); + $$ = ($1 | $3) & ~4; + } + | '-' expression %prec UNARY_MINUS + { + generate ("n"); + $$ = $2 & ~4; + } + | named_expression + { + $$ = 1; + if ($1 < 0) + sprintf (genstr, "L%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + | NUMBER + { + int len = strlen($1); + $$ = 1; + if (len == 1 && *$1 == '0') + generate ("0"); + else if (len == 1 && *$1 == '1') + generate ("1"); + else + { + generate ("K"); + generate ($1); + generate (":"); + } + free ($1); + } + | '(' expression ')' + { $$ = $2 | 5; } + | NAME '(' opt_argument_list ')' + { + $$ = 1; + if ($3 != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup ($1,FUNCT), + call_str ($3)); + free_args ($3); + } + else + { + sprintf (genstr, "C%d:", lookup ($1,FUNCT)); + } + generate (genstr); + } + | INCR_DECR named_expression + { + $$ = 1; + if ($2 < 0) + { + if ($1 == '+') + sprintf (genstr, "DA%d:L%d:", -$2, -$2); + else + sprintf (genstr, "DM%d:L%d:", -$2, -$2); + } + else + { + if ($1 == '+') + sprintf (genstr, "i%d:l%d:", $2, $2); + else + sprintf (genstr, "d%d:l%d:", $2, $2); + } + generate (genstr); + } + | named_expression INCR_DECR + { + $$ = 1; + if ($1 < 0) + { + sprintf (genstr, "DL%d:x", -$1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "A%d:", -$1); + else + sprintf (genstr, "M%d:", -$1); + } + else + { + sprintf (genstr, "l%d:", $1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "i%d:", $1); + else + sprintf (genstr, "d%d:", $1); + } + generate (genstr); + } + | Length '(' expression ')' + { generate ("cL"); $$ = 1;} + | Sqrt '(' expression ')' + { generate ("cR"); $$ = 1;} + | Scale '(' expression ')' + { generate ("cS"); $$ = 1;} + | Read '(' ')' + { + warn ("read function"); + generate ("cI"); $$ = 1; + } + ; +named_expression : NAME + { $$ = lookup($1,SIMPLE); } + | NAME '[' expression ']' + { + if ($3 > 1) warn("comparison in subscript"); + $$ = lookup($1,ARRAY); + } + | Ibase + { $$ = 0; } + | Obase + { $$ = 1; } + | Scale + { $$ = 2; } + | HistoryVar + { $$ = 3; + warn ("History variable"); + } + | Last + { $$ = 4; + warn ("Last variable"); + } + ; + + +required_eol : { warn ("End of line required"); } + | ENDOFLINE + | required_eol ENDOFLINE + { warn ("Too many end of lines"); } + ; + +%% + diff --git a/bc/bcdefs.h b/bc/bcdefs.h new file mode 100644 index 0000000..260cd12 --- /dev/null +++ b/bc/bcdefs.h @@ -0,0 +1,188 @@ +/* bcdefs.h: The single file to include all constants and type definitions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +/* Include the configuration file. */ +#include "config.h" + +/* Standard includes for all files. */ +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#else +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif + +#if defined(LIBEDIT) +#include +#endif + +#if defined(READLINE) +#include +#include +#endif + +/* Include the other definitions. */ +#include "const.h" +#include "number.h" + +/* These definitions define all the structures used in + code and data storage. This includes the representation of + labels. The "guiding" principle is to make structures that + take a minimum of space when unused but can be built to contain + the full structures. */ + +/* Labels are first. Labels are generated sequentially in functions + and full code. They just "point" to a single bye in the code. The + "address" is the byte number. The byte number is used to get an + actual character pointer. */ + +typedef struct bc_label_group + { + long l_adrs [ BC_LABEL_GROUP ]; + struct bc_label_group *l_next; + } bc_label_group; + +/* Argument list. Recorded in the function so arguments can + be checked at call time. */ + +typedef struct arg_list + { + int av_name; + int arg_is_var; /* Extension ... variable parameters. */ + struct arg_list *next; + } arg_list; + +/* Each function has its own code segments and labels. There can be + no jumps between functions so labels are unique to a function. */ + +typedef struct + { + char f_defined; /* Is this function defined yet. */ + char *f_body; + int f_body_size; /* Size of body. Power of 2. */ + int f_code_size; + bc_label_group *f_label; + arg_list *f_params; + arg_list *f_autos; + } bc_function; + +/* Code addresses. */ +typedef struct { + int pc_func; + int pc_addr; + } program_counter; + + +/* Variables are "pushable" (auto) and thus we need a stack mechanism. + This is built into the variable record. */ + +typedef struct bc_var + { + bc_num v_value; + struct bc_var *v_next; + } bc_var; + + +/* bc arrays can also be "auto" variables and thus need the same + kind of stacking mechanisms. */ + +typedef struct bc_array_node + { + union + { + bc_num n_num [NODE_SIZE]; + struct bc_array_node *n_down [NODE_SIZE]; + } n_items; + } bc_array_node; + +typedef struct bc_array + { + bc_array_node *a_tree; + short a_depth; + } bc_array; + +typedef struct bc_var_array + { + bc_array *a_value; + char a_param; + struct bc_var_array *a_next; + } bc_var_array; + + +/* For the stacks, execution and function, we need records to allow + for arbitrary size. */ + +typedef struct estack_rec { + bc_num s_num; + struct estack_rec *s_next; +} estack_rec; + +typedef struct fstack_rec { + int s_val; + struct fstack_rec *s_next; +} fstack_rec; + + +/* The following are for the name tree. */ + +typedef struct id_rec { + char *id; /* The program name. */ + /* A name == 0 => nothing assigned yet. */ + int a_name; /* The array variable name (number). */ + int f_name; /* The function name (number). */ + int v_name; /* The variable name (number). */ + short balance; /* For the balanced tree. */ + struct id_rec *left, *right; /* Tree pointers. */ +} id_rec; + + +/* A list of files to process. */ + +typedef struct file_node { + char *name; + struct file_node *next; +} file_node; + +/* Macro Definitions */ + +#if defined(LIBEDIT) +#define HISTORY_SIZE(n) history(hist, &histev, H_SETSIZE, n) +#define UNLIMIT_HISTORY history(hist, &histev, H_SETSIZE, INT_MAX) +#endif + +#if defined(READLINE) +#define HISTORY_SIZE(n) stifle_history(n) +#define UNLIMIT_HISTORY unstifle_history() +#endif diff --git a/bc/const.h b/bc/const.h new file mode 100644 index 0000000..1a7c5b8 --- /dev/null +++ b/bc/const.h @@ -0,0 +1,98 @@ +/* const.h: Constants for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */ + +#ifndef INT_MAX +#define INT_MAX 0x7FFFFFFF +#endif +#ifndef LONG_MAX +#define LONG_MAX 0x7FFFFFFF +#endif + + +/* Define constants in some reasonable size. The next 4 constants are + POSIX constants. */ + +#ifdef BC_BASE_MAX + /* on a POSIX.2 system may have defined these. Override. */ +# undef BC_BASE_MAX +# undef BC_SCALE_MAX +# undef BC_STRING_MAX +# undef BC_DIM_MAX +#endif + +#define BC_BASE_MAX INT_MAX +#define BC_SCALE_MAX INT_MAX +#define BC_STRING_MAX INT_MAX + + +/* Definitions for arrays. */ + +#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */ + +#define NODE_SIZE 16 /* Must be a power of 2. */ +#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */ +#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */ +#define NODE_DEPTH 4 + + +/* Other BC limits defined but not part of POSIX. */ + +#define BC_LABEL_GROUP 64 +#define BC_LABEL_LOG 6 +#define BC_START_SIZE 1024 /* Initial code body size. */ + +/* Maximum number of variables, arrays and functions and the + allocation increment for the dynamic arrays. */ + +#define MAX_STORE 32767 +#define STORE_INCR 32 + +/* Other interesting constants. */ + +#define FALSE 0 +#define TRUE 1 + +/* for use with lookup (). */ +#define SIMPLE 0 +#define ARRAY 1 +#define FUNCT 2 +#define FUNCTDEF 3 + +#define EXTERN extern +#ifdef __STDC__ +#define CONST const +#define VOID void +#else +#define CONST +#define VOID +#endif diff --git a/bc/execute.c b/bc/execute.c new file mode 100644 index 0000000..d2864d1 --- /dev/null +++ b/bc/execute.c @@ -0,0 +1,788 @@ +/* execute.c - run a bc program. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include +#include "global.h" +#include "proto.h" + + +/* The SIGINT interrupt handling routine. */ + +int had_sigint; + +void +stop_execution (sig) + int sig; +{ + had_sigint = TRUE; + printf ("\n"); + rt_error ("interrupted execution"); +} + + +/* Get the current byte and advance the PC counter. */ + +unsigned char +byte (pc) + program_counter *pc; +{ + return (functions[pc->pc_func].f_body[pc->pc_addr++]); +} + + +/* The routine that actually runs the machine. */ + +void +execute () +{ + int label_num, l_gp, l_off; + bc_label_group *gp; + + char inst, ch; + int new_func; + int var_name; + + int const_base; + + bc_num temp_num; + arg_list *auto_list; + + /* Initialize this run... */ + pc.pc_func = 0; + pc.pc_addr = 0; + runtime_error = FALSE; + bc_init_num (&temp_num); + + /* Set up the interrupt mechanism for an interactive session. */ + if (interactive) + { + signal (SIGINT, stop_execution); + had_sigint = FALSE; + } + + while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error) + { + inst = byte(&pc); + +#if DEBUG > 3 + { /* Print out address and the stack before each instruction.*/ + int depth; estack_rec *temp = ex_stack; + + printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst); + if (temp == NULL) printf ("empty stack.\n", inst); + else + { + depth = 1; + while (temp != NULL) + { + printf (" %d = ", depth); + bc_out_num (temp->s_num, 10, out_char, std_only); + depth++; + temp = temp->s_next; + } + out_char ('\n'); + } + } +#endif + + switch ( inst ) + { + + case 'A' : /* increment array variable (Add one). */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + incr_array (var_name); + break; + + case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */ + case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */ + c_code = !bc_is_zero (ex_stack->s_num); + pop (); + case 'J' : /* Jump to a label. */ + label_num = byte(&pc); /* Low order bits first. */ + label_num += byte(&pc) << 8; + if (inst == 'J' || (inst == 'B' && c_code) + || (inst == 'Z' && !c_code)) { + gp = functions[pc.pc_func].f_label; + l_gp = label_num >> BC_LABEL_LOG; + l_off = label_num % BC_LABEL_GROUP; + while (l_gp-- > 0) gp = gp->l_next; + pc.pc_addr = gp->l_adrs[l_off]; + } + break; + + case 'C' : /* Call a function. */ + /* Get the function number. */ + new_func = byte(&pc); + if ((new_func & 0x80) != 0) + new_func = ((new_func & 0x7f) << 8) + byte(&pc); + + /* Check to make sure it is defined. */ + if (!functions[new_func].f_defined) + { + rt_error ("Function %s not defined.", f_names[new_func]); + break; + } + + /* Check and push parameters. */ + process_params (&pc, new_func); + + /* Push auto variables. */ + for (auto_list = functions[new_func].f_autos; + auto_list != NULL; + auto_list = auto_list->next) + auto_var (auto_list->av_name); + + /* Push pc and ibase. */ + fpush (pc.pc_func); + fpush (pc.pc_addr); + fpush (i_base); + + /* Reset pc to start of function. */ + pc.pc_func = new_func; + pc.pc_addr = 0; + break; + + case 'D' : /* Duplicate top of stack */ + push_copy (ex_stack->s_num); + break; + + case 'K' : /* Push a constant */ + /* Get the input base and convert it to a bc number. */ + if (pc.pc_func == 0) + const_base = i_base; + else + const_base = fn_stack->s_val; + if (const_base == 10) + push_b10_const (&pc); + else + push_constant (prog_char, const_base); + break; + + case 'L' : /* load array variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + load_array (var_name); + break; + + case 'M' : /* decrement array variable (Minus!) */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + decr_array (var_name); + break; + + case 'O' : /* Write a string to the output with processing. */ + while ((ch = byte(&pc)) != '"') + if (ch != '\\') + out_schar (ch); + else + { + ch = byte(&pc); + if (ch == '"') break; + switch (ch) + { + case 'a': out_schar (007); break; + case 'b': out_schar ('\b'); break; + case 'f': out_schar ('\f'); break; + case 'n': out_schar ('\n'); break; + case 'q': out_schar ('"'); break; + case 'r': out_schar ('\r'); break; + case 't': out_schar ('\t'); break; + case '\\': out_schar ('\\'); break; + default: break; + } + } + fflush (stdout); + break; + + case 'R' : /* Return from function */ + if (pc.pc_func != 0) + { + /* "Pop" autos and parameters. */ + pop_vars(functions[pc.pc_func].f_autos); + pop_vars(functions[pc.pc_func].f_params); + /* reset the pc. */ + fpop (); + pc.pc_addr = fpop (); + pc.pc_func = fpop (); + } + else + rt_error ("Return from main program."); + break; + + case 'S' : /* store array variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f ) << 8) + byte(&pc); + store_array (var_name); + break; + + case 'T' : /* Test tos for zero */ + c_code = bc_is_zero (ex_stack->s_num); + assign (c_code); + break; + + case 'W' : /* Write the value on the top of the stack. */ + case 'P' : /* Write the value on the top of the stack. No newline. */ + bc_out_num (ex_stack->s_num, o_base, out_char, std_only); + if (inst == 'W') out_char ('\n'); + store_var (4); /* Special variable "last". */ + fflush (stdout); + pop (); + break; + + case 'c' : /* Call special function. */ + new_func = byte(&pc); + + switch (new_func) + { + case 'L': /* Length function. */ + /* For the number 0.xxxx, 0 is not significant. */ + if (ex_stack->s_num->n_len == 1 && + ex_stack->s_num->n_scale != 0 && + ex_stack->s_num->n_value[0] == 0 ) + bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); + else + bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_len + + ex_stack->s_num->n_scale); + break; + + case 'S': /* Scale function. */ + bc_int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); + break; + + case 'R': /* Square Root function. */ + if (!bc_sqrt (&ex_stack->s_num, scale)) + rt_error ("Square root of a negative number"); + break; + + case 'I': /* Read function. */ + push_constant (input_char, i_base); + break; + } + break; + + case 'd' : /* Decrement number */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + decr_var (var_name); + break; + + case 'h' : /* Halt the machine. */ + exit (0); + + case 'i' : /* increment number */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + incr_var (var_name); + break; + + case 'l' : /* load variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + load_var (var_name); + break; + + case 'n' : /* Negate top of stack. */ + bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0); + break; + + case 'p' : /* Pop the execution stack. */ + pop (); + break; + + case 's' : /* store variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name & 0x7f) << 8) + byte(&pc); + store_var (var_name); + break; + + case 'w' : /* Write a string to the output. */ + while ((ch = byte(&pc)) != '"') out_schar (ch); + fflush (stdout); + break; + + case 'x' : /* Exchange Top of Stack with the one under the tos. */ + if (check_stack(2)) { + bc_num temp = ex_stack->s_num; + ex_stack->s_num = ex_stack->s_next->s_num; + ex_stack->s_next->s_num = temp; + } + break; + + case '0' : /* Load Constant 0. */ + push_copy (_zero_); + break; + + case '1' : /* Load Constant 0. */ + push_copy (_one_); + break; + + case '!' : /* Negate the boolean value on top of the stack. */ + c_code = bc_is_zero (ex_stack->s_num); + assign (c_code); + break; + + case '&' : /* compare greater than */ + if (check_stack(2)) + { + c_code = !bc_is_zero (ex_stack->s_next->s_num) + && !bc_is_zero (ex_stack->s_num); + pop (); + assign (c_code); + } + break; + + case '|' : /* compare greater than */ + if (check_stack(2)) + { + c_code = !bc_is_zero (ex_stack->s_next->s_num) + || !bc_is_zero (ex_stack->s_num); + pop (); + assign (c_code); + } + break; + + case '+' : /* add */ + if (check_stack(2)) + { + bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0); + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + break; + + case '-' : /* subtract */ + if (check_stack(2)) + { + bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0); + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + break; + + case '*' : /* multiply */ + if (check_stack(2)) + { + bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num, + &temp_num, scale); + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + break; + + case '/' : /* divide */ + if (check_stack(2)) + { + if (bc_divide (ex_stack->s_next->s_num, + ex_stack->s_num, &temp_num, scale) == 0) + { + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + else + rt_error ("Divide by zero"); + } + break; + + case '%' : /* remainder */ + if (check_stack(2)) + { + if (bc_is_zero (ex_stack->s_num)) + rt_error ("Modulo by zero"); + else + { + bc_modulo (ex_stack->s_next->s_num, + ex_stack->s_num, &temp_num, scale); + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + } + break; + + case '^' : /* raise */ + if (check_stack(2)) + { + bc_raise (ex_stack->s_next->s_num, + ex_stack->s_num, &temp_num, scale); + if (bc_is_zero (ex_stack->s_next->s_num) && bc_is_neg (ex_stack->s_num)) + rt_error ("divide by zero"); + pop(); + pop(); + push_num (temp_num); + bc_init_num (&temp_num); + } + break; + + case '=' : /* compare equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) == 0; + pop (); + assign (c_code); + } + break; + + case '#' : /* compare not equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) != 0; + pop (); + assign (c_code); + } + break; + + case '<' : /* compare less than */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) == -1; + pop (); + assign (c_code); + } + break; + + case '{' : /* compare less than or equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) <= 0; + pop (); + assign (c_code); + } + break; + + case '>' : /* compare greater than */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) == 1; + pop (); + assign (c_code); + } + break; + + case '}' : /* compare greater than or equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) >= 0; + pop (); + assign (c_code); + } + break; + + default : /* error! */ + rt_error ("bad instruction: inst=%c", inst); + } + } + + /* Clean up the function stack and pop all autos/parameters. */ + while (pc.pc_func != 0) + { + pop_vars(functions[pc.pc_func].f_autos); + pop_vars(functions[pc.pc_func].f_params); + fpop (); + pc.pc_addr = fpop (); + pc.pc_func = fpop (); + } + + /* Clean up the execution stack. */ + while (ex_stack != NULL) pop(); + + /* Clean up the interrupt stuff. */ + if (interactive) + { + signal (SIGINT, use_quit); + if (had_sigint) + printf ("Interruption completed.\n"); + } +} + + +/* Prog_char gets another byte from the program. It is used for + conversion of text constants in the code to numbers. */ + +char +prog_char () +{ + return byte(&pc); +} + + +/* Read a character from the standard input. This function is used + by the "read" function. */ + +char +input_char () +{ + char in_ch; + + /* Get a character from the standard input for the read function. */ + in_ch = getchar(); + + /* Check for a \ quoted newline. */ + if (in_ch == '\\') + { + in_ch = getchar(); + if (in_ch == '\n') + in_ch = getchar(); + } + + /* Classify and preprocess the input character. */ + if (isdigit((int)in_ch)) + return (in_ch - '0'); + if (in_ch >= 'A' && in_ch <= 'F') + return (in_ch + 10 - 'A'); + if (in_ch >= 'a' && in_ch <= 'f') + return (in_ch + 10 - 'a'); + if (in_ch == '.' || in_ch == '+' || in_ch == '-') + return (in_ch); + if (in_ch <= ' ') + return (' '); + + return (':'); +} + + +/* Push_constant converts a sequence of input characters as returned + by IN_CHAR into a number. The number is pushed onto the execution + stack. The number is converted as a number in base CONV_BASE. */ + +void +push_constant (in_char, conv_base) + char (*in_char)(VOID); + int conv_base; +{ + int digits; + bc_num build, temp, result, mult, divisor; + char in_ch, first_ch; + char negative; + + /* Initialize all bc numbers */ + bc_init_num (&temp); + bc_init_num (&result); + bc_init_num (&mult); + build = bc_copy_num (_zero_); + negative = FALSE; + + /* The conversion base. */ + bc_int2num (&mult, conv_base); + + /* Get things ready. */ + in_ch = in_char(); + while (in_ch == ' ') + in_ch = in_char(); + + if (in_ch == '+') + in_ch = in_char(); + else + if (in_ch == '-') + { + negative = TRUE; + in_ch = in_char(); + } + + /* Check for the special case of a single digit. */ + if (in_ch < 16) + { + first_ch = in_ch; + in_ch = in_char(); + if (in_ch < 16 && first_ch >= conv_base) + first_ch = conv_base - 1; + bc_int2num (&build, (int) first_ch); + } + + /* Convert the integer part. */ + while (in_ch < 16) + { + if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; + bc_multiply (build, mult, &result, 0); + bc_int2num (&temp, (int) in_ch); + bc_add (result, temp, &build, 0); + in_ch = in_char(); + } + if (in_ch == '.') + { + in_ch = in_char(); + if (in_ch >= conv_base) in_ch = conv_base-1; + bc_free_num (&result); + bc_free_num (&temp); + divisor = bc_copy_num (_one_); + result = bc_copy_num (_zero_); + digits = 0; + while (in_ch < 16) + { + bc_multiply (result, mult, &result, 0); + bc_int2num (&temp, (int) in_ch); + bc_add (result, temp, &result, 0); + bc_multiply (divisor, mult, &divisor, 0); + digits++; + in_ch = in_char(); + if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; + } + bc_divide (result, divisor, &result, digits); + bc_add (build, result, &build, 0); + } + + /* Final work. */ + if (negative) + bc_sub (_zero_, build, &build, 0); + + push_num (build); + bc_free_num (&temp); + bc_free_num (&result); + bc_free_num (&mult); +} + + +/* When converting base 10 constants from the program, we use this + more efficient way to convert them to numbers. PC tells where + the constant starts and is expected to be advanced to after + the constant. */ + +void +push_b10_const (pc) + program_counter *pc; +{ + bc_num build; + program_counter look_pc; + int kdigits, kscale; + char inchar; + char *ptr; + + /* Count the digits and get things ready. */ + look_pc = *pc; + kdigits = 0; + kscale = 0; + inchar = byte (&look_pc); + while (inchar != '.' && inchar != ':') + { + kdigits++; + inchar = byte(&look_pc); + } + if (inchar == '.' ) + { + inchar = byte(&look_pc); + while (inchar != ':') + { + kscale++; + inchar = byte(&look_pc); + } + } + + /* Get the first character again and move the pc. */ + inchar = byte(pc); + + /* Secial cases of 0, 1, and A-F single inputs. */ + if (kdigits == 1 && kscale == 0) + { + if (inchar == 0) + { + push_copy (_zero_); + inchar = byte(pc); + return; + } + if (inchar == 1) { + push_copy (_one_); + inchar = byte(pc); + return; + } + if (inchar > 9) + { + bc_init_num (&build); + bc_int2num (&build, inchar); + push_num (build); + inchar = byte(pc); + return; + } + } + + /* Build the new number. */ + if (kdigits == 0) + { + build = bc_new_num (1,kscale); + ptr = build->n_value; + *ptr++ = 0; + } + else + { + build = bc_new_num (kdigits,kscale); + ptr = build->n_value; + } + + while (inchar != ':') + { + if (inchar != '.') + { + if (inchar > 9) + *ptr++ = 9; + else + *ptr++ = inchar; + } + inchar = byte(pc); + } + push_num (build); +} + + +/* Put the correct value on the stack for C_CODE. Frees TOS num. */ + +void +assign (c_code) + char c_code; +{ + bc_free_num (&ex_stack->s_num); + if (c_code) + ex_stack->s_num = bc_copy_num (_one_); + else + ex_stack->s_num = bc_copy_num (_zero_); +} + diff --git a/bc/fix-libmath_h b/bc/fix-libmath_h new file mode 100755 index 0000000..f973a8c --- /dev/null +++ b/bc/fix-libmath_h @@ -0,0 +1,9 @@ +ed libmath.h < 1) { + f += 1; + x /= 2; + scale += 1; + } + + /* Initialize the variables. */ + scale = n; + v = 1+x + a = x + d = 1 + + for (i=2; 1; i++) { + e = (a *= x) / (d *= i) + if (e == 0) { + if (f>0) while (f--) v = v*v; + scale = z + if (m) return (1/v); + return (v/1); + } + v += e + } +} + +/* Natural log. Uses the fact that ln(x^2) = 2*ln(x) + The series used is: + ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1) +*/ + +define l(x) { + auto e, f, i, m, n, v, z + + /* return something for the special case. */ + if (x <= 0) return ((1 - 10^scale)/1) + + /* Precondition x to make .5 < x < 2.0. */ + z = scale; + scale = 6 + scale; + f = 2; + i=0 + while (x >= 2) { /* for large numbers */ + f *= 2; + x = sqrt(x); + } + while (x <= .5) { /* for small numbers */ + f *= 2; + x = sqrt(x); + } + + /* Set up the loop. */ + v = n = (x-1)/(x+1) + m = n*n + + /* Sum the series. */ + for (i=3; 1; i+=2) { + e = (n *= m) / i + if (e == 0) { + v = f*v + scale = z + return (v/1) + } + v += e + } +} + +/* Sin(x) uses the standard series: + sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */ + +define s(x) { + auto e, i, m, n, s, v, z + + /* precondition x. */ + z = scale + scale = 1.1*z + 2; + v = a(1) + if (x < 0) { + m = 1; + x = -x; + } + scale = 0 + n = (x / v + 2 )/4 + x = x - 4*n*v + if (n%2) x = -x + + /* Do the loop. */ + scale = z + 2; + v = e = x + s = -x*x + for (i=3; 1; i+=2) { + e *= s/(i*(i-1)) + if (e == 0) { + scale = z + if (m) return (-v/1); + return (v/1); + } + v += e + } +} + +/* Cosine : cos(x) = sin(x+pi/2) */ +define c(x) { + auto v, z; + z = scale; + scale = scale*1.2; + v = s(x+a(1)*2); + scale = z; + return (v/1); +} + +/* Arctan: Using the formula: + atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here) + For under .2, use the series: + atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */ + +define a(x) { + auto a, e, f, i, m, n, s, v, z + + /* a is the value of a(.2) if it is needed. */ + /* f is the value to multiply by a in the return. */ + /* e is the value of the current term in the series. */ + /* v is the accumulated value of the series. */ + /* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */ + /* i is the denominator value for series element. */ + /* n is the numerator value for the series element. */ + /* s is -x*x. */ + /* z is the saved user's scale. */ + + /* Negative x? */ + m = 1; + if (x<0) { + m = -1; + x = -x; + } + + /* Special case and for fast answers */ + if (x==1) { + if (scale <= 25) return (.7853981633974483096156608/m) + if (scale <= 40) return (.7853981633974483096156608458198757210492/m) + if (scale <= 60) \ + return (.785398163397448309615660845819875721049292349843776455243736/m) + } + if (x==.2) { + if (scale <= 25) return (.1973955598498807583700497/m) + if (scale <= 40) return (.1973955598498807583700497651947902934475/m) + if (scale <= 60) \ + return (.197395559849880758370049765194790293447585103787852101517688/m) + } + + + /* Save the scale. */ + z = scale; + + /* Note: a and f are known to be zero due to being auto vars. */ + /* Calculate atan of a known number. */ + if (x > .2) { + scale = z+5; + a = a(.2); + } + + /* Precondition x. */ + scale = z+3; + while (x > .2) { + f += 1; + x = (x-.2) / (1+x*.2); + } + + /* Initialize the series. */ + v = n = x; + s = -x*x; + + /* Calculate the series. */ + for (i=3; 1; i+=2) { + e = (n *= s) / i; + if (e == 0) { + scale = z; + return ((f*a+v)/m); + } + v += e + } +} + + +/* Bessel function of integer order. Uses the following: + j(-n,x) = (-1)^n*j(n,x) + j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2)) + - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... ) +*/ +define j(n,x) { + auto a, b, d, e, f, i, m, s, v, z + + /* Make n an integer and check for negative n. */ + z = scale; + scale = 0; + n = n/1; + if (n<0) { + n = -n; + if (n%2 == 1) m = 1; + } + + /* save ibase */ + b = ibase; + ibase = A; + + /* Compute the factor of x^n/(2^n*n!) */ + f = 1; + for (i=2; i<=n; i++) f = f*i; + scale = 1.5*z; + f = x^n / 2^n / f; + + /* Initialize the loop .*/ + v = e = 1; + s = -x*x/4 + scale = 1.5*z + length(f) - scale(f); + + /* The Loop.... */ + for (i=1; 1; i++) { + e = e * s / i / (n+i); + if (e == 0) { + ibase = b; + scale = z + if (m) return (-f*v/1); + return (f*v/1); + } + v += e; + } +} diff --git a/bc/libmath.h b/bc/libmath.h new file mode 100644 index 0000000..bf48f4b --- /dev/null +++ b/bc/libmath.h @@ -0,0 +1,40 @@ +{"@iK20:s2:p@r", +"@iF1,5.6,7,8,9,10,11,12,13,14[l5:0Z3: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:0Z10: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= f->f_body_size) + { + f->f_body_size *= 2; + new_body = (char *) bc_malloc (f->f_body_size); + memcpy(new_body, f->f_body, f->f_body_size/2); + free (f->f_body); + f->f_body = new_body; + } + + /* Store the byte. */ + f->f_body[pc] = byte; + f->f_code_size++; +} + + +/* Define a label LAB to be the current program counter. */ + +void +def_label (lab) + long lab; +{ + bc_label_group *temp; + int group, offset, func; + + /* Get things ready. */ + group = lab >> BC_LABEL_LOG; + offset = lab % BC_LABEL_GROUP; + func = load_adr.pc_func; + + /* Make sure there is at least one label group. */ + if (functions[func].f_label == NULL) + { + functions[func].f_label = + (bc_label_group *) bc_malloc (sizeof(bc_label_group)); + functions[func].f_label->l_next = NULL; + } + + /* Add the label group. */ + temp = functions[func].f_label; + while (group > 0) + { + if (temp->l_next == NULL) + { + temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group)); + temp->l_next->l_next = NULL; + } + temp = temp->l_next; + group --; + } + + /* Define it! */ + temp->l_adrs [offset] = load_adr.pc_addr; +} + +/* Several instructions have integers in the code. They + are all known to be legal longs. So, no error code + is added. STR is the pointer to the load string and + must be moved to the last non-digit character. */ + +long +long_val (str) + char **str; +{ int val = 0; + char neg = FALSE; + + if (**str == '-') + { + neg = TRUE; + (*str)++; + } + while (isdigit((int)(**str))) + val = val*10 + *(*str)++ - '0'; + + if (neg) + return -val; + else + return val; +} + + +/* load_code loads the CODE into the machine. */ + +void +load_code (code) + char *code; +{ + char *str; + long ap_name; /* auto or parameter name. */ + long label_no; + long vaf_name; /* variable, array or function number. */ + long func; + program_counter save_adr; + + /* Initialize. */ + str = code; + + /* Scan the code. */ + while (*str != 0) + { + /* If there was an error, don't continue. */ + if (had_error) return; + + if (load_str) + { + if (*str == '"') load_str = FALSE; + addbyte (*str++); + } + else + if (load_const) + { + if (*str == '\n') + str++; + else + { + if (*str == ':') + { + load_const = FALSE; + addbyte (*str++); + } + else + if (*str == '.') + addbyte (*str++); + else + if (*str >= 'A') + addbyte (*str++ + 10 - 'A'); + else + addbyte (*str++ - '0'); + } + } + else + { + switch (*str) + { + + case '"': /* Starts a string. */ + load_str = TRUE; + break; + + case 'N': /* A label */ + str++; + label_no = long_val (&str); + def_label (label_no); + break; + + case 'B': /* Branch to label. */ + case 'J': /* Jump to label. */ + case 'Z': /* Branch Zero to label. */ + addbyte(*str++); + label_no = long_val (&str); + if (label_no > 65535L) + { /* Better message? */ + fprintf (stderr,"Program too big.\n"); + exit(1); + } + addbyte ( (char) (label_no & 0xFF)); + addbyte ( (char) (label_no >> 8)); + break; + + case 'F': /* A function, get the name and initialize it. */ + str++; + func = long_val (&str); + clear_func (func); +#if DEBUG > 2 + printf ("Loading function number %d\n", func); +#endif + /* get the parameters */ + while (*str++ != '.') + { + if (*str == '.') + { + str++; + break; + } + if (*str == '*') + { + str++; + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("var parameter number %d\n", ap_name); +#endif + functions[(int)func].f_params = + nextarg (functions[(int)func].f_params, ap_name, + TRUE); + } + else + { + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("parameter number %d\n", ap_name); +#endif + functions[(int)func].f_params = + nextarg (functions[(int)func].f_params, ap_name, + FALSE); + } + } + + /* get the auto vars */ + while (*str != '[') + { + if (*str == ',') str++; + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("auto number %d\n", ap_name); +#endif + functions[(int)func].f_autos = + nextarg (functions[(int)func].f_autos, ap_name, FALSE); + } + save_adr = load_adr; + load_adr.pc_func = func; + load_adr.pc_addr = 0; + break; + + case ']': /* A function end */ + functions[load_adr.pc_func].f_defined = TRUE; + load_adr = save_adr; + break; + + case 'C': /* Call a function. */ + addbyte (*str++); + func = long_val (&str); + if (func < 128) + addbyte ( (char) func); + else + { + addbyte (((func >> 8) & 0xff) | 0x80); + addbyte (func & 0xff); + } + if (*str == ',') str++; + while (*str != ':') + addbyte (*str++); + addbyte (':'); + break; + + case 'c': /* Call a special function. */ + addbyte (*str++); + addbyte (*str); + break; + + case 'K': /* A constant.... may have an "F" in it. */ + addbyte (*str); + load_const = TRUE; + break; + + case 'd': /* Decrement. */ + case 'i': /* Increment. */ + case 'l': /* Load. */ + case 's': /* Store. */ + case 'A': /* Array Increment */ + case 'M': /* Array Decrement */ + case 'L': /* Array Load */ + case 'S': /* Array Store */ + addbyte (*str++); + vaf_name = long_val (&str); + if (vaf_name < 128) + addbyte (vaf_name); + else + { + addbyte (((vaf_name >> 8) & 0xff) | 0x80); + addbyte (vaf_name & 0xff); + } + break; + + case '@': /* A command! */ + switch (*(++str)) + { + case 'i': + init_load (); + break; + case 'r': + execute (); + break; + } + break; + + case '\n': /* Ignore the newlines */ + break; + + default: /* Anything else */ + addbyte (*str); + } + str++; + } + } +} diff --git a/bc/main.c b/bc/main.c new file mode 100644 index 0000000..1b9f6d2 --- /dev/null +++ b/bc/main.c @@ -0,0 +1,352 @@ +/* main.c: The main program for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include +#include "global.h" +#include "proto.h" +#include "getopt.h" + + +/* Variables for processing multiple files. */ +static char first_file; + +/* Points to the last node in the file name list for easy adding. */ +static file_node *last = NULL; + +/* long option support */ +static struct option long_options[] = +{ + {"compile", 0, &compile_only, TRUE}, + {"help", 0, 0, 'h'}, + {"interactive", 0, 0, 'i'}, + {"mathlib", 0, &use_math, TRUE}, + {"quiet", 0, &quiet, TRUE}, + {"standard", 0, &std_only, TRUE}, + {"version", 0, 0, 'v'}, + {"warn", 0, &warn_not_std, TRUE}, + + {0, 0, 0, 0} +}; + + +void +usage (char *progname) +{ + printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname, + " -h --help print this usage and exit\n", + " -i --interactive force interactive mode\n", + " -l --mathlib use the predefine math routnes\n", + " -q --quiet don't print initial banner\n", + " -s --standard non-standard bc constructs are errors\n", + " -w --warn warn about non-standard bc constructs\n", + " -v --version print version information and exit\n"); +} + + +void +parse_args (argc, argv) + int argc; + char **argv; +{ + int optch; + int long_index; + file_node *temp; + + /* Force getopt to initialize. Depends on GNU getopt. */ + optind = 0; + + /* Parse the command line */ + while (1) + { + optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index); + + if (optch == EOF) /* End of arguments. */ + break; + + switch (optch) + { + case 'c': /* compile only */ + compile_only = TRUE; + break; + + case 'h': /* help */ + usage(argv[0]); + exit (0); + break; + + case 'i': /* force interactive */ + interactive = TRUE; + break; + + case 'l': /* math lib */ + use_math = TRUE; + break; + + case 'q': /* quiet mode */ + quiet = TRUE; + break; + + case 's': /* Non standard features give errors. */ + std_only = TRUE; + break; + + case 'v': /* Print the version. */ + show_bc_version (); + exit (0); + break; + + case 'w': /* Non standard features give warnings. */ + warn_not_std = TRUE; + break; + + default: + usage(argv[0]); + exit (1); + } + } + + /* Add file names to a list of files to process. */ + while (optind < argc) + { + temp = (file_node *) bc_malloc(sizeof(file_node)); + temp->name = argv[optind]; + temp->next = NULL; + if (last == NULL) + file_names = temp; + else + last->next = temp; + last = temp; + optind++; + } +} + +/* The main program for bc. */ +int +main (argc, argv) + int argc; + char *argv[]; +{ + char *env_value; + char *env_argv[30]; + int env_argc; + + /* Initialize many variables. */ + compile_only = FALSE; + use_math = FALSE; + warn_not_std = FALSE; + std_only = FALSE; + if (isatty(0) && isatty(1)) + interactive = TRUE; + else + interactive = FALSE; + quiet = FALSE; + file_names = NULL; + +#ifdef HAVE_SETVBUF + /* attempt to simplify interaction with applications such as emacs */ + (void) setvbuf(stdout, NULL, _IOLBF, 0); +#endif + + /* Environment arguments. */ + env_value = getenv ("BC_ENV_ARGS"); + if (env_value != NULL) + { + env_argc = 1; + env_argv[0] = "BC_ENV_ARGS"; + while (*env_value != 0) + { + if (*env_value != ' ') + { + env_argv[env_argc++] = env_value; + while (*env_value != ' ' && *env_value != 0) + env_value++; + if (*env_value != 0) + { + *env_value = 0; + env_value++; + } + } + else + env_value++; + } + parse_args (env_argc, env_argv); + } + + /* Command line arguments. */ + parse_args (argc, argv); + + /* Other environment processing. */ + if (getenv ("POSIXLY_CORRECT") != NULL) + std_only = TRUE; + + env_value = getenv ("BC_LINE_LENGTH"); + if (env_value != NULL) + { + line_size = atoi (env_value); + if (line_size < 2) + line_size = 70; + } + else + line_size = 70; + + /* Initialize the machine. */ + init_storage(); + init_load(); + + /* Set up interrupts to print a message. */ + if (interactive) + signal (SIGINT, use_quit); + + /* Initialize the front end. */ + init_tree(); + init_gen (); + is_std_in = FALSE; + first_file = TRUE; + if (!open_new_file ()) + exit (1); + +#if defined(LIBEDIT) + if (interactive) { + /* Enable libedit support. */ + edit = el_init ("bc", stdin, stdout, stderr); + hist = history_init(); + el_set (edit, EL_EDITOR, "emacs"); + el_set (edit, EL_HIST, history, hist); + el_set (edit, EL_PROMPT, null_prompt); + el_source (edit, NULL); + history (hist, &histev, H_SETSIZE, INT_MAX); + } +#endif + +#if defined(READLINE) + if (interactive) { + /* Readline support. Set both application name and input file. */ + rl_readline_name = "bc"; + rl_instream = stdin; + using_history (); + } +#endif + + /* Do the parse. */ + yyparse (); + + /* End the compile only output with a newline. */ + if (compile_only) + printf ("\n"); + + exit (0); +} + + +/* This is the function that opens all the files. + It returns TRUE if the file was opened, otherwise + it returns FALSE. */ + +int +open_new_file () +{ + FILE *new_file; + file_node *temp; + + /* Set the line number. */ + line_no = 1; + + /* Check to see if we are done. */ + if (is_std_in) return (FALSE); + + /* Open the other files. */ + if (use_math && first_file) + { + /* Load the code from a precompiled version of the math libarary. */ + extern char *libmath[]; + char **mstr; + char tmp; + /* These MUST be in the order of first mention of each function. + That is why "a" comes before "c" even though "a" is defined after + after "c". "a" is used in "s"! */ + tmp = lookup ("e", FUNCT); + tmp = lookup ("l", FUNCT); + tmp = lookup ("s", FUNCT); + tmp = lookup ("a", FUNCT); + tmp = lookup ("c", FUNCT); + tmp = lookup ("j", FUNCT); + mstr = libmath; + while (*mstr) { + load_code (*mstr); + mstr++; + } + } + + /* One of the argv values. */ + if (file_names != NULL) + { + new_file = fopen (file_names->name, "r"); + if (new_file != NULL) + { + new_yy_file (new_file); + temp = file_names; + file_name = temp->name; + file_names = temp->next; + free (temp); + return TRUE; + } + fprintf (stderr, "File %s is unavailable.\n", file_names->name); + exit (1); + } + + /* If we fall through to here, we should return stdin. */ + new_yy_file (stdin); + is_std_in = TRUE; + return TRUE; +} + + +/* Set yyin to the new file. */ + +void +new_yy_file (file) + FILE *file; +{ + if (!first_file) fclose (yyin); + yyin = file; + first_file = FALSE; +} + + +/* Message to use quit. */ + +void +use_quit (sig) + int sig; +{ + printf ("\n(interrupt) use quit to exit.\n"); + signal (SIGINT, use_quit); +} diff --git a/bc/proto.h b/bc/proto.h new file mode 100644 index 0000000..1e7311f --- /dev/null +++ b/bc/proto.h @@ -0,0 +1,148 @@ +/* proto.h: Prototype function definitions for "external" functions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +/* For the pc version using k&r ACK. (minix1.5 and earlier.) */ +#ifdef SHORTNAMES +#define init_numbers i_numbers +#define push_constant push__constant +#define load_const in_load_const +#define yy_get_next_buffer yyget_next_buffer +#define yy_init_buffer yyinit_buffer +#define yy_last_accepting_state yylast_accepting_state +#define arglist1 arg1list +#endif + +/* Include the standard library header files. */ +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +/* Define the _PROTOTYPE macro if it is needed. */ + +#ifndef _PROTOTYPE +#ifdef __STDC__ +#define _PROTOTYPE(func, args) func args +#else +#define _PROTOTYPE(func, args) func() +#endif +#endif + +/* From execute.c */ +_PROTOTYPE(void stop_execution, (int)); +_PROTOTYPE(unsigned char byte, (program_counter *pc)); +_PROTOTYPE(void execute, (void)); +_PROTOTYPE(char prog_char, (void)); +_PROTOTYPE(char input_char, (void)); +_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base)); +_PROTOTYPE(void push_b10_const, (program_counter *pc)); +_PROTOTYPE(void assign, (int c_code)); + +/* From util.c */ +_PROTOTYPE(char *strcopyof, (char *str)); +_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val, int is_var)); +_PROTOTYPE(char *arg_str, (arg_list *args)); +_PROTOTYPE(char *call_str, (arg_list *args)); +_PROTOTYPE(void free_args, (arg_list *args)); +_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos)); +_PROTOTYPE(void init_gen, (void)); +_PROTOTYPE(void generate, (char *str)); +_PROTOTYPE(void run_code, (void)); +_PROTOTYPE(void out_char, (int ch)); +_PROTOTYPE(void out_schar, (int ch)); +_PROTOTYPE(id_rec *find_id, (id_rec *tree, char *id)); +_PROTOTYPE(int insert_id_rec, (id_rec **root, id_rec *new_id)); +_PROTOTYPE(void init_tree, (void)); +_PROTOTYPE(int lookup, (char *name, int namekind)); +_PROTOTYPE(char *bc_malloc, (int)); +_PROTOTYPE(void out_of_memory, (void)); +_PROTOTYPE(void welcome, (void)); +_PROTOTYPE(void warranty, (char *)); +_PROTOTYPE(void show_bc_version, (void)); +_PROTOTYPE(void limits, (void)); +_PROTOTYPE(void yyerror, (char *str ,...)); +_PROTOTYPE(void warn, (char *mesg ,...)); +_PROTOTYPE(void rt_error, (char *mesg ,...)); +_PROTOTYPE(void rt_warn, (char *mesg ,...)); + +/* From load.c */ +_PROTOTYPE(void init_load, (void)); +_PROTOTYPE(void addbyte, (int byte)); +_PROTOTYPE(void def_label, (long lab)); +_PROTOTYPE(long long_val, (char **str)); +_PROTOTYPE(void load_code, (char *code)); + +/* From main.c */ +_PROTOTYPE(int open_new_file, (void)); +_PROTOTYPE(void new_yy_file, (FILE *file)); +_PROTOTYPE(void use_quit, (int)); + +/* From storage.c */ +_PROTOTYPE(void init_storage, (void)); +_PROTOTYPE(void more_functions, (void)); +_PROTOTYPE(void more_variables, (void)); +_PROTOTYPE(void more_arrays, (void)); +_PROTOTYPE(void clear_func, (int func )); +_PROTOTYPE(int fpop, (void)); +_PROTOTYPE(void fpush, (int val )); +_PROTOTYPE(void pop, (void)); +_PROTOTYPE(void push_copy, (bc_num num )); +_PROTOTYPE(void push_num, (bc_num num )); +_PROTOTYPE(char check_stack, (int depth )); +_PROTOTYPE(bc_var *get_var, (int var_name )); +_PROTOTYPE(bc_num *get_array_num, (int var_index, long index )); +_PROTOTYPE(void store_var, (int var_name )); +_PROTOTYPE(void store_array, (int var_name )); +_PROTOTYPE(void load_var, (int var_name )); +_PROTOTYPE(void load_array, (int var_name )); +_PROTOTYPE(void decr_var, (int var_name )); +_PROTOTYPE(void decr_array, (int var_name )); +_PROTOTYPE(void incr_var, (int var_name )); +_PROTOTYPE(void incr_array, (int var_name )); +_PROTOTYPE(void auto_var, (int name )); +_PROTOTYPE(void free_a_tree, (bc_array_node *root, int depth )); +_PROTOTYPE(void pop_vars, (arg_list *list )); +_PROTOTYPE(void process_params, (program_counter *pc, int func )); + +/* For the scanner and parser.... */ +_PROTOTYPE(int yyparse, (void)); +_PROTOTYPE(int yylex, (void)); + +#if defined(LIBEDIT) +/* The *?*&^ prompt function */ +_PROTOTYPE(char *null_prompt, (EditLine *)); +#endif + +/* Other things... */ +#ifndef HAVE_UNISTD_H +_PROTOTYPE (int getopt, (int, char *[], CONST char *)); +#endif diff --git a/bc/sbc.y b/bc/sbc.y new file mode 100644 index 0000000..b1ff1d1 --- /dev/null +++ b/bc/sbc.y @@ -0,0 +1,448 @@ +%{ +/* sbc.y: A POSIX bc processor written for minix with no extensions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" /* To get the global variables. */ +#include "proto.h" +%} + +%start program + +%union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } + +%token ENDOFLINE AND OR NOT +%token STRING NAME NUMBER +/* '-', '+' are tokens themselves */ +%token ASSIGN_OP +/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */ +%token REL_OP +/* '==', '<=', '>=', '!=', '<', '>' */ +%token INCR_DECR +/* '++', '--' */ +%token Define Break Quit Length +/* 'define', 'break', 'quit', 'length' */ +%token Return For If While Sqrt Else +/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */ +%token Scale Ibase Obase Auto Read +/* 'scale', 'ibase', 'obase', 'auto', 'read' */ +%token Warranty, Halt, Last, Continue, Print, Limits +/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */ + +/* The types of all other non-terminals. */ +%type expression named_expression return_expression +%type opt_parameter_list parameter_list opt_auto_define_list +%type define_list opt_argument_list argument_list +%type program input_item semicolon_list statement_list +%type statement_or_error statement function relational_expression + +/* precedence */ +%nonassoc REL_OP +%right ASSIGN_OP +%left '+' '-' +%left '*' '/' '%' +%right '^' +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%% +program : /* empty */ + { + $$ = 0; + std_only = TRUE; + if (interactive) + { + printf ("s%s\n", BC_VERSION); + welcome(); + } + } + | program input_item + ; +input_item : semicolon_list ENDOFLINE + { run_code(); } + | function + { run_code(); } + | error ENDOFLINE + { + yyerrok; + init_gen() ; + } + ; +semicolon_list : /* empty */ + { $$ = 0; } + | statement_or_error + | semicolon_list ';' statement_or_error + | semicolon_list ';' + ; +statement_list : /* empty */ + { $$ = 0; } + | statement + | statement_list ENDOFLINE + | statement_list ENDOFLINE statement + | statement_list ';' + | statement_list ';' statement + ; +statement_or_error : statement + | error statement + { $$ = $2; } + ; +statement : Warranty + { warranty("s"); } + | expression + { + if ($1 & 1) + generate ("W"); + else + generate ("p"); + } + | STRING + { + $$ = 0; + generate ("w"); + generate ($1); + free ($1); + } + | Break + { + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } + | Quit + { exit(0); } + | Return + { generate ("0R"); } + | Return '(' return_expression ')' + { generate ("R"); } + | For + { + $1 = break_label; + break_label = next_label++; + } + '(' expression ';' + { + $4 = next_label++; + sprintf (genstr, "pN%1d:", $4); + generate (genstr); + } + relational_expression ';' + { + $7 = next_label++; + sprintf (genstr, "B%1d:J%1d:", $7, break_label); + generate (genstr); + $$ = next_label++; + sprintf (genstr, "N%1d:", $$); + generate (genstr); + } + expression ')' + { + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } + statement + { + sprintf (genstr, "J%1d:N%1d:", $9, + break_label); + generate (genstr); + break_label = $1; + } + | If '(' relational_expression ')' + { + $3 = next_label++; + sprintf (genstr, "Z%1d:", $3); + generate (genstr); + } + statement + { + sprintf (genstr, "N%1d:", $3); + generate (genstr); + } + | While + { + $1 = next_label++; + sprintf (genstr, "N%1d:", $1); + generate (genstr); + } + '(' relational_expression + { + $4 = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } + ')' statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + break_label = $4; + } + | '{' statement_list '}' + { $$ = 0; } + ; +function : Define NAME '(' opt_parameter_list ')' '{' + ENDOFLINE opt_auto_define_list + { + check_params ($4,$8); + sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT), + arg_str ($4), arg_str ($8)); + generate (genstr); + free_args ($4); + free_args ($8); + $1 = next_label; + next_label = 0; + } + statement_list ENDOFLINE '}' + { + generate ("0R]"); + next_label = $1; + } + ; +opt_parameter_list : /* empty */ + { $$ = NULL; } + | parameter_list + ; +parameter_list : NAME + { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); } + ; +opt_auto_define_list : /* empty */ + { $$ = NULL; } + | Auto define_list ENDOFLINE + { $$ = $2; } + | Auto define_list ';' + { $$ = $2; } + ; +define_list : NAME + { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); } + | NAME '[' ']' + { $$ = nextarg (NULL, lookup($1,ARRAY), FALSE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); } + | define_list ',' NAME '[' ']' + { $$ = nextarg ($1, lookup($3,ARRAY), FALSE); } + ; +opt_argument_list : /* empty */ + { $$ = NULL; } + | argument_list + ; +argument_list : expression + { $$ = nextarg (NULL,0, FALSE); } + | argument_list ',' expression + { $$ = nextarg ($1,0, FALSE); } + ; +relational_expression : expression + { $$ = 0; } + | expression REL_OP expression + { + $$ = 0; + switch (*($2)) + { + case '=': + generate ("="); + break; + case '!': + generate ("#"); + break; + case '<': + if ($2[1] == '=') + generate ("{"); + else + generate ("<"); + break; + case '>': + if ($2[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } + ; +return_expression : /* empty */ + { + $$ = 0; + generate ("0"); + } + | expression + ; +expression : named_expression ASSIGN_OP + { + if ($2 != '=') + { + if ($1 < 0) + sprintf (genstr, "DL%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + } + expression + { + $$ = 0; + if ($2 != '=') + { + sprintf (genstr, "%c", $2); + generate (genstr); + } + if ($1 < 0) + sprintf (genstr, "S%d:", -$1); + else + sprintf (genstr, "s%d:", $1); + generate (genstr); + } + | expression '+' expression + { generate ("+"); } + | expression '-' expression + { generate ("-"); } + | expression '*' expression + { generate ("*"); } + | expression '/' expression + { generate ("/"); } + | expression '%' expression + { generate ("%"); } + | expression '^' expression + { generate ("^"); } + | '-' expression %prec UNARY_MINUS + { generate ("n"); $$ = 1;} + | named_expression + { + $$ = 1; + if ($1 < 0) + sprintf (genstr, "L%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + | NUMBER + { + int len = strlen($1); + $$ = 1; + if (len == 1 && *$1 == '0') + generate ("0"); + else + { + if (len == 1 && *$1 == '1') + generate ("1"); + else + { + generate ("K"); + generate ($1); + generate (":"); + } + free ($1); + } + } + | '(' expression ')' + { $$ = 1; } + | NAME '(' opt_argument_list ')' + { + $$ = 1; + if ($3 != NULL) + { + sprintf (genstr, "C%d,%s:", lookup($1,FUNCT), + arg_str ($3)); + free_args ($3); + } + else + sprintf (genstr, "C%d:", lookup($1,FUNCT)); + generate (genstr); + } + | INCR_DECR named_expression + { + $$ = 1; + if ($2 < 0) + { + if ($1 == '+') + sprintf (genstr, "DA%d:L%d:", -$2, -$2); + else + sprintf (genstr, "DM%d:L%d:", -$2, -$2); + } + else + { + if ($1 == '+') + sprintf (genstr, "i%d:l%d:", $2, $2); + else + sprintf (genstr, "d%d:l%d:", $2, $2); + } + generate (genstr); + } + | named_expression INCR_DECR + { + $$ = 1; + if ($1 < 0) + { + sprintf (genstr, "DL%d:x", -$1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "A%d:", -$1); + else + sprintf (genstr, "M%d:", -$1); + } + else + { + sprintf (genstr, "l%d:", $1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "i%d:", $1); + else + sprintf (genstr, "d%d:", $1); + } + generate (genstr); + } + | Length '(' expression ')' + { generate ("cL"); $$ = 1;} + | Sqrt '(' expression ')' + { generate ("cR"); $$ = 1;} + | Scale '(' expression ')' + { generate ("cS"); $$ = 1;} + ; +named_expression : NAME + { $$ = lookup($1,SIMPLE); } + | NAME '[' expression ']' + { $$ = lookup($1,ARRAY); } + | Ibase + { $$ = 0; } + | Obase + { $$ = 1; } + | Scale + { $$ = 2; } + ; + +%% diff --git a/bc/scan.c b/bc/scan.c new file mode 100644 index 0000000..8d9c92d --- /dev/null +++ b/bc/scan.c @@ -0,0 +1,2259 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 44 +#define YY_END_OF_BUFFER 45 +static yyconst short int yy_accept[298] = + { 0, + 0, 0, 2, 2, 45, 43, 38, 36, 30, 43, + 1, 31, 43, 27, 31, 27, 27, 26, 31, 42, + 34, 32, 34, 43, 27, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 43, 2, 2, 3, 2, 2, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 38, + 34, 0, 41, 32, 28, 35, 42, 0, 39, 42, + 42, 0, 33, 37, 40, 40, 40, 40, 40, 40, + + 40, 40, 40, 40, 10, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 29, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 42, 0, 0, 42, 0, + 40, 40, 40, 40, 40, 9, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + + 2, 2, 2, 2, 2, 2, 16, 40, 40, 40, + 17, 19, 40, 40, 20, 40, 40, 40, 40, 6, + 18, 40, 40, 12, 40, 40, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 40, 40, 40, + 14, 40, 40, 15, 24, 40, 13, 40, 11, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 40, 4, 40, 7, 25, 8, 40, 2, + 2, 2, 2, 2, 2, 2, 40, 21, 40, 2, + 2, 2, 23, 22, 2, 2, 0 + + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 7, 8, 1, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 1, 18, 19, + 20, 21, 1, 1, 22, 22, 22, 22, 22, 22, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 23, 24, 25, 26, 27, 1, 28, 29, 30, 31, + + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 37, 49, 37, + 50, 37, 51, 52, 53, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[54] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1 + } ; + +static yyconst short int yy_base[302] = + { 0, + 0, 0, 53, 0, 525, 526, 522, 526, 503, 517, + 526, 501, 512, 526, 499, 95, 94, 94, 99, 105, + 498, 114, 497, 513, 495, 466, 468, 470, 479, 471, + 467, 0, 81, 102, 105, 479, 462, 458, 473, 94, + 104, 452, 0, 501, 526, 482, 139, 0, 481, 492, + 0, 479, 131, 132, 131, 125, 132, 478, 150, 477, + 493, 475, 160, 115, 117, 126, 130, 125, 446, 183, + 184, 186, 187, 123, 445, 180, 185, 192, 440, 489, + 526, 485, 526, 526, 526, 526, 158, 486, 526, 162, + 221, 485, 526, 526, 0, 440, 454, 444, 451, 437, + + 437, 442, 434, 451, 0, 432, 436, 436, 447, 438, + 437, 195, 444, 426, 425, 433, 526, 0, 466, 0, + 178, 0, 0, 0, 0, 222, 464, 0, 230, 233, + 463, 0, 417, 65, 189, 208, 193, 205, 213, 220, + 214, 235, 416, 218, 224, 227, 241, 234, 237, 243, + 246, 231, 232, 245, 0, 275, 460, 278, 279, 459, + 419, 432, 412, 422, 425, 0, 409, 408, 408, 406, + 418, 415, 404, 408, 401, 416, 398, 406, 397, 398, + 403, 287, 438, 288, 437, 182, 250, 239, 270, 275, + 391, 266, 268, 271, 273, 274, 288, 279, 285, 281, + + 299, 390, 292, 287, 293, 298, 0, 399, 400, 394, + 0, 0, 392, 401, 0, 385, 384, 398, 382, 0, + 0, 383, 395, 0, 398, 393, 376, 294, 303, 302, + 375, 374, 306, 312, 373, 305, 308, 313, 310, 372, + 371, 314, 317, 370, 335, 332, 0, 376, 384, 370, + 0, 379, 367, 0, 0, 371, 0, 370, 0, 362, + 325, 336, 322, 361, 137, 323, 360, 359, 331, 358, + 333, 357, 356, 0, 353, 0, 0, 0, 355, 349, + 343, 327, 342, 340, 334, 338, 346, 0, 238, 344, + 236, 339, 0, 0, 177, 102, 526, 392, 120, 395, + + 398 + } ; + +static yyconst short int yy_def[302] = + { 0, + 297, 1, 297, 3, 297, 297, 297, 297, 297, 298, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 297, 300, 300, 297, 300, 301, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 300, 297, + 297, 298, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 299, 299, 299, 299, 299, 299, + + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 297, 300, 300, 300, + 301, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 300, 297, 297, 297, 297, 297, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 300, 300, 300, 300, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 63, 63, 63, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 299, 299, 299, 299, 299, 299, 299, 63, + 63, 63, 63, 63, 63, 63, 299, 299, 299, 63, + 63, 63, 299, 299, 63, 63, 0, 297, 297, 297, + + 297 + } ; + +static yyconst short int yy_nxt[580] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 15, 16, 14, 17, 18, 19, 20, 14, 21, 22, + 23, 20, 14, 24, 14, 25, 6, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 32, 32, 35, 32, + 32, 36, 37, 38, 39, 40, 32, 32, 41, 32, + 14, 42, 14, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 51, 52, 53, 51, 54, 55, 56, 57, + 51, 58, 59, 60, 57, 51, 61, 51, 62, 43, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 69, + 69, 72, 69, 69, 73, 74, 75, 76, 77, 69, + + 69, 78, 69, 51, 79, 51, 86, 86, 102, 89, + 87, 186, 133, 84, 84, 87, 103, 88, 84, 90, + 93, 91, 95, 113, 93, 93, 91, 93, 92, 93, + 104, 115, 106, 81, 105, 128, 107, 114, 116, 93, + 108, 82, 125, 122, 123, 125, 129, 126, 130, 133, + 123, 123, 126, 130, 127, 131, 132, 137, 136, 135, + 132, 132, 133, 132, 133, 132, 139, 148, 138, 120, + 133, 283, 133, 133, 156, 132, 133, 133, 159, 156, + 82, 157, 122, 159, 133, 160, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + + 133, 133, 133, 133, 133, 133, 133, 134, 133, 133, + 140, 150, 142, 144, 151, 147, 143, 145, 141, 153, + 187, 146, 176, 227, 133, 189, 154, 133, 152, 133, + 133, 133, 133, 133, 133, 90, 133, 91, 182, 133, + 133, 177, 91, 182, 92, 183, 184, 129, 188, 130, + 190, 184, 133, 185, 130, 133, 131, 191, 192, 193, + 133, 133, 194, 195, 196, 133, 197, 133, 198, 199, + 201, 133, 200, 203, 133, 204, 205, 228, 133, 133, + 206, 133, 133, 133, 133, 229, 133, 294, 133, 202, + 133, 156, 133, 133, 87, 159, 156, 133, 157, 87, + + 159, 88, 160, 182, 184, 230, 231, 236, 182, 184, + 183, 185, 232, 133, 233, 133, 234, 133, 133, 235, + 133, 133, 133, 237, 238, 239, 133, 240, 133, 241, + 243, 260, 133, 244, 133, 133, 246, 245, 261, 133, + 133, 133, 262, 264, 267, 133, 133, 263, 270, 133, + 133, 265, 133, 133, 266, 133, 268, 133, 269, 133, + 133, 133, 271, 272, 133, 280, 282, 281, 284, 133, + 133, 285, 133, 286, 133, 295, 291, 293, 133, 133, + 133, 133, 133, 133, 292, 133, 133, 133, 296, 133, + 133, 133, 82, 82, 82, 118, 290, 118, 121, 121, + + 121, 289, 288, 287, 133, 133, 133, 133, 133, 133, + 279, 278, 277, 276, 275, 274, 273, 133, 133, 133, + 133, 133, 133, 133, 259, 258, 257, 256, 255, 254, + 253, 252, 251, 250, 249, 248, 247, 242, 133, 159, + 156, 226, 225, 224, 223, 222, 221, 220, 219, 218, + 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, + 207, 159, 156, 133, 133, 91, 158, 119, 181, 180, + 179, 178, 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 91, 158, 83, + 80, 155, 149, 133, 123, 94, 120, 120, 123, 124, + + 123, 120, 119, 117, 112, 111, 110, 109, 101, 100, + 99, 98, 97, 96, 84, 94, 81, 81, 84, 85, + 84, 83, 81, 80, 297, 5, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297 + } ; + +static yyconst short int yy_chk[580] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 16, 17, 33, 19, + 18, 134, 134, 17, 16, 18, 33, 18, 19, 20, + 22, 20, 299, 40, 22, 22, 20, 22, 20, 22, + 34, 41, 35, 22, 34, 56, 35, 40, 41, 22, + 35, 47, 53, 47, 56, 54, 57, 55, 57, 296, + 53, 54, 55, 57, 55, 57, 59, 66, 65, 64, + 59, 59, 64, 59, 65, 59, 68, 74, 67, 59, + 74, 265, 68, 66, 87, 59, 63, 67, 90, 87, + 121, 87, 121, 90, 265, 90, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 70, 76, 71, 72, 77, 73, 71, 72, 70, 78, + 135, 72, 112, 186, 295, 137, 78, 76, 77, 186, + 70, 71, 77, 72, 73, 91, 135, 91, 126, 78, + 137, 112, 91, 126, 91, 126, 129, 130, 136, 130, + 138, 129, 138, 129, 130, 136, 130, 139, 140, 141, + 139, 141, 142, 144, 145, 144, 146, 140, 147, 148, + 150, 145, 149, 151, 146, 152, 153, 187, 152, 153, + 154, 148, 142, 291, 149, 188, 188, 289, 147, 150, + 150, 156, 154, 151, 158, 159, 156, 187, 156, 158, + + 159, 158, 159, 182, 184, 189, 190, 196, 182, 184, + 182, 184, 192, 192, 193, 193, 194, 189, 194, 195, + 195, 196, 190, 197, 198, 199, 198, 200, 200, 201, + 203, 228, 199, 204, 204, 197, 206, 205, 229, 203, + 205, 228, 230, 234, 238, 206, 201, 233, 243, 230, + 229, 236, 236, 233, 237, 237, 239, 239, 242, 234, + 238, 242, 245, 246, 243, 261, 263, 262, 266, 263, + 266, 269, 261, 271, 282, 290, 282, 287, 269, 246, + 271, 285, 245, 262, 286, 286, 292, 284, 292, 283, + 281, 290, 298, 298, 298, 300, 280, 300, 301, 301, + + 301, 279, 275, 273, 272, 270, 268, 267, 264, 260, + 258, 256, 253, 252, 250, 249, 248, 244, 241, 240, + 235, 232, 231, 227, 226, 225, 223, 222, 219, 218, + 217, 216, 214, 213, 210, 209, 208, 202, 191, 185, + 183, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 172, 171, 170, 169, 168, 167, 165, 164, 163, 162, + 161, 160, 157, 143, 133, 131, 127, 119, 116, 115, + 114, 113, 111, 110, 109, 108, 107, 106, 104, 103, + 102, 101, 100, 99, 98, 97, 96, 92, 88, 82, + 80, 79, 75, 69, 62, 61, 60, 58, 52, 50, + + 49, 46, 44, 42, 39, 38, 37, 36, 31, 30, + 29, 28, 27, 26, 25, 24, 23, 21, 15, 13, + 12, 10, 9, 7, 5, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "scan.l" +#define INITIAL 0 +#line 2 "scan.l" +/* scan.l: the (f)lex description file for the scanner. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "bc.h" +#include "global.h" +#include "proto.h" +#include + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* Force . as last for now. */ +#define DOT_IS_LAST + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +#if defined(LIBEDIT) +/* Support for the BSD libedit with history for + nicer input on the interactive part of input. */ + +#include + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + bcel_input((char *)buf, &result, max_size) + +/* Variables to help interface editline with bc. */ +static const char *bcel_line = (char *)NULL; +static int bcel_len = 0; + + +/* Required to get rid of that ugly ? default prompt! */ +char * +null_prompt (EditLine *el) +{ + return ""; +} + + +/* bcel_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + stdin, use editline. Otherwise, just read it. +*/ + +static void +bcel_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (!edit || yyin != stdin) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (bcel_len == 0) + { + bcel_line = el_gets(edit, &bcel_len); + if (bcel_line == NULL) { + /* end of file */ + *result = 0; + bcel_len = 0; + return; + } + if (bcel_len != 0) + history (hist, &histev, H_ENTER, bcel_line); + fflush (stdout); + } + + if (bcel_len <= max) + { + strncpy (buf, bcel_line, bcel_len); + *result = bcel_len; + bcel_len = 0; + } + else + { + strncpy (buf, bcel_line, max); + *result = max; + bcel_line += max; + bcel_len -= max; + } +} +#endif + +#ifdef READLINE +/* Support for the readline and history libraries. This allows + nicer input on the interactive part of input. */ + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + rl_input((char *)buf, &result, max_size) + +/* Variables to help interface readline with bc. */ +static char *rl_line = (char *)NULL; +static char *rl_start = (char *)NULL; +static int rl_len = 0; + +/* Definitions for readline access. */ +extern FILE *rl_instream; +_PROTOTYPE(char *readline, (char *)); + +/* rl_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + rl_instream (stdin), use readline. Otherwise, just read it. +*/ + +static void +rl_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (yyin != rl_instream) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (rl_len == 0) + { + if (rl_start) + free(rl_start); + rl_start = readline (""); + if (rl_start == NULL) { + /* end of file */ + *result = 0; + rl_len = 0; + return; + } + rl_line = rl_start; + rl_len = strlen (rl_line)+1; + if (rl_len != 1) + add_history (rl_line); + rl_line[rl_len-1] = '\n'; + fflush (stdout); + } + + if (rl_len <= max) + { + strncpy (buf, rl_line, rl_len); + *result = rl_len; + rl_len = 0; + } + else + { + strncpy (buf, rl_line, max); + *result = max; + rl_line += max; + rl_len -= max; + } +} +#endif + +#if !defined(READLINE) && !defined(LIBEDIT) + +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#endif + +#define slcomment 1 + +#line 809 "lex.yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 222 "scan.l" + +#line 962 "lex.yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 526 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 223 "scan.l" +{ + if (!std_only) + BEGIN(slcomment); + else + yyerror ("illegal character: #"); + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 229 "scan.l" +{ BEGIN(INITIAL); } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 230 "scan.l" +{ line_no++; BEGIN(INITIAL); return(ENDOFLINE); } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 231 "scan.l" +return(Define); + YY_BREAK +case 5: +YY_RULE_SETUP +#line 232 "scan.l" +return(Break); + YY_BREAK +case 6: +YY_RULE_SETUP +#line 233 "scan.l" +return(Quit); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 234 "scan.l" +return(Length); + YY_BREAK +case 8: +YY_RULE_SETUP +#line 235 "scan.l" +return(Return); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 236 "scan.l" +return(For); + YY_BREAK +case 10: +YY_RULE_SETUP +#line 237 "scan.l" +return(If); + YY_BREAK +case 11: +YY_RULE_SETUP +#line 238 "scan.l" +return(While); + YY_BREAK +case 12: +YY_RULE_SETUP +#line 239 "scan.l" +return(Sqrt); + YY_BREAK +case 13: +YY_RULE_SETUP +#line 240 "scan.l" +return(Scale); + YY_BREAK +case 14: +YY_RULE_SETUP +#line 241 "scan.l" +return(Ibase); + YY_BREAK +case 15: +YY_RULE_SETUP +#line 242 "scan.l" +return(Obase); + YY_BREAK +case 16: +YY_RULE_SETUP +#line 243 "scan.l" +return(Auto); + YY_BREAK +case 17: +YY_RULE_SETUP +#line 244 "scan.l" +return(Else); + YY_BREAK +case 18: +YY_RULE_SETUP +#line 245 "scan.l" +return(Read); + YY_BREAK +case 19: +YY_RULE_SETUP +#line 246 "scan.l" +return(Halt); + YY_BREAK +case 20: +YY_RULE_SETUP +#line 247 "scan.l" +return(Last); + YY_BREAK +case 21: +YY_RULE_SETUP +#line 248 "scan.l" +{ +#if defined(READLINE) || defined(LIBEDIT) + return(HistoryVar); +#else + yylval.s_value = strcopyof(yytext); return(NAME); +#endif + } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 256 "scan.l" +return(Warranty); + YY_BREAK +case 23: +YY_RULE_SETUP +#line 257 "scan.l" +return(Continue); + YY_BREAK +case 24: +YY_RULE_SETUP +#line 258 "scan.l" +return(Print); + YY_BREAK +case 25: +YY_RULE_SETUP +#line 259 "scan.l" +return(Limits); + YY_BREAK +case 26: +YY_RULE_SETUP +#line 260 "scan.l" +{ +#ifdef DOT_IS_LAST + return(Last); +#else + yyerror ("illegal character: %s",yytext); +#endif + } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 267 "scan.l" +{ yylval.c_value = yytext[0]; + return((int)yytext[0]); } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 269 "scan.l" +{ return(AND); } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 270 "scan.l" +{ return(OR); } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 271 "scan.l" +{ return(NOT); } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 272 "scan.l" +{ yylval.c_value = yytext[0]; return((int)yytext[0]); } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 273 "scan.l" +{ yylval.c_value = yytext[0]; return(ASSIGN_OP); } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 274 "scan.l" +{ +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned ="); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 288 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(REL_OP); } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 289 "scan.l" +{ yylval.c_value = yytext[0]; return(INCR_DECR); } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 290 "scan.l" +{ line_no++; return(ENDOFLINE); } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 291 "scan.l" +{ line_no++; /* ignore a "quoted" newline */ } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 292 "scan.l" +{ /* ignore spaces and tabs */ } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 293 "scan.l" +{ + int c; + + for (;;) + { + while ( ((c=input()) != '*') && (c != EOF)) + /* eat it */ + if (c == '\n') line_no++; + if (c == '*') + { + while ( (c=input()) == '*') /* eat it*/; + if (c == '/') break; /* at end of comment */ + if (c == '\n') line_no++; + } + if (c == EOF) + { + fprintf (stderr,"EOF encountered in a comment.\n"); + break; + } + } + } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 314 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(NAME); } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 315 "scan.l" +{ + unsigned char *look; + int count = 0; + yylval.s_value = strcopyof(yytext); + for (look = yytext; *look != 0; look++) + { + if (*look == '\n') line_no++; + if (*look == '"') count++; + } + if (count != 2) yyerror ("NUL character in string."); + return(STRING); + } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 327 "scan.l" +{ + unsigned char *src, *dst; + int len; + /* remove a trailing decimal point. */ + len = strlen(yytext); + if (yytext[len-1] == '.') + yytext[len-1] = 0; + /* remove leading zeros. */ + src = yytext; + dst = yytext; + while (*src == '0') src++; + if (*src == 0) src--; + /* Copy strings removing the newlines. */ + while (*src != 0) + { + if (*src == '\\') + { + src++; src++; + line_no++; + } + else + *dst++ = *src++; + } + *dst = 0; + yylval.s_value = strcopyof(yytext); + return(NUMBER); + } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 354 "scan.l" +{ + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%03o", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 363 "scan.l" +ECHO; + YY_BREAK +#line 1361 "lex.yy.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(slcomment): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 297); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 363 "scan.l" + + + + +/* This is the way to get multiple files input into lex. */ + +int +yywrap() +{ + if (!open_new_file ()) return (1); /* EOF on standard in. */ + return (0); /* We have more input. */ +} diff --git a/bc/scan.l b/bc/scan.l new file mode 100644 index 0000000..b4addaa --- /dev/null +++ b/bc/scan.l @@ -0,0 +1,374 @@ +%{ +/* scan.l: the (f)lex description file for the scanner. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "bc.h" +#include "global.h" +#include "proto.h" +#include + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* Force . as last for now. */ +#define DOT_IS_LAST + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +#if defined(LIBEDIT) +/* Support for the BSD libedit with history for + nicer input on the interactive part of input. */ + +#include + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + bcel_input((char *)buf, &result, max_size) + +/* Variables to help interface editline with bc. */ +static const char *bcel_line = (char *)NULL; +static int bcel_len = 0; + + +/* Required to get rid of that ugly ? default prompt! */ +char * +null_prompt (EditLine *el) +{ + return ""; +} + + +/* bcel_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + stdin, use editline. Otherwise, just read it. +*/ + +static void +bcel_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (!edit || yyin != stdin) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (bcel_len == 0) + { + bcel_line = el_gets(edit, &bcel_len); + if (bcel_line == NULL) { + /* end of file */ + *result = 0; + bcel_len = 0; + return; + } + if (bcel_len != 0) + history (hist, &histev, H_ENTER, bcel_line); + fflush (stdout); + } + + if (bcel_len <= max) + { + strncpy (buf, bcel_line, bcel_len); + *result = bcel_len; + bcel_len = 0; + } + else + { + strncpy (buf, bcel_line, max); + *result = max; + bcel_line += max; + bcel_len -= max; + } +} +#endif + +#ifdef READLINE +/* Support for the readline and history libraries. This allows + nicer input on the interactive part of input. */ + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + rl_input((char *)buf, &result, max_size) + +/* Variables to help interface readline with bc. */ +static char *rl_line = (char *)NULL; +static char *rl_start = (char *)NULL; +static int rl_len = 0; + +/* Definitions for readline access. */ +extern FILE *rl_instream; +_PROTOTYPE(char *readline, (char *)); + +/* rl_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + rl_instream (stdin), use readline. Otherwise, just read it. +*/ + +static void +rl_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (yyin != rl_instream) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (rl_len == 0) + { + if (rl_start) + free(rl_start); + rl_start = readline (""); + if (rl_start == NULL) { + /* end of file */ + *result = 0; + rl_len = 0; + return; + } + rl_line = rl_start; + rl_len = strlen (rl_line)+1; + if (rl_len != 1) + add_history (rl_line); + rl_line[rl_len-1] = '\n'; + fflush (stdout); + } + + if (rl_len <= max) + { + strncpy (buf, rl_line, rl_len); + *result = rl_len; + rl_len = 0; + } + else + { + strncpy (buf, rl_line, max); + *result = max; + rl_line += max; + rl_len -= max; + } +} +#endif + +#if !defined(READLINE) && !defined(LIBEDIT) + +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#endif + +%} +DIGIT [0-9A-F] +LETTER [a-z] +%s slcomment +%% +"#" { + if (!std_only) + BEGIN(slcomment); + else + yyerror ("illegal character: #"); + } +[^\n]* { BEGIN(INITIAL); } +"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); } +define return(Define); +break return(Break); +quit return(Quit); +length return(Length); +return return(Return); +for return(For); +if return(If); +while return(While); +sqrt return(Sqrt); +scale return(Scale); +ibase return(Ibase); +obase return(Obase); +auto return(Auto); +else return(Else); +read return(Read); +halt return(Halt); +last return(Last); +history { +#if defined(READLINE) || defined(LIBEDIT) + return(HistoryVar); +#else + yylval.s_value = strcopyof(yytext); return(NAME); +#endif + } + +warranty return(Warranty); +continue return(Continue); +print return(Print); +limits return(Limits); +"." { +#ifdef DOT_IS_LAST + return(Last); +#else + yyerror ("illegal character: %s",yytext); +#endif + } +"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; + return((int)yytext[0]); } +&& { return(AND); } +\|\| { return(OR); } +"!" { return(NOT); } +"*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); } +"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); } +=\+|=-|=\*|=\/|=%|=\^ { +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned ="); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } +==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); } +\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); } +"\n" { line_no++; return(ENDOFLINE); } +\\\n { line_no++; /* ignore a "quoted" newline */ } +[ \t]+ { /* ignore spaces and tabs */ } +"/*" { + int c; + + for (;;) + { + while ( ((c=input()) != '*') && (c != EOF)) + /* eat it */ + if (c == '\n') line_no++; + if (c == '*') + { + while ( (c=input()) == '*') /* eat it*/; + if (c == '/') break; /* at end of comment */ + if (c == '\n') line_no++; + } + if (c == EOF) + { + fprintf (stderr,"EOF encountered in a comment.\n"); + break; + } + } + } +[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); } +\"[^\"]*\" { + unsigned char *look; + int count = 0; + yylval.s_value = strcopyof(yytext); + for (look = yytext; *look != 0; look++) + { + if (*look == '\n') line_no++; + if (*look == '"') count++; + } + if (count != 2) yyerror ("NUL character in string."); + return(STRING); + } +{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* { + unsigned char *src, *dst; + int len; + /* remove a trailing decimal point. */ + len = strlen(yytext); + if (yytext[len-1] == '.') + yytext[len-1] = 0; + /* remove leading zeros. */ + src = yytext; + dst = yytext; + while (*src == '0') src++; + if (*src == 0) src--; + /* Copy strings removing the newlines. */ + while (*src != 0) + { + if (*src == '\\') + { + src++; src++; + line_no++; + } + else + *dst++ = *src++; + } + *dst = 0; + yylval.s_value = strcopyof(yytext); + return(NUMBER); + } +. { + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%03o", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } +%% + + + +/* This is the way to get multiple files input into lex. */ + +int +yywrap() +{ + if (!open_new_file ()) return (1); /* EOF on standard in. */ + return (0); /* We have more input. */ +} diff --git a/bc/storage.c b/bc/storage.c new file mode 100644 index 0000000..10ebf5c --- /dev/null +++ b/bc/storage.c @@ -0,0 +1,1067 @@ +/* storage.c: Code and data storage manipulations. This includes labels. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" + + +/* Initialize the storage at the beginning of the run. */ + +void +init_storage () +{ + + /* Functions: we start with none and ask for more. */ + f_count = 0; + more_functions (); + f_names[0] = "(main)"; + + /* Variables. */ + v_count = 0; + more_variables (); + + /* Arrays. */ + a_count = 0; + more_arrays (); + + /* Other things... */ + ex_stack = NULL; + fn_stack = NULL; + i_base = 10; + o_base = 10; + scale = 0; +#if defined(READLINE) || defined(LIBEDIT) + n_history = -1; +#endif + c_code = FALSE; + bc_init_numbers(); +} + +/* Three functions for increasing the number of functions, variables, or + arrays that are needed. This adds another 32 of the requested object. */ + +void +more_functions (VOID) +{ + int old_count; + int indx; + bc_function *old_f; + bc_function *f; + char **old_names; + + /* Save old information. */ + old_count = f_count; + old_f = functions; + old_names = f_names; + + /* Add a fixed amount and allocate new space. */ + f_count += STORE_INCR; + functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function)); + f_names = (char **) bc_malloc (f_count*sizeof (char *)); + + /* Copy old ones. */ + for (indx = 0; indx < old_count; indx++) + { + functions[indx] = old_f[indx]; + f_names[indx] = old_names[indx]; + } + + /* Initialize the new ones. */ + for (; indx < f_count; indx++) + { + f = &functions[indx]; + f->f_defined = FALSE; + f->f_body = (char *) bc_malloc (BC_START_SIZE); + f->f_body_size = BC_START_SIZE; + f->f_code_size = 0; + f->f_label = NULL; + f->f_autos = NULL; + f->f_params = NULL; + } + + /* Free the old elements. */ + if (old_count != 0) + { + free (old_f); + free (old_names); + } +} + +void +more_variables () +{ + int indx; + int old_count; + bc_var **old_var; + char **old_names; + + /* Save the old values. */ + old_count = v_count; + old_var = variables; + old_names = v_names; + + /* Increment by a fixed amount and allocate. */ + v_count += STORE_INCR; + variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *)); + v_names = (char **) bc_malloc (v_count*sizeof(char *)); + + /* Copy the old variables. */ + for (indx = 3; indx < old_count; indx++) + variables[indx] = old_var[indx]; + + /* Initialize the new elements. */ + for (; indx < v_count; indx++) + variables[indx] = NULL; + + /* Free the old elements. */ + if (old_count != 0) + { + free (old_var); + free (old_names); + } +} + +void +more_arrays () +{ + int indx; + int old_count; + bc_var_array **old_ary; + char **old_names; + + /* Save the old values. */ + old_count = a_count; + old_ary = arrays; + old_names = a_names; + + /* Increment by a fixed amount and allocate. */ + a_count += STORE_INCR; + arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *)); + a_names = (char **) bc_malloc (a_count*sizeof(char *)); + + /* Copy the old arrays. */ + for (indx = 1; indx < old_count; indx++) + arrays[indx] = old_ary[indx]; + + + /* Initialize the new elements. */ + for (; indx < v_count; indx++) + arrays[indx] = NULL; + + /* Free the old elements. */ + if (old_count != 0) + { + free (old_ary); + free (old_names); + } +} + + +/* clear_func clears out function FUNC and makes it ready to redefine. */ + +void +clear_func (func) + int func; +{ + bc_function *f; + bc_label_group *lg; + + /* Set the pointer to the function. */ + f = &functions[func]; + f->f_defined = FALSE; + /* XXX restore f_body to initial size??? */ + f->f_code_size = 0; + if (f->f_autos != NULL) + { + free_args (f->f_autos); + f->f_autos = NULL; + } + if (f->f_params != NULL) + { + free_args (f->f_params); + f->f_params = NULL; + } + while (f->f_label != NULL) + { + lg = f->f_label->l_next; + free (f->f_label); + f->f_label = lg; + } +} + + +/* Pop the function execution stack and return the top. */ + +int +fpop() +{ + fstack_rec *temp; + int retval; + + if (fn_stack != NULL) + { + temp = fn_stack; + fn_stack = temp->s_next; + retval = temp->s_val; + free (temp); + } + else + { + retval = 0; + rt_error ("function stack underflow, contact maintainer."); + } + return (retval); +} + + +/* Push VAL on to the function stack. */ + +void +fpush (val) + int val; +{ + fstack_rec *temp; + + temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec)); + temp->s_next = fn_stack; + temp->s_val = val; + fn_stack = temp; +} + + +/* Pop and discard the top element of the regular execution stack. */ + +void +pop () +{ + estack_rec *temp; + + if (ex_stack != NULL) + { + temp = ex_stack; + ex_stack = temp->s_next; + bc_free_num (&temp->s_num); + free (temp); + } +} + + +/* Push a copy of NUM on to the regular execution stack. */ + +void +push_copy (num) + bc_num num; +{ + estack_rec *temp; + + temp = (estack_rec *) bc_malloc (sizeof (estack_rec)); + temp->s_num = bc_copy_num (num); + temp->s_next = ex_stack; + ex_stack = temp; +} + + +/* Push NUM on to the regular execution stack. Do NOT push a copy. */ + +void +push_num (num) + bc_num num; +{ + estack_rec *temp; + + temp = (estack_rec *) bc_malloc (sizeof (estack_rec)); + temp->s_num = num; + temp->s_next = ex_stack; + ex_stack = temp; +} + + +/* Make sure the ex_stack has at least DEPTH elements on it. + Return TRUE if it has at least DEPTH elements, otherwise + return FALSE. */ + +char +check_stack (depth) + int depth; +{ + estack_rec *temp; + + temp = ex_stack; + while ((temp != NULL) && (depth > 0)) + { + temp = temp->s_next; + depth--; + } + if (depth > 0) + { + rt_error ("Stack error."); + return FALSE; + } + return TRUE; +} + + +/* The following routines manipulate simple variables and + array variables. */ + +/* get_var returns a pointer to the variable VAR_NAME. If one does not + exist, one is created. */ + +bc_var * +get_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + var_ptr = variables[var_name]; + if (var_ptr == NULL) + { + var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var)); + bc_init_num (&var_ptr->v_value); + } + return var_ptr; +} + + +/* get_array_num returns the address of the bc_num in the array + structure. If more structure is requried to get to the index, + this routine does the work to create that structure. VAR_INDEX + is a zero based index into the arrays storage array. INDEX is + the index into the bc array. */ + +bc_num * +get_array_num (var_index, index) + int var_index; + long index; +{ + bc_var_array *ary_ptr; + bc_array *a_var; + bc_array_node *temp; + int log, ix, ix1; + int sub [NODE_DEPTH]; + + /* Get the array entry. */ + ary_ptr = arrays[var_index]; + if (ary_ptr == NULL) + { + ary_ptr = arrays[var_index] = + (bc_var_array *) bc_malloc (sizeof (bc_var_array)); + ary_ptr->a_value = NULL; + ary_ptr->a_next = NULL; + ary_ptr->a_param = FALSE; + } + + a_var = ary_ptr->a_value; + if (a_var == NULL) { + a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array)); + a_var->a_tree = NULL; + a_var->a_depth = 0; + } + + /* Get the index variable. */ + sub[0] = index & NODE_MASK; + ix = index >> NODE_SHIFT; + log = 1; + while (ix > 0 || log < a_var->a_depth) + { + sub[log] = ix & NODE_MASK; + ix >>= NODE_SHIFT; + log++; + } + + /* Build any tree that is necessary. */ + while (log > a_var->a_depth) + { + temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + if (a_var->a_depth != 0) + { + temp->n_items.n_down[0] = a_var->a_tree; + for (ix=1; ix < NODE_SIZE; ix++) + temp->n_items.n_down[ix] = NULL; + } + else + { + for (ix=0; ix < NODE_SIZE; ix++) + temp->n_items.n_num[ix] = bc_copy_num(_zero_); + } + a_var->a_tree = temp; + a_var->a_depth++; + } + + /* Find the indexed variable. */ + temp = a_var->a_tree; + while ( log-- > 1) + { + ix1 = sub[log]; + if (temp->n_items.n_down[ix1] == NULL) + { + temp->n_items.n_down[ix1] = + (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + temp = temp->n_items.n_down[ix1]; + if (log > 1) + for (ix=0; ix < NODE_SIZE; ix++) + temp->n_items.n_down[ix] = NULL; + else + for (ix=0; ix < NODE_SIZE; ix++) + temp->n_items.n_num[ix] = bc_copy_num(_zero_); + } + else + temp = temp->n_items.n_down[ix1]; + } + + /* Return the address of the indexed variable. */ + return &(temp->n_items.n_num[sub[0]]); +} + + +/* Store the top of the execution stack into VAR_NAME. + This includes the special variables ibase, obase, and scale. */ + +void +store_var (var_name) + int var_name; +{ + bc_var *var_ptr; + long temp; + char toobig; + + if (var_name > 3) + { + /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + { + bc_free_num(&var_ptr->v_value); + var_ptr->v_value = bc_copy_num (ex_stack->s_num); + } + } + else + { + /* It is a special variable... */ + toobig = FALSE; + temp = 0; + if (bc_is_neg (ex_stack->s_num)) + { + switch (var_name) + { + case 0: + rt_warn ("negative ibase, set to 2"); + temp = 2; + break; + case 1: + rt_warn ("negative obase, set to 2"); + temp = 2; + break; + case 2: + rt_warn ("negative scale, set to 0"); + temp = 0; + break; +#if defined(READLINE) || defined(LIBEDIT) + case 3: + temp = -1; + break; +#endif + } + } + else + { + temp = bc_num2long (ex_stack->s_num); + if (!bc_is_zero (ex_stack->s_num) && temp == 0) + toobig = TRUE; + } + switch (var_name) + { + case 0: + if (temp < 2 && !toobig) + { + i_base = 2; + rt_warn ("ibase too small, set to 2"); + } + else + if (temp > 16 || toobig) + { + i_base = 16; + rt_warn ("ibase too large, set to 16"); + } + else + i_base = (int) temp; + break; + + case 1: + if (temp < 2 && !toobig) + { + o_base = 2; + rt_warn ("obase too small, set to 2"); + } + else + if (temp > BC_BASE_MAX || toobig) + { + o_base = BC_BASE_MAX; + rt_warn ("obase too large, set to %d", BC_BASE_MAX); + } + else + o_base = (int) temp; + break; + + case 2: + /* WARNING: The following if statement may generate a compiler + warning if INT_MAX == LONG_MAX. This is NOT a problem. */ + if (temp > BC_SCALE_MAX || toobig ) + { + scale = BC_SCALE_MAX; + rt_warn ("scale too large, set to %d", BC_SCALE_MAX); + } + else + scale = (int) temp; + break; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: + if (toobig) + { + temp = -1; + rt_warn ("history too large, set to unlimited"); + UNLIMIT_HISTORY; + } + else + { + n_history = temp; + if (temp < 0) + UNLIMIT_HISTORY; + else + HISTORY_SIZE(n_history); + } +#endif + } + } +} + + +/* Store the top of the execution stack into array VAR_NAME. + VAR_NAME is the name of an array, and the next to the top + of stack for the index into the array. */ + +void +store_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + if (!check_stack(2)) return; + index = bc_num2long (ex_stack->s_next->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_is_zero(ex_stack->s_next->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + bc_free_num (num_ptr); + *num_ptr = bc_copy_num (ex_stack->s_num); + bc_free_num (&ex_stack->s_next->s_num); + ex_stack->s_next->s_num = ex_stack->s_num; + bc_init_num (&ex_stack->s_num); + pop(); + } + } +} + + +/* Load a copy of VAR_NAME on to the execution stack. This includes + the special variables ibase, obase and scale. */ + +void +load_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + switch (var_name) + { + + case 0: + /* Special variable ibase. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, i_base); + break; + + case 1: + /* Special variable obase. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, o_base); + break; + + case 2: + /* Special variable scale. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, scale); + break; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: + /* Special variable history. */ + push_copy (_zero_); + bc_int2num (&ex_stack->s_num, n_history); + break; +#endif + + default: + /* It is a simple variable. */ + var_ptr = variables[var_name]; + if (var_ptr != NULL) + push_copy (var_ptr->v_value); + else + push_copy (_zero_); + } +} + + +/* Load a copy of VAR_NAME on to the execution stack. This includes + the special variables ibase, obase and scale. */ + +void +load_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + if (!check_stack(1)) return; + index = bc_num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_is_zero(ex_stack->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + pop(); + push_copy (*num_ptr); + } + } +} + + +/* Decrement VAR_NAME by one. This includes the special variables + ibase, obase, and scale. */ + +void +decr_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + switch (var_name) + { + + case 0: /* ibase */ + if (i_base > 2) + i_base--; + else + rt_warn ("ibase too small in --"); + break; + + case 1: /* obase */ + if (o_base > 2) + o_base--; + else + rt_warn ("obase too small in --"); + break; + + case 2: /* scale */ + if (scale > 0) + scale--; + else + rt_warn ("scale can not be negative in -- "); + break; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: /* history */ + n_history--; + if (n_history >= 0) + HISTORY_SIZE(n_history); + else + { + n_history = -1; + rt_warn ("history is negative, set to unlimited"); + UNLIMIT_HISTORY; + } +#endif + + default: /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value, 0); + } +} + + +/* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of + the execution stack is the index and it is popped off the stack. */ + +void +decr_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + /* It is an array variable. */ + if (!check_stack (1)) return; + index = bc_num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_is_zero (ex_stack->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + pop (); + bc_sub (*num_ptr, _one_, num_ptr, 0); + } + } +} + + +/* Increment VAR_NAME by one. This includes the special variables + ibase, obase, and scale. */ + +void +incr_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + switch (var_name) + { + + case 0: /* ibase */ + if (i_base < 16) + i_base++; + else + rt_warn ("ibase too big in ++"); + break; + + case 1: /* obase */ + if (o_base < BC_BASE_MAX) + o_base++; + else + rt_warn ("obase too big in ++"); + break; + + case 2: + if (scale < BC_SCALE_MAX) + scale++; + else + rt_warn ("Scale too big in ++"); + break; + +#if defined(READLINE) || defined(LIBEDIT) + case 3: /* history */ + n_history++; + if (n_history > 0) + HISTORY_SIZE(n_history); + else + { + n_history = -1; + rt_warn ("history set to unlimited"); + UNLIMIT_HISTORY; + } +#endif + + default: /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + bc_add (var_ptr->v_value, _one_, &var_ptr->v_value, 0); + + } +} + + +/* Increment VAR_NAME by one. VAR_NAME is an array and top of + execution stack is the index and is popped off the stack. */ + +void +incr_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + if (!check_stack (1)) return; + index = bc_num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !bc_is_zero (ex_stack->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + pop (); + bc_add (*num_ptr, _one_, num_ptr, 0); + } + } +} + + +/* Routines for processing autos variables and parameters. */ + +/* NAME is an auto variable that needs to be pushed on its stack. */ + +void +auto_var (name) + int name; +{ + bc_var *v_temp; + bc_var_array *a_temp; + int ix; + + if (name > 0) + { + /* A simple variable. */ + ix = name; + v_temp = (bc_var *) bc_malloc (sizeof (bc_var)); + v_temp->v_next = variables[ix]; + bc_init_num (&v_temp->v_value); + variables[ix] = v_temp; + } + else + { + /* An array variable. */ + ix = -name; + a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array)); + a_temp->a_next = arrays[ix]; + a_temp->a_value = NULL; + a_temp->a_param = FALSE; + arrays[ix] = a_temp; + } +} + + +/* Free_a_tree frees everything associated with an array variable tree. + This is used when popping an array variable off its auto stack. */ + +void +free_a_tree ( root, depth ) + bc_array_node *root; + int depth; +{ + int ix; + + if (root != NULL) + { + if (depth > 1) + for (ix = 0; ix < NODE_SIZE; ix++) + free_a_tree (root->n_items.n_down[ix], depth-1); + else + for (ix = 0; ix < NODE_SIZE; ix++) + bc_free_num ( &(root->n_items.n_num[ix])); + free (root); + } +} + + +/* LIST is an NULL terminated list of varible names that need to be + popped off their auto stacks. */ + +void +pop_vars (list) + arg_list *list; +{ + bc_var *v_temp; + bc_var_array *a_temp; + int ix; + + while (list != NULL) + { + ix = list->av_name; + if (ix > 0) + { + /* A simple variable. */ + v_temp = variables[ix]; + if (v_temp != NULL) + { + variables[ix] = v_temp->v_next; + bc_free_num (&v_temp->v_value); + free (v_temp); + } + } + else + { + /* An array variable. */ + ix = -ix; + a_temp = arrays[ix]; + if (a_temp != NULL) + { + arrays[ix] = a_temp->a_next; + if (!a_temp->a_param && a_temp->a_value != NULL) + { + free_a_tree (a_temp->a_value->a_tree, + a_temp->a_value->a_depth); + free (a_temp->a_value); + } + free (a_temp); + } + } + list = list->next; + } +} + +/* COPY_NODE: Copies an array node for a call by value parameter. */ +bc_array_node * +copy_tree (ary_node, depth) + bc_array_node *ary_node; + int depth; +{ + bc_array_node *res = (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + int i; + + if (depth > 1) + for (i=0; in_items.n_down[i] != NULL) + res->n_items.n_down[i] = + copy_tree (ary_node->n_items.n_down[i], depth - 1); + else + res->n_items.n_down[i] = NULL; + else + for (i=0; in_items.n_num[i] != NULL) + res->n_items.n_num[i] = bc_copy_num (ary_node->n_items.n_num[i]); + else + res->n_items.n_num[i] = NULL; + return res; +} + +/* COPY_ARRAY: Copies an array for a call by value array parameter. + ARY is the pointer to the bc_array structure. */ + +bc_array * +copy_array (ary) + bc_array *ary; +{ + bc_array *res = (bc_array *) bc_malloc (sizeof(bc_array)); + res->a_depth = ary->a_depth; + res->a_tree = copy_tree (ary->a_tree, ary->a_depth); + return (res); +} + + +/* A call is being made to FUNC. The call types are at PC. Process + the parameters by doing an auto on the parameter variable and then + store the value at the new variable or put a pointer the the array + variable. */ + +void +process_params (pc, func) + program_counter *pc; + int func; +{ + char ch; + arg_list *params; + int ix, ix1; + bc_var *v_temp; + bc_var_array *a_src, *a_dest; + bc_num *n_temp; + + /* Get the parameter names from the function. */ + params = functions[func].f_params; + + while ((ch = byte(pc)) != ':') + { + if (params != NULL) + { + if ((ch == '0') && params->av_name > 0) + { + /* A simple variable. */ + ix = params->av_name; + v_temp = (bc_var *) bc_malloc (sizeof(bc_var)); + v_temp->v_next = variables[ix]; + v_temp->v_value = ex_stack->s_num; + bc_init_num (&ex_stack->s_num); + variables[ix] = v_temp; + } + else + if ((ch == '1') && (params->av_name < 0)) + { + /* The variables is an array variable. */ + + /* Compute source index and make sure some structure exists. */ + ix = (int) bc_num2long (ex_stack->s_num); + n_temp = get_array_num (ix, 0); + + /* Push a new array and Compute Destination index */ + auto_var (params->av_name); + ix1 = -params->av_name; + + /* Set up the correct pointers in the structure. */ + if (ix == ix1) + a_src = arrays[ix]->a_next; + else + a_src = arrays[ix]; + a_dest = arrays[ix1]; + if (params->arg_is_var) + { + a_dest->a_param = TRUE; + a_dest->a_value = a_src->a_value; + } + else + { + a_dest->a_param = FALSE; + a_dest->a_value = copy_array (a_src->a_value); + } + } + else + { + if (params->av_name < 0) + rt_error ("Parameter type mismatch parameter %s.", + a_names[-params->av_name]); + else + rt_error ("Parameter type mismatch, parameter %s.", + v_names[params->av_name]); + params++; + } + pop (); + } + else + { + rt_error ("Parameter number mismatch"); + return; + } + params = params->next; + } + if (params != NULL) + rt_error ("Parameter number mismatch"); +} diff --git a/bc/util.c b/bc/util.c new file mode 100644 index 0000000..c305c2e --- /dev/null +++ b/bc/util.c @@ -0,0 +1,873 @@ +/* util.c: Utility routines for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991-1994, 1997, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + The Free Software Foundation, Inc. + 59 Temple Place, Suite 330 + Boston, MA 02111 USA + + You may contact the author by: + e-mail: philnelson@acm.org + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +#include "bcdefs.h" +#ifndef VARARGS +#include +#else +#include +#endif +#include "global.h" +#include "proto.h" + + +/* strcopyof mallocs new memory and copies a string to to the new + memory. */ + +char * +strcopyof (str) + char *str; +{ + char *temp; + + temp = (char *) bc_malloc (strlen (str)+1); + return (strcpy (temp,str)); +} + + +/* nextarg adds another value to the list of arguments. */ + +arg_list * +nextarg (args, val, is_var) + arg_list *args; + int val; + int is_var; +{ arg_list *temp; + + temp = (arg_list *) bc_malloc (sizeof (arg_list)); + temp->av_name = val; + temp->arg_is_var = is_var; + temp->next = args; + + return (temp); +} + + +/* For generate, we must produce a string in the form + "val,val,...,val". We also need a couple of static variables + for retaining old generated strings. It also uses a recursive + function that builds the string. */ + +static char *arglist1 = NULL, *arglist2 = NULL; + + +/* make_arg_str does the actual construction of the argument string. + ARGS is the pointer to the list and LEN is the maximum number of + characters needed. 1 char is the minimum needed. + */ + +_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len)); + +static char * +make_arg_str (args, len) + arg_list *args; + int len; +{ + char *temp; + char sval[20]; + + /* Recursive call. */ + if (args != NULL) + temp = make_arg_str (args->next, len+12); + else + { + temp = (char *) bc_malloc (len); + *temp = 0; + return temp; + } + + /* Add the current number to the end of the string. */ + if (args->arg_is_var) + if (len != 1) + sprintf (sval, "*%d,", args->av_name); + else + sprintf (sval, "*%d", args->av_name); + else + if (len != 1) + sprintf (sval, "%d,", args->av_name); + else + sprintf (sval, "%d", args->av_name); + temp = strcat (temp, sval); + return (temp); +} + +char * +arg_str (args) + arg_list *args; +{ + if (arglist2 != NULL) + free (arglist2); + arglist2 = arglist1; + arglist1 = make_arg_str (args, 1); + return (arglist1); +} + +char * +call_str (args) + arg_list *args; +{ + arg_list *temp; + int arg_count; + int ix; + + if (arglist2 != NULL) + free (arglist2); + arglist2 = arglist1; + + /* Count the number of args and add the 0's and 1's. */ + for (temp = args, arg_count = 0; temp != NULL; temp = temp->next) + arg_count++; + arglist1 = (char *) bc_malloc(arg_count+1); + for (temp = args, ix=0; temp != NULL; temp = temp->next) + arglist1[ix++] = ( temp->av_name ? '1' : '0'); + arglist1[ix] = 0; + + return (arglist1); +} + +/* free_args frees an argument list ARGS. */ + +void +free_args (args) + arg_list *args; +{ + arg_list *temp; + + temp = args; + while (temp != NULL) + { + args = args->next; + free (temp); + temp = args; + } +} + + +/* Check for valid parameter (PARAMS) and auto (AUTOS) lists. + There must be no duplicates any where. Also, this is where + warnings are generated for array parameters. */ + +void +check_params ( params, autos ) + arg_list *params, *autos; +{ + arg_list *tmp1, *tmp2; + + /* Check for duplicate parameters. */ + if (params != NULL) + { + tmp1 = params; + while (tmp1 != NULL) + { + tmp2 = tmp1->next; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("duplicate parameter names"); + tmp2 = tmp2->next; + } + if (tmp1->arg_is_var) + warn ("Variable array parameter"); + tmp1 = tmp1->next; + } + } + + /* Check for duplicate autos. */ + if (autos != NULL) + { + tmp1 = autos; + while (tmp1 != NULL) + { + tmp2 = tmp1->next; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("duplicate auto variable names"); + tmp2 = tmp2->next; + } + if (tmp1->arg_is_var) + yyerror ("* not allowed here"); + tmp1 = tmp1->next; + } + } + + /* Check for duplicate between parameters and autos. */ + if ((params != NULL) && (autos != NULL)) + { + tmp1 = params; + while (tmp1 != NULL) + { + tmp2 = autos; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("variable in both parameter and auto lists"); + tmp2 = tmp2->next; + } + tmp1 = tmp1->next; + } + } +} + + +/* Initialize the code generator the parser. */ + +void +init_gen () +{ + /* Get things ready. */ + break_label = 0; + continue_label = 0; + next_label = 1; + out_count = 2; + if (compile_only) + printf ("@i"); + else + init_load (); + had_error = FALSE; + did_gen = FALSE; +} + + +/* generate code STR for the machine. */ + +void +generate (str) + char *str; +{ + did_gen = TRUE; + if (compile_only) + { + printf ("%s",str); + out_count += strlen(str); + if (out_count > 60) + { + printf ("\n"); + out_count = 0; + } + } + else + load_code (str); +} + + +/* Execute the current code as loaded. */ + +void +run_code() +{ + /* If no compile errors run the current code. */ + if (!had_error && did_gen) + { + if (compile_only) + { + printf ("@r\n"); + out_count = 0; + } + else + execute (); + } + + /* Reinitialize the code generation and machine. */ + if (did_gen) + init_gen(); + else + had_error = FALSE; +} + + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\". Always used for numbers. */ + +void +out_char (ch) + int ch; +{ + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + out_col++; + if (out_col == line_size-1) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + putchar (ch); + } +} + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\". This one is for strings. + In POSIX bc, strings are not broken across lines. */ + +void +out_schar (ch) + int ch; +{ + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + if (!std_only) + { + out_col++; + if (out_col == line_size-1) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + } + putchar (ch); + } +} + + +/* The following are "Symbol Table" routines for the parser. */ + +/* find_id returns a pointer to node in TREE that has the correct + ID. If there is no node in TREE with ID, NULL is returned. */ + +id_rec * +find_id (tree, id) + id_rec *tree; + char *id; +{ + int cmp_result; + + /* Check for an empty tree. */ + if (tree == NULL) + return NULL; + + /* Recursively search the tree. */ + cmp_result = strcmp (id, tree->id); + if (cmp_result == 0) + return tree; /* This is the item. */ + else if (cmp_result < 0) + return find_id (tree->left, id); + else + return find_id (tree->right, id); +} + + +/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is + provided. insert_id_rec returns TRUE if the tree height from + ROOT down is increased otherwise it returns FALSE. This is a + recursive balanced binary tree insertion algorithm. */ + +int insert_id_rec (root, new_id) + id_rec **root; + id_rec *new_id; +{ + id_rec *A, *B; + + /* If root is NULL, this where it is to be inserted. */ + if (*root == NULL) + { + *root = new_id; + new_id->left = NULL; + new_id->right = NULL; + new_id->balance = 0; + return (TRUE); + } + + /* We need to search for a leaf. */ + if (strcmp (new_id->id, (*root)->id) < 0) + { + /* Insert it on the left. */ + if (insert_id_rec (&((*root)->left), new_id)) + { + /* The height increased. */ + (*root)->balance --; + + switch ((*root)->balance) + { + case 0: /* no height increase. */ + return (FALSE); + case -1: /* height increase. */ + return (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"); +} -- cgit v1.2.1