summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkejun.zhou <dp583@stebjsxu0119.(none)>2012-07-09 18:38:20 +0800
committerkejun.zhou <kejun.zhou@linaro.org>2012-07-09 18:41:49 +0800
commit7fdbd157db916b2e4ea04f116ae04677538d56a3 (patch)
tree9f2b2ff196f1bc0c7b06fde311ad9eeb72911c9d
downloadtools_for_pm-qa-7fdbd157db916b2e4ea04f116ae04677538d56a3.tar.gz
Project init.
Signed-off-by: kejun.zhou <kejun.zhou@linaro.org>
-rw-r--r--Android.mk1
-rw-r--r--bc/Android.mk11
-rw-r--r--bc/bc.c2620
-rw-r--r--bc/bc.h127
-rw-r--r--bc/bcdefs.h202
-rw-r--r--bc/config.h124
-rw-r--r--bc/const.h97
-rw-r--r--bc/execute.c793
-rw-r--r--bc/global.c40
-rw-r--r--bc/global.h155
-rw-r--r--bc/libmath.h46
-rw-r--r--bc/load.c351
-rw-r--r--bc/main.c370
-rw-r--r--bc/number.c1804
-rw-r--r--bc/number.h153
-rw-r--r--bc/proto.h150
-rw-r--r--bc/scan.c2489
-rw-r--r--bc/storage.c1073
-rw-r--r--bc/util.c846
-rw-r--r--bc/warranty.c75
-rw-r--r--bc/y.tab.h137
-rw-r--r--fake_udevadm/Android.mk12
-rw-r--r--fake_udevadm/fake_udevadm.c92
23 files changed, 11768 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/bc/Android.mk b/bc/Android.mk
new file mode 100644
index 0000000..c01b2a6
--- /dev/null
+++ b/bc/Android.mk
@@ -0,0 +1,11 @@
+include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= main.c bc.c scan.c execute.c load.c storage.c util.c global.c warranty.c number.c
+LOCAL_MODULE := bc
+systemtarball: bc
+LOCAL_STATIC_LIBRARIES := libcutils libc
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
diff --git a/bc/bc.c b/bc/bc.c
new file mode 100644
index 0000000..56077a6
--- /dev/null
+++ b/bc/bc.c
@@ -0,0 +1,2620 @@
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, 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. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ENDOFLINE = 258,
+ AND = 259,
+ OR = 260,
+ NOT = 261,
+ STRING = 262,
+ NAME = 263,
+ NUMBER = 264,
+ ASSIGN_OP = 265,
+ REL_OP = 266,
+ INCR_DECR = 267,
+ Define = 268,
+ Break = 269,
+ Quit = 270,
+ Length = 271,
+ Return = 272,
+ For = 273,
+ If = 274,
+ While = 275,
+ Sqrt = 276,
+ Else = 277,
+ Scale = 278,
+ Ibase = 279,
+ Obase = 280,
+ Auto = 281,
+ Read = 282,
+ Random = 283,
+ Warranty = 284,
+ Halt = 285,
+ Last = 286,
+ Continue = 287,
+ Print = 288,
+ Limits = 289,
+ UNARY_MINUS = 290,
+ HistoryVar = 291,
+ Void = 292
+ };
+#endif
+/* Tokens. */
+#define ENDOFLINE 258
+#define AND 259
+#define OR 260
+#define NOT 261
+#define STRING 262
+#define NAME 263
+#define NUMBER 264
+#define ASSIGN_OP 265
+#define REL_OP 266
+#define INCR_DECR 267
+#define Define 268
+#define Break 269
+#define Quit 270
+#define Length 271
+#define Return 272
+#define For 273
+#define If 274
+#define While 275
+#define Sqrt 276
+#define Else 277
+#define Scale 278
+#define Ibase 279
+#define Obase 280
+#define Auto 281
+#define Read 282
+#define Random 283
+#define Warranty 284
+#define Halt 285
+#define Last 286
+#define Continue 287
+#define Print 288
+#define Limits 289
+#define UNARY_MINUS 290
+#define HistoryVar 291
+#define Void 292
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 33 "bc.y"
+
+
+#include "bcdefs.h"
+#include "global.h"
+#include "proto.h"
+
+/* current function number. */
+int cur_func = -1;
+
+/* Expression encoded information -- See comment at expression rules. */
+#define EX_ASSGN 0
+#define EX_REG 1
+#define EX_COMP 2
+#define EX_PAREN 4
+#define EX_VOID 8
+#define EX_EMPTY 16
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 54 "bc.y"
+typedef union YYSTYPE {
+ char *s_value;
+ char c_value;
+ int i_value;
+ arg_list *a_value;
+ } YYSTYPE;
+/* Line 196 of yacc.c. */
+#line 185 "bc.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 219 of yacc.c. */
+#line 197 "bc.c"
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T) && (defined (__STDC__) || defined (__cplusplus))
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYINCLUDED_STDLIB_H
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2005 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM ((YYSIZE_T) -1)
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if (! defined (malloc) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if (! defined (free) && ! defined (YYINCLUDED_STDLIB_H) \
+ && (defined (__STDC__) || defined (__cplusplus)))
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifdef __cplusplus
+}
+# endif
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short int yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined (__GNUC__) && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 719
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 53
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 36
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 112
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 198
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 292
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned 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, 42, 52, 2,
+ 45, 46, 40, 38, 49, 39, 2, 41, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 44,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 50, 2, 51, 43, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 47, 2, 48, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 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, 2, 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, 36, 37
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned short int yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 10, 12, 15, 16, 18,
+ 19, 21, 25, 28, 29, 31, 34, 38, 41, 45,
+ 47, 50, 52, 54, 56, 58, 60, 62, 64, 66,
+ 69, 70, 71, 72, 73, 88, 89, 98, 99, 100,
+ 109, 113, 114, 118, 120, 124, 126, 128, 129, 130,
+ 135, 136, 150, 151, 153, 154, 156, 157, 161, 165,
+ 167, 171, 176, 181, 185, 191, 198, 205, 206, 208,
+ 210, 214, 218, 224, 225, 227, 228, 230, 231, 236,
+ 237, 242, 243, 248, 251, 255, 259, 263, 267, 271,
+ 275, 279, 282, 284, 286, 290, 295, 298, 301, 306,
+ 311, 316, 320, 324, 326, 331, 333, 335, 337, 339,
+ 341, 342, 344
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 54, 0, -1, -1, 54, 55, -1, 57, 3, -1,
+ 73, -1, 1, 3, -1, -1, 3, -1, -1, 59,
+ -1, 57, 44, 59, -1, 57, 44, -1, -1, 59,
+ -1, 58, 3, -1, 58, 3, 59, -1, 58, 44,
+ -1, 58, 44, 60, -1, 60, -1, 1, 60, -1,
+ 29, -1, 34, -1, 83, -1, 7, -1, 14, -1,
+ 32, -1, 15, -1, 30, -1, 17, 82, -1, -1,
+ -1, -1, -1, 18, 61, 45, 81, 44, 62, 81,
+ 44, 63, 81, 46, 64, 56, 60, -1, -1, 19,
+ 45, 83, 46, 65, 56, 60, 71, -1, -1, -1,
+ 20, 66, 45, 83, 67, 46, 56, 60, -1, 47,
+ 58, 48, -1, -1, 33, 68, 69, -1, 70, -1,
+ 70, 49, 69, -1, 7, -1, 83, -1, -1, -1,
+ 22, 72, 56, 60, -1, -1, 13, 75, 8, 45,
+ 76, 46, 56, 47, 88, 77, 74, 58, 48, -1,
+ -1, 37, -1, -1, 78, -1, -1, 26, 78, 3,
+ -1, 26, 78, 44, -1, 8, -1, 8, 50, 51,
+ -1, 40, 8, 50, 51, -1, 52, 8, 50, 51,
+ -1, 78, 49, 8, -1, 78, 49, 8, 50, 51,
+ -1, 78, 49, 40, 8, 50, 51, -1, 78, 49,
+ 52, 8, 50, 51, -1, -1, 80, -1, 83, -1,
+ 8, 50, 51, -1, 80, 49, 83, -1, 80, 49,
+ 8, 50, 51, -1, -1, 83, -1, -1, 83, -1,
+ -1, 87, 10, 84, 83, -1, -1, 83, 4, 85,
+ 83, -1, -1, 83, 5, 86, 83, -1, 6, 83,
+ -1, 83, 11, 83, -1, 83, 38, 83, -1, 83,
+ 39, 83, -1, 83, 40, 83, -1, 83, 41, 83,
+ -1, 83, 42, 83, -1, 83, 43, 83, -1, 39,
+ 83, -1, 87, -1, 9, -1, 45, 83, 46, -1,
+ 8, 45, 79, 46, -1, 12, 87, -1, 87, 12,
+ -1, 16, 45, 83, 46, -1, 21, 45, 83, 46,
+ -1, 23, 45, 83, 46, -1, 27, 45, 46, -1,
+ 28, 45, 46, -1, 8, -1, 8, 50, 83, 51,
+ -1, 24, -1, 25, -1, 23, -1, 36, -1, 31,
+ -1, -1, 3, -1, 88, 3, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short int yyrline[] =
+{
+ 0, 124, 124, 132, 134, 136, 138, 144, 145, 149,
+ 150, 151, 152, 155, 156, 157, 158, 159, 160, 162,
+ 163, 166, 168, 170, 179, 186, 196, 207, 209, 211,
+ 214, 219, 231, 244, 213, 264, 263, 279, 285, 278,
+ 299, 302, 301, 305, 306, 308, 314, 321, 323, 322,
+ 334, 332, 359, 360, 367, 368, 371, 372, 374, 377,
+ 379, 381, 385, 389, 391, 393, 397, 403, 404, 406,
+ 414, 420, 428, 446, 450, 453, 459, 474, 473, 503,
+ 502, 518, 517, 535, 543, 573, 580, 587, 594, 601,
+ 608, 615, 622, 631, 647, 653, 672, 691, 714, 721,
+ 728, 735, 741, 748, 750, 758, 760, 762, 764, 768,
+ 775, 776, 777
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "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", "Random", "Warranty",
+ "Halt", "Last", "Continue", "Print", "Limits", "UNARY_MINUS",
+ "HistoryVar", "Void", "'+'", "'-'", "'*'", "'/'", "'%'", "'^'", "';'",
+ "'('", "')'", "'{'", "'}'", "','", "'['", "']'", "'&'", "$accept",
+ "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_void", "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", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short int yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 43, 45,
+ 42, 47, 37, 94, 59, 40, 41, 123, 125, 44,
+ 91, 93, 38
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 53, 54, 54, 55, 55, 55, 56, 56, 57,
+ 57, 57, 57, 58, 58, 58, 58, 58, 58, 59,
+ 59, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 61, 62, 63, 64, 60, 65, 60, 66, 67, 60,
+ 60, 68, 60, 69, 69, 70, 70, 71, 72, 71,
+ 74, 73, 75, 75, 76, 76, 77, 77, 77, 78,
+ 78, 78, 78, 78, 78, 78, 78, 79, 79, 80,
+ 80, 80, 80, 81, 81, 82, 82, 84, 83, 85,
+ 83, 86, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 87, 87, 87, 87, 87, 87, 87,
+ 88, 88, 88
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 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, 13, 0, 1, 0, 1, 0, 3, 3, 1,
+ 3, 4, 4, 3, 5, 6, 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, 3, 1, 4, 1, 1, 1, 1, 1,
+ 0, 1, 2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 1, 0, 0, 24, 103, 93, 0, 52,
+ 25, 27, 0, 75, 30, 0, 37, 0, 107, 105,
+ 106, 0, 0, 21, 28, 109, 26, 41, 22, 108,
+ 0, 0, 0, 3, 0, 10, 19, 5, 23, 92,
+ 6, 20, 83, 67, 0, 103, 107, 96, 53, 0,
+ 0, 29, 76, 0, 0, 0, 0, 0, 0, 0,
+ 0, 91, 0, 0, 0, 14, 4, 0, 79, 81,
+ 0, 0, 0, 0, 0, 0, 0, 77, 97, 103,
+ 0, 68, 69, 0, 0, 0, 73, 0, 0, 0,
+ 0, 101, 102, 45, 42, 43, 46, 94, 0, 17,
+ 40, 11, 0, 0, 84, 85, 86, 87, 88, 89,
+ 90, 0, 0, 95, 0, 104, 54, 98, 0, 74,
+ 35, 38, 99, 100, 0, 16, 18, 80, 82, 78,
+ 70, 103, 71, 59, 0, 0, 0, 55, 31, 7,
+ 0, 44, 0, 0, 0, 0, 7, 0, 73, 8,
+ 0, 7, 72, 60, 0, 0, 0, 63, 0, 0,
+ 0, 47, 0, 61, 62, 110, 0, 0, 0, 32,
+ 48, 36, 39, 111, 56, 64, 0, 0, 73, 7,
+ 112, 0, 50, 65, 66, 0, 0, 0, 0, 33,
+ 49, 57, 58, 0, 7, 51, 0, 34
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short int yydefgoto[] =
+{
+ -1, 1, 33, 150, 34, 64, 65, 36, 53, 148,
+ 178, 194, 139, 55, 140, 60, 94, 95, 171, 179,
+ 37, 188, 49, 136, 182, 137, 80, 81, 118, 51,
+ 38, 111, 102, 103, 39, 174
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -144
+static const short int yypact[] =
+{
+ -144, 188, -144, 392, 595, -144, -36, -144, 484, -31,
+ -144, -144, -32, 595, -144, -11, -144, -10, -7, -144,
+ -144, -6, -5, -144, -144, -144, -144, -144, -144, -144,
+ 595, 595, 222, -144, 2, -144, -144, -144, 676, 14,
+ -144, -144, 131, 621, 595, -27, -144, -144, -144, 54,
+ 595, -144, 676, 20, 595, 21, 595, 595, 13, 37,
+ 569, -144, 425, 535, 1, -144, -144, 318, -144, -144,
+ 595, 595, 595, 595, 595, 595, 595, -144, -144, -23,
+ 41, 36, 676, 39, 43, 436, 595, 445, 595, 485,
+ 494, -144, -144, -144, -144, 40, 676, -144, 270, 535,
+ -144, -144, 595, 595, -22, 51, 51, 4, 4, 4,
+ 4, 595, 105, -144, 647, -144, 23, -144, 53, 676,
+ -144, 676, -144, -144, 569, -144, -144, 131, 123, -22,
+ -144, -20, 676, 45, 91, 94, 57, 55, -144, 102,
+ 60, -144, 352, 56, 58, 65, 102, 24, 595, -144,
+ 535, 102, -144, -144, 67, 68, 69, 70, 115, 116,
+ 81, 109, 535, -144, -144, 132, 86, 88, 89, -144,
+ -144, -144, -144, -144, 7, -144, 92, 97, 595, 102,
+ -144, 23, -144, -144, -144, 99, 535, 12, 222, -144,
+ -144, -144, -144, 9, 102, -144, 535, -144
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const short int yypgoto[] =
+{
+ -144, -144, -144, -143, -144, -39, 0, -3, -144, -144,
+ -144, -144, -144, -144, -144, -144, 27, -144, -144, -144,
+ -144, -144, -144, -144, -144, -29, -144, -144, -141, -144,
+ -2, -144, -144, -144, 145, -144
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -16
+static const short int yytable[] =
+{
+ 41, 35, 42, 156, 98, 66, 48, 160, 162, 43,
+ 180, 52, 98, 50, 44, 191, 71, 72, 73, 74,
+ 75, 76, 43, 44, 77, 43, 78, 112, 61, 62,
+ 142, 133, 157, 181, 54, 56, 186, 185, 57, 58,
+ 59, 82, 83, 68, 69, 99, 67, 76, 85, 100,
+ 70, 196, 87, 99, 89, 90, 192, 195, 96, 91,
+ 41, 147, 84, 134, 158, 86, 88, 101, 104, 105,
+ 106, 107, 108, 109, 110, 135, 159, 71, 72, 73,
+ 74, 75, 76, 92, 119, 114, 121, 113, 116, 124,
+ 115, 73, 74, 75, 76, 143, 126, 138, 125, 144,
+ 127, 128, 145, 146, 147, 149, 151, 153, 154, 129,
+ 83, 4, 132, 6, 7, 155, 165, 8, 163, 164,
+ 166, 12, 96, 167, 168, 169, 17, 68, 18, 19,
+ 20, 170, 21, 22, 70, 173, 25, 175, 176, 177,
+ 83, 29, 70, 183, 30, 189, 119, 161, 184, 193,
+ 31, 141, 187, 47, 0, 0, 130, 0, 0, 172,
+ 0, 71, 72, 73, 74, 75, 76, 0, 0, 71,
+ 72, 73, 74, 75, 76, 0, 119, 0, 0, 0,
+ 0, 0, 0, 190, 0, 0, 0, 0, 2, 3,
+ 0, -9, 0, 197, 4, 5, 6, 7, 0, 0,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 0, 18, 19, 20, 0, 21, 22, 23, 24, 25,
+ 26, 27, 28, 63, 29, -13, 0, 30, 4, 5,
+ 6, 7, -9, 31, 8, 32, 10, 11, 12, 13,
+ 14, 15, 16, 17, 0, 18, 19, 20, 0, 21,
+ 22, 23, 24, 25, 26, 27, 28, 0, 29, 0,
+ 0, 30, 0, 0, 0, 0, -13, 31, 0, 32,
+ -13, 63, 0, -15, 0, 0, 4, 5, 6, 7,
+ 0, 0, 8, 0, 10, 11, 12, 13, 14, 15,
+ 16, 17, 0, 18, 19, 20, 0, 21, 22, 23,
+ 24, 25, 26, 27, 28, 0, 29, 0, 0, 30,
+ 0, 0, 0, 0, -15, 31, 0, 32, -15, 63,
+ 0, -12, 0, 0, 4, 5, 6, 7, 0, 0,
+ 8, 0, 10, 11, 12, 13, 14, 15, 16, 17,
+ 0, 18, 19, 20, 0, 21, 22, 23, 24, 25,
+ 26, 27, 28, 0, 29, 0, 0, 30, 4, 0,
+ 6, 7, -12, 31, 8, 32, 0, 0, 12, 0,
+ 0, 0, 0, 17, 0, 18, 19, 20, 0, 21,
+ 22, 0, 0, 25, 0, 0, 0, 0, 29, 0,
+ 0, 30, 0, 0, 0, 40, 0, 31, 4, 5,
+ 6, 7, 0, 152, 8, 0, 10, 11, 12, 13,
+ 14, 15, 16, 17, 0, 18, 19, 20, 0, 21,
+ 22, 23, 24, 25, 26, 27, 28, 0, 29, 68,
+ 69, 30, 0, 0, 0, 0, 70, 31, 0, 32,
+ 68, 69, 0, 0, 0, 0, 0, 70, 0, 68,
+ 69, 0, 0, 0, 0, 0, 70, 0, 0, 0,
+ 0, 0, 0, 71, 72, 73, 74, 75, 76, 0,
+ 0, 97, 0, 0, 71, 72, 73, 74, 75, 76,
+ 0, 0, 117, 71, 72, 73, 74, 75, 76, 68,
+ 69, 120, 45, 0, 0, 0, 70, 0, 68, 69,
+ 0, 0, 0, 0, 0, 70, 0, 46, 19, 20,
+ 0, 0, 0, 0, 0, 25, 0, 0, 0, 0,
+ 29, 0, 0, 71, 72, 73, 74, 75, 76, 0,
+ 0, 122, 71, 72, 73, 74, 75, 76, 0, 0,
+ 123, 4, 5, 6, 7, 0, 0, 8, 0, 10,
+ 11, 12, 13, 14, 15, 16, 17, 0, 18, 19,
+ 20, 0, 21, 22, 23, 24, 25, 26, 27, 28,
+ 0, 29, 0, 0, 30, 4, 93, 6, 7, 0,
+ 31, 8, 32, 0, 0, 12, 0, 0, 0, 0,
+ 17, 0, 18, 19, 20, 0, 21, 22, 0, 0,
+ 25, 4, 0, 6, 7, 29, 0, 8, 30, 0,
+ 0, 12, 0, 0, 31, 0, 17, 0, 18, 19,
+ 20, 0, 21, 22, 0, 0, 25, 4, 0, 79,
+ 7, 29, 0, 8, 30, 0, 0, 12, 0, 0,
+ 31, 0, 17, 0, 18, 19, 20, 0, 21, 22,
+ 0, 0, 25, 4, 0, 131, 7, 29, 0, 8,
+ 30, 0, 0, 12, 0, 0, 31, 0, 17, 0,
+ 18, 19, 20, 0, 21, 22, 0, 0, 25, 0,
+ 68, 69, 0, 29, 0, 0, 30, 70, 0, 0,
+ 0, 0, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 71, 72, 73, 74, 75, 76
+};
+
+static const short int yycheck[] =
+{
+ 3, 1, 4, 146, 3, 3, 37, 148, 151, 45,
+ 3, 13, 3, 45, 50, 3, 38, 39, 40, 41,
+ 42, 43, 45, 50, 10, 45, 12, 50, 30, 31,
+ 50, 8, 8, 26, 45, 45, 179, 178, 45, 45,
+ 45, 43, 44, 4, 5, 44, 44, 43, 50, 48,
+ 11, 194, 54, 44, 56, 57, 44, 48, 60, 46,
+ 63, 49, 8, 40, 40, 45, 45, 67, 70, 71,
+ 72, 73, 74, 75, 76, 52, 52, 38, 39, 40,
+ 41, 42, 43, 46, 86, 49, 88, 46, 45, 49,
+ 51, 40, 41, 42, 43, 50, 99, 44, 98, 8,
+ 102, 103, 8, 46, 49, 3, 46, 51, 50, 111,
+ 112, 6, 114, 8, 9, 50, 47, 12, 51, 51,
+ 50, 16, 124, 8, 8, 44, 21, 4, 23, 24,
+ 25, 22, 27, 28, 11, 3, 31, 51, 50, 50,
+ 142, 36, 11, 51, 39, 46, 148, 150, 51, 188,
+ 45, 124, 181, 8, -1, -1, 51, -1, -1, 162,
+ -1, 38, 39, 40, 41, 42, 43, -1, -1, 38,
+ 39, 40, 41, 42, 43, -1, 178, -1, -1, -1,
+ -1, -1, -1, 186, -1, -1, -1, -1, 0, 1,
+ -1, 3, -1, 196, 6, 7, 8, 9, -1, -1,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ -1, 23, 24, 25, -1, 27, 28, 29, 30, 31,
+ 32, 33, 34, 1, 36, 3, -1, 39, 6, 7,
+ 8, 9, 44, 45, 12, 47, 14, 15, 16, 17,
+ 18, 19, 20, 21, -1, 23, 24, 25, -1, 27,
+ 28, 29, 30, 31, 32, 33, 34, -1, 36, -1,
+ -1, 39, -1, -1, -1, -1, 44, 45, -1, 47,
+ 48, 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, 34, -1, 36, -1, -1, 39,
+ -1, -1, -1, -1, 44, 45, -1, 47, 48, 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, 34, -1, 36, -1, -1, 39, 6, -1,
+ 8, 9, 44, 45, 12, 47, -1, -1, 16, -1,
+ -1, -1, -1, 21, -1, 23, 24, 25, -1, 27,
+ 28, -1, -1, 31, -1, -1, -1, -1, 36, -1,
+ -1, 39, -1, -1, -1, 3, -1, 45, 6, 7,
+ 8, 9, -1, 51, 12, -1, 14, 15, 16, 17,
+ 18, 19, 20, 21, -1, 23, 24, 25, -1, 27,
+ 28, 29, 30, 31, 32, 33, 34, -1, 36, 4,
+ 5, 39, -1, -1, -1, -1, 11, 45, -1, 47,
+ 4, 5, -1, -1, -1, -1, -1, 11, -1, 4,
+ 5, -1, -1, -1, -1, -1, 11, -1, -1, -1,
+ -1, -1, -1, 38, 39, 40, 41, 42, 43, -1,
+ -1, 46, -1, -1, 38, 39, 40, 41, 42, 43,
+ -1, -1, 46, 38, 39, 40, 41, 42, 43, 4,
+ 5, 46, 8, -1, -1, -1, 11, -1, 4, 5,
+ -1, -1, -1, -1, -1, 11, -1, 23, 24, 25,
+ -1, -1, -1, -1, -1, 31, -1, -1, -1, -1,
+ 36, -1, -1, 38, 39, 40, 41, 42, 43, -1,
+ -1, 46, 38, 39, 40, 41, 42, 43, -1, -1,
+ 46, 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, 34,
+ -1, 36, -1, -1, 39, 6, 7, 8, 9, -1,
+ 45, 12, 47, -1, -1, 16, -1, -1, -1, -1,
+ 21, -1, 23, 24, 25, -1, 27, 28, -1, -1,
+ 31, 6, -1, 8, 9, 36, -1, 12, 39, -1,
+ -1, 16, -1, -1, 45, -1, 21, -1, 23, 24,
+ 25, -1, 27, 28, -1, -1, 31, 6, -1, 8,
+ 9, 36, -1, 12, 39, -1, -1, 16, -1, -1,
+ 45, -1, 21, -1, 23, 24, 25, -1, 27, 28,
+ -1, -1, 31, 6, -1, 8, 9, 36, -1, 12,
+ 39, -1, -1, 16, -1, -1, 45, -1, 21, -1,
+ 23, 24, 25, -1, 27, 28, -1, -1, 31, -1,
+ 4, 5, -1, 36, -1, -1, 39, 11, -1, -1,
+ -1, -1, 45, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 38, 39, 40, 41, 42, 43
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 54, 0, 1, 6, 7, 8, 9, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 23, 24,
+ 25, 27, 28, 29, 30, 31, 32, 33, 34, 36,
+ 39, 45, 47, 55, 57, 59, 60, 73, 83, 87,
+ 3, 60, 83, 45, 50, 8, 23, 87, 37, 75,
+ 45, 82, 83, 61, 45, 66, 45, 45, 45, 45,
+ 68, 83, 83, 1, 58, 59, 3, 44, 4, 5,
+ 11, 38, 39, 40, 41, 42, 43, 10, 12, 8,
+ 79, 80, 83, 83, 8, 83, 45, 83, 45, 83,
+ 83, 46, 46, 7, 69, 70, 83, 46, 3, 44,
+ 48, 59, 85, 86, 83, 83, 83, 83, 83, 83,
+ 83, 84, 50, 46, 49, 51, 45, 46, 81, 83,
+ 46, 83, 46, 46, 49, 59, 60, 83, 83, 83,
+ 51, 8, 83, 8, 40, 52, 76, 78, 44, 65,
+ 67, 69, 50, 50, 8, 8, 46, 49, 62, 3,
+ 56, 46, 51, 51, 50, 50, 56, 8, 40, 52,
+ 81, 60, 56, 51, 51, 47, 50, 8, 8, 44,
+ 22, 71, 60, 3, 88, 51, 50, 50, 63, 72,
+ 3, 26, 77, 51, 51, 81, 56, 78, 74, 46,
+ 60, 3, 44, 58, 64, 48, 56, 60
+};
+
+#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 yyerrorlab
+
+
+/* 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); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short int *bottom;
+ short int *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu), ",
+ yyrule - 1, yylno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname[yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ size_t yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+#endif /* YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+ ;
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short int yyssa[YYINITDEPTH];
+ short int *yyss = yyssa;
+ short int *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK (yyvsp--, yyssp--)
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ 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;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* 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 int *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ short int *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a look-ahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+#line 124 "bc.y"
+ {
+ (yyval.i_value) = 0;
+ if (interactive && !quiet)
+ {
+ show_bc_version ();
+ welcome ();
+ }
+ }
+ break;
+
+ case 4:
+#line 135 "bc.y"
+ { run_code (); }
+ break;
+
+ case 5:
+#line 137 "bc.y"
+ { run_code (); }
+ break;
+
+ case 6:
+#line 139 "bc.y"
+ {
+ yyerrok;
+ init_gen ();
+ }
+ break;
+
+ case 8:
+#line 146 "bc.y"
+ { warn ("newline not allowed"); }
+ break;
+
+ case 9:
+#line 149 "bc.y"
+ { (yyval.i_value) = 0; }
+ break;
+
+ case 13:
+#line 155 "bc.y"
+ { (yyval.i_value) = 0; }
+ break;
+
+ case 20:
+#line 164 "bc.y"
+ { (yyval.i_value) = (yyvsp[0].i_value); }
+ break;
+
+ case 21:
+#line 167 "bc.y"
+ { warranty (""); }
+ break;
+
+ case 22:
+#line 169 "bc.y"
+ { limits (); }
+ break;
+
+ case 23:
+#line 171 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_COMP)
+ warn ("comparison in expression");
+ if ((yyvsp[0].i_value) & EX_REG)
+ generate ("W");
+ else
+ generate ("p");
+ }
+ break;
+
+ case 24:
+#line 180 "bc.y"
+ {
+ (yyval.i_value) = 0;
+ generate ("w");
+ generate ((yyvsp[0].s_value));
+ free ((yyvsp[0].s_value));
+ }
+ break;
+
+ case 25:
+#line 187 "bc.y"
+ {
+ if (break_label == 0)
+ yyerror ("Break outside a for/while");
+ else
+ {
+ sprintf (genstr, "J%1d:", break_label);
+ generate (genstr);
+ }
+ }
+ break;
+
+ case 26:
+#line 197 "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 27:
+#line 208 "bc.y"
+ { exit (0); }
+ break;
+
+ case 28:
+#line 210 "bc.y"
+ { generate ("h"); }
+ break;
+
+ case 29:
+#line 212 "bc.y"
+ { generate ("R"); }
+ break;
+
+ case 30:
+#line 214 "bc.y"
+ {
+ (yyvsp[0].i_value) = break_label;
+ break_label = next_label++;
+ }
+ break;
+
+ case 31:
+#line 219 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_COMP)
+ warn ("Comparison in first for expression");
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("first expression is void");
+ if (!((yyvsp[-1].i_value) & EX_EMPTY))
+ generate ("p");
+ (yyvsp[-1].i_value) = next_label++;
+ sprintf (genstr, "N%1d:", (yyvsp[-1].i_value));
+ generate (genstr);
+ }
+ break;
+
+ case 32:
+#line 231 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("second expression is void");
+ if ((yyvsp[-1].i_value) & EX_EMPTY ) 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 33:
+#line 244 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_COMP)
+ warn ("Comparison in third for expression");
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("third expression is void");
+ if ((yyvsp[-1].i_value) & EX_EMPTY)
+ 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 34:
+#line 256 "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 35:
+#line 264 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("void expression");
+ (yyvsp[-1].i_value) = if_label;
+ if_label = next_label++;
+ sprintf (genstr, "Z%1d:", if_label);
+ generate (genstr);
+ }
+ break;
+
+ case 36:
+#line 273 "bc.y"
+ {
+ sprintf (genstr, "N%1d:", if_label);
+ generate (genstr);
+ if_label = (yyvsp[-5].i_value);
+ }
+ break;
+
+ case 37:
+#line 279 "bc.y"
+ {
+ (yyvsp[0].i_value) = next_label++;
+ sprintf (genstr, "N%1d:", (yyvsp[0].i_value));
+ generate (genstr);
+ }
+ break;
+
+ case 38:
+#line 285 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror ("void expression");
+ (yyvsp[0].i_value) = break_label;
+ break_label = next_label++;
+ sprintf (genstr, "Z%1d:", break_label);
+ generate (genstr);
+ }
+ break;
+
+ case 39:
+#line 294 "bc.y"
+ {
+ sprintf (genstr, "J%1d:N%1d:", (yyvsp[-7].i_value), break_label);
+ generate (genstr);
+ break_label = (yyvsp[-4].i_value);
+ }
+ break;
+
+ case 40:
+#line 300 "bc.y"
+ { (yyval.i_value) = 0; }
+ break;
+
+ case 41:
+#line 302 "bc.y"
+ { warn ("print statement"); }
+ break;
+
+ case 45:
+#line 309 "bc.y"
+ {
+ generate ("O");
+ generate ((yyvsp[0].s_value));
+ free ((yyvsp[0].s_value));
+ }
+ break;
+
+ case 46:
+#line 315 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror ("void expression in print");
+ generate ("P");
+ }
+ break;
+
+ case 48:
+#line 323 "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 50:
+#line 334 "bc.y"
+ { char *params, *autos;
+ /* Check auto list against parameter list? */
+ check_params ((yyvsp[-5].a_value),(yyvsp[0].a_value));
+ params = arg_str ((yyvsp[-5].a_value));
+ autos = arg_str ((yyvsp[0].a_value));
+ set_genstr_size (30 + strlen (params)
+ + strlen (autos));
+ cur_func = lookup((yyvsp[-7].s_value),FUNCTDEF);
+ sprintf (genstr, "F%d,%s.%s[", cur_func, params,
+ autos);
+ generate (genstr);
+ functions[cur_func].f_void = (yyvsp[-8].i_value);
+ free_args ((yyvsp[-5].a_value));
+ free_args ((yyvsp[0].a_value));
+ (yyvsp[-9].i_value) = next_label;
+ next_label = 1;
+ }
+ break;
+
+ case 51:
+#line 352 "bc.y"
+ {
+ generate ("0R]");
+ next_label = (yyvsp[-12].i_value);
+ cur_func = -1;
+ }
+ break;
+
+ case 52:
+#line 359 "bc.y"
+ { (yyval.i_value) = 0; }
+ break;
+
+ case 53:
+#line 361 "bc.y"
+ {
+ (yyval.i_value) = 1;
+ warn ("void functions");
+ }
+ break;
+
+ case 54:
+#line 367 "bc.y"
+ { (yyval.a_value) = NULL; }
+ break;
+
+ case 56:
+#line 371 "bc.y"
+ { (yyval.a_value) = NULL; }
+ break;
+
+ case 57:
+#line 373 "bc.y"
+ { (yyval.a_value) = (yyvsp[-1].a_value); }
+ break;
+
+ case 58:
+#line 375 "bc.y"
+ { (yyval.a_value) = (yyvsp[-1].a_value); }
+ break;
+
+ case 59:
+#line 378 "bc.y"
+ { (yyval.a_value) = nextarg (NULL, lookup ((yyvsp[0].s_value),SIMPLE), FALSE);}
+ break;
+
+ case 60:
+#line 380 "bc.y"
+ { (yyval.a_value) = nextarg (NULL, lookup ((yyvsp[-2].s_value),ARRAY), FALSE); }
+ break;
+
+ case 61:
+#line 382 "bc.y"
+ { (yyval.a_value) = nextarg (NULL, lookup ((yyvsp[-2].s_value),ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
+ break;
+
+ case 62:
+#line 386 "bc.y"
+ { (yyval.a_value) = nextarg (NULL, lookup ((yyvsp[-2].s_value),ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
+ break;
+
+ case 63:
+#line 390 "bc.y"
+ { (yyval.a_value) = nextarg ((yyvsp[-2].a_value), lookup ((yyvsp[0].s_value),SIMPLE), FALSE); }
+ break;
+
+ case 64:
+#line 392 "bc.y"
+ { (yyval.a_value) = nextarg ((yyvsp[-4].a_value), lookup ((yyvsp[-2].s_value),ARRAY), FALSE); }
+ break;
+
+ case 65:
+#line 394 "bc.y"
+ { (yyval.a_value) = nextarg ((yyvsp[-5].a_value), lookup ((yyvsp[-2].s_value),ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
+ break;
+
+ case 66:
+#line 398 "bc.y"
+ { (yyval.a_value) = nextarg ((yyvsp[-5].a_value), lookup ((yyvsp[-2].s_value),ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
+ break;
+
+ case 67:
+#line 403 "bc.y"
+ { (yyval.a_value) = NULL; }
+ break;
+
+ case 69:
+#line 407 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_COMP)
+ warn ("comparison in argument");
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror ("void argument");
+ (yyval.a_value) = nextarg (NULL,0,FALSE);
+ }
+ break;
+
+ case 70:
+#line 415 "bc.y"
+ {
+ sprintf (genstr, "K%d:", -lookup ((yyvsp[-2].s_value),ARRAY));
+ generate (genstr);
+ (yyval.a_value) = nextarg (NULL,1,FALSE);
+ }
+ break;
+
+ case 71:
+#line 421 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_COMP)
+ warn ("comparison in argument");
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror ("void argument");
+ (yyval.a_value) = nextarg ((yyvsp[-2].a_value),0,FALSE);
+ }
+ break;
+
+ case 72:
+#line 429 "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 73:
+#line 446 "bc.y"
+ {
+ (yyval.i_value) = EX_EMPTY;
+ warn ("Missing expression in for statement");
+ }
+ break;
+
+ case 75:
+#line 453 "bc.y"
+ {
+ (yyval.i_value) = 0;
+ generate ("0");
+ if (cur_func == -1)
+ yyerror("Return outside of a function.");
+ }
+ break;
+
+ case 76:
+#line 460 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_COMP)
+ warn ("comparison in return expresion");
+ if (!((yyvsp[0].i_value) & EX_PAREN))
+ warn ("return expression requires parenthesis");
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror("return requires non-void expression");
+ if (cur_func == -1)
+ yyerror("Return outside of a function.");
+ else if (functions[cur_func].f_void)
+ yyerror("Return expression in a void function.");
+ }
+ break;
+
+ case 77:
+#line 474 "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 78:
+#line 485 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_ASSGN)
+ warn("comparison in assignment");
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror("Assignment of a void expression");
+ 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) = EX_ASSGN;
+ }
+ break;
+
+ case 79:
+#line 503 "bc.y"
+ {
+ warn("&& operator");
+ (yyvsp[0].i_value) = next_label++;
+ sprintf (genstr, "DZ%d:p", (yyvsp[0].i_value));
+ generate (genstr);
+ }
+ break;
+
+ case 80:
+#line 510 "bc.y"
+ {
+ if (((yyvsp[-3].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with &&");
+ 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)) & ~EX_PAREN;
+ }
+ break;
+
+ case 81:
+#line 518 "bc.y"
+ {
+ warn("|| operator");
+ (yyvsp[0].i_value) = next_label++;
+ sprintf (genstr, "B%d:", (yyvsp[0].i_value));
+ generate (genstr);
+ }
+ break;
+
+ case 82:
+#line 525 "bc.y"
+ {
+ int tmplab;
+ if (((yyvsp[-3].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with ||");
+ 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)) & ~EX_PAREN;
+ }
+ break;
+
+ case 83:
+#line 536 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror ("void expression with !");
+ (yyval.i_value) = (yyvsp[0].i_value) & ~EX_PAREN;
+ warn("! operator");
+ generate ("!");
+ }
+ break;
+
+ case 84:
+#line 544 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with comparison");
+ (yyval.i_value) = EX_REG | EX_COMP;
+ 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 85:
+#line 574 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with +");
+ generate ("+");
+ (yyval.i_value) = ((yyvsp[-2].i_value) | (yyvsp[0].i_value)) & ~EX_PAREN;
+ }
+ break;
+
+ case 86:
+#line 581 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with -");
+ generate ("-");
+ (yyval.i_value) = ((yyvsp[-2].i_value) | (yyvsp[0].i_value)) & ~EX_PAREN;
+ }
+ break;
+
+ case 87:
+#line 588 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with *");
+ generate ("*");
+ (yyval.i_value) = ((yyvsp[-2].i_value) | (yyvsp[0].i_value)) & ~EX_PAREN;
+ }
+ break;
+
+ case 88:
+#line 595 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with /");
+ generate ("/");
+ (yyval.i_value) = ((yyvsp[-2].i_value) | (yyvsp[0].i_value)) & ~EX_PAREN;
+ }
+ break;
+
+ case 89:
+#line 602 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with %");
+ generate ("%");
+ (yyval.i_value) = ((yyvsp[-2].i_value) | (yyvsp[0].i_value)) & ~EX_PAREN;
+ }
+ break;
+
+ case 90:
+#line 609 "bc.y"
+ {
+ if (((yyvsp[-2].i_value) & EX_VOID) || ((yyvsp[0].i_value) & EX_VOID))
+ yyerror ("void expression with ^");
+ generate ("^");
+ (yyval.i_value) = ((yyvsp[-2].i_value) | (yyvsp[0].i_value)) & ~EX_PAREN;
+ }
+ break;
+
+ case 91:
+#line 616 "bc.y"
+ {
+ if ((yyvsp[0].i_value) & EX_VOID)
+ yyerror ("void expression with unary -");
+ generate ("n");
+ (yyval.i_value) = (yyvsp[0].i_value) & ~EX_PAREN;
+ }
+ break;
+
+ case 92:
+#line 623 "bc.y"
+ {
+ (yyval.i_value) = EX_REG;
+ 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 93:
+#line 632 "bc.y"
+ {
+ int len = strlen((yyvsp[0].s_value));
+ (yyval.i_value) = EX_REG;
+ 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 94:
+#line 648 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("void expression in parenthesis");
+ (yyval.i_value) = (yyvsp[-1].i_value) | EX_REG | EX_PAREN;
+ }
+ break;
+
+ case 95:
+#line 654 "bc.y"
+ { int fn;
+ fn = lookup ((yyvsp[-3].s_value),FUNCT);
+ if (functions[fn].f_void)
+ (yyval.i_value) = EX_VOID;
+ else
+ (yyval.i_value) = EX_REG;
+ if ((yyvsp[-1].a_value) != NULL)
+ { char *params = call_str ((yyvsp[-1].a_value));
+ set_genstr_size (20 + strlen (params));
+ sprintf (genstr, "C%d,%s:", fn, params);
+ free_args ((yyvsp[-1].a_value));
+ }
+ else
+ {
+ sprintf (genstr, "C%d:", fn);
+ }
+ generate (genstr);
+ }
+ break;
+
+ case 96:
+#line 673 "bc.y"
+ {
+ (yyval.i_value) = EX_REG;
+ 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 97:
+#line 692 "bc.y"
+ {
+ (yyval.i_value) = EX_REG;
+ 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 98:
+#line 715 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("void expression in length()");
+ generate ("cL");
+ (yyval.i_value) = EX_REG;
+ }
+ break;
+
+ case 99:
+#line 722 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("void expression in sqrt()");
+ generate ("cR");
+ (yyval.i_value) = EX_REG;
+ }
+ break;
+
+ case 100:
+#line 729 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror ("void expression in scale()");
+ generate ("cS");
+ (yyval.i_value) = EX_REG;
+ }
+ break;
+
+ case 101:
+#line 736 "bc.y"
+ {
+ warn ("read function");
+ generate ("cI");
+ (yyval.i_value) = EX_REG;
+ }
+ break;
+
+ case 102:
+#line 742 "bc.y"
+ {
+ warn ("random function");
+ generate ("cX");
+ (yyval.i_value) = EX_REG;
+ }
+ break;
+
+ case 103:
+#line 749 "bc.y"
+ { (yyval.i_value) = lookup((yyvsp[0].s_value),SIMPLE); }
+ break;
+
+ case 104:
+#line 751 "bc.y"
+ {
+ if ((yyvsp[-1].i_value) & EX_VOID)
+ yyerror("void expression as subscript");
+ if ((yyvsp[-1].i_value) & EX_COMP)
+ warn("comparison in subscript");
+ (yyval.i_value) = lookup((yyvsp[-3].s_value),ARRAY);
+ }
+ break;
+
+ case 105:
+#line 759 "bc.y"
+ { (yyval.i_value) = 0; }
+ break;
+
+ case 106:
+#line 761 "bc.y"
+ { (yyval.i_value) = 1; }
+ break;
+
+ case 107:
+#line 763 "bc.y"
+ { (yyval.i_value) = 2; }
+ break;
+
+ case 108:
+#line 765 "bc.y"
+ { (yyval.i_value) = 3;
+ warn ("History variable");
+ }
+ break;
+
+ case 109:
+#line 769 "bc.y"
+ { (yyval.i_value) = 4;
+ warn ("Last variable");
+ }
+ break;
+
+ case 110:
+#line 775 "bc.y"
+ { warn ("End of line required"); }
+ break;
+
+ case 112:
+#line 778 "bc.y"
+ { warn ("Too many end of lines"); }
+ break;
+
+
+ default: break;
+ }
+
+/* Line 1126 of yacc.c. */
+#line 2350 "bc.c"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+
+
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* 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 - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ char *yymsg = 0;
+# define YYERROR_VERBOSE_ARGS_MAXIMUM 5
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+#if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+#endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= yysize1 < yysize;
+ yysize = yysize1;
+
+ if (!yysize_overflow && yysize <= YYSTACK_ALLOC_MAXIMUM)
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyf))
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ goto yyexhaustedlab;
+ }
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror (YY_("syntax error"));
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding", yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (0)
+ goto yyerrorlab;
+
+yyvsp -= yylen;
+ yyssp -= yylen;
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping", yystos[yystate], yyvsp);
+ YYPOPSTACK;
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
+}
+
+
+#line 781 "bc.y"
+
+
+
diff --git a/bc/bc.h b/bc/bc.h
new file mode 100644
index 0000000..464d715
--- /dev/null
+++ b/bc/bc.h
@@ -0,0 +1,127 @@
+/* A Bison parser, made by GNU Bison 2.1. */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, 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. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ENDOFLINE = 258,
+ AND = 259,
+ OR = 260,
+ NOT = 261,
+ STRING = 262,
+ NAME = 263,
+ NUMBER = 264,
+ ASSIGN_OP = 265,
+ REL_OP = 266,
+ INCR_DECR = 267,
+ Define = 268,
+ Break = 269,
+ Quit = 270,
+ Length = 271,
+ Return = 272,
+ For = 273,
+ If = 274,
+ While = 275,
+ Sqrt = 276,
+ Else = 277,
+ Scale = 278,
+ Ibase = 279,
+ Obase = 280,
+ Auto = 281,
+ Read = 282,
+ Random = 283,
+ Warranty = 284,
+ Halt = 285,
+ Last = 286,
+ Continue = 287,
+ Print = 288,
+ Limits = 289,
+ UNARY_MINUS = 290,
+ HistoryVar = 291,
+ Void = 292
+ };
+#endif
+/* Tokens. */
+#define ENDOFLINE 258
+#define AND 259
+#define OR 260
+#define NOT 261
+#define STRING 262
+#define NAME 263
+#define NUMBER 264
+#define ASSIGN_OP 265
+#define REL_OP 266
+#define INCR_DECR 267
+#define Define 268
+#define Break 269
+#define Quit 270
+#define Length 271
+#define Return 272
+#define For 273
+#define If 274
+#define While 275
+#define Sqrt 276
+#define Else 277
+#define Scale 278
+#define Ibase 279
+#define Obase 280
+#define Auto 281
+#define Read 282
+#define Random 283
+#define Warranty 284
+#define Halt 285
+#define Last 286
+#define Continue 287
+#define Print 288
+#define Limits 289
+#define UNARY_MINUS 290
+#define HistoryVar 291
+#define Void 292
+
+
+
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 54 "bc.y"
+typedef union YYSTYPE {
+ char *s_value;
+ char c_value;
+ int i_value;
+ arg_list *a_value;
+ } YYSTYPE;
+/* Line 1447 of yacc.c. */
+#line 119 "bc.h"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
+
+
diff --git a/bc/bcdefs.h b/bc/bcdefs.h
new file mode 100644
index 0000000..29c4d52
--- /dev/null
+++ b/bc/bcdefs.h
@@ -0,0 +1,202 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* bcdefs.h: The single file to include all constants and type definitions. */
+
+/* Include the configuration file. */
+#include "config.h"
+
+/* Standard includes for all files. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <ctype.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if defined(LIBEDIT)
+#include <histedit.h>
+#endif
+
+#if defined(READLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+/* Initialization magic ... */
+#ifdef _GLOBAL_C
+#define EXTERN
+#define INIT(x) = x
+#else
+#define EXTERN extern
+#define INIT(x)
+#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_void; /* Is this function a void function. */
+ 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
+
+/* Now the global variable declarations. */
+#include "global.h"
diff --git a/bc/config.h b/bc/config.h
new file mode 100644
index 0000000..7d89955
--- /dev/null
+++ b/bc/config.h
@@ -0,0 +1,124 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define the bc copyright line. */
+#define BC_COPYRIGHT "Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc."
+
+/* Define the dc copyright line. */
+#define DC_COPYRIGHT "Copyright 1994, 1997, 1998, 2000, 2001, 2004, 2005, 2006 Free Software Foundation, Inc."
+
+/* Define the dc version number. */
+#define DC_VERSION "1.3.95"
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the `fstat' function. */
+#define HAVE_FSTAT 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `isgraph' function. */
+#define HAVE_ISGRAPH 1
+
+/* Define to 1 if you have the <lib.h> header file. */
+/* #undef HAVE_LIB_H */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `setvbuf' function. */
+#define HAVE_SETVBUF 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define if libedit is used */
+/* #undef LIBEDIT */
+
+/* Name of package */
+#define PACKAGE "bc"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "bc"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "bc 1.06.95"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "bc"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.06.95"
+
+/* Define if readline is used */
+/* #undef READLINE */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.06.95"
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+/* #undef YYTEXT_POINTER */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `size_t' if <sys/types.h> does not define. */
+/* #undef ptrdiff_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/bc/const.h b/bc/const.h
new file mode 100644
index 0000000..1b3040b
--- /dev/null
+++ b/bc/const.h
@@ -0,0 +1,97 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* const.h: Constants for bc. */
+
+/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */
+
+#ifndef INT_MAX
+#define INT_MAX 0x7FFFFFFF
+#endif
+#ifndef LONG_MAX
+#define LONG_MAX 0x7FFFFFFF
+#endif
+
+
+/* Define constants in some reasonable size. The next 4 constants are
+ POSIX constants. */
+
+#ifdef BC_BASE_MAX
+ /* <limits.h> on a POSIX.2 system may have defined these. Override. */
+# undef BC_BASE_MAX
+# undef BC_SCALE_MAX
+# undef BC_STRING_MAX
+# undef BC_DIM_MAX
+#endif
+
+#define BC_BASE_MAX INT_MAX
+#define BC_SCALE_MAX INT_MAX
+#define BC_STRING_MAX INT_MAX
+
+
+/* Definitions for arrays. */
+
+#define BC_DIM_MAX 16777215 /* this should be NODE_SIZE^NODE_DEPTH-1 */
+
+#define NODE_SIZE 64 /* Must be a power of 2. */
+#define NODE_MASK 0x3f /* Must be NODE_SIZE-1. */
+#define NODE_SHIFT 6 /* 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
+
+#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..e4e8ef7
--- /dev/null
+++ b/bc/execute.c
@@ -0,0 +1,793 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+/* execute.c - run a bc program. */
+
+#include "bcdefs.h"
+#include <signal.h>
+#include "proto.h"
+
+
+/* The SIGINT interrupt handling routine. */
+
+int had_sigint;
+
+void
+stop_execution (sig)
+ int sig;
+{
+ had_sigint = TRUE;
+}
+
+
+/* Get the current byte and advance the PC counter. */
+
+unsigned char
+byte (p)
+ program_counter *p;
+{
+ return (functions[p->pc_func].f_body[p->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 && !had_sigint)
+ {
+ 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;
+
+ case 'X': /* Random function. */
+ push_copy (_zero_);
+ bc_int2num (&ex_stack->s_num, random());
+ 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 1. */
+ 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 ("\ninterrupted execution.\n");
+ }
+}
+
+
+/* Prog_char gets another byte from the program. It is used for
+ conversion of text constants in the code to numbers. */
+
+int
+prog_char ()
+{
+ return (int) byte(&pc);
+}
+
+
+/* Read a character from the standard input. This function is used
+ by the "read" function. */
+
+int
+input_char ()
+{
+ int 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();
+ out_col = 0; /* Saw a new line */
+ }
+ }
+
+ /* Classify and preprocess the input character. */
+ if (isdigit(in_ch))
+ return (in_ch - '0');
+ if (in_ch >= 'A' && in_ch <= 'F')
+ return (in_ch + 10 - 'A');
+ if (in_ch >= 'a' && in_ch <= 'f')
+ return (in_ch + 10 - 'a');
+ if (in_ch == '.' || in_ch == '+' || in_ch == '-')
+ return (in_ch);
+ if (in_ch <= ' ')
+ return (' ');
+
+ return (':');
+}
+
+
+/* Push_constant converts a sequence of input characters as returned
+ by IN_CHAR into a number. The number is pushed onto the execution
+ stack. The number is converted as a number in base CONV_BASE. */
+
+void
+push_constant (in_char, conv_base)
+ int (*in_char)(VOID);
+ int conv_base;
+{
+ int digits;
+ bc_num build, temp, result, mult, divisor;
+ int 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 (progctr)
+ program_counter *progctr;
+{
+ bc_num build;
+ program_counter look_pc;
+ int kdigits, kscale;
+ unsigned char inchar;
+ char *ptr;
+
+ /* Count the digits and get things ready. */
+ look_pc = *progctr;
+ 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 progctr. */
+ inchar = byte(progctr);
+
+ /* Secial cases of 0, 1, and A-F single inputs. */
+ if (kdigits == 1 && kscale == 0)
+ {
+ if (inchar == 0)
+ {
+ push_copy (_zero_);
+ inchar = byte(progctr);
+ return;
+ }
+ if (inchar == 1) {
+ push_copy (_one_);
+ inchar = byte(progctr);
+ return;
+ }
+ if (inchar > 9)
+ {
+ bc_init_num (&build);
+ bc_int2num (&build, inchar);
+ push_num (build);
+ inchar = byte(progctr);
+ 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(progctr);
+ }
+ push_num (build);
+}
+
+
+/* Put the correct value on the stack for C_CODE. Frees TOS num. */
+
+void
+assign (code)
+ char code;
+{
+ bc_free_num (&ex_stack->s_num);
+ if (code)
+ ex_stack->s_num = bc_copy_num (_one_);
+ else
+ ex_stack->s_num = bc_copy_num (_zero_);
+}
+
diff --git a/bc/global.c b/bc/global.c
new file mode 100644
index 0000000..a388a0c
--- /dev/null
+++ b/bc/global.c
@@ -0,0 +1,40 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* global.c: This defines the global variables. */
+
+/* We are global.c ... so define and initialize variables here. */
+
+#define _GLOBAL_C
+
+#include "bcdefs.h"
+
+CONST char *libmath[] =
+#include "libmath.h"
+;
diff --git a/bc/global.h b/bc/global.h
new file mode 100644
index 0000000..706abd0
--- /dev/null
+++ b/bc/global.h
@@ -0,0 +1,155 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* global.h: The global variables for bc. */
+
+/* The current break level's lable. */
+EXTERN int break_label;
+
+/* The current if statement's else label or label after else. */
+EXTERN int if_label;
+
+/* The current for statement label for continuing the loop. */
+EXTERN int continue_label;
+
+/* Next available label number. */
+EXTERN int next_label;
+
+/* Byte code character storage. Used in many places for generation of code. */
+EXTERN char *genstr INIT(NULL);
+EXTERN int genlen INIT(0);
+
+/* Count of characters printed to the output in compile_only mode. */
+EXTERN int out_count;
+
+/* Have we generated any code since the last initialization of the code
+ generator. */
+EXTERN char did_gen;
+
+/* Is this run an interactive execution. (Is stdin a terminal?) */
+EXTERN char interactive INIT(FALSE);
+
+/* Just generate the byte code. -c flag. */
+EXTERN int compile_only INIT(FALSE);
+
+/* Load the standard math functions. -l flag. */
+EXTERN int use_math INIT(FALSE);
+
+/* Give a warning on use of any non-standard feature (non-POSIX). -w flag. */
+EXTERN int warn_not_std INIT(FALSE);
+
+/* Accept POSIX bc only! -s flag. */
+EXTERN int std_only INIT(FALSE);
+
+/* Don't print the banner at start up. -q flag. */
+EXTERN int quiet INIT(FALSE);
+
+/* The list of file names to process. */
+EXTERN file_node *file_names INIT(NULL);
+
+/* The name of the current file being processed. */
+EXTERN char *file_name;
+
+/* Is the current file a named file or standard input? */
+EXTERN char is_std_in;
+
+/* global variables for the bc machine. All will be dynamic in size.*/
+/* Function storage. main is (0) and functions (1-f_count) */
+
+EXTERN bc_function *functions;
+EXTERN char **f_names;
+EXTERN int f_count;
+
+/* Variable stoarge and reverse names. */
+
+EXTERN bc_var **variables;
+EXTERN char **v_names;
+EXTERN int v_count;
+
+/* Array Variable storage and reverse names. */
+
+EXTERN bc_var_array **arrays;
+EXTERN char **a_names;
+EXTERN int a_count;
+
+/* Execution stack. */
+EXTERN estack_rec *ex_stack;
+
+/* Function return stack. */
+EXTERN fstack_rec *fn_stack;
+
+/* Current ibase, obase, scale, and n_history (if needed). */
+EXTERN int i_base;
+EXTERN int o_base;
+EXTERN int scale;
+#if defined(READLINE) || defined(LIBEDIT)
+EXTERN int n_history;
+#endif
+
+#if defined(LIBEDIT)
+/* LIBEDIT data */
+EditLine *edit INIT(NULL);
+History *hist;
+HistEvent histev;
+#endif
+
+/* "Condition code" -- false (0) or true (1) */
+EXTERN char c_code;
+
+/* Records the number of the runtime error. */
+EXTERN char runtime_error;
+
+/* Holds the current location of execution. */
+EXTERN program_counter pc;
+
+/* For POSIX bc, this is just for number output, not strings. */
+EXTERN int out_col;
+
+/* Keeps track of the current number of characters per output line.
+ This includes the \n at the end of the line. */
+EXTERN int line_size;
+
+/* Input Line numbers and other error information. */
+EXTERN int line_no;
+EXTERN int had_error;
+
+/* For larger identifiers, a tree, and how many "storage" locations
+ have been allocated. */
+
+EXTERN int next_array;
+EXTERN int next_func;
+EXTERN int next_var;
+
+EXTERN id_rec *name_tree;
+
+/* For use with getopt. Do not declare them here.*/
+extern int optind;
+
+/* Access to the yy input file. Defined in scan.c. */
+extern FILE *yyin;
diff --git a/bc/libmath.h b/bc/libmath.h
new file mode 100644
index 0000000..63e1acb
--- /dev/null
+++ b/bc/libmath.h
@@ -0,0 +1,46 @@
+{"@iK20:s2:p@r",
+"@iF1,5.6,7,8,9,10,11,12,13,14,15[l0:KA:#Z1:l0:s7:pKA:s0:pl5:C1,0:",
+"s14:pl7:s0:pl14:RN1:l5:0<Z2:1s12:pl5:ns5:pN2:l2:s15:pK6:l15:+",
+"K.44:l5:*+s13:pl5:cS1+s2:pN3:l5:1>Z4:l10:1+s10:pl5:K2:/s5:pl2:",
+"1+s2:pJ3:N4:l13:s2:p1l5:+s14:pl5:s6:p1s8:pK2:s11:pN6:1B7:J5:N8:",
+"l11:i11:pJ6:N7:l6:l5:*s6:l8:l11:*s8:/s9:pl9:0=Z9:l10:0>Z10:N11:",
+"l10:d10:Z12:l14:l14:*s14:pJ11:N12:N10:l15:s2:pl12:Z13:1l14:/R",
+"N13:l14:1/RN9:l14:l9:+s14:pJ8:N5:0R]@r",
+"@iF2,5.7,9,10,11,12,13,14,15[l0:KA:#Z1:l0:s7:pKA:s0:pl5:C2,0:",
+"s14:pl7:s0:pl14:RN1:l5:0{Z2:1K10:l2:^-1/RN2:l2:s15:pK6:l2:+s2:",
+"pK2:s10:p0s11:pN3:l5:K2:}Z4:l10:K2:*s10:pl5:cRs5:pJ3:N4:N5:l5:",
+"K.5:{Z6:l10:K2:*s10:pl5:cRs5:pJ5:N6:l5:1-l5:1+/s13:s14:pl13:l13:",
+"*s12:pK3:s11:pN8:1B9:J7:N10:l11:K2:+s11:pJ8:N9:l13:l12:*s13:l11:",
+"/s9:pl9:0=Z11:l10:l14:*s14:pl15:s2:pl14:1/RN11:l14:l9:+s14:pJ10:N7:",
+"0R]@r",
+"@iF3,5.7,9,11,12,13,16,14,15[l0:KA:#Z1:l0:s7:pKA:s0:pl5:C3,0:",
+"s14:pl7:s0:pl14:RN1:l2:s15:pK1.1:l15:*K2:+s2:p1C4,0:s14:pl5:0",
+"<Z2:1s12:pl5:ns5:pN2:0s2:pl5:l14:/K2:+K4:/s13:pl5:K4:l13:*l14:",
+"*-s5:pl13:K2:%Z3:l5:ns5:pN3:l15:K2:+s2:pl5:s9:s14:pl5:nl5:*s16:",
+"pK3:s11:pN5:1B6:J4:N7:l11:K2:+s11:pJ5:N6:l9:l16:l11:l11:1-*/*",
+"s9:pl9:0=Z8:l15:s2:pl12:Z9:l14:n1/RN9:l14:1/RN8:l14:l9:+s14:p",
+"J7:N4:0R]@r",
+"@iF5,5.7,14,15[l0:KA:#Z1:l0:s7:pKA:s0:pl5:C5,0:s14:pl7:s0:pl14:",
+"RN1:l2:s15:pl2:K1.2:*s2:pl5:1C4,0:K2:*+C3,0:s14:pl15:s2:pl14:",
+"1/R0R]@r",
+"@iF4,5.6,7,9,10,11,12,13,16,14,15[l0:KA:#Z1:l0:s7:pKA:s0:pl5:",
+"C4,0:s14:pl7:s0:pl14:RN1:1s12:pl5:0<Z2:1ns12:pl5:ns5:pN2:l5:1",
+"=Z3:l2:K25:{Z4:K.7853981633974483096156608:l12:/RN4:l2:K40:{Z5:",
+"K.7853981633974483096156608458198757210492:l12:/RN5:l2:K60:{Z6:",
+"K.785398163397448309615660845819875721049292349843776455243736",
+":l12:/RN6:N3:l5:K.2:=Z7:l2:K25:{Z8:K.1973955598498807583700497",
+":l12:/RN8:l2:K40:{Z9:K.1973955598498807583700497651947902934475",
+":l12:/RN9:l2:K60:{Z10:K.197395559849880758370049765194790293447585103787852101517688",
+":l12:/RN10:N7:l2:s15:pl5:K.2:>Z11:l15:K5:+s2:pK.2:C4,0:s6:pN11:",
+"l15:K3:+s2:pN12:l5:K.2:>Z13:l10:1+s10:pl5:K.2:-1l5:K.2:*+/s5:",
+"pJ12:N13:l5:s13:s14:pl5:nl5:*s16:pK3:s11:pN15:1B16:J14:N17:l11:",
+"K2:+s11:pJ15:N16:l13:l16:*s13:l11:/s9:pl9:0=Z18:l15:s2:pl10:l6:",
+"*l14:+l12:/RN18:l14:l9:+s14:pJ17:N14:0R]@r",
+"@iF6,13,5.6,7,8,9,10,11,12,16,14,15[l0:KA:#Z1:l0:s7:pKA:s0:pl13:",
+"l5:C6,00:s14:pl7:s0:pl14:RN1:l2:s15:p0s2:pl13:1/s13:pl13:0<Z2:",
+"l13:ns13:pl13:K2:%1=Z3:1s12:pN3:N2:1s10:pK2:s11:pN5:l11:l13:{",
+"B6:J4:N7:l11:i11:pJ5:N6:l10:l11:*s10:pJ7:N4:K1.5:l15:*s2:pl5:",
+"l13:^K2:l13:^/l10:/s10:p1s9:s14:pl5:nl5:*K4:/s16:pK1.5:l15:*l10:",
+"cL+l10:cS-s2:p1s11:pN9:1B10:J8:N11:l11:i11:pJ9:N10:l9:l16:*l11:",
+"/l13:l11:+/s9:pl9:0=Z12:l15:s2:pl12:Z13:l10:nl14:*1/RN13:l10:",
+"l14:*1/RN12:l14:l9:+s14:pJ11:N8:0R]@r",0}
diff --git a/bc/load.c b/bc/load.c
new file mode 100644
index 0000000..1035198
--- /dev/null
+++ b/bc/load.c
@@ -0,0 +1,351 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* load.c: This code "loads" code into the code segments. */
+
+#include "bcdefs.h"
+#include "proto.h"
+
+/* Load variables. */
+
+program_counter load_adr;
+char load_str;
+char load_const;
+
+/* Initialize the load sequence. */
+void
+init_load ()
+{
+ clear_func(0);
+ load_adr.pc_func = 0;
+ load_adr.pc_addr = 0;
+ load_str = FALSE;
+ load_const = FALSE;
+}
+
+/* addbyte adds one BYTE to the current code segment. */
+void
+addbyte (thebyte)
+ int thebyte;
+{
+ int prog_addr;
+ bc_function *f;
+ char *new_body;
+
+ /* If there was an error, don't continue. */
+ if (had_error) return;
+
+ /* Calculate the segment and offset. */
+ prog_addr = load_adr.pc_addr++;
+ f = &functions[load_adr.pc_func];
+
+ if (prog_addr >= 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 thebyte. */
+ f->f_body[prog_addr] = (char) (thebyte & 0xff);
+ 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)
+ const 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)
+ const char *code;
+{
+ const char *str;
+ long ap_name; /* auto or parameter name. */
+ long label_no;
+ long vaf_name; /* variable, array or function number. */
+ long func;
+ static program_counter save_adr;
+
+ /* Initialize. */
+ str = code;
+
+ /* Scan the code. */
+ while (*str != 0)
+ {
+ /* If there was an error, don't continue. */
+ if (had_error) return;
+
+ if (load_str)
+ {
+ if (*str == '"') load_str = FALSE;
+ addbyte (*str++);
+ }
+ else
+ if (load_const)
+ {
+ if (*str == '\n')
+ str++;
+ else
+ {
+ if (*str == ':')
+ {
+ load_const = FALSE;
+ addbyte (*str++);
+ }
+ else
+ if (*str == '.')
+ addbyte (*str++);
+ else
+ if (*str >= 'A')
+ addbyte (*str++ + 10 - 'A');
+ else
+ addbyte (*str++ - '0');
+ }
+ }
+ else
+ {
+ switch (*str)
+ {
+
+ case '"': /* Starts a string. */
+ load_str = TRUE;
+ break;
+
+ case 'N': /* A label */
+ str++;
+ label_no = long_val (&str);
+ def_label (label_no);
+ break;
+
+ case 'B': /* Branch to label. */
+ case 'J': /* Jump to label. */
+ case 'Z': /* Branch Zero to label. */
+ addbyte(*str++);
+ label_no = long_val (&str);
+ if (label_no > 65535L)
+ { /* Better message? */
+ fprintf (stderr,"Program too big.\n");
+ exit(1);
+ }
+ addbyte ( (char) (label_no & 0xFF));
+ addbyte ( (char) (label_no >> 8));
+ break;
+
+ case 'F': /* A function, get the name and initialize it. */
+ str++;
+ func = long_val (&str);
+ clear_func (func);
+#if DEBUG > 2
+ printf ("Loading function number %d\n", func);
+#endif
+ /* get the parameters */
+ while (*str++ != '.')
+ {
+ if (*str == '.')
+ {
+ str++;
+ break;
+ }
+ if (*str == '*')
+ {
+ str++;
+ ap_name = long_val (&str);
+#if DEBUG > 2
+ printf ("var parameter number %d\n", ap_name);
+#endif
+ functions[(int)func].f_params =
+ nextarg (functions[(int)func].f_params, ap_name,
+ TRUE);
+ }
+ else
+ {
+ ap_name = long_val (&str);
+#if DEBUG > 2
+ printf ("parameter number %d\n", ap_name);
+#endif
+ functions[(int)func].f_params =
+ nextarg (functions[(int)func].f_params, ap_name,
+ FALSE);
+ }
+ }
+
+ /* get the auto vars */
+ while (*str != '[')
+ {
+ if (*str == ',') str++;
+ ap_name = long_val (&str);
+#if DEBUG > 2
+ printf ("auto number %d\n", ap_name);
+#endif
+ functions[(int)func].f_autos =
+ nextarg (functions[(int)func].f_autos, ap_name, FALSE);
+ }
+ save_adr = load_adr;
+ load_adr.pc_func = func;
+ load_adr.pc_addr = 0;
+ break;
+
+ case ']': /* A function end */
+ functions[load_adr.pc_func].f_defined = TRUE;
+ load_adr = save_adr;
+ break;
+
+ case 'C': /* Call a function. */
+ addbyte (*str++);
+ func = long_val (&str);
+ if (func < 128)
+ addbyte ( (char) func);
+ else
+ {
+ addbyte (((func >> 8) & 0xff) | 0x80);
+ addbyte (func & 0xff);
+ }
+ if (*str == ',') str++;
+ while (*str != ':')
+ addbyte (*str++);
+ addbyte (':');
+ break;
+
+ case 'c': /* Call a special function. */
+ addbyte (*str++);
+ addbyte (*str);
+ break;
+
+ case 'K': /* A constant.... may have an "F" in it. */
+ addbyte (*str);
+ load_const = TRUE;
+ break;
+
+ case 'd': /* Decrement. */
+ case 'i': /* Increment. */
+ case 'l': /* Load. */
+ case 's': /* Store. */
+ case 'A': /* Array Increment */
+ case 'M': /* Array Decrement */
+ case 'L': /* Array Load */
+ case 'S': /* Array Store */
+ addbyte (*str++);
+ vaf_name = long_val (&str);
+ if (vaf_name < 128)
+ addbyte (vaf_name);
+ else
+ {
+ addbyte (((vaf_name >> 8) & 0xff) | 0x80);
+ addbyte (vaf_name & 0xff);
+ }
+ break;
+
+ case '@': /* A command! */
+ switch (*(++str))
+ {
+ case 'i':
+ init_load ();
+ break;
+ case 'r':
+ execute ();
+ break;
+ }
+ break;
+
+ case '\n': /* Ignore the newlines */
+ break;
+
+ default: /* Anything else */
+ addbyte (*str);
+ }
+ str++;
+ }
+ }
+}
diff --git a/bc/main.c b/bc/main.c
new file mode 100644
index 0000000..3ae427d
--- /dev/null
+++ b/bc/main.c
@@ -0,0 +1,370 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* main.c: The main program for bc. */
+
+#include "bcdefs.h"
+#include <signal.h>
+#include <errno.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}
+};
+
+
+static void
+usage (const char *progname)
+{
+ printf ("usage: %s [options] [file ...]\n%s%s%s%s%s%s%s", progname,
+ " -h --help print this usage and exit\n",
+ " -i --interactive force interactive mode\n",
+ " -l --mathlib use the predefined math routines\n",
+ " -q --quiet don't print initial banner\n",
+ " -s --standard non-standard bc constructs are errors\n",
+ " -w --warn warn about non-standard bc constructs\n",
+ " -v --version print version information and exit\n");
+}
+
+
+static void
+parse_args (argc, argv)
+ int argc;
+ char **argv;
+{
+ int optch;
+ int long_index;
+ file_node *temp;
+
+ /* Force getopt to initialize. Depends on GNU getopt. */
+ optind = 0;
+
+ /* Parse the command line */
+ while (1)
+ {
+ optch = getopt_long (argc, argv, "chilqswv", long_options, &long_index);
+
+ if (optch == EOF) /* End of arguments. */
+ break;
+
+ switch (optch)
+ {
+ case 0: /* Long option setting a var. */
+ break;
+
+ case 'c': /* compile only */
+ compile_only = TRUE;
+ break;
+
+ case 'h': /* help */
+ usage(argv[0]);
+ exit (0);
+ break;
+
+ case 'i': /* force interactive */
+ interactive = TRUE;
+ break;
+
+ case 'l': /* math lib */
+ use_math = TRUE;
+ break;
+
+ case 'q': /* quiet mode */
+ quiet = TRUE;
+ break;
+
+ case 's': /* Non standard features give errors. */
+ std_only = TRUE;
+ break;
+
+ case 'v': /* Print the version. */
+ show_bc_version ();
+ exit (0);
+ break;
+
+ case 'w': /* Non standard features give warnings. */
+ warn_not_std = TRUE;
+ break;
+
+ default:
+ usage(argv[0]);
+ exit (1);
+ }
+ }
+
+#ifdef QUIET
+ quiet = TRUE;
+#endif
+
+ /* 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;
+ const char *env_argv[30];
+ int env_argc;
+
+ /* Interactive? */
+ if (isatty(0) && isatty(1))
+ interactive = TRUE;
+
+#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 < 3 && line_size != 0)
+ 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");
+
+#if defined(LIBEDIT)
+ if (edit != NULL)
+ el_end(edit);
+#endif
+ 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;
+{
+#ifdef DONTEXIT
+ int save = errno;
+ write (1, "\n(interrupt) use quit to exit.\n", 31);
+ signal (SIGINT, use_quit);
+ errno = save;
+#else
+ write (1, "\n(interrupt) Exiting bc.\n", 26);
+#ifdef READLINE
+ rl_initialize (); /* Clear readline buffer */
+#endif
+#if defined(LIBEDIT)
+ if (edit != NULL)
+ el_end(edit);
+#endif
+ exit(0);
+#endif
+}
diff --git a/bc/number.c b/bc/number.c
new file mode 100644
index 0000000..7a81b2d
--- /dev/null
+++ b/bc/number.c
@@ -0,0 +1,1804 @@
+/* number.c: Implements arbitrary precision numbers. */
+/*
+ Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to:
+
+ The Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1301 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 <stdio.h>
+#include "config.h"
+#include "number.h"
+#include <assert.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ctype.h>
+
+/* Prototypes needed for external utility routines. */
+
+#define bc_rt_warn rt_warn
+#define bc_rt_error rt_error
+#define bc_out_of_memory out_of_memory
+
+_PROTOTYPE(void rt_warn, (const char *mesg ,...));
+_PROTOTYPE(void rt_error, (const char *mesg ,...));
+_PROTOTYPE(void out_of_memory, (void));
+
+/* Storage used for special numbers. */
+bc_num _zero_;
+bc_num _one_;
+bc_num _two_;
+
+static bc_num _bc_Free_list = NULL;
+
+/* new_num allocates a number and sets fields to known values. */
+
+bc_num
+bc_new_num (length, scale)
+ int length, scale;
+{
+ bc_num temp;
+
+ if (_bc_Free_list != NULL) {
+ temp = _bc_Free_list;
+ _bc_Free_list = temp->n_next;
+ } else {
+ temp = (bc_num) malloc (sizeof(bc_struct));
+ if (temp == NULL) bc_out_of_memory ();
+ }
+ temp->n_sign = PLUS;
+ temp->n_len = length;
+ temp->n_scale = scale;
+ temp->n_refs = 1;
+ temp->n_ptr = (char *) malloc (length+scale);
+ if (temp->n_ptr == NULL) bc_out_of_memory();
+ temp->n_value = temp->n_ptr;
+ memset (temp->n_ptr, 0, length+scale);
+ return temp;
+}
+
+/* "Frees" a bc_num NUM. Actually decreases reference count and only
+ frees the storage if reference count is zero. */
+
+void
+bc_free_num (num)
+ bc_num *num;
+{
+ if (*num == NULL) return;
+ (*num)->n_refs--;
+ if ((*num)->n_refs == 0) {
+ if ((*num)->n_ptr)
+ free ((*num)->n_ptr);
+ (*num)->n_next = _bc_Free_list;
+ _bc_Free_list = *num;
+ }
+ *num = NULL;
+}
+
+
+/* Intitialize the number package! */
+
+void
+bc_init_numbers ()
+{
+ _zero_ = bc_new_num (1,0);
+ _one_ = bc_new_num (1,0);
+ _one_->n_value[0] = 1;
+ _two_ = bc_new_num (1,0);
+ _two_->n_value[0] = 2;
+}
+
+
+/* Make a copy of a number! Just increments the reference count! */
+
+bc_num
+bc_copy_num (num)
+ bc_num num;
+{
+ num->n_refs++;
+ return num;
+}
+
+
+/* Initialize a number NUM by making it a copy of zero. */
+
+void
+bc_init_num (num)
+ bc_num *num;
+{
+ *num = bc_copy_num (_zero_);
+}
+
+/* For many things, we may have leading zeros in a number NUM.
+ _bc_rm_leading_zeros just moves the data "value" pointer to the
+ correct place and adjusts the length. */
+
+static void
+_bc_rm_leading_zeros (num)
+ bc_num num;
+{
+ /* We can move n_value to point to the first non zero digit! */
+ while (*num->n_value == 0 && num->n_len > 1) {
+ num->n_value++;
+ num->n_len--;
+ }
+}
+
+
+/* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less
+ than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just
+ compare the magnitudes. */
+
+static int
+_bc_do_compare (n1, n2, use_sign, ignore_last)
+ bc_num n1, n2;
+ int use_sign;
+ int ignore_last;
+{
+ char *n1ptr, *n2ptr;
+ int count;
+
+ /* First, compare signs. */
+ if (use_sign && n1->n_sign != n2->n_sign)
+ {
+ if (n1->n_sign == PLUS)
+ return (1); /* Positive N1 > Negative N2 */
+ else
+ return (-1); /* Negative N1 < Positive N1 */
+ }
+
+ /* Now compare the magnitude. */
+ if (n1->n_len != n2->n_len)
+ {
+ if (n1->n_len > n2->n_len)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ else
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* If we get here, they have the same number of integer digits.
+ check the integer part and the equal length part of the fraction. */
+ count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
+ n1ptr = n1->n_value;
+ n2ptr = n2->n_value;
+
+ while ((count > 0) && (*n1ptr == *n2ptr))
+ {
+ n1ptr++;
+ n2ptr++;
+ count--;
+ }
+ if (ignore_last && count == 1 && n1->n_scale == n2->n_scale)
+ return (0);
+ if (count != 0)
+ {
+ if (*n1ptr > *n2ptr)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ else
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* They are equal up to the last part of the equal part of the fraction. */
+ if (n1->n_scale != n2->n_scale)
+ {
+ if (n1->n_scale > n2->n_scale)
+ {
+ for (count = n1->n_scale-n2->n_scale; count>0; count--)
+ if (*n1ptr++ != 0)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ }
+ else
+ {
+ for (count = n2->n_scale-n1->n_scale; count>0; count--)
+ if (*n2ptr++ != 0)
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+ }
+
+ /* They must be equal! */
+ return (0);
+}
+
+
+/* This is the "user callable" routine to compare numbers N1 and N2. */
+
+int
+bc_compare (n1, n2)
+ bc_num n1, n2;
+{
+ return _bc_do_compare (n1, n2, TRUE, FALSE);
+}
+
+/* In some places we need to check if the number is negative. */
+
+char
+bc_is_neg (num)
+ bc_num num;
+{
+ return num->n_sign == MINUS;
+}
+
+/* In some places we need to check if the number NUM is zero. */
+
+char
+bc_is_zero (num)
+ bc_num num;
+{
+ int count;
+ char *nptr;
+
+ /* Quick check. */
+ if (num == _zero_) return TRUE;
+
+ /* Initialize */
+ count = num->n_len + num->n_scale;
+ nptr = num->n_value;
+
+ /* The check */
+ while ((count > 0) && (*nptr++ == 0)) count--;
+
+ if (count != 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+/* In some places we need to check if the number NUM is almost zero.
+ Specifically, all but the last digit is 0 and the last digit is 1.
+ Last digit is defined by scale. */
+
+char
+bc_is_near_zero (num, scale)
+ bc_num num;
+ int scale;
+{
+ int count;
+ char *nptr;
+
+ /* Error checking */
+ if (scale > num->n_scale)
+ scale = num->n_scale;
+
+ /* Initialize */
+ count = num->n_len + scale;
+ nptr = num->n_value;
+
+ /* The check */
+ while ((count > 0) && (*nptr++ == 0)) count--;
+
+ if (count != 0 && (count != 1 || *--nptr != 1))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/* Perform addition: N1 is added to N2 and the value is
+ returned. The signs of N1 and N2 are ignored.
+ SCALE_MIN is to set the minimum scale of the result. */
+
+static bc_num
+_bc_do_add (n1, n2, scale_min)
+ bc_num n1, n2;
+ int scale_min;
+{
+ bc_num sum;
+ int sum_scale, sum_digits;
+ char *n1ptr, *n2ptr, *sumptr;
+ int carry, n1bytes, n2bytes;
+ int count;
+
+ /* Prepare sum. */
+ sum_scale = MAX (n1->n_scale, n2->n_scale);
+ sum_digits = MAX (n1->n_len, n2->n_len) + 1;
+ sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
+
+ /* Zero extra digits made by scale_min. */
+ if (scale_min > sum_scale)
+ {
+ sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
+ for (count = scale_min - sum_scale; count > 0; count--)
+ *sumptr++ = 0;
+ }
+
+ /* Start with the fraction part. Initialize the pointers. */
+ n1bytes = n1->n_scale;
+ n2bytes = n2->n_scale;
+ n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
+ n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
+ sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
+
+ /* Add the fraction part. First copy the longer fraction.*/
+ if (n1bytes != n2bytes)
+ {
+ if (n1bytes > n2bytes)
+ while (n1bytes>n2bytes)
+ { *sumptr-- = *n1ptr--; n1bytes--;}
+ else
+ while (n2bytes>n1bytes)
+ { *sumptr-- = *n2ptr--; n2bytes--;}
+ }
+
+ /* Now add the remaining fraction part and equal size integer parts. */
+ n1bytes += n1->n_len;
+ n2bytes += n2->n_len;
+ carry = 0;
+ while ((n1bytes > 0) && (n2bytes > 0))
+ {
+ *sumptr = *n1ptr-- + *n2ptr-- + carry;
+ if (*sumptr > (BASE-1))
+ {
+ carry = 1;
+ *sumptr -= BASE;
+ }
+ else
+ carry = 0;
+ sumptr--;
+ n1bytes--;
+ n2bytes--;
+ }
+
+ /* Now add carry the longer integer part. */
+ if (n1bytes == 0)
+ { n1bytes = n2bytes; n1ptr = n2ptr; }
+ while (n1bytes-- > 0)
+ {
+ *sumptr = *n1ptr-- + carry;
+ if (*sumptr > (BASE-1))
+ {
+ carry = 1;
+ *sumptr -= BASE;
+ }
+ else
+ carry = 0;
+ sumptr--;
+ }
+
+ /* Set final carry. */
+ if (carry == 1)
+ *sumptr += 1;
+
+ /* Adjust sum and return. */
+ _bc_rm_leading_zeros (sum);
+ return sum;
+}
+
+
+/* Perform subtraction: N2 is subtracted from N1 and the value is
+ returned. The signs of N1 and N2 are ignored. Also, N1 is
+ assumed to be larger than N2. SCALE_MIN is the minimum scale
+ of the result. */
+
+static bc_num
+_bc_do_sub (n1, n2, scale_min)
+ bc_num n1, n2;
+ int scale_min;
+{
+ bc_num diff;
+ int diff_scale, diff_len;
+ int min_scale, min_len;
+ char *n1ptr, *n2ptr, *diffptr;
+ int borrow, count, val;
+
+ /* Allocate temporary storage. */
+ diff_len = MAX (n1->n_len, n2->n_len);
+ diff_scale = MAX (n1->n_scale, n2->n_scale);
+ min_len = MIN (n1->n_len, n2->n_len);
+ min_scale = MIN (n1->n_scale, n2->n_scale);
+ diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
+
+ /* Zero extra digits made by scale_min. */
+ if (scale_min > diff_scale)
+ {
+ diffptr = (char *) (diff->n_value + diff_len + diff_scale);
+ for (count = scale_min - diff_scale; count > 0; count--)
+ *diffptr++ = 0;
+ }
+
+ /* Initialize the subtract. */
+ n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
+ n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
+ diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
+
+ /* Subtract the numbers. */
+ borrow = 0;
+
+ /* Take care of the longer scaled number. */
+ if (n1->n_scale != min_scale)
+ {
+ /* n1 has the longer scale */
+ for (count = n1->n_scale - min_scale; count > 0; count--)
+ *diffptr-- = *n1ptr--;
+ }
+ else
+ {
+ /* n2 has the longer scale */
+ for (count = n2->n_scale - min_scale; count > 0; count--)
+ {
+ val = - *n2ptr-- - borrow;
+ if (val < 0)
+ {
+ val += BASE;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+ }
+
+ /* Now do the equal length scale and integer parts. */
+
+ for (count = 0; count < min_len + min_scale; count++)
+ {
+ val = *n1ptr-- - *n2ptr-- - borrow;
+ if (val < 0)
+ {
+ val += BASE;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+
+ /* If n1 has more digits then n2, we now do that subtract. */
+ if (diff_len != min_len)
+ {
+ for (count = diff_len - min_len; count > 0; count--)
+ {
+ val = *n1ptr-- - borrow;
+ if (val < 0)
+ {
+ val += BASE;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+ }
+
+ /* Clean up and return. */
+ _bc_rm_leading_zeros (diff);
+ return diff;
+}
+
+
+/* Here is the full subtract routine that takes care of negative numbers.
+ N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN
+ is the minimum scale for the result. */
+
+void
+bc_sub (n1, n2, result, scale_min)
+ bc_num n1, n2, *result;
+ int scale_min;
+{
+ bc_num diff = NULL;
+ int cmp_res;
+ int res_scale;
+
+ if (n1->n_sign != n2->n_sign)
+ {
+ diff = _bc_do_add (n1, n2, scale_min);
+ diff->n_sign = n1->n_sign;
+ }
+ else
+ {
+ /* subtraction must be done. */
+ /* Compare magnitudes. */
+ cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE);
+ switch (cmp_res)
+ {
+ case -1:
+ /* n1 is less than n2, subtract n1 from n2. */
+ diff = _bc_do_sub (n2, n1, scale_min);
+ diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
+ break;
+ case 0:
+ /* They are equal! return zero! */
+ res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
+ diff = bc_new_num (1, res_scale);
+ memset (diff->n_value, 0, res_scale+1);
+ break;
+ case 1:
+ /* n2 is less than n1, subtract n2 from n1. */
+ diff = _bc_do_sub (n1, n2, scale_min);
+ diff->n_sign = n1->n_sign;
+ break;
+ }
+ }
+
+ /* Clean up and return. */
+ bc_free_num (result);
+ *result = diff;
+}
+
+
+/* Here is the full add routine that takes care of negative numbers.
+ N1 is added to N2 and the result placed into RESULT. SCALE_MIN
+ is the minimum scale for the result. */
+
+void
+bc_add (n1, n2, result, scale_min)
+ bc_num n1, n2, *result;
+ int scale_min;
+{
+ bc_num sum = NULL;
+ int cmp_res;
+ int res_scale;
+
+ if (n1->n_sign == n2->n_sign)
+ {
+ sum = _bc_do_add (n1, n2, scale_min);
+ sum->n_sign = n1->n_sign;
+ }
+ else
+ {
+ /* subtraction must be done. */
+ cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
+ switch (cmp_res)
+ {
+ case -1:
+ /* n1 is less than n2, subtract n1 from n2. */
+ sum = _bc_do_sub (n2, n1, scale_min);
+ sum->n_sign = n2->n_sign;
+ break;
+ case 0:
+ /* They are equal! return zero with the correct scale! */
+ res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
+ sum = bc_new_num (1, res_scale);
+ memset (sum->n_value, 0, res_scale+1);
+ break;
+ case 1:
+ /* n2 is less than n1, subtract n2 from n1. */
+ sum = _bc_do_sub (n1, n2, scale_min);
+ sum->n_sign = n1->n_sign;
+ }
+ }
+
+ /* Clean up and return. */
+ bc_free_num (result);
+ *result = sum;
+}
+
+/* Recursive vs non-recursive multiply crossover ranges. */
+#if defined(MULDIGITS)
+#include "muldigits.h"
+#else
+#define MUL_BASE_DIGITS 80
+#endif
+
+int mul_base_digits = MUL_BASE_DIGITS;
+#define MUL_SMALL_DIGITS mul_base_digits/4
+
+/* Multiply utility routines */
+
+static bc_num
+new_sub_num (length, scale, value)
+ int length, scale;
+ char *value;
+{
+ bc_num temp;
+
+ if (_bc_Free_list != NULL) {
+ temp = _bc_Free_list;
+ _bc_Free_list = temp->n_next;
+ } else {
+ temp = (bc_num) malloc (sizeof(bc_struct));
+ if (temp == NULL) bc_out_of_memory ();
+ }
+ temp->n_sign = PLUS;
+ temp->n_len = length;
+ temp->n_scale = scale;
+ temp->n_refs = 1;
+ temp->n_ptr = NULL;
+ temp->n_value = value;
+ return temp;
+}
+
+static void
+_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod)
+{
+ char *n1ptr, *n2ptr, *pvptr;
+ char *n1end, *n2end; /* To the end of n1 and n2. */
+ int indx, sum, prodlen;
+
+ prodlen = n1len+n2len+1;
+
+ *prod = bc_new_num (prodlen, 0);
+
+ n1end = (char *) (n1->n_value + n1len - 1);
+ n2end = (char *) (n2->n_value + n2len - 1);
+ pvptr = (char *) ((*prod)->n_value + prodlen - 1);
+ sum = 0;
+
+ /* Here is the loop... */
+ for (indx = 0; indx < prodlen-1; indx++)
+ {
+ n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
+ n2ptr = (char *) (n2end - MIN(indx, n2len-1));
+ while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
+ sum += *n1ptr-- * *n2ptr++;
+ *pvptr-- = sum % BASE;
+ sum = sum / BASE;
+ }
+ *pvptr = sum;
+}
+
+
+/* A special adder/subtractor for the recursive divide and conquer
+ multiply algorithm. Note: if sub is called, accum must
+ be larger that what is being subtracted. Also, accum and val
+ must have n_scale = 0. (e.g. they must look like integers. *) */
+static void
+_bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
+{
+ signed char *accp, *valp;
+ int count, carry;
+
+ count = val->n_len;
+ if (val->n_value[0] == 0)
+ count--;
+ assert (accum->n_len+accum->n_scale >= shift+count);
+
+ /* Set up pointers and others */
+ accp = (signed char *)(accum->n_value +
+ accum->n_len + accum->n_scale - shift - 1);
+ valp = (signed char *)(val->n_value + val->n_len - 1);
+ carry = 0;
+
+ if (sub) {
+ /* Subtraction, carry is really borrow. */
+ while (count--) {
+ *accp -= *valp-- + carry;
+ if (*accp < 0) {
+ carry = 1;
+ *accp-- += BASE;
+ } else {
+ carry = 0;
+ accp--;
+ }
+ }
+ while (carry) {
+ *accp -= carry;
+ if (*accp < 0)
+ *accp-- += BASE;
+ else
+ carry = 0;
+ }
+ } else {
+ /* Addition */
+ while (count--) {
+ *accp += *valp-- + carry;
+ if (*accp > (BASE-1)) {
+ carry = 1;
+ *accp-- -= BASE;
+ } else {
+ carry = 0;
+ accp--;
+ }
+ }
+ while (carry) {
+ *accp += carry;
+ if (*accp > (BASE-1))
+ *accp-- -= BASE;
+ else
+ carry = 0;
+ }
+ }
+}
+
+/* Recursive divide and conquer multiply algorithm.
+ Based on
+ Let u = u0 + u1*(b^n)
+ Let v = v0 + v1*(b^n)
+ Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0
+
+ B is the base of storage, number of digits in u1,u0 close to equal.
+*/
+static void
+_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod)
+{
+ bc_num u0, u1, v0, v1;
+ int u0len, v0len;
+ bc_num m1, m2, m3, d1, d2;
+ int n, prodlen, m1zero;
+ int d1len, d2len;
+
+ /* Base case? */
+ if ((ulen+vlen) < mul_base_digits
+ || ulen < MUL_SMALL_DIGITS
+ || vlen < MUL_SMALL_DIGITS ) {
+ _bc_simp_mul (u, ulen, v, vlen, prod);
+ return;
+ }
+
+ /* Calculate n -- the u and v split point in digits. */
+ n = (MAX(ulen, vlen)+1) / 2;
+
+ /* Split u and v. */
+ if (ulen < n) {
+ u1 = bc_copy_num (_zero_);
+ u0 = new_sub_num (ulen,0, u->n_value);
+ } else {
+ u1 = new_sub_num (ulen-n, 0, u->n_value);
+ u0 = new_sub_num (n, 0, u->n_value+ulen-n);
+ }
+ if (vlen < n) {
+ v1 = bc_copy_num (_zero_);
+ v0 = new_sub_num (vlen,0, v->n_value);
+ } else {
+ v1 = new_sub_num (vlen-n, 0, v->n_value);
+ v0 = new_sub_num (n, 0, v->n_value+vlen-n);
+ }
+ _bc_rm_leading_zeros (u1);
+ _bc_rm_leading_zeros (u0);
+ u0len = u0->n_len;
+ _bc_rm_leading_zeros (v1);
+ _bc_rm_leading_zeros (v0);
+ v0len = v0->n_len;
+
+ m1zero = bc_is_zero(u1) || bc_is_zero(v1);
+
+ /* Calculate sub results ... */
+
+ bc_init_num(&d1);
+ bc_init_num(&d2);
+ bc_sub (u1, u0, &d1, 0);
+ d1len = d1->n_len;
+ bc_sub (v0, v1, &d2, 0);
+ d2len = d2->n_len;
+
+
+ /* Do recursive multiplies and shifted adds. */
+ if (m1zero)
+ m1 = bc_copy_num (_zero_);
+ else
+ _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1);
+
+ if (bc_is_zero(d1) || bc_is_zero(d2))
+ m2 = bc_copy_num (_zero_);
+ else
+ _bc_rec_mul (d1, d1len, d2, d2len, &m2);
+
+ if (bc_is_zero(u0) || bc_is_zero(v0))
+ m3 = bc_copy_num (_zero_);
+ else
+ _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3);
+
+ /* Initialize product */
+ prodlen = ulen+vlen+1;
+ *prod = bc_new_num(prodlen, 0);
+
+ if (!m1zero) {
+ _bc_shift_addsub (*prod, m1, 2*n, 0);
+ _bc_shift_addsub (*prod, m1, n, 0);
+ }
+ _bc_shift_addsub (*prod, m3, n, 0);
+ _bc_shift_addsub (*prod, m3, 0, 0);
+ _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
+
+ /* Now clean up! */
+ bc_free_num (&u1);
+ bc_free_num (&u0);
+ bc_free_num (&v1);
+ bc_free_num (&m1);
+ bc_free_num (&v0);
+ bc_free_num (&m2);
+ bc_free_num (&m3);
+ bc_free_num (&d1);
+ bc_free_num (&d2);
+}
+
+/* The multiply routine. N2 times N1 is put int PROD with the scale of
+ the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
+ */
+
+void
+bc_multiply (n1, n2, prod, scale)
+ bc_num n1, n2, *prod;
+ int scale;
+{
+ bc_num pval;
+ int len1, len2;
+ int full_scale, prod_scale;
+
+ /* Initialize things. */
+ len1 = n1->n_len + n1->n_scale;
+ len2 = n2->n_len + n2->n_scale;
+ full_scale = n1->n_scale + n2->n_scale;
+ prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
+
+ /* Do the multiply */
+ _bc_rec_mul (n1, len1, n2, len2, &pval);
+
+ /* Assign to prod and clean up the number. */
+ pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
+ pval->n_value = pval->n_ptr;
+ pval->n_len = len2 + len1 + 1 - full_scale;
+ pval->n_scale = prod_scale;
+ _bc_rm_leading_zeros (pval);
+ if (bc_is_zero (pval))
+ pval->n_sign = PLUS;
+ bc_free_num (prod);
+ *prod = pval;
+}
+
+/* Some utility routines for the divide: First a one digit multiply.
+ NUM (with SIZE digits) is multiplied by DIGIT and the result is
+ placed into RESULT. It is written so that NUM and RESULT can be
+ the same pointers. */
+
+static void
+_one_mult (num, size, digit, result)
+ unsigned char *num;
+ int size, digit;
+ unsigned char *result;
+{
+ int carry, value;
+ unsigned char *nptr, *rptr;
+
+ if (digit == 0)
+ memset (result, 0, size);
+ else
+ {
+ if (digit == 1)
+ memcpy (result, num, size);
+ else
+ {
+ /* Initialize */
+ nptr = (unsigned char *) (num+size-1);
+ rptr = (unsigned char *) (result+size-1);
+ carry = 0;
+
+ while (size-- > 0)
+ {
+ value = *nptr-- * digit + carry;
+ *rptr-- = value % BASE;
+ carry = value / BASE;
+ }
+
+ if (carry != 0) *rptr = carry;
+ }
+ }
+}
+
+
+/* The full division routine. This computes N1 / N2. It returns
+ 0 if the division is ok and the result is in QUOT. The number of
+ digits after the decimal point is SCALE. It returns -1 if division
+ by zero is tried. The algorithm is found in Knuth Vol 2. p237. */
+
+int
+bc_divide (n1, n2, quot, scale)
+ bc_num n1, n2, *quot;
+ int scale;
+{
+ bc_num qval;
+ unsigned char *num1, *num2;
+ unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
+ int scale1, val;
+ unsigned int len1, len2, scale2, qdigits, extra, count;
+ unsigned int qdig, qguess, borrow, carry;
+ unsigned char *mval;
+ char zero;
+ unsigned int norm;
+
+ /* Test for divide by zero. */
+ if (bc_is_zero (n2)) return -1;
+
+ /* Test for divide by 1. If it is we must truncate. */
+ if (n2->n_scale == 0)
+ {
+ if (n2->n_len == 1 && *n2->n_value == 1)
+ {
+ qval = bc_new_num (n1->n_len, scale);
+ qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
+ memset (&qval->n_value[n1->n_len],0,scale);
+ memcpy (qval->n_value, n1->n_value,
+ n1->n_len + MIN(n1->n_scale,scale));
+ bc_free_num (quot);
+ *quot = qval;
+ }
+ }
+
+ /* Set up the divide. Move the decimal point on n1 by n2's scale.
+ Remember, zeros on the end of num2 are wasted effort for dividing. */
+ scale2 = n2->n_scale;
+ n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
+ while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
+
+ len1 = n1->n_len + scale2;
+ scale1 = n1->n_scale - scale2;
+ if (scale1 < scale)
+ extra = scale - scale1;
+ else
+ extra = 0;
+ num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2);
+ if (num1 == NULL) bc_out_of_memory();
+ memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
+ memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
+
+ len2 = n2->n_len + scale2;
+ num2 = (unsigned char *) malloc (len2+1);
+ if (num2 == NULL) bc_out_of_memory();
+ memcpy (num2, n2->n_value, len2);
+ *(num2+len2) = 0;
+ n2ptr = num2;
+ while (*n2ptr == 0)
+ {
+ n2ptr++;
+ len2--;
+ }
+
+ /* Calculate the number of quotient digits. */
+ if (len2 > len1+scale)
+ {
+ qdigits = scale+1;
+ zero = TRUE;
+ }
+ else
+ {
+ zero = FALSE;
+ if (len2>len1)
+ qdigits = scale+1; /* One for the zero integer part. */
+ else
+ qdigits = len1-len2+scale+1;
+ }
+
+ /* Allocate and zero the storage for the quotient. */
+ qval = bc_new_num (qdigits-scale,scale);
+ memset (qval->n_value, 0, qdigits);
+
+ /* Allocate storage for the temporary storage mval. */
+ mval = (unsigned char *) malloc (len2+1);
+ if (mval == NULL) bc_out_of_memory ();
+
+ /* Now for the full divide algorithm. */
+ if (!zero)
+ {
+ /* Normalize */
+ norm = 10 / ((int)*n2ptr + 1);
+ if (norm != 1)
+ {
+ _one_mult (num1, len1+scale1+extra+1, norm, num1);
+ _one_mult (n2ptr, len2, norm, n2ptr);
+ }
+
+ /* Initialize divide loop. */
+ qdig = 0;
+ if (len2 > len1)
+ qptr = (unsigned char *) qval->n_value+len2-len1;
+ else
+ qptr = (unsigned char *) qval->n_value;
+
+ /* Loop */
+ while (qdig <= len1+scale-len2)
+ {
+ /* Calculate the quotient digit guess. */
+ if (*n2ptr == num1[qdig])
+ qguess = 9;
+ else
+ qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
+
+ /* Test qguess. */
+ if (n2ptr[1]*qguess >
+ (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ + num1[qdig+2])
+ {
+ qguess--;
+ /* And again. */
+ if (n2ptr[1]*qguess >
+ (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ + num1[qdig+2])
+ qguess--;
+ }
+
+ /* Multiply and subtract. */
+ borrow = 0;
+ if (qguess != 0)
+ {
+ *mval = 0;
+ _one_mult (n2ptr, len2, qguess, mval+1);
+ ptr1 = (unsigned char *) num1+qdig+len2;
+ ptr2 = (unsigned char *) mval+len2;
+ for (count = 0; count < len2+1; count++)
+ {
+ val = (int) *ptr1 - (int) *ptr2-- - borrow;
+ if (val < 0)
+ {
+ val += 10;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *ptr1-- = val;
+ }
+ }
+
+ /* Test for negative result. */
+ if (borrow == 1)
+ {
+ qguess--;
+ ptr1 = (unsigned char *) num1+qdig+len2;
+ ptr2 = (unsigned char *) n2ptr+len2-1;
+ carry = 0;
+ for (count = 0; count < len2; count++)
+ {
+ val = (int) *ptr1 + (int) *ptr2-- + carry;
+ if (val > 9)
+ {
+ val -= 10;
+ carry = 1;
+ }
+ else
+ carry = 0;
+ *ptr1-- = val;
+ }
+ if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
+ }
+
+ /* We now know the quotient digit. */
+ *qptr++ = qguess;
+ qdig++;
+ }
+ }
+
+ /* Clean up and return the number. */
+ qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
+ if (bc_is_zero (qval)) qval->n_sign = PLUS;
+ _bc_rm_leading_zeros (qval);
+ bc_free_num (quot);
+ *quot = qval;
+
+ /* Clean up temporary storage. */
+ free (mval);
+ free (num1);
+ free (num2);
+
+ return 0; /* Everything is OK. */
+}
+
+
+/* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and
+ NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT
+ is NULL then that store will be omitted.
+ */
+
+int
+bc_divmod (num1, num2, quot, rem, scale)
+ bc_num num1, num2, *quot, *rem;
+ int scale;
+{
+ bc_num quotient = NULL;
+ bc_num temp;
+ int rscale;
+
+ /* Check for correct numbers. */
+ if (bc_is_zero (num2)) return -1;
+
+ /* Calculate final scale. */
+ rscale = MAX (num1->n_scale, num2->n_scale+scale);
+ bc_init_num(&temp);
+
+ /* Calculate it. */
+ bc_divide (num1, num2, &temp, scale);
+ if (quot)
+ quotient = bc_copy_num (temp);
+ bc_multiply (temp, num2, &temp, rscale);
+ bc_sub (num1, temp, rem, rscale);
+ bc_free_num (&temp);
+
+ if (quot)
+ {
+ bc_free_num (quot);
+ *quot = quotient;
+ }
+
+ return 0; /* Everything is OK. */
+}
+
+
+/* Modulo for numbers. This computes NUM1 % NUM2 and puts the
+ result in RESULT. */
+
+int
+bc_modulo (num1, num2, result, scale)
+ bc_num num1, num2, *result;
+ int scale;
+{
+ return bc_divmod (num1, num2, NULL, result, scale);
+}
+
+/* Raise BASE to the EXPO power, reduced modulo MOD. The result is
+ placed in RESULT. If a EXPO is not an integer,
+ only the integer part is used. */
+
+int
+bc_raisemod (base, expo, mod, result, scale)
+ bc_num base, expo, mod, *result;
+ int scale;
+{
+ bc_num power, exponent, parity, temp;
+ int rscale;
+
+ /* Check for correct numbers. */
+ if (bc_is_zero(mod)) return -1;
+ if (bc_is_neg(expo)) return -1;
+
+ /* Set initial values. */
+ power = bc_copy_num (base);
+ exponent = bc_copy_num (expo);
+ temp = bc_copy_num (_one_);
+ bc_init_num(&parity);
+
+ /* Check the base for scale digits. */
+ if (base->n_scale != 0)
+ bc_rt_warn ("non-zero scale in base");
+
+ /* Check the exponent for scale digits. */
+ if (exponent->n_scale != 0)
+ {
+ bc_rt_warn ("non-zero scale in exponent");
+ bc_divide (exponent, _one_, &exponent, 0); /*truncate */
+ }
+
+ /* Check the modulus for scale digits. */
+ if (mod->n_scale != 0)
+ bc_rt_warn ("non-zero scale in modulus");
+
+ /* Do the calculation. */
+ rscale = MAX(scale, base->n_scale);
+ while ( !bc_is_zero(exponent) )
+ {
+ (void) bc_divmod (exponent, _two_, &exponent, &parity, 0);
+ if ( !bc_is_zero(parity) )
+ {
+ bc_multiply (temp, power, &temp, rscale);
+ (void) bc_modulo (temp, mod, &temp, scale);
+ }
+
+ bc_multiply (power, power, &power, rscale);
+ (void) bc_modulo (power, mod, &power, scale);
+ }
+
+ /* Assign the value. */
+ bc_free_num (&power);
+ bc_free_num (&exponent);
+ bc_free_num (result);
+ *result = temp;
+ return 0; /* Everything is OK. */
+}
+
+/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
+ Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
+ only the integer part is used. */
+
+void
+bc_raise (num1, num2, result, scale)
+ bc_num num1, num2, *result;
+ int scale;
+{
+ bc_num temp, power;
+ long exponent;
+ int rscale;
+ int pwrscale;
+ int calcscale;
+ char neg;
+
+ /* Check the exponent for scale digits and convert to a long. */
+ if (num2->n_scale != 0)
+ bc_rt_warn ("non-zero scale in exponent");
+ exponent = bc_num2long (num2);
+ if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0))
+ bc_rt_error ("exponent too large in raise");
+
+ /* Special case if exponent is a zero. */
+ if (exponent == 0)
+ {
+ bc_free_num (result);
+ *result = bc_copy_num (_one_);
+ return;
+ }
+
+ /* Other initializations. */
+ if (exponent < 0)
+ {
+ neg = TRUE;
+ exponent = -exponent;
+ rscale = scale;
+ }
+ else
+ {
+ neg = FALSE;
+ rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
+ }
+
+ /* Set initial value of temp. */
+ power = bc_copy_num (num1);
+ pwrscale = num1->n_scale;
+ while ((exponent & 1) == 0)
+ {
+ pwrscale = 2*pwrscale;
+ bc_multiply (power, power, &power, pwrscale);
+ exponent = exponent >> 1;
+ }
+ temp = bc_copy_num (power);
+ calcscale = pwrscale;
+ exponent = exponent >> 1;
+
+ /* Do the calculation. */
+ while (exponent > 0)
+ {
+ pwrscale = 2*pwrscale;
+ bc_multiply (power, power, &power, pwrscale);
+ if ((exponent & 1) == 1) {
+ calcscale = pwrscale + calcscale;
+ bc_multiply (temp, power, &temp, calcscale);
+ }
+ exponent = exponent >> 1;
+ }
+
+ /* Assign the value. */
+ if (neg)
+ {
+ bc_divide (_one_, temp, result, rscale);
+ bc_free_num (&temp);
+ }
+ else
+ {
+ bc_free_num (result);
+ *result = temp;
+ if ((*result)->n_scale > rscale)
+ (*result)->n_scale = rscale;
+ }
+ bc_free_num (&power);
+}
+
+/* Take the square root NUM and return it in NUM with SCALE digits
+ after the decimal place. */
+
+int
+bc_sqrt (num, scale)
+ bc_num *num;
+ int scale;
+{
+ int rscale, cmp_res, done;
+ int cscale;
+ bc_num guess, guess1, point5, diff;
+
+ /* Initial checks. */
+ cmp_res = bc_compare (*num, _zero_);
+ if (cmp_res < 0)
+ return 0; /* error */
+ else
+ {
+ if (cmp_res == 0)
+ {
+ bc_free_num (num);
+ *num = bc_copy_num (_zero_);
+ return 1;
+ }
+ }
+ cmp_res = bc_compare (*num, _one_);
+ if (cmp_res == 0)
+ {
+ bc_free_num (num);
+ *num = bc_copy_num (_one_);
+ return 1;
+ }
+
+ /* Initialize the variables. */
+ rscale = MAX (scale, (*num)->n_scale);
+ bc_init_num(&guess);
+ bc_init_num(&guess1);
+ bc_init_num(&diff);
+ point5 = bc_new_num (1,1);
+ point5->n_value[1] = 5;
+
+
+ /* Calculate the initial guess. */
+ if (cmp_res < 0)
+ {
+ /* The number is between 0 and 1. Guess should start at 1. */
+ guess = bc_copy_num (_one_);
+ cscale = (*num)->n_scale;
+ }
+ else
+ {
+ /* The number is greater than 1. Guess should start at 10^(exp/2). */
+ bc_int2num (&guess,10);
+
+ bc_int2num (&guess1,(*num)->n_len);
+ bc_multiply (guess1, point5, &guess1, 0);
+ guess1->n_scale = 0;
+ bc_raise (guess, guess1, &guess, 0);
+ bc_free_num (&guess1);
+ cscale = 3;
+ }
+
+ /* Find the square root using Newton's algorithm. */
+ done = FALSE;
+ while (!done)
+ {
+ bc_free_num (&guess1);
+ guess1 = bc_copy_num (guess);
+ bc_divide (*num, guess, &guess, cscale);
+ bc_add (guess, guess1, &guess, 0);
+ bc_multiply (guess, point5, &guess, cscale);
+ bc_sub (guess, guess1, &diff, cscale+1);
+ if (bc_is_near_zero (diff, cscale))
+ {
+ if (cscale < rscale+1)
+ cscale = MIN (cscale*3, rscale+1);
+ else
+ done = TRUE;
+ }
+ }
+
+ /* Assign the number and clean up. */
+ bc_free_num (num);
+ bc_divide (guess,_one_,num,rscale);
+ bc_free_num (&guess);
+ bc_free_num (&guess1);
+ bc_free_num (&point5);
+ bc_free_num (&diff);
+ return 1;
+}
+
+
+/* The following routines provide output for bcd numbers package
+ using the rules of POSIX bc for output. */
+
+/* This structure is used for saving digits in the conversion process. */
+typedef struct stk_rec {
+ long digit;
+ struct stk_rec *next;
+} stk_rec;
+
+/* The reference string for digits. */
+static char ref_str[] = "0123456789ABCDEF";
+
+
+/* A special output routine for "multi-character digits." Exactly
+ SIZE characters must be output for the value VAL. If SPACE is
+ non-zero, we must output one space before the number. OUT_CHAR
+ is the actual routine for writing the characters. */
+
+void
+bc_out_long (val, size, space, out_char)
+ long val;
+ int size, space;
+#ifdef __STDC__
+ void (*out_char)(int);
+#else
+ void (*out_char)();
+#endif
+{
+ char digits[40];
+ int len, ix;
+
+ if (space) (*out_char) (' ');
+ sprintf (digits, "%ld", val);
+ len = strlen (digits);
+ while (size > len)
+ {
+ (*out_char) ('0');
+ size--;
+ }
+ for (ix=0; ix < len; ix++)
+ (*out_char) (digits[ix]);
+}
+
+/* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR
+ as the routine to do the actual output of the characters. */
+
+void
+bc_out_num (num, o_base, out_char, leading_zero)
+ bc_num num;
+ int o_base;
+#ifdef __STDC__
+ void (*out_char)(int);
+#else
+ void (*out_char)();
+#endif
+ int leading_zero;
+{
+ char *nptr;
+ int ix, fdigit, pre_space;
+ stk_rec *digits, *temp;
+ bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
+
+ /* The negative sign if needed. */
+ if (num->n_sign == MINUS) (*out_char) ('-');
+
+ /* Output the number. */
+ if (bc_is_zero (num))
+ (*out_char) ('0');
+ else
+ if (o_base == 10)
+ {
+ /* The number is in base 10, do it the fast way. */
+ nptr = num->n_value;
+ if (num->n_len > 1 || *nptr != 0)
+ for (ix=num->n_len; ix>0; ix--)
+ (*out_char) (BCD_CHAR(*nptr++));
+ else
+ nptr++;
+
+ if (leading_zero && bc_is_zero (num))
+ (*out_char) ('0');
+
+ /* Now the fraction. */
+ if (num->n_scale > 0)
+ {
+ (*out_char) ('.');
+ for (ix=0; ix<num->n_scale; ix++)
+ (*out_char) (BCD_CHAR(*nptr++));
+ }
+ }
+ else
+ {
+ /* special case ... */
+ if (leading_zero && bc_is_zero (num))
+ (*out_char) ('0');
+
+ /* The number is some other base. */
+ digits = NULL;
+ bc_init_num (&int_part);
+ bc_divide (num, _one_, &int_part, 0);
+ bc_init_num (&frac_part);
+ bc_init_num (&cur_dig);
+ bc_init_num (&base);
+ bc_sub (num, int_part, &frac_part, 0);
+ /* Make the INT_PART and FRAC_PART positive. */
+ int_part->n_sign = PLUS;
+ frac_part->n_sign = PLUS;
+ bc_int2num (&base, o_base);
+ bc_init_num (&max_o_digit);
+ bc_int2num (&max_o_digit, o_base-1);
+
+
+ /* Get the digits of the integer part and push them on a stack. */
+ while (!bc_is_zero (int_part))
+ {
+ bc_modulo (int_part, base, &cur_dig, 0);
+ temp = (stk_rec *) malloc (sizeof(stk_rec));
+ if (temp == NULL) bc_out_of_memory();
+ temp->digit = bc_num2long (cur_dig);
+ temp->next = digits;
+ digits = temp;
+ bc_divide (int_part, base, &int_part, 0);
+ }
+
+ /* Print the digits on the stack. */
+ if (digits != NULL)
+ {
+ /* Output the digits. */
+ while (digits != NULL)
+ {
+ temp = digits;
+ digits = digits->next;
+ if (o_base <= 16)
+ (*out_char) (ref_str[ (int) temp->digit]);
+ else
+ bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char);
+ free (temp);
+ }
+ }
+
+ /* Get and print the digits of the fraction part. */
+ if (num->n_scale > 0)
+ {
+ (*out_char) ('.');
+ pre_space = 0;
+ t_num = bc_copy_num (_one_);
+ while (t_num->n_len <= num->n_scale) {
+ bc_multiply (frac_part, base, &frac_part, num->n_scale);
+ fdigit = bc_num2long (frac_part);
+ bc_int2num (&int_part, fdigit);
+ bc_sub (frac_part, int_part, &frac_part, 0);
+ if (o_base <= 16)
+ (*out_char) (ref_str[fdigit]);
+ else {
+ bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
+ pre_space = 1;
+ }
+ bc_multiply (t_num, base, &t_num, 0);
+ }
+ bc_free_num (&t_num);
+ }
+
+ /* Clean up. */
+ bc_free_num (&int_part);
+ bc_free_num (&frac_part);
+ bc_free_num (&base);
+ bc_free_num (&cur_dig);
+ bc_free_num (&max_o_digit);
+ }
+}
+/* Convert a number NUM to a long. The function returns only the integer
+ part of the number. For numbers that are too large to represent as
+ a long, this function returns a zero. This can be detected by checking
+ the NUM for zero after having a zero returned. */
+
+long
+bc_num2long (num)
+ bc_num num;
+{
+ long val;
+ char *nptr;
+ int i;
+
+ /* Extract the int value, ignore the fraction. */
+ val = 0;
+ nptr = num->n_value;
+ for (i=num->n_len; (i>0) && (val<=(LONG_MAX/BASE)); i--)
+ val = val*BASE + *nptr++;
+
+ /* Check for overflow. If overflow, return zero. */
+ if (i>0) val = 0;
+ if (val < 0) val = 0;
+
+ /* Return the value. */
+ if (num->n_sign == PLUS)
+ return (val);
+ else
+ return (-val);
+}
+
+
+/* Convert an integer VAL to a bc number NUM. */
+
+void
+bc_int2num (num, val)
+ bc_num *num;
+ int val;
+{
+ char buffer[30];
+ char *bptr, *vptr;
+ int ix = 1;
+ char neg = 0;
+
+ /* Sign. */
+ if (val < 0)
+ {
+ neg = 1;
+ val = -val;
+ }
+
+ /* Get things going. */
+ bptr = buffer;
+ *bptr++ = val % BASE;
+ val = val / BASE;
+
+ /* Extract remaining digits. */
+ while (val != 0)
+ {
+ *bptr++ = val % BASE;
+ val = val / BASE;
+ ix++; /* Count the digits. */
+ }
+
+ /* Make the number. */
+ bc_free_num (num);
+ *num = bc_new_num (ix, 0);
+ if (neg) (*num)->n_sign = MINUS;
+
+ /* Assign the digits. */
+ vptr = (*num)->n_value;
+ while (ix-- > 0)
+ *vptr++ = *--bptr;
+}
+
+/* Convert a numbers to a string. Base 10 only.*/
+
+char
+*bc_num2str (num)
+ bc_num num;
+{
+ char *str, *sptr;
+ char *nptr;
+ int i, signch;
+
+ /* Allocate the string memory. */
+ signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */
+ if (num->n_scale > 0)
+ str = (char *) malloc (num->n_len + num->n_scale + 2 + signch);
+ else
+ str = (char *) malloc (num->n_len + 1 + signch);
+ if (str == NULL) bc_out_of_memory();
+
+ /* The negative sign if needed. */
+ sptr = str;
+ if (signch) *sptr++ = '-';
+
+ /* Load the whole number. */
+ nptr = num->n_value;
+ for (i=num->n_len; i>0; i--)
+ *sptr++ = BCD_CHAR(*nptr++);
+
+ /* Now the fraction. */
+ if (num->n_scale > 0)
+ {
+ *sptr++ = '.';
+ for (i=0; i<num->n_scale; i++)
+ *sptr++ = BCD_CHAR(*nptr++);
+ }
+
+ /* Terminate the string and return it! */
+ *sptr = '\0';
+ return (str);
+}
+/* Convert strings to bc numbers. Base 10 only.*/
+
+void
+bc_str2num (num, str, scale)
+ bc_num *num;
+ char *str;
+ int scale;
+{
+ int digits, strscale;
+ char *ptr, *nptr;
+ char zero_int;
+
+ /* Prepare num. */
+ bc_free_num (num);
+
+ /* Check for valid number and count digits. */
+ ptr = str;
+ digits = 0;
+ strscale = 0;
+ zero_int = FALSE;
+ if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */
+ while (*ptr == '0') ptr++; /* Skip leading zeros. */
+ while (isdigit((int)*ptr)) ptr++, digits++; /* digits */
+ if (*ptr == '.') ptr++; /* decimal point */
+ while (isdigit((int)*ptr)) ptr++, strscale++; /* digits */
+ if ((*ptr != '\0') || (digits+strscale == 0))
+ {
+ *num = bc_copy_num (_zero_);
+ return;
+ }
+
+ /* Adjust numbers and allocate storage and initialize fields. */
+ strscale = MIN(strscale, scale);
+ if (digits == 0)
+ {
+ zero_int = TRUE;
+ digits = 1;
+ }
+ *num = bc_new_num (digits, strscale);
+
+ /* Build the whole number. */
+ ptr = str;
+ if (*ptr == '-')
+ {
+ (*num)->n_sign = MINUS;
+ ptr++;
+ }
+ else
+ {
+ (*num)->n_sign = PLUS;
+ if (*ptr == '+') ptr++;
+ }
+ while (*ptr == '0') ptr++; /* Skip leading zeros. */
+ nptr = (*num)->n_value;
+ if (zero_int)
+ {
+ *nptr++ = 0;
+ digits = 0;
+ }
+ for (;digits > 0; digits--)
+ *nptr++ = CH_VAL(*ptr++);
+
+
+ /* Build the fractional part. */
+ if (strscale > 0)
+ {
+ ptr++; /* skip the decimal point! */
+ for (;strscale > 0; strscale--)
+ *nptr++ = CH_VAL(*ptr++);
+ }
+}
+
+/* Debugging routines */
+
+#ifdef DEBUG
+
+/* pn prints the number NUM in base 10. */
+
+static void
+out_char (int c)
+{
+ putchar(c);
+}
+
+
+void
+pn (num)
+ bc_num num;
+{
+ bc_out_num (num, 10, out_char, 0);
+ out_char ('\n');
+}
+
+
+/* pv prints a character array as if it was a string of bcd digits. */
+void
+pv (name, num, len)
+ char *name;
+ unsigned char *num;
+ int len;
+{
+ int i;
+ printf ("%s=", name);
+ for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
+ printf ("\n");
+}
+
+#endif
diff --git a/bc/number.h b/bc/number.h
new file mode 100644
index 0000000..9b034b6
--- /dev/null
+++ b/bc/number.h
@@ -0,0 +1,153 @@
+/* number.h: Arbitrary precision numbers header file. */
+/*
+ Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to:
+
+ The Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1301 USA
+
+
+ You may contact the author by:
+ e-mail: philnelson@acm.org
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#ifndef _NUMBER_H_
+#define _NUMBER_H_
+
+typedef enum {PLUS, MINUS} sign;
+
+typedef struct bc_struct *bc_num;
+
+typedef struct bc_struct
+ {
+ sign n_sign;
+ int n_len; /* The number of digits before the decimal point. */
+ int n_scale; /* The number of digits after the decimal point. */
+ int n_refs; /* The number of pointers to this number. */
+ bc_num n_next; /* Linked list for available list. */
+ char *n_ptr; /* The pointer to the actual storage.
+ If NULL, n_value points to the inside of
+ another number (bc_multiply...) and should
+ not be "freed." */
+ char *n_value; /* The number. Not zero char terminated.
+ May not point to the same place as n_ptr as
+ in the case of leading zeros generated. */
+ } bc_struct;
+
+
+/* The base used in storing the numbers in n_value above.
+ Currently this MUST be 10. */
+
+#define BASE 10
+
+/* Some useful macros and constants. */
+
+#define CH_VAL(c) (c - '0')
+#define BCD_CHAR(d) (d + '0')
+
+#ifdef MIN
+#undef MIN
+#undef MAX
+#endif
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)>(b)?(b):(a))
+#define ODD(a) ((a)&1)
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 0x7fffffff
+#endif
+
+
+/* Global numbers. */
+extern bc_num _zero_;
+extern bc_num _one_;
+extern bc_num _two_;
+
+
+/* Function Prototypes */
+
+/* Define the _PROTOTYPE macro if it is needed. */
+
+#ifndef _PROTOTYPE
+#ifdef __STDC__
+#define _PROTOTYPE(func, args) func args
+#else
+#define _PROTOTYPE(func, args) func()
+#endif
+#endif
+
+_PROTOTYPE(void bc_init_numbers, (void));
+
+_PROTOTYPE(bc_num bc_new_num, (int length, int scale));
+
+_PROTOTYPE(void bc_free_num, (bc_num *num));
+
+_PROTOTYPE(bc_num bc_copy_num, (bc_num num));
+
+_PROTOTYPE(void bc_init_num, (bc_num *num));
+
+_PROTOTYPE(void bc_str2num, (bc_num *num, char *str, int scale));
+
+_PROTOTYPE(char *bc_num2str, (bc_num num));
+
+_PROTOTYPE(void bc_int2num, (bc_num *num, int val));
+
+_PROTOTYPE(long bc_num2long, (bc_num num));
+
+_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2));
+
+_PROTOTYPE(char bc_is_zero, (bc_num num));
+
+_PROTOTYPE(char bc_is_near_zero, (bc_num num, int scale));
+
+_PROTOTYPE(char bc_is_neg, (bc_num num));
+
+_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result, int scale_min));
+
+_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result, int scale_min));
+
+_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale));
+
+_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale));
+
+_PROTOTYPE(int bc_modulo, (bc_num num1, bc_num num2, bc_num *result,
+ int scale));
+
+_PROTOTYPE(int bc_divmod, (bc_num num1, bc_num num2, bc_num *quot,
+ bc_num *rem, int scale));
+
+_PROTOTYPE(int bc_raisemod, (bc_num base, bc_num expo, bc_num mod,
+ bc_num *result, int scale));
+
+_PROTOTYPE(void bc_raise, (bc_num num1, bc_num num2, bc_num *result,
+ int scale));
+
+_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale));
+
+_PROTOTYPE(void bc_out_num, (bc_num num, int o_base, void (* out_char)(int),
+ int leading_zero));
+
+#endif
diff --git a/bc/proto.h b/bc/proto.h
new file mode 100644
index 0000000..6d1b08b
--- /dev/null
+++ b/bc/proto.h
@@ -0,0 +1,150 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* proto.h: Prototype function definitions for "external" functions. */
+
+/* For the pc version using k&r ACK. (minix1.5 and earlier.) */
+#ifdef SHORTNAMES
+#define init_numbers i_numbers
+#define push_constant push__constant
+#define load_const in_load_const
+#define yy_get_next_buffer yyget_next_buffer
+#define yy_init_buffer yyinit_buffer
+#define yy_last_accepting_state yylast_accepting_state
+#define arglist1 arg1list
+#endif
+
+/* Include the standard library header files. */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* Define the _PROTOTYPE macro if it is needed. */
+
+#ifndef _PROTOTYPE
+#ifdef __STDC__
+#define _PROTOTYPE(func, args) func args
+#else
+#define _PROTOTYPE(func, args) func()
+#endif
+#endif
+
+/* From execute.c */
+_PROTOTYPE(void stop_execution, (int));
+_PROTOTYPE(unsigned char byte, (program_counter *pc_));
+_PROTOTYPE(void execute, (void));
+_PROTOTYPE(int prog_char, (void));
+_PROTOTYPE(int input_char, (void));
+_PROTOTYPE(void push_constant, (int (*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, (const 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 set_genstr_size, (int));
+_PROTOTYPE(void init_gen, (void));
+_PROTOTYPE(void generate, (const 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, const 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(void *bc_malloc, (int));
+_PROTOTYPE(void out_of_memory, (void));
+_PROTOTYPE(void welcome, (void));
+_PROTOTYPE(void warranty, (const char *));
+_PROTOTYPE(void show_bc_version, (void));
+_PROTOTYPE(void limits, (void));
+_PROTOTYPE(void yyerror, (const char *str ,...));
+_PROTOTYPE(void warn, (const char *mesg ,...));
+_PROTOTYPE(void rt_error, (const char *mesg ,...));
+_PROTOTYPE(void rt_warn, (const 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, (const char **str));
+_PROTOTYPE(void load_code, (const 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/scan.c b/bc/scan.c
new file mode 100644
index 0000000..1f78ec2
--- /dev/null
+++ b/bc/scan.c
@@ -0,0 +1,2489 @@
+
+#line 3 "scan.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#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. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+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
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - 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).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+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;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* 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
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* 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".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* 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 = 0; /* 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 (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (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 = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 46
+#define YY_END_OF_BUFFER 47
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[316] =
+ { 0,
+ 0, 0, 2, 2, 47, 45, 40, 38, 32, 45,
+ 1, 33, 33, 29, 33, 29, 29, 28, 33, 44,
+ 36, 34, 36, 45, 29, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 45, 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,
+ 2, 40, 36, 0, 43, 34, 30, 37, 44, 0,
+ 41, 44, 44, 0, 35, 39, 42, 42, 42, 42,
+
+ 42, 42, 42, 42, 42, 42, 10, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 31, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 44, 0, 0, 44, 0, 42, 42, 42, 42,
+ 42, 9, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 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, 16, 42, 42, 42,
+ 17, 20, 42, 42, 21, 42, 42, 42, 42, 6,
+ 42, 18, 42, 42, 12, 22, 42, 42, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 5, 42, 42, 42, 14, 42, 42, 15, 26, 42,
+ 42, 13, 42, 11, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 42, 4,
+ 42, 7, 27, 19, 8, 42, 2, 2, 2, 2,
+
+ 2, 2, 2, 2, 42, 23, 42, 2, 2, 2,
+ 25, 24, 2, 2, 0
+ } ;
+
+static yyconst flex_int32_t 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, 49, 50, 37,
+ 51, 37, 52, 53, 54, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 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 flex_int32_t yy_meta[55] =
+ { 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,
+ 3, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[320] =
+ { 0,
+ 0, 0, 54, 0, 553, 554, 550, 554, 531, 545,
+ 554, 529, 540, 554, 527, 97, 96, 96, 101, 107,
+ 526, 116, 525, 541, 523, 494, 496, 498, 507, 499,
+ 495, 0, 83, 104, 107, 507, 490, 486, 106, 96,
+ 491, 113, 479, 0, 529, 554, 510, 141, 0, 509,
+ 520, 0, 507, 133, 135, 130, 139, 141, 506, 150,
+ 505, 521, 503, 160, 123, 125, 137, 112, 130, 474,
+ 184, 185, 187, 188, 134, 473, 193, 183, 132, 194,
+ 467, 517, 554, 513, 554, 554, 554, 554, 221, 514,
+ 554, 222, 232, 513, 554, 554, 0, 468, 482, 472,
+
+ 479, 465, 465, 470, 462, 479, 0, 460, 464, 464,
+ 475, 466, 465, 459, 206, 471, 453, 461, 451, 459,
+ 554, 0, 492, 0, 178, 0, 0, 0, 0, 233,
+ 490, 0, 241, 244, 489, 0, 443, 67, 192, 189,
+ 219, 138, 203, 221, 180, 234, 442, 224, 223, 233,
+ 246, 239, 240, 236, 250, 251, 235, 253, 245, 255,
+ 0, 278, 486, 287, 288, 485, 445, 458, 438, 448,
+ 451, 0, 435, 434, 434, 432, 444, 441, 430, 434,
+ 427, 442, 441, 423, 431, 422, 437, 422, 427, 291,
+ 462, 297, 461, 244, 268, 259, 281, 286, 415, 275,
+
+ 277, 280, 283, 293, 284, 287, 295, 290, 308, 309,
+ 414, 303, 297, 315, 302, 310, 0, 423, 424, 418,
+ 0, 0, 416, 425, 0, 409, 408, 422, 406, 0,
+ 410, 0, 406, 418, 0, 0, 421, 416, 399, 314,
+ 312, 313, 398, 397, 311, 323, 396, 317, 319, 336,
+ 322, 395, 330, 394, 328, 342, 393, 392, 347, 345,
+ 0, 398, 406, 392, 0, 401, 389, 0, 0, 394,
+ 392, 0, 391, 0, 383, 338, 348, 337, 382, 346,
+ 341, 381, 380, 343, 351, 379, 356, 378, 373, 0,
+ 364, 0, 0, 0, 0, 367, 365, 364, 350, 363,
+
+ 362, 361, 359, 355, 374, 0, 337, 368, 237, 357,
+ 0, 0, 168, 127, 554, 416, 122, 419, 422
+ } ;
+
+static yyconst flex_int16_t yy_def[320] =
+ { 0,
+ 315, 1, 315, 3, 315, 315, 315, 315, 315, 316,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 317, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
+ 317, 317, 315, 318, 318, 315, 318, 319, 318, 318,
+ 318, 318, 318, 318, 318, 318, 318, 318, 318, 318,
+ 318, 318, 318, 318, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 318, 315, 315, 316, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 317, 317, 317, 317,
+
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
+ 315, 318, 318, 318, 319, 318, 318, 318, 318, 318,
+ 318, 318, 318, 318, 318, 318, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 318, 315, 315, 315, 315, 315, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 318,
+ 318, 318, 318, 64, 64, 64, 64, 64, 64, 64,
+
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 317, 317, 317, 317, 317, 317, 317, 317, 317, 317,
+ 317, 317, 317, 317, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 317, 317,
+ 317, 317, 317, 317, 317, 317, 64, 64, 64, 64,
+
+ 64, 64, 64, 64, 317, 317, 317, 64, 64, 64,
+ 317, 317, 64, 64, 0, 315, 315, 315, 315
+ } ;
+
+static yyconst flex_int16_t yy_nxt[609] =
+ { 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, 42,
+ 32, 14, 43, 14, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 52, 53, 54, 52, 55, 56, 57,
+ 58, 52, 59, 60, 61, 58, 52, 62, 52, 63,
+ 44, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 70, 70, 73, 70, 70, 74, 75, 76, 77, 78,
+
+ 70, 70, 79, 80, 70, 52, 81, 52, 88, 88,
+ 104, 91, 89, 194, 137, 86, 86, 89, 105, 90,
+ 86, 92, 95, 93, 97, 116, 95, 95, 93, 95,
+ 94, 95, 106, 114, 108, 83, 107, 115, 109, 117,
+ 119, 95, 110, 84, 129, 126, 130, 120, 129, 132,
+ 142, 130, 127, 131, 127, 133, 136, 134, 127, 137,
+ 136, 136, 134, 136, 135, 136, 140, 139, 141, 124,
+ 137, 143, 137, 158, 137, 136, 137, 137, 152, 137,
+ 84, 137, 126, 198, 137, 137, 137, 137, 137, 137,
+ 137, 137, 137, 137, 137, 137, 137, 137, 137, 137,
+
+ 137, 137, 137, 137, 137, 137, 137, 138, 137, 137,
+ 137, 144, 156, 146, 148, 137, 151, 147, 149, 145,
+ 154, 159, 150, 195, 155, 201, 157, 137, 160, 196,
+ 137, 137, 137, 183, 137, 137, 137, 162, 165, 137,
+ 137, 137, 162, 165, 163, 166, 92, 199, 93, 190,
+ 137, 197, 184, 93, 190, 94, 191, 192, 133, 200,
+ 134, 202, 192, 204, 193, 134, 137, 135, 137, 203,
+ 137, 137, 205, 206, 207, 208, 209, 210, 212, 213,
+ 137, 137, 137, 137, 137, 239, 137, 137, 214, 215,
+ 216, 137, 137, 137, 162, 240, 211, 137, 137, 162,
+
+ 137, 163, 137, 89, 165, 241, 137, 190, 89, 165,
+ 90, 166, 190, 192, 191, 137, 242, 243, 192, 249,
+ 193, 244, 137, 245, 137, 246, 248, 137, 137, 247,
+ 137, 137, 250, 137, 137, 251, 252, 137, 253, 254,
+ 137, 256, 137, 257, 137, 258, 259, 276, 260, 137,
+ 137, 275, 278, 277, 279, 137, 137, 137, 137, 137,
+ 137, 137, 137, 280, 137, 281, 137, 282, 283, 137,
+ 137, 284, 285, 286, 287, 137, 288, 137, 297, 298,
+ 300, 299, 302, 137, 137, 137, 301, 312, 137, 137,
+ 137, 303, 137, 137, 137, 137, 304, 137, 137, 313,
+
+ 309, 310, 137, 137, 137, 311, 137, 314, 137, 137,
+ 137, 137, 308, 307, 306, 137, 84, 84, 84, 122,
+ 305, 122, 125, 125, 125, 137, 137, 137, 137, 137,
+ 137, 296, 295, 294, 293, 292, 291, 290, 289, 137,
+ 137, 137, 137, 137, 137, 137, 137, 274, 273, 272,
+ 271, 270, 269, 268, 267, 266, 265, 264, 263, 262,
+ 261, 255, 137, 165, 162, 238, 237, 236, 235, 234,
+ 233, 232, 231, 230, 229, 228, 227, 226, 225, 224,
+ 223, 222, 221, 220, 219, 218, 217, 165, 162, 137,
+ 137, 93, 164, 123, 189, 188, 187, 186, 185, 182,
+
+ 181, 180, 179, 178, 177, 176, 175, 174, 173, 172,
+ 171, 170, 169, 168, 167, 93, 164, 85, 82, 161,
+ 153, 137, 127, 96, 124, 124, 127, 128, 127, 124,
+ 123, 121, 118, 113, 112, 111, 103, 102, 101, 100,
+ 99, 98, 86, 96, 83, 83, 86, 87, 86, 85,
+ 83, 82, 315, 5, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+
+ 315, 315, 315, 315, 315, 315, 315, 315
+ } ;
+
+static yyconst flex_int16_t yy_chk[609] =
+ { 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, 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, 3, 16, 17,
+ 33, 19, 18, 138, 138, 17, 16, 18, 33, 18,
+ 19, 20, 22, 20, 317, 40, 22, 22, 20, 22,
+ 20, 22, 34, 39, 35, 22, 34, 39, 35, 40,
+ 42, 22, 35, 48, 54, 48, 56, 42, 55, 57,
+ 68, 56, 54, 56, 55, 58, 60, 58, 57, 68,
+ 60, 60, 58, 60, 58, 60, 66, 65, 67, 60,
+ 65, 69, 66, 79, 314, 60, 64, 69, 75, 79,
+ 125, 75, 125, 142, 67, 142, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 71, 78, 72, 73, 313, 74, 72, 73, 71,
+ 77, 80, 73, 139, 77, 145, 78, 145, 80, 140,
+ 78, 71, 72, 115, 73, 74, 140, 89, 92, 139,
+ 77, 80, 89, 92, 89, 92, 93, 143, 93, 130,
+ 143, 141, 115, 93, 130, 93, 130, 133, 134, 144,
+ 134, 146, 133, 149, 133, 134, 141, 134, 144, 148,
+ 149, 148, 150, 151, 152, 153, 154, 155, 156, 157,
+ 150, 146, 157, 154, 309, 194, 152, 153, 158, 159,
+ 160, 194, 159, 151, 162, 195, 155, 155, 156, 162,
+
+ 158, 162, 160, 164, 165, 196, 196, 190, 164, 165,
+ 164, 165, 190, 192, 190, 195, 197, 198, 192, 205,
+ 192, 200, 200, 201, 201, 202, 204, 202, 197, 203,
+ 203, 205, 206, 198, 206, 207, 208, 208, 209, 210,
+ 204, 212, 207, 213, 213, 214, 215, 241, 216, 215,
+ 212, 240, 245, 242, 246, 209, 210, 216, 245, 241,
+ 242, 240, 214, 248, 248, 249, 249, 250, 251, 251,
+ 246, 253, 255, 256, 259, 255, 260, 253, 276, 277,
+ 280, 278, 284, 250, 278, 276, 281, 307, 281, 256,
+ 284, 285, 260, 280, 259, 277, 287, 299, 285, 308,
+
+ 299, 304, 304, 287, 310, 305, 303, 310, 302, 301,
+ 300, 298, 297, 296, 291, 308, 316, 316, 316, 318,
+ 289, 318, 319, 319, 319, 288, 286, 283, 282, 279,
+ 275, 273, 271, 270, 267, 266, 264, 263, 262, 258,
+ 257, 254, 252, 247, 244, 243, 239, 238, 237, 234,
+ 233, 231, 229, 228, 227, 226, 224, 223, 220, 219,
+ 218, 211, 199, 193, 191, 189, 188, 187, 186, 185,
+ 184, 183, 182, 181, 180, 179, 178, 177, 176, 175,
+ 174, 173, 171, 170, 169, 168, 167, 166, 163, 147,
+ 137, 135, 131, 123, 120, 119, 118, 117, 116, 114,
+
+ 113, 112, 111, 110, 109, 108, 106, 105, 104, 103,
+ 102, 101, 100, 99, 98, 94, 90, 84, 82, 81,
+ 76, 70, 63, 62, 61, 59, 53, 51, 50, 47,
+ 45, 43, 41, 38, 37, 36, 31, 30, 29, 28,
+ 27, 26, 25, 24, 23, 21, 15, 13, 12, 10,
+ 9, 7, 5, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+
+ 315, 315, 315, 315, 315, 315, 315, 315
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* 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"
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+/* scan.l: the (f)lex description file for the scanner. */
+#line 33 "scan.l"
+
+#include "bcdefs.h"
+#include "bc.h"
+#include "global.h"
+#include "proto.h"
+#include <errno.h>
+
+/* Using flex, we can ask for a smaller input buffer. With lex, this
+ does nothing! */
+
+#ifdef SMALL_BUF
+#undef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 512
+#endif
+
+/* Force . as last for now. */
+#define DOT_IS_LAST
+
+/* We want to define our own yywrap. */
+#undef yywrap
+_PROTOTYPE(int yywrap, (void));
+
+#if defined(LIBEDIT)
+/* Support for the BSD libedit with history for
+ nicer input on the interactive part of input. */
+
+#include <histedit.h>
+
+/* Have input call the following function. */
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ bcel_input((char *)buf, &result, max_size)
+
+/* Variables to help interface editline with bc. */
+static const char *bcel_line = (char *)NULL;
+static int bcel_len = 0;
+
+
+/* Required to get rid of that ugly ? default prompt! */
+char *
+null_prompt (EditLine *el)
+{
+ return "";
+}
+
+
+/* bcel_input puts upto MAX characters into BUF with the number put in
+ BUF placed in *RESULT. If the yy input file is the same as
+ stdin, use editline. Otherwise, just read it.
+*/
+
+static void
+bcel_input (buf, result, max)
+ char *buf;
+ int *result;
+ int max;
+{
+ if (!edit || yyin != stdin)
+ {
+ while ( (*result = read( fileno(yyin), buf, max )) < 0 )
+ if (errno != EINTR)
+ {
+ yyerror( "read() in flex scanner failed" );
+ exit (1);
+ }
+ return;
+ }
+
+ /* Do we need a new string? */
+ if (bcel_len == 0)
+ {
+ bcel_line = el_gets(edit, &bcel_len);
+ if (bcel_line == NULL) {
+ /* end of file */
+ *result = 0;
+ bcel_len = 0;
+ return;
+ }
+ if (bcel_len != 0)
+ history (hist, &histev, H_ENTER, bcel_line);
+ fflush (stdout);
+ }
+
+ if (bcel_len <= max)
+ {
+ strncpy (buf, bcel_line, bcel_len);
+ *result = bcel_len;
+ bcel_len = 0;
+ }
+ else
+ {
+ strncpy (buf, bcel_line, max);
+ *result = max;
+ bcel_line += max;
+ bcel_len -= max;
+ }
+}
+#endif
+
+#ifdef READLINE
+/* Support for the readline and history libraries. This allows
+ nicer input on the interactive part of input. */
+
+/* Have input call the following function. */
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ rl_input((char *)buf, &result, max_size)
+
+/* Variables to help interface readline with bc. */
+static char *rl_line = (char *)NULL;
+static char *rl_start = (char *)NULL;
+static int rl_len = 0;
+
+/* Definitions for readline access. */
+extern FILE *rl_instream;
+
+/* rl_input puts upto MAX characters into BUF with the number put in
+ BUF placed in *RESULT. If the yy input file is the same as
+ rl_instream (stdin), use readline. Otherwise, just read it.
+*/
+
+static void
+rl_input (buf, result, max)
+ char *buf;
+ int *result;
+ int max;
+{
+ if (yyin != rl_instream)
+ {
+ while ( (*result = read( fileno(yyin), buf, max )) < 0 )
+ if (errno != EINTR)
+ {
+ yyerror( "read() in flex scanner failed" );
+ exit (1);
+ }
+ return;
+ }
+
+ /* Do we need a new string? */
+ if (rl_len == 0)
+ {
+ if (rl_start)
+ free(rl_start);
+ rl_start = readline ("");
+ if (rl_start == NULL) {
+ /* end of file */
+ *result = 0;
+ rl_len = 0;
+ return;
+ }
+ rl_line = rl_start;
+ rl_len = strlen (rl_line)+1;
+ if (rl_len != 1)
+ add_history (rl_line);
+ rl_line[rl_len-1] = '\n';
+ fflush (stdout);
+ }
+
+ if (rl_len <= max)
+ {
+ strncpy (buf, rl_line, rl_len);
+ *result = rl_len;
+ rl_len = 0;
+ }
+ else
+ {
+ strncpy (buf, rl_line, max);
+ *result = max;
+ rl_line += max;
+ rl_len -= max;
+ }
+}
+#endif
+
+#if !defined(READLINE) && !defined(LIBEDIT)
+
+/* MINIX returns from read with < 0 if SIGINT is encountered.
+ In flex, we can redefine YY_INPUT to the following. In lex, this
+ does nothing! */
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
+ if (errno != EINTR) \
+ YY_FATAL_ERROR( "read() in flex scanner failed" );
+#endif
+
+
+#line 909 "scan.c"
+
+#define INITIAL 0
+#define slcomment 1
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#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_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t 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 \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#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
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* 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
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 223 "scan.l"
+
+#line 1065 "scan.c"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#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 ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ 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 >= 316 )
+ 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] != 554 );
+
+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 224 "scan.l"
+{
+ if (!std_only)
+ BEGIN(slcomment);
+ else
+ yyerror ("illegal character: #");
+ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 230 "scan.l"
+{ BEGIN(INITIAL); }
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 231 "scan.l"
+{ line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 232 "scan.l"
+return(Define);
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 233 "scan.l"
+return(Break);
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 234 "scan.l"
+return(Quit);
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 235 "scan.l"
+return(Length);
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 236 "scan.l"
+return(Return);
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 237 "scan.l"
+return(For);
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 238 "scan.l"
+return(If);
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 239 "scan.l"
+return(While);
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 240 "scan.l"
+return(Sqrt);
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 241 "scan.l"
+return(Scale);
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 242 "scan.l"
+return(Ibase);
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 243 "scan.l"
+return(Obase);
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 244 "scan.l"
+return(Auto);
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 245 "scan.l"
+return(Else);
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 246 "scan.l"
+return(Read);
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 247 "scan.l"
+return(Random);
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 248 "scan.l"
+return(Halt);
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 249 "scan.l"
+return(Last);
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 250 "scan.l"
+return(Void);
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 251 "scan.l"
+{
+#if defined(READLINE) || defined(LIBEDIT)
+ return(HistoryVar);
+#else
+ yylval.s_value = strcopyof(yytext); return(NAME);
+#endif
+ }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 259 "scan.l"
+return(Warranty);
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 260 "scan.l"
+return(Continue);
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 261 "scan.l"
+return(Print);
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 262 "scan.l"
+return(Limits);
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 263 "scan.l"
+{
+#ifdef DOT_IS_LAST
+ return(Last);
+#else
+ yyerror ("illegal character: %s",yytext);
+#endif
+ }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 270 "scan.l"
+{ yylval.c_value = yytext[0];
+ return((int)yytext[0]); }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 272 "scan.l"
+{ return(AND); }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 273 "scan.l"
+{ return(OR); }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 274 "scan.l"
+{ return(NOT); }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 275 "scan.l"
+{ yylval.c_value = yytext[0]; return((int)yytext[0]); }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 276 "scan.l"
+{ yylval.c_value = yytext[0]; return(ASSIGN_OP); }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 277 "scan.l"
+{
+#ifdef OLD_EQ_OP
+ char warn_save;
+ warn_save = warn_not_std;
+ warn_not_std = TRUE;
+ warn ("Old fashioned =<op>");
+ warn_not_std = warn_save;
+ yylval.c_value = yytext[1];
+#else
+ yylval.c_value = '=';
+ yyless (1);
+#endif
+ return(ASSIGN_OP);
+ }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 291 "scan.l"
+{ yylval.s_value = strcopyof(yytext); return(REL_OP); }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 292 "scan.l"
+{ yylval.c_value = yytext[0]; return(INCR_DECR); }
+ YY_BREAK
+case 38:
+/* rule 38 can match eol */
+YY_RULE_SETUP
+#line 293 "scan.l"
+{ line_no++; return(ENDOFLINE); }
+ YY_BREAK
+case 39:
+/* rule 39 can match eol */
+YY_RULE_SETUP
+#line 294 "scan.l"
+{ line_no++; /* ignore a "quoted" newline */ }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 295 "scan.l"
+{ /* ignore spaces and tabs */ }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 296 "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 42:
+YY_RULE_SETUP
+#line 317 "scan.l"
+{ yylval.s_value = strcopyof(yytext); return(NAME); }
+ YY_BREAK
+case 43:
+/* rule 43 can match eol */
+YY_RULE_SETUP
+#line 318 "scan.l"
+{
+ const 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 44:
+/* rule 44 can match eol */
+YY_RULE_SETUP
+#line 330 "scan.l"
+{
+ 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 45:
+YY_RULE_SETUP
+#line 357 "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 46:
+YY_RULE_SETUP
+#line 366 "scan.l"
+ECHO;
+ YY_BREAK
+#line 1479 "scan.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_LVALUE->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_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->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_LVALUE->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_LVALUE->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 (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->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_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->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_LVALUE->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_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* 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. */
+ yyrealloc((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_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->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_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->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 (void)
+{
+ 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 >= 316 )
+ 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 );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ 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 >= 316 )
+ 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 == 315);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up yytext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->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_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->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;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#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_LVALUE->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 );
+
+ /*FALLTHROUGH*/
+
+ 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;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ 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_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = 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;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(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 *) yyalloc(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;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+#ifndef _UNISTD_H /* assume unistd.h has isatty() for us */
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __THROW /* this is a gnuism */
+extern int isatty (int ) __THROW;
+#else
+extern int isatty (int );
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ 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( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ 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) yyalloc(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;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param str a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * __yystr )
+{
+
+ return yy_scan_bytes(__yystr,strlen(__yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_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;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (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. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* 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 );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 366 "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/storage.c b/bc/storage.c
new file mode 100644
index 0000000..699729a
--- /dev/null
+++ b/bc/storage.c
@@ -0,0 +1,1073 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* storage.c: Code and data storage manipulations. This includes labels. */
+
+#include "bcdefs.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] = (char *)"(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];
+ v_names[indx] = old_names[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];
+ a_names[indx] = old_names[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, idx)
+ int var_index;
+ long idx;
+{
+ 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] = idx & NODE_MASK;
+ ix = idx >> 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 idx;
+
+ if (!check_stack(2)) return;
+ idx = bc_num2long (ex_stack->s_next->s_num);
+ if (idx < 0 || idx > BC_DIM_MAX ||
+ (idx == 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, idx);
+ 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 idx;
+
+ if (!check_stack(1)) return;
+ idx = bc_num2long (ex_stack->s_num);
+ if (idx < 0 || idx > BC_DIM_MAX ||
+ (idx == 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, idx);
+ 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 idx;
+
+ /* It is an array variable. */
+ if (!check_stack (1)) return;
+ idx = bc_num2long (ex_stack->s_num);
+ if (idx < 0 || idx > BC_DIM_MAX ||
+ (idx == 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, idx);
+ 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 idx;
+
+ if (!check_stack (1)) return;
+ idx = bc_num2long (ex_stack->s_num);
+ if (idx < 0 || idx > BC_DIM_MAX ||
+ (idx == 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, idx);
+ 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; i<NODE_SIZE; i++)
+ if (ary_node->n_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; i<NODE_SIZE; i++)
+ if (ary_node->n_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 (progctr, func)
+ program_counter *progctr;
+ 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(progctr)) != ':')
+ {
+ 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..30beaf9
--- /dev/null
+++ b/bc/util.c
@@ -0,0 +1,846 @@
+/* This file is part of GNU bc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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.
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 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
+
+*************************************************************************/
+
+/* util.c: Utility routines for bc. */
+
+#include "bcdefs.h"
+#ifndef VARARGS
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "proto.h"
+
+
+/* strcopyof mallocs new memory and copies a string to to the new
+ memory. */
+
+char *
+strcopyof (str)
+ const 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;
+ }
+ }
+}
+
+/* genstr management to avoid buffer overflow. */
+void
+set_genstr_size (size)
+ int size;
+{
+ if (size > genlen) {
+ if (genstr != NULL)
+ free(genstr);
+ genstr = (char *) bc_malloc (size);
+ genlen = size;
+ }
+}
+
+
+/* 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;
+ set_genstr_size (64);
+}
+
+
+/* generate code STR for the machine. */
+
+void
+generate (str)
+ const char *str;
+{
+ did_gen = TRUE;
+ if (compile_only)
+ {
+ printf ("%s",str);
+ out_count += strlen(str);
+ if (out_count > 60)
+ {
+ printf ("\n");
+ out_count = 0;
+ }
+ }
+ else
+ load_code (str);
+}
+
+
+/* Execute the current code as loaded. */
+
+void
+run_code()
+{
+ /* If no compile errors run the current code. */
+ if (!had_error && did_gen)
+ {
+ if (compile_only)
+ {
+ printf ("@r\n");
+ out_count = 0;
+ }
+ else
+ execute ();
+ }
+
+ /* Reinitialize the code generation and machine. */
+ if (did_gen)
+ init_gen();
+ else
+ had_error = FALSE;
+}
+
+
+/* Output routines: Write a character CH to the standard output.
+ It keeps track of the number of characters output and may
+ break the output with a "\<cr>". Always used for numbers. */
+
+void
+out_char (ch)
+ int ch;
+{
+ if (ch == '\n')
+ {
+ out_col = 0;
+ putchar ('\n');
+ }
+ else
+ {
+ out_col++;
+ if (out_col == line_size-1 && line_size != 0)
+ {
+ putchar ('\\');
+ putchar ('\n');
+ out_col = 1;
+ }
+ putchar (ch);
+ }
+}
+
+/* Output routines: Write a character CH to the standard output.
+ It keeps track of the number of characters output and may
+ break the output with a "\<cr>". This one is for strings.
+ In POSIX bc, strings are not broken across lines. */
+
+void
+out_schar (ch)
+ int ch;
+{
+ if (ch == '\n')
+ {
+ out_col = 0;
+ putchar ('\n');
+ }
+ else
+ {
+ if (!std_only)
+ {
+ out_col++;
+ if (out_col == line_size-1 && line_size != 0)
+ {
+ 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;
+ const char *id;
+{
+ int cmp_result;
+
+ /* Check for an empty tree. */
+ if (tree == NULL)
+ return NULL;
+
+ /* Recursively search the tree. */
+ cmp_result = strcmp (id, tree->id);
+ if (cmp_result == 0)
+ return tree; /* This is the item. */
+ else if (cmp_result < 0)
+ return find_id (tree->left, id);
+ else
+ return find_id (tree->right, id);
+}
+
+
+/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
+ provided. insert_id_rec returns TRUE if the tree height from
+ ROOT down is increased otherwise it returns FALSE. This is a
+ recursive balanced binary tree insertion algorithm. */
+
+int insert_id_rec (root, new_id)
+ id_rec **root;
+ id_rec *new_id;
+{
+ id_rec *A, *B;
+
+ /* If root is NULL, this where it is to be inserted. */
+ if (*root == NULL)
+ {
+ *root = new_id;
+ new_id->left = NULL;
+ new_id->right = NULL;
+ new_id->balance = 0;
+ return (TRUE);
+ }
+
+ /* We need to search for a leaf. */
+ if (strcmp (new_id->id, (*root)->id) < 0)
+ {
+ /* Insert it on the left. */
+ if (insert_id_rec (&((*root)->left), new_id))
+ {
+ /* The height increased. */
+ (*root)->balance --;
+
+ switch ((*root)->balance)
+ {
+ case 0: /* no height increase. */
+ return (FALSE);
+ case -1: /* height increase. */
+ return (TRUE);
+ case -2: /* we need to do a rebalancing act. */
+ A = *root;
+ B = (*root)->left;
+ if (B->balance <= 0)
+ {
+ /* Single Rotate. */
+ A->left = B->right;
+ B->right = A;
+ *root = B;
+ A->balance = 0;
+ B->balance = 0;
+ }
+ else
+ {
+ /* Double Rotate. */
+ *root = B->right;
+ B->right = (*root)->left;
+ A->left = (*root)->right;
+ (*root)->left = B;
+ (*root)->right = A;
+ switch ((*root)->balance)
+ {
+ case -1:
+ A->balance = 1;
+ B->balance = 0;
+ break;
+ case 0:
+ A->balance = 0;
+ B->balance = 0;
+ break;
+ case 1:
+ A->balance = 0;
+ B->balance = -1;
+ break;
+ }
+ (*root)->balance = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Insert it on the right. */
+ if (insert_id_rec (&((*root)->right), new_id))
+ {
+ /* The height increased. */
+ (*root)->balance ++;
+
+ switch ((*root)->balance)
+ {
+ case 0: /* no height increase. */
+ return (FALSE);
+ case 1: /* height increase. */
+ return (TRUE);
+ case 2: /* we need to do a rebalancing act. */
+ A = *root;
+ B = (*root)->right;
+ if (B->balance >= 0)
+ {
+ /* Single Rotate. */
+ A->right = B->left;
+ B->left = A;
+ *root = B;
+ A->balance = 0;
+ B->balance = 0;
+ }
+ else
+ {
+ /* Double Rotate. */
+ *root = B->left;
+ B->left = (*root)->right;
+ A->right = (*root)->left;
+ (*root)->left = A;
+ (*root)->right = B;
+ switch ((*root)->balance)
+ {
+ case -1:
+ A->balance = 0;
+ B->balance = 1;
+ break;
+ case 0:
+ A->balance = 0;
+ B->balance = 0;
+ break;
+ case 1:
+ A->balance = -1;
+ B->balance = 0;
+ break;
+ }
+ (*root)->balance = 0;
+ }
+ }
+ }
+ }
+
+ /* If we fall through to here, the tree did not grow in height. */
+ return (FALSE);
+}
+
+
+/* Initialize variables for the symbol table tree. */
+
+void
+init_tree()
+{
+ name_tree = NULL;
+ next_array = 1;
+ next_func = 1;
+ /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */
+ next_var = 5;
+}
+
+
+/* Lookup routines for symbol table names. */
+
+int
+lookup (name, namekind)
+ char *name;
+ int namekind;
+{
+ id_rec *id;
+
+ /* Warn about non-standard name. */
+ if (strlen(name) != 1)
+ warn ("multiple letter name - %s", name);
+
+ /* Look for the id. */
+ id = find_id (name_tree, name);
+ if (id == NULL)
+ {
+ /* We need to make a new item. */
+ id = (id_rec *) bc_malloc (sizeof (id_rec));
+ id->id = strcopyof (name);
+ id->a_name = 0;
+ id->f_name = 0;
+ id->v_name = 0;
+ insert_id_rec (&name_tree, id);
+ }
+
+ /* Return the correct value. */
+ switch (namekind)
+ {
+
+ case ARRAY:
+ /* ARRAY variable numbers are returned as negative numbers. */
+ if (id->a_name != 0)
+ {
+ free (name);
+ return (-id->a_name);
+ }
+ id->a_name = next_array++;
+ if (id->a_name < MAX_STORE)
+ {
+ if (id->a_name >= a_count)
+ more_arrays ();
+ a_names[id->a_name] = name;
+ return (-id->a_name);
+ }
+ yyerror ("Too many array variables");
+ exit (1);
+
+ case FUNCT:
+ case FUNCTDEF:
+ if (id->f_name != 0)
+ {
+ if (namekind != FUNCT)
+ 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++;
+ if (id->f_name < MAX_STORE)
+ {
+ if (id->f_name >= f_count)
+ more_functions ();
+ f_names[id->f_name] = name;
+ 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++;
+ if (id->v_name <= MAX_STORE)
+ {
+ if (id->v_name >= v_count)
+ more_variables ();
+ v_names[id->v_name - 1] = name;
+ 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 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. */
+
+void *
+bc_malloc (size)
+ int size;
+{
+ void *ptr;
+
+ ptr = (void *) 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 (const char *str, ...)
+#else
+void
+yyerror (str)
+ const char *str;
+#endif
+#else
+void
+yyerror (str, va_alist)
+ const char *str;
+#endif
+{
+ const 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 (const char *mesg, ...)
+#else
+void
+warn (mesg)
+ const char *mesg;
+#endif
+#else
+void
+warn (mesg, va_alist)
+ const char *mesg;
+#endif
+{
+ const 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: Error: ",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 (const char *mesg, ...)
+#else
+void
+rt_error (mesg)
+ const char *mesg;
+#endif
+#else
+void
+rt_error (mesg, va_alist)
+ const 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 (const char *mesg, ...)
+#else
+void
+rt_warn (mesg)
+ const char *mesg;
+#endif
+#else
+void
+rt_warn (mesg, va_alist)
+ const char *mesg;
+#endif
+{
+ va_list args;
+
+ fprintf (stderr, "Runtime warning (func=%s, adr=%d): ",
+ f_names[pc.pc_func], pc.pc_addr);
+#ifndef VARARGS
+ va_start (args, mesg);
+#else
+ va_start (args);
+#endif
+ vfprintf (stderr, mesg, args);
+ va_end (args);
+
+ fprintf (stderr, "\n");
+}
diff --git a/bc/warranty.c b/bc/warranty.c
new file mode 100644
index 0000000..47f00ed
--- /dev/null
+++ b/bc/warranty.c
@@ -0,0 +1,75 @@
+/* warranty.c: warranty routines for bc. */
+
+/* This file is part of GNU bc.
+ Copyright (C) 1991-1994, 1997, 2000, 2003, 2004 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.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1301 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 "proto.h"
+
+
+/* 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)
+ const 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"
+" 51 Franklin Street, Fifth Floor\n"
+" Boston, MA 02110-1301 USA\n\n");
+}
diff --git a/bc/y.tab.h b/bc/y.tab.h
new file mode 100644
index 0000000..59271fa
--- /dev/null
+++ b/bc/y.tab.h
@@ -0,0 +1,137 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ ENDOFLINE = 258,
+ AND = 259,
+ OR = 260,
+ NOT = 261,
+ STRING = 262,
+ NAME = 263,
+ NUMBER = 264,
+ ASSIGN_OP = 265,
+ REL_OP = 266,
+ INCR_DECR = 267,
+ Define = 268,
+ Break = 269,
+ Quit = 270,
+ Length = 271,
+ Return = 272,
+ For = 273,
+ If = 274,
+ While = 275,
+ Sqrt = 276,
+ Else = 277,
+ Scale = 278,
+ Ibase = 279,
+ Obase = 280,
+ Auto = 281,
+ Read = 282,
+ Random = 283,
+ Warranty = 284,
+ Halt = 285,
+ Last = 286,
+ Continue = 287,
+ Print = 288,
+ Limits = 289,
+ UNARY_MINUS = 290,
+ HistoryVar = 291,
+ Void = 292
+ };
+#endif
+/* Tokens. */
+#define ENDOFLINE 258
+#define AND 259
+#define OR 260
+#define NOT 261
+#define STRING 262
+#define NAME 263
+#define NUMBER 264
+#define ASSIGN_OP 265
+#define REL_OP 266
+#define INCR_DECR 267
+#define Define 268
+#define Break 269
+#define Quit 270
+#define Length 271
+#define Return 272
+#define For 273
+#define If 274
+#define While 275
+#define Sqrt 276
+#define Else 277
+#define Scale 278
+#define Ibase 279
+#define Obase 280
+#define Auto 281
+#define Read 282
+#define Random 283
+#define Warranty 284
+#define Halt 285
+#define Last 286
+#define Continue 287
+#define Print 288
+#define Limits 289
+#define UNARY_MINUS 290
+#define HistoryVar 291
+#define Void 292
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 54 "bc.y"
+{
+ char *s_value;
+ char c_value;
+ int i_value;
+ arg_list *a_value;
+ }
+/* Line 1489 of yacc.c. */
+#line 130 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/fake_udevadm/Android.mk b/fake_udevadm/Android.mk
new file mode 100644
index 0000000..79729e2
--- /dev/null
+++ b/fake_udevadm/Android.mk
@@ -0,0 +1,12 @@
+include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= fake_udevadm.c
+LOCAL_MODULE := fake_udevadm
+systemtarball: fake_udevadm
+LOCAL_STATIC_LIBRARIES := libcutils libc
+LOCAL_MODULE_TAGS := tests
+LOCAL_LDLIBS += -lrt
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
diff --git a/fake_udevadm/fake_udevadm.c b/fake_udevadm/fake_udevadm.c
new file mode 100644
index 0000000..ec08c58
--- /dev/null
+++ b/fake_udevadm/fake_udevadm.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <time.h>
+#include <sys/time.h>
+
+#define UEVENT_BUFFER_SIZE 2048
+
+static int init_hotplug_sock()
+{
+ const int buffersize = 1024;
+ int ret;
+
+ struct sockaddr_nl snl;
+ bzero(&snl, sizeof(struct sockaddr_nl));
+ snl.nl_family = AF_NETLINK;
+ snl.nl_pid = getpid();
+ snl.nl_groups = 1;
+
+ int s = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+ if (s == -1) {
+ perror("socket");
+ return -1;
+ }
+ setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
+
+ ret = bind(s, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl));
+ if (ret < 0) {
+ perror("bind");
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ char DEVICE[] = "cpu";
+ int hotplug_sock = init_hotplug_sock();
+ char header[2048];
+ char *s;
+ struct timespec ts;
+
+ /* only support "udevadm monitor --kernel --subsystem-match=cpu"*/
+ if (argc != 4 || strcmp(argv[1], "monitor") || strcmp(argv[2], "--kernel") || strcmp(argv[3], "--subsystem-match=cpu")) {
+ printf("This is a fake udevadm. This fake udevadm only supports \"udevadm monitor --kernel --subsystem-match=cpu\"\n");
+ return -1;
+ }
+
+ while(1) {
+ /* Netlink message buffer */
+ char buf[UEVENT_BUFFER_SIZE * 2] = {0};
+ int len = recv(hotplug_sock, &buf, sizeof(buf), 0);
+ if (len <= 0)
+ continue;
+
+ if (strstr(buf, DEVICE) == NULL)
+ continue;
+
+ char action[64];
+ char *p = buf;
+ int i;
+ for (i = 0; *p !='@'; i++, p++) {
+ action[i] = *p;
+ }
+ action[i] = '\0';
+
+ int j;
+ char path[1024];
+ p++;
+ for (j = 0; *p != '\0'; j++, p++) {
+ path[j] = *p;
+ }
+ path[j] = '\0';
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ printf("%-6s[%llu.%06u] %-8s %s (%s)\n",
+ "KERNEL",
+ (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000,
+ action,
+ path,
+ DEVICE
+ );
+ fflush(stdout);
+ }
+
+ return 0;
+}