From 9ff140b1e18a8f50fe78ef0c76ace1acaf0572ad Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 17 Feb 2020 18:08:47 -0500
Subject: [PATCH 10/31] FIXME: WIP on reproducer for PR analyzer/93773

---
 gawk/awk.h         | 2077 ++++++++++
 gawk/awkgram.c     | 9365 ++++++++++++++++++++++++++++++++++++++++++++
 gawk/custom.h      |   82 +
 gawk/gettext.h     |  301 ++
 gawk/mbsupport.h   |   58 +
 gawk/protos.h      |  152 +
 gawk/support/dfa.h |  122 +
 7 files changed, 12157 insertions(+)
 create mode 100644 gawk/awk.h
 create mode 100644 gawk/awkgram.c
 create mode 100644 gawk/custom.h
 create mode 100644 gawk/gettext.h
 create mode 100644 gawk/mbsupport.h
 create mode 100644 gawk/protos.h
 create mode 100644 gawk/support/dfa.h

diff --git a/gawk/awk.h b/gawk/awk.h
new file mode 100644
index 00000000000..363e4403f3e
--- /dev/null
+++ b/gawk/awk.h
@@ -0,0 +1,2077 @@
+/*
+ * awk.h -- Definitions for gawk.
+ */
+
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-2019 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK 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
+ */
+
+/* ------------------------------ Includes ------------------------------ */
+
+/*
+ * config.h absolutely, positively, *M*U*S*T* be included before
+ * any system headers.  Otherwise, extreme death, destruction
+ * and loss of life results.
+ */
+#if defined(_TANDEM_SOURCE)
+/*
+ * config.h forces this even on non-tandem systems but it
+ * causes problems elsewhere if used in the check below.
+ * so workaround it. bleah.
+ */
+#define tandem_for_real	1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(tandem_for_real) && ! defined(_SCO_DS)
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <ctype.h>
+#include <setjmp.h>
+
+#include "gettext.h"
+#define _(msgid)  gettext(msgid)
+#define N_(msgid) msgid
+
+#if ! (defined(HAVE_LIBINTL_H) && defined(ENABLE_NLS) && ENABLE_NLS > 0)
+#ifndef LOCALEDIR
+#define LOCALEDIR NULL
+#endif /* LOCALEDIR */
+#endif
+
+#if !defined(__SUNPRO_C)
+#if !defined(__STDC__) || __STDC__ < 1
+#error "gawk no longer supports non-C89 environments (no __STDC__ or __STDC__ < 1)"
+#endif
+#endif
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#if ! defined(errno)
+extern int errno;
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif	/* not STDC_HEADERS */
+
+
+/* We can handle multibyte strings.  */
+#include <wchar.h>
+#include <wctype.h>
+
+#include "mbsupport.h" /* defines stuff for DJGPP to fake MBS */
+
+#ifdef STDC_HEADERS
+#include <float.h>
+#endif
+
+#undef CHARBITS
+#undef INTBITS
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+/* ----------------- System dependencies (with more includes) -----------*/
+
+/* This section is the messiest one in the file, not a lot that can be done */
+
+#ifndef VMS
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#else	/* VMS */
+#include <stddef.h>
+#include <stat.h>
+#include <file.h>	/* avoid <fcntl.h> in io.c */
+/* debug.c needs this; when _DECC_V4_SOURCE is defined (as it is
+   in our config.h [vms/vms-conf.h]), off_t won't get declared */
+# if !defined(__OFF_T) && !defined(_OFF_T)
+#  if defined(____OFF_T) || defined(___OFF_T)
+typedef __off_t off_t;	/* __off_t is either int or __int64 */
+#  else
+typedef int off_t;
+#  endif
+# endif
+#endif	/* VMS */
+
+#include "protos.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif	/* NEED_MEMORY_H */
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif	/* HAVE_STRINGS_H */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif	/* HAVE_UNISTD_H */
+
+#ifdef VMS
+#include <unixlib.h>
+#include "vms/redirect.h"
+#endif  /*VMS*/
+
+#ifndef O_BINARY
+#define O_BINARY	0
+#endif
+
+#ifndef HAVE_SETLOCALE
+#define setlocale(locale, val)	/* nothing */
+#endif /* HAVE_SETLOCALE */
+
+#if HAVE_MEMCPY_ULONG
+extern char *memcpy_ulong(char *dest, const char *src, unsigned long l);
+#define memcpy memcpy_ulong
+#endif
+#if HAVE_MEMSET_ULONG
+extern void *memset_ulong(void *dest, int val, unsigned long l);
+#define memset memset_ulong
+#endif
+
+#ifdef HAVE_FWRITE_UNLOCKED
+#define fwrite	fwrite_unlocked
+#endif /* HAVE_FWRITE_UNLOCKED */
+
+#if defined(__DJGPP__) || defined(__EMX__) || defined(__MINGW32__)
+#include "nonposix.h"
+#endif /* defined(__DJGPP__) || defined(__EMX__) || defined(__MINGW32__) */
+
+/* use this as lintwarn("...")
+   this is a hack but it gives us the right semantics */
+#define lintwarn (*(set_loc(__FILE__, __LINE__),lintfunc))
+/* same thing for warning */
+#define warning (*(set_loc(__FILE__, __LINE__),r_warning))
+
+#ifdef HAVE_MPFR
+#include <gmp.h>
+#include <mpfr.h>
+#ifndef MPFR_RNDN
+/* for compatibility with MPFR 2.X */
+#define MPFR_RNDN GMP_RNDN
+#define MPFR_RNDZ GMP_RNDZ
+#define MPFR_RNDU GMP_RNDU
+#define MPFR_RNDD GMP_RNDD
+#endif
+#endif
+
+#include "regex.h"
+#include "dfa.h"
+typedef struct Regexp {
+	struct re_pattern_buffer pat;
+	struct re_registers regs;
+	struct dfa *dfareg;
+	bool has_meta;		/* re has meta chars so (probably) isn't simple string */
+	bool maybe_long;	/* re has meta chars that can match long text */
+} Regexp;
+#define	RESTART(rp,s)	(rp)->regs.start[0]
+#define	REEND(rp,s)	(rp)->regs.end[0]
+#define	SUBPATSTART(rp,s,n)	(rp)->regs.start[n]
+#define	SUBPATEND(rp,s,n)	(rp)->regs.end[n]
+#define	NUMSUBPATS(rp,s)	(rp)->regs.num_regs
+
+/* regexp matching flags: */
+#define RE_NO_FLAGS	0	/* empty flags */
+#define RE_NEED_START	1	/* need to know start/end of match */
+#define RE_NO_BOL	2	/* not allowed to match ^ in regexp */
+
+#include "gawkapi.h"
+
+/* Stuff for losing systems. */
+#if !defined(HAVE_STRTOD)
+extern double gawk_strtod();
+#define strtod gawk_strtod
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(arg)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#endif /* ATTRIBUTE_NORETURN */
+
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#endif /* ATTRIBUTE_PRINTF */
+
+/* ------------------ Constants, Structures, Typedefs  ------------------ */
+
+#define AWKNUM	double
+
+enum defrule { BEGIN = 1, Rule, END, BEGINFILE, ENDFILE,
+	MAXRULE /* sentinel, not legal */ };
+extern const char *const ruletab[];
+
+
+typedef enum nodevals {
+	/* illegal entry == 0 */
+	Node_illegal,
+
+	Node_val,		/* node is a value - type in flags */
+	Node_regex,		/* a regexp, text, compiled, flags, etc */
+	Node_dynregex,		/* a dynamic regexp */
+
+	/* symbol table values */
+	Node_var,		/* scalar variable, lnode is value */
+	Node_var_array,		/* array is ptr to elements, table_size num of eles */
+	Node_var_new,		/* newly created variable, may become an array */
+	Node_param_list,	/* lnode is a variable, rnode is more list */
+	Node_func,		/* lnode is param. list, rnode is body */
+	Node_ext_func,		/* extension function, code_ptr is builtin code */
+	Node_builtin_func,	/* built-in function, main use is for FUNCTAB */
+
+	Node_array_ref,		/* array passed by ref as parameter */
+	Node_array_tree,	/* Hashed array tree (HAT) */
+	Node_array_leaf,	/* Linear 1-D array */
+	Node_dump_array,	/* array info */
+
+	/* program execution -- stack item types */
+	Node_arrayfor,
+	Node_frame,
+	Node_instruction,
+
+	Node_final		/* sentry value, not legal */
+} NODETYPE;
+
+struct exp_node;
+
+typedef union bucket_item {
+	struct {
+		union bucket_item *next;
+		char *str;
+		size_t len;
+		size_t code;
+		struct exp_node *name;
+		struct exp_node *val;
+	} hs;
+	struct {
+		union bucket_item *next;
+		long li[2];
+		struct exp_node *val[2];
+		size_t cnt;
+	} hi;
+} BUCKET;
+
+enum commenttype {
+	EOL_COMMENT = 1,
+	BLOCK_COMMENT,
+	FOR_COMMENT	// special case
+};
+
+/* string hash table */
+#define ahnext		hs.next
+#define	ahname		hs.name	/* a string index node */
+#define	ahname_str	hs.str	/* shallow copy; = ahname->stptr */
+#define	ahname_len	hs.len	/* = ahname->stlen */
+#define	ahvalue		hs.val
+#define	ahcode		hs.code
+
+/* integer hash table */
+#define	ainext		hi.next
+#define ainum		hi.li	/* integer indices */
+#define aivalue		hi.val
+#define aicount		hi.cnt
+
+struct exp_instruction;
+
+typedef int (*Func_print)(FILE *, const char *, ...);
+typedef struct exp_node **(*afunc_t)(struct exp_node *, struct exp_node *);
+typedef struct {
+	const char *name;
+	afunc_t init;
+	afunc_t type_of;	/* avoid reserved word typeof */
+	afunc_t lookup;
+	afunc_t exists;
+	afunc_t clear;
+	afunc_t remove;
+	afunc_t list;
+	afunc_t copy;
+	afunc_t dump;
+	afunc_t store;
+} array_funcs_t;
+
+/*
+ * NOTE - this struct is a rather kludgey -- it is packed to minimize
+ * space usage, at the expense of cleanliness.  Alter at own risk.
+ */
+typedef struct exp_node {
+	union {
+		struct {
+			union {
+				struct exp_node *lptr;
+				struct exp_instruction *li;
+				long ll;
+				const array_funcs_t *lp;
+			} l;
+			union {
+				struct exp_node *rptr;
+				Regexp *preg[2];
+				struct exp_node **av;
+				BUCKET **bv;
+				void (*uptr)(void);
+				struct exp_instruction *iptr;
+			} r;
+			union {
+				struct exp_node *extra;
+				void (*aptr)(void);
+				long xl;
+				void *cmnt;	// used by pretty printer
+			} x;
+			char *name;
+			size_t reserved;
+			struct exp_node *rn;
+			unsigned long cnt;
+			unsigned long reflags;
+#				define	CONSTANT	1
+#				define	FS_DFLT		2
+		} nodep;
+
+		struct {
+#ifdef HAVE_MPFR
+			union {
+				AWKNUM fltnum;
+				mpfr_t mpnum;
+				mpz_t mpi;
+			} nm;
+			int rndmode;
+#else
+			AWKNUM fltnum;
+#endif
+			char *sp;
+			size_t slen;
+			long sref;
+			int idx;
+			wchar_t *wsp;
+			size_t wslen;
+			struct exp_node *typre;
+			enum commenttype comtype;
+		} val;
+	} sub;
+	NODETYPE type;
+	unsigned int flags;
+
+/* type = Node_val */
+	/*
+	 * STRING and NUMBER are mutually exclusive, except for the special
+	 * case of an uninitialized value, represented internally by
+	 * Nnull_string. They represent the type of a value as assigned.
+	 * Nnull_string has both STRING and NUMBER attributes, but all other
+	 * scalar values should have precisely one of these bits set.
+	 *
+	 * STRCUR and NUMCUR are not mutually exclusive. They represent that
+	 * the particular type of value is up to date.  For example,
+	 *
+	 * 	a = 5		# NUMBER | NUMCUR
+	 * 	b = a ""	# Adds STRCUR to a, since a string value
+	 * 			# is now available. But the type hasn't changed!
+	 *
+	 * 	a = "42"	# STRING | STRCUR
+	 * 	b = a + 0	# Adds NUMCUR to a, since numeric value
+	 * 			# is now available. But the type hasn't changed!
+	 *
+	 * USER_INPUT is the joker.  When STRING|USER_INPUT is set, it means
+	 * "this is string data, but the user may have really wanted it to be a
+	 * number. If we have to guess, like in a comparison, turn it into a
+	 * number if the string is indeed numeric."
+	 * For example,    gawk -v a=42 ....
+	 * Here, `a' gets STRING|STRCUR|USER_INPUT and then when used where
+	 * a number is needed, it gets turned into a NUMBER and STRING
+	 * is cleared. In that case, we leave the USER_INPUT in place, so
+	 * the combination NUMBER|USER_INPUT means it is a strnum a.k.a. a
+	 * "numeric string".
+	 *
+	 * WSTRCUR is for efficiency. If in a multibyte locale, and we
+	 * need to do something character based (substr, length, etc.)
+	 * we create the corresponding wide character string and store it,
+	 * and add WSTRCUR to the flags so that we don't have to do the
+	 * conversion more than once.
+	 *
+	 * The NUMINT flag may be used with a value of any type -- NUMBER,
+	 * STRING, or STRNUM. It indicates that the string representation
+	 * equals the result of sprintf("%ld", <numeric value>). So, for
+	 * example, NUMINT should NOT be set if it's a strnum or string value
+	 * where the string is " 1" or "01" or "+1" or "1.0" or "0.1E1". This
+	 * is a hint to indicate that an integer array optimization may be
+	 * used when this value appears as a subscript.
+	 *
+	 * We hope that the rest of the flags are self-explanatory. :-)
+	 */
+#		define	MALLOC	0x0001       /* stptr can be free'd, i.e. not a field node pointing into a shared buffer */
+#		define	STRING	0x0002       /* assigned as string */
+#		define	STRCUR	0x0004       /* string value is current */
+#		define	NUMCUR	0x0008       /* numeric value is current */
+#		define	NUMBER	0x0010       /* assigned as number */
+#		define	USER_INPUT 0x0020    /* user input: if NUMERIC then
+		                              * a NUMBER */
+#		define	INTLSTR	0x0040       /* use localized version */
+#		define	NUMINT	0x0080       /* numeric value is an integer */
+#		define	INTIND	0x0100	     /* integral value is array index;
+		                              * lazy conversion to string.
+		                              */
+#		define	WSTRCUR	0x0200       /* wide str value is current */
+#		define	MPFN	0x0400       /* arbitrary-precision floating-point number */
+#		define	MPZN	0x0800       /* arbitrary-precision integer */
+#		define	NO_EXT_SET 0x1000    /* extension cannot set a value for this variable */
+#		define	NULL_FIELD 0x2000    /* this is the null field */
+
+/* type = Node_var_array */
+#		define	ARRAYMAXED	0x4000       /* array is at max size */
+#		define	HALFHAT		0x8000       /* half-capacity Hashed Array Tree;
+		                                      * See cint_array.c */
+#		define	XARRAY		0x10000
+#		define	NUMCONSTSTR	0x20000	/* have string value for numeric constant */
+#		define  REGEX           0x40000 /* this is a typed regex */
+} NODE;
+
+#define vname sub.nodep.name
+
+#define lnode	sub.nodep.l.lptr
+#define rnode	sub.nodep.r.rptr
+
+/* Node_param_list */
+#define param      vname
+#define dup_ent    sub.nodep.r.rptr
+
+/* Node_param_list, Node_func */
+#define param_cnt  sub.nodep.l.ll
+
+/* Node_func */
+#define fparms		sub.nodep.rn
+#define code_ptr    sub.nodep.r.iptr
+
+/* Node_regex, Node_dynregex */
+#define re_reg	sub.nodep.r.preg
+#define re_flags sub.nodep.reflags
+#define re_text lnode
+#define re_exp	sub.nodep.x.extra
+#define re_cnt	flags
+
+/* Node_val */
+/*
+ * Note that the string in stptr may not be NUL-terminated, but it is
+ * guaranteed to have at least one extra byte that may be temporarily set
+ * to '\0'. This is helpful when calling functions such as strtod that require
+ * a NUL-terminated argument. In particular, field values $n for n > 0 and
+ * n < NF will not have a NUL terminator, since they point into the $0 buffer.
+ * All other strings are NUL-terminated.
+ */
+#define stptr	sub.val.sp
+#define stlen	sub.val.slen
+#define valref	sub.val.sref
+#define stfmt	sub.val.idx
+#define strndmode sub.val.rndmode
+#define wstptr	sub.val.wsp
+#define wstlen	sub.val.wslen
+#ifdef HAVE_MPFR
+#define mpg_numbr	sub.val.nm.mpnum
+#define mpg_i		sub.val.nm.mpi
+#define numbr		sub.val.nm.fltnum
+#else
+#define numbr		sub.val.fltnum
+#endif
+#define typed_re	sub.val.typre
+
+/*
+ * If stfmt is set to STFMT_UNUSED, it means that the string representation
+ * stored in stptr is not a function of the value of CONVFMT or OFMT. That
+ * indicates that either the string value was explicitly assigned, or it
+ * was converted from a NUMBER that has an integer value. When stfmt is not
+ * set to STFMT_UNUSED, it is an offset into the fmt_list array of distinct
+ * CONVFMT and OFMT node pointers.
+ */
+#define STFMT_UNUSED	-1
+
+/* Node_arrayfor */
+#define for_list	sub.nodep.r.av
+#define for_list_size	sub.nodep.reflags
+#define cur_idx		sub.nodep.l.ll
+#define for_array 	sub.nodep.rn
+
+/* Node_frame: */
+#define stack        sub.nodep.r.av
+#define func_node    sub.nodep.x.extra
+#define prev_frame_size	sub.nodep.reflags
+#define reti         sub.nodep.l.li
+
+/* Node_var: */
+#define var_value    lnode
+#define var_update   sub.nodep.r.uptr
+#define var_assign   sub.nodep.x.aptr
+
+/* Node_var_array: */
+#define buckets		sub.nodep.r.bv
+#define nodes		sub.nodep.r.av
+#define array_funcs	sub.nodep.l.lp
+#define array_base	sub.nodep.l.ll
+#define table_size	sub.nodep.reflags
+#define array_size	sub.nodep.cnt
+#define array_capacity	sub.nodep.reserved
+#define xarray		sub.nodep.rn
+#define parent_array	sub.nodep.x.extra
+
+#define ainit		array_funcs->init
+#define atypeof		array_funcs->type_of
+#define alookup 	array_funcs->lookup
+#define aexists 	array_funcs->exists
+#define aclear		array_funcs->clear
+#define aremove		array_funcs->remove
+#define alist		array_funcs->list
+#define acopy		array_funcs->copy
+#define adump		array_funcs->dump
+#define astore		array_funcs->store
+
+/* Node_array_ref: */
+#define orig_array lnode
+#define prev_array rnode
+
+/* Node_array_print */
+#define adepth     sub.nodep.l.ll
+#define alevel     sub.nodep.x.xl
+
+/* Op_comment	*/
+#define comment_type	sub.val.comtype
+
+/* --------------------------------lint warning types----------------------------*/
+typedef enum lintvals {
+	LINT_illegal,
+	LINT_assign_in_cond,
+	LINT_no_effect
+} LINTTYPE;
+
+/* --------------------------------Instruction ---------------------------------- */
+
+typedef enum opcodeval {
+	Op_illegal = 0,		/* illegal entry */
+
+	/* binary operators */
+	Op_times,
+	Op_times_i,
+	Op_quotient,
+	Op_quotient_i,
+	Op_mod,
+	Op_mod_i,
+	Op_plus,
+	Op_plus_i,
+	Op_minus,
+	Op_minus_i,
+	Op_exp,
+	Op_exp_i,
+	Op_concat,
+
+	/* line range instruction pair */
+	Op_line_range,		/* flags for Op_cond_pair */
+	Op_cond_pair,		/* conditional pair */
+
+	Op_subscript,
+	Op_sub_array,
+
+	/* unary operators */
+	Op_preincrement,
+	Op_predecrement,
+	Op_postincrement,
+	Op_postdecrement,
+	Op_unary_minus,
+	Op_unary_plus,
+	Op_field_spec,
+
+	/* unary relationals */
+	Op_not,
+
+	/* assignments */
+	Op_assign,
+	Op_store_var,		/* simple variable assignment optimization */
+	Op_store_sub,		/* array[subscript] assignment optimization */
+	Op_store_field,  	/* $n assignment optimization */
+	Op_assign_times,
+	Op_assign_quotient,
+	Op_assign_mod,
+	Op_assign_plus,
+	Op_assign_minus,
+	Op_assign_exp,
+	Op_assign_concat,
+
+	/* boolean binaries */
+	Op_and,			/* a left subexpression in && */
+	Op_and_final,		/* right subexpression of && */
+	Op_or,
+	Op_or_final,
+
+	/* binary relationals */
+	Op_equal,
+	Op_notequal,
+	Op_less,
+	Op_greater,
+	Op_leq,
+	Op_geq,
+	Op_match,
+	Op_match_rec,		/* match $0 */
+	Op_nomatch,
+
+	Op_rule,
+
+	/* keywords */
+	Op_K_case,
+	Op_K_default,
+	Op_K_break,
+	Op_K_continue,
+	Op_K_print,
+	Op_K_print_rec,
+	Op_K_printf,
+	Op_K_next,
+	Op_K_exit,
+	Op_K_return,
+	Op_K_return_from_eval,
+	Op_K_delete,
+	Op_K_delete_loop,
+	Op_K_getline_redir,
+	Op_K_getline,
+	Op_K_nextfile,
+	Op_K_namespace,
+
+	Op_builtin,
+	Op_sub_builtin,		/* sub, gsub and gensub */
+	Op_ext_builtin,
+	Op_in_array,		/* boolean test of membership in array */
+
+	/* function call instruction */
+	Op_func_call,
+	Op_indirect_func_call,
+
+	Op_push,		/* scalar variable */
+	Op_push_arg,		/* variable type (scalar or array) argument to built-in */
+	Op_push_arg_untyped,	/* like Op_push_arg, but for typeof */
+	Op_push_i,		/* number, string */
+	Op_push_re,		/* regex */
+	Op_push_array,
+	Op_push_param,
+	Op_push_lhs,
+	Op_subscript_lhs,
+	Op_field_spec_lhs,
+	Op_no_op,		/* jump target */
+	Op_pop,			/* pop an item from the runtime stack */
+	Op_jmp,
+	Op_jmp_true,
+	Op_jmp_false,
+	Op_get_record,
+	Op_newfile,
+	Op_arrayfor_init,
+	Op_arrayfor_incr,
+	Op_arrayfor_final,
+
+	Op_var_update,		/* update value of NR, NF or FNR */
+	Op_var_assign,
+	Op_field_assign,
+	Op_subscript_assign,
+	Op_after_beginfile,
+	Op_after_endfile,
+
+	Op_func,
+
+	Op_comment,		/* for pretty printing */
+	Op_exec_count,
+	Op_breakpoint,
+	Op_lint,
+	Op_atexit,
+	Op_stop,
+
+	/* parsing (yylex and yyparse), should never appear in valid compiled code */
+	Op_token,
+	Op_symbol,
+	Op_list,
+
+	/* program structures -- for use in the profiler/pretty printer */
+	Op_K_do,
+	Op_K_for,
+	Op_K_arrayfor,
+	Op_K_while,
+	Op_K_switch,
+	Op_K_if,
+	Op_K_else,
+	Op_K_function,
+	Op_cond_exp,
+	Op_parens,
+	Op_final			/* sentry value, not legal */
+} OPCODE;
+
+enum redirval {
+	/* I/O redirections */
+	redirect_none = 0,
+	redirect_output,
+	redirect_append,
+	redirect_pipe,
+	redirect_pipein,
+	redirect_input,
+	redirect_twoway
+};
+
+struct break_point;
+
+typedef struct exp_instruction {
+	struct exp_instruction *nexti;
+	union {
+		NODE *dn;
+		struct exp_instruction *di;
+		NODE *(*fptr)(int);
+		awk_value_t *(*efptr)(int num_actual_args,
+					awk_value_t *result,
+					struct awk_ext_func *finfo);
+		long dl;
+		char *name;
+	} d;
+
+	union {
+		long  xl;
+		NODE *xn;
+		void (*aptr)(void);
+		struct exp_instruction *xi;
+		struct break_point *bpt;
+		awk_ext_func_t *exf;
+	} x;
+
+	struct exp_instruction *comment;
+	short source_line;
+	short pool_size;	// memory management in symbol.c
+	OPCODE opcode;
+} INSTRUCTION;
+
+#define func_name       d.name
+
+#define memory          d.dn
+#define builtin         d.fptr
+#define extfunc         d.efptr
+#define builtin_idx     d.dl
+
+#define expr_count      x.xl
+
+#define c_function	x.exf
+
+#define target_continue d.di
+#define target_jmp      d.di
+#define target_break    x.xi
+
+/* Op_sub_builtin */
+#define sub_flags       d.dl
+#define GSUB            0x01	/* builtin is gsub */
+#define GENSUB          0x02	/* builtin is gensub */
+#define LITERAL         0x04	/* target is a literal string */
+
+
+/* Op_K_exit */
+#define target_end      d.di
+#define target_atexit   x.xi
+
+/* Op_newfile, Op_K_getline, Op_nextfile */
+#define target_endfile	x.xi
+
+/* Op_newfile */
+#define target_get_record	x.xi
+
+/* Op_get_record, Op_K_nextfile */
+#define target_newfile	d.di
+
+/* Op_K_getline */
+#define target_beginfile	d.di
+
+/* Op_get_record */
+#define has_endfile		x.xl
+
+/* Op_token */
+#define lextok          d.name
+#define param_count     x.xl
+
+/* Op_rule */
+#define in_rule         x.xl
+#define source_file     d.name
+
+ /* Op_K_case, Op_K_default */
+#define case_stmt       x.xi
+#define case_exp        d.di
+#define stmt_start      case_exp
+#define stmt_end        case_stmt
+#define match_exp       x.xl
+
+#define target_stmt     x.xi
+
+/* Op_K_switch */
+#define switch_end      x.xi
+#define switch_start    d.di
+
+/* Op_K_getline, Op_K_getline_redir */
+#define into_var        x.xl
+
+/* Op_K_getline_redir, Op_K_print, Op_K_print_rec, Op_K_printf */
+#define redir_type      d.dl
+
+/* Op_arrayfor_incr	*/
+#define array_var       x.xn
+
+/* Op_line_range */
+#define triggered       x.xl
+
+/* Op_cond_pair */
+#define line_range      x.xi
+
+/* Op_func_call, Op_func */
+#define func_body       x.xn
+
+/* Op_subscript */
+#define sub_count       d.dl
+
+/* Op_push_lhs, Op_subscript_lhs, Op_field_spec_lhs */
+#define do_reference    x.xl
+
+/* Op_list, Op_rule, Op_func */
+#define lasti           d.di
+#define firsti          x.xi
+
+/* Op_rule, Op_func */
+#define last_line       x.xl
+#define first_line      source_line
+
+/* Op_lint */
+#define lint_type       d.dl
+
+/* Op_field_spec_lhs */
+#define target_assign	d.di
+
+/* Op_var_assign */
+#define assign_var	x.aptr
+
+/* Op_var_update */
+#define update_var	x.aptr
+
+/* Op_field_assign */
+#define field_assign    x.aptr
+
+/* Op_field_assign, Op_var_assign */
+#define assign_ctxt	d.dl
+
+/* Op_concat */
+#define concat_flag     d.dl
+#define CSUBSEP		1
+#define CSVAR		2
+
+/* Op_breakpoint */
+#define break_pt        x.bpt
+
+/*------------------ pretty printing/profiling --------*/
+/* Op_exec_count */
+#define exec_count      d.dl
+
+/* Op_K_while */
+#define while_body      d.di
+
+/* Op_K_do */
+#define doloop_cond     d.di
+
+/* Op_K_for */
+#define forloop_cond    d.di
+#define forloop_body    x.xi
+
+/* Op_K_if */
+#define branch_if       d.di
+#define branch_else     x.xi
+
+/* Op_K_else */
+#define branch_end      x.xi
+
+/* Op_line_range */
+#define condpair_left   d.di
+#define condpair_right  x.xi
+
+/* Op_Rule, Op_Func */
+#define ns_name		d.name
+
+/* Op_store_var */
+#define initval         x.xn
+
+typedef struct iobuf {
+	awk_input_buf_t public;	/* exposed to extensions */
+	char *buf;              /* start data buffer */
+	char *off;              /* start of current record in buffer */
+	char *dataend;          /* first byte in buffer to hold new data,
+				   NULL if not read yet */
+	char *end;              /* end of buffer */
+	size_t readsize;        /* set from fstat call */
+	size_t size;            /* buffer size */
+	ssize_t count;          /* amount read last time */
+	size_t scanoff;         /* where we were in the buffer when we had
+				   to regrow/refill */
+	bool valid;
+	int errcode;
+
+	int flag;
+#		define	IOP_IS_TTY	1
+#		define  IOP_AT_EOF      2
+#		define  IOP_CLOSED      4
+#		define  IOP_AT_START    8
+} IOBUF;
+
+typedef void (*Func_ptr)(void);
+
+/* structure used to dynamically maintain a linked-list of open files/pipes */
+struct redirect {
+	unsigned int flag;
+#		define	RED_FILE	1
+#		define	RED_PIPE	2
+#		define	RED_READ	4
+#		define	RED_WRITE	8
+#		define	RED_APPEND	16
+#		define	RED_NOBUF	32
+#		define	RED_USED	64	/* closed temporarily to reuse fd */
+#		define	RED_EOF		128
+#		define	RED_TWOWAY	256
+#		define	RED_PTY		512
+#		define	RED_SOCKET	1024
+#		define	RED_TCP		2048
+	char *value;
+	FILE *ifp;	/* input fp, needed for PIPES_SIMULATED */
+	IOBUF *iop;
+	int pid;
+	int status;
+	struct redirect *prev;
+	struct redirect *next;
+	const char *mode;
+	awk_output_buf_t output;
+};
+
+/* values for BINMODE, used as bit flags */
+
+enum binmode_values {
+	TEXT_TRANSLATE = 0,	/* usual \r\n ---> \n translation */
+	BINMODE_INPUT = 1,	/* no translation for input files */
+	BINMODE_OUTPUT = 2,	/* no translation for output files */
+	BINMODE_BOTH = 3	/* no translation for either */
+};
+
+/*
+ * structure for our source, either a command line string or a source file.
+ */
+
+typedef struct srcfile {
+	struct srcfile *next;
+	struct srcfile *prev;
+
+	enum srctype {
+		SRC_CMDLINE = 1,
+		SRC_STDIN,
+		SRC_FILE,
+		SRC_INC,
+		SRC_EXTLIB
+	} stype;
+	char *src;	/* name on command line or include statement */
+	char *fullpath;	/* full path after AWKPATH search */
+	time_t mtime;
+	struct stat sbuf;
+	int srclines;	/* no of lines in source */
+	size_t bufsize;
+	char *buf;
+	int *line_offset;	/* offset to the beginning of each line */
+	int fd;
+	int maxlen;	/* size of the longest line */
+
+	void (*fini_func)();	/* dynamic extension of type SRC_EXTLIB */
+
+	char *lexptr;
+	char *lexend;
+	char *lexeme;
+	char *lexptr_begin;
+	int lasttok;
+	INSTRUCTION *comment;	/* comment on @load line */
+	const char *namespace;
+} SRCFILE;
+
+// structure for INSTRUCTION pool, needed mainly for debugger
+typedef struct instruction_pool {
+#define MAX_INSTRUCTION_ALLOC	4	// we don't call bcalloc with more than this
+	struct instruction_mem_pool {
+		struct instruction_block *block_list;
+		INSTRUCTION *free_space;	// free location in active block
+		INSTRUCTION *free_list;
+	} pool[MAX_INSTRUCTION_ALLOC];
+} INSTRUCTION_POOL;
+
+/* structure for execution context */
+typedef struct context {
+	INSTRUCTION_POOL pools;
+	NODE symbols;
+	INSTRUCTION rule_list;
+	SRCFILE srcfiles;
+	int sourceline;
+	char *source;
+	void (*install_func)(NODE *);
+	struct context *prev;
+} AWK_CONTEXT;
+
+/* for debugging purposes */
+struct flagtab {
+	int val;
+	const char *name;
+};
+
+
+struct block_item {
+	struct block_item *freep;
+};
+
+struct block_header {
+	struct block_item *freep;
+	size_t size;
+};
+
+enum block_id {
+	BLOCK_NODE = 0,
+	BLOCK_BUCKET,
+	BLOCK_MPFR,
+	BLOCK_MPZ,
+	BLOCK_MAX	/* count */
+};
+
+typedef int (*Func_pre_exec)(INSTRUCTION **);
+typedef void (*Func_post_exec)(INSTRUCTION *);
+
+#ifndef LONG_MAX
+#define LONG_MAX ((long)(~(1L << (sizeof (long) * 8 - 1))))
+#endif
+#ifndef ULONG_MAX
+#define ULONG_MAX (~(unsigned long)0)
+#endif
+#ifndef LONG_MIN
+#define LONG_MIN ((long)(-LONG_MAX - 1L))
+#endif
+#define UNLIMITED    LONG_MAX
+
+/* -------------------------- External variables -------------------------- */
+/* gawk builtin variables */
+extern long NF;
+extern long NR;
+extern long FNR;
+extern int BINMODE;
+extern bool IGNORECASE;
+extern bool RS_is_null;
+extern char *OFS;
+extern int OFSlen;
+extern char *ORS;
+extern int ORSlen;
+extern char *OFMT;
+extern char *CONVFMT;
+extern int CONVFMTidx;
+extern int OFMTidx;
+#ifdef HAVE_MPFR
+extern int MPFR_round_mode;
+#endif
+extern char *TEXTDOMAIN;
+extern NODE *BINMODE_node, *CONVFMT_node, *FIELDWIDTHS_node, *FILENAME_node;
+extern NODE *FNR_node, *FS_node, *IGNORECASE_node, *NF_node;
+extern NODE *NR_node, *OFMT_node, *OFS_node, *ORS_node, *RLENGTH_node;
+extern NODE *RSTART_node, *RS_node, *RT_node, *SUBSEP_node, *PROCINFO_node;
+extern NODE *LINT_node, *ERRNO_node, *TEXTDOMAIN_node, *FPAT_node;
+extern NODE *PREC_node, *ROUNDMODE_node;
+extern NODE *Nnull_string;
+extern NODE *Null_field;
+extern NODE **fields_arr;
+extern int sourceline;
+extern char *source;
+extern int errcount;
+extern int (*interpret)(INSTRUCTION *);	/* interpreter routine */
+extern NODE *(*make_number)(double);	/* double instead of AWKNUM on purpose */
+extern NODE *(*str2number)(NODE *);
+extern NODE *(*format_val)(const char *, int, NODE *);
+extern int (*cmp_numbers)(const NODE *, const NODE *);
+
+/* built-in array types */
+extern const array_funcs_t str_array_func;
+extern const array_funcs_t cint_array_func;
+extern const array_funcs_t int_array_func;
+
+/* special node used to indicate success in array routines (not NULL) */
+extern NODE *success_node;
+
+extern struct block_header nextfree[];
+extern bool field0_valid;
+
+extern int do_flags;
+
+extern SRCFILE *srcfiles; /* source files */
+
+enum do_flag_values {
+	DO_LINT_INVALID	   = 0x00001,	/* only warn about invalid */
+	DO_LINT_EXTENSIONS = 0x00002,	/* warn about gawk extensions */
+	DO_LINT_ALL	   = 0x00004,	/* warn about all things */
+	DO_LINT_OLD	   = 0x00008,	/* warn about stuff not in V7 awk */
+	DO_TRADITIONAL	   = 0x00010,	/* no gnu extensions, add traditional weirdnesses */
+	DO_POSIX	   = 0x00020,	/* turn off gnu and unix extensions */
+	DO_INTL		   = 0x00040,	/* dump locale-izable strings to stdout */
+	DO_NON_DEC_DATA	   = 0x00080,	/* allow octal/hex C style DATA. Use with caution! */
+	DO_INTERVALS	   = 0x00100,	/* allow {...,...} in regexps, see resetup() */
+	DO_PRETTY_PRINT	   = 0x00200,	/* pretty print the program */
+	DO_DUMP_VARS	   = 0x00400,	/* dump all global variables at end */
+	DO_TIDY_MEM	   = 0x00800,	/* release vars when done */
+	DO_SANDBOX	   = 0x01000,	/* sandbox mode - disable 'system' function & redirections */
+	DO_PROFILE	   = 0x02000,	/* profile the program */
+	DO_DEBUG	   = 0x04000,	/* debug the program */
+	DO_MPFR		   = 0x08000	/* arbitrary-precision floating-point math */
+};
+
+#define do_traditional      (do_flags & DO_TRADITIONAL)
+#define do_posix            (do_flags & DO_POSIX)
+#define do_intl             (do_flags & DO_INTL)
+#define do_non_decimal_data (do_flags & DO_NON_DEC_DATA)
+#define do_intervals        (do_flags & DO_INTERVALS)
+#define do_pretty_print     (do_flags & DO_PRETTY_PRINT)
+#define do_profile          (do_flags & DO_PROFILE)
+#define do_dump_vars        (do_flags & DO_DUMP_VARS)
+#define do_tidy_mem         (do_flags & DO_TIDY_MEM)
+#define do_sandbox          (do_flags & DO_SANDBOX)
+#define do_debug            (do_flags & DO_DEBUG)
+#define do_mpfr             (do_flags & DO_MPFR)
+
+extern bool do_optimize;
+extern int use_lc_numeric;
+extern int exit_val;
+
+#ifdef NO_LINT
+#define do_lint 0
+#define do_lint_old 0
+#else
+#define do_lint             (do_flags & (DO_LINT_INVALID|DO_LINT_ALL))
+#define do_lint_old         (do_flags & DO_LINT_OLD)
+#define do_lint_extensions  (do_flags & DO_LINT_EXTENSIONS)
+#endif
+extern int gawk_mb_cur_max;
+
+#if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
+extern GETGROUPS_T *groupset;
+extern int ngroups;
+#endif
+
+#ifdef HAVE_LOCALE_H
+extern struct lconv loc;
+#endif /* HAVE_LOCALE_H */
+
+#ifdef HAVE_MPFR
+extern mpfr_prec_t PRECISION;
+extern mpfr_rnd_t ROUND_MODE;
+extern mpz_t MNR;
+extern mpz_t MFNR;
+extern mpz_t mpzval;
+extern bool do_ieee_fmt;	/* emulate IEEE 754 floating-point format */
+#endif
+
+
+extern const char *myname;
+extern const char def_strftime_format[];
+
+extern char quote;
+extern char *defpath;
+extern char *deflibpath;
+extern char envsep;
+
+extern char casetable[];	/* for case-independent regexp matching */
+
+extern const char awk_namespace[];	/* "awk" */
+extern const char *current_namespace;
+extern bool namespace_changed;
+
+/* ------------------------- Runtime stack -------------------------------- */
+
+typedef union stack_item {
+	NODE *rptr;	/* variable etc. */
+	NODE **lptr;	/* address of a variable etc. */
+} STACK_ITEM;
+
+extern STACK_ITEM *stack_ptr;
+extern NODE *frame_ptr;
+extern STACK_ITEM *stack_bottom;
+extern STACK_ITEM *stack_top;
+
+#define decr_sp()		(stack_ptr--)
+#define incr_sp()		((stack_ptr < stack_top) ? ++stack_ptr : grow_stack())
+#define stack_adj(n)		(stack_ptr += (n))
+#define stack_empty()		(stack_ptr < stack_bottom)
+
+#define POP()			(decr_sp()->rptr)
+#define POP_ADDRESS()		(decr_sp()->lptr)
+#define PEEK(n)			((stack_ptr - (n))->rptr)
+#define TOP()			(stack_ptr->rptr)		/* same as PEEK(0) */
+#define TOP_ADDRESS()		(stack_ptr->lptr)
+#define PUSH(r)			(void) (incr_sp()->rptr = (r))
+#define PUSH_ADDRESS(l)		(void) (incr_sp()->lptr = (l))
+#define REPLACE(r)		(void) (stack_ptr->rptr = (r))
+#define REPLACE_ADDRESS(l)	(void) (stack_ptr->lptr = (l))
+
+/* function param */
+#define GET_PARAM(n)	frame_ptr->stack[n]
+
+/*
+ * UPREF --- simplified versions of dupnode, does not handle FIELD node.
+ * Most appropriate use is for elements on the runtime stack.
+ * When in doubt, use dupnode.
+ */
+
+#define UPREF(r)	(void) ((r)->valref++)
+
+extern void r_unref(NODE *tmp);
+
+static inline void
+DEREF(NODE *r)
+{
+	assert(r->valref > 0);
+	if (--r->valref == 0)
+		r_unref(r);
+}
+
+#define POP_NUMBER() force_number(POP_SCALAR())
+#define TOP_NUMBER() force_number(TOP_SCALAR())
+
+/* ------------------------- Pseudo-functions ------------------------- */
+#ifdef HAVE_MPFR
+
+#if 0
+
+/*
+ * In principle, there is no need to have both the MPFN and MPZN flags,
+ * since we are using 2 bits to encode 1 bit of information. But
+ * there may be some minor performance advantages from testing only the
+ * node flag bits without needing also to access the global do_mpfr flag bit.
+ */
+#define numtype_choose(n, mpfrval, mpzval, dblval)	\
+ (!do_mpfr ? (dblval) : (((n)->flags & MPFN) ? (mpfrval) : (mpzval)))
+
+#endif
+
+/* N.B. This implementation seems to give the fastest results. */
+#define numtype_choose(n, mpfrval, mpzval, dblval)	\
+ (!((n)->flags & (MPFN|MPZN)) ? (dblval) : (((n)->flags & MPFN) ? (mpfrval) : (mpzval)))
+
+/* conversion to C types */
+#define get_number_ui(n)	numtype_choose((n), mpfr_get_ui((n)->mpg_numbr, ROUND_MODE), mpz_get_ui((n)->mpg_i), (unsigned long) (n)->numbr)
+
+#define get_number_si(n)	numtype_choose((n), mpfr_get_si((n)->mpg_numbr, ROUND_MODE), mpz_get_si((n)->mpg_i), (long) (n)->numbr)
+
+#define get_number_d(n)		numtype_choose((n), mpfr_get_d((n)->mpg_numbr, ROUND_MODE), mpz_get_d((n)->mpg_i), (double) (n)->numbr)
+
+#define get_number_uj(n)	numtype_choose((n), mpfr_get_uj((n)->mpg_numbr, ROUND_MODE), (uintmax_t) mpz_get_d((n)->mpg_i), (uintmax_t) (n)->numbr)
+
+#define iszero(n)		numtype_choose((n), mpfr_zero_p((n)->mpg_numbr), (mpz_sgn((n)->mpg_i) == 0), ((n)->numbr == 0.0))
+
+#define IEEE_FMT(r, t)		(void) (do_ieee_fmt && format_ieee(r, t))
+
+#define mpg_float()		mpg_node(MPFN)
+#define mpg_integer()		mpg_node(MPZN)
+#define is_mpg_float(n)		(((n)->flags & MPFN) != 0)
+#define is_mpg_integer(n)	(((n)->flags & MPZN) != 0)
+#define is_mpg_number(n)	(((n)->flags & (MPZN|MPFN)) != 0)
+#else
+#define get_number_ui(n)	(unsigned long) (n)->numbr
+#define get_number_si(n)	(long) (n)->numbr
+#define get_number_d(n)		(double) (n)->numbr
+#define get_number_uj(n)	(uintmax_t) (n)->numbr
+
+#define is_mpg_number(n)	0
+#define is_mpg_float(n)		0
+#define is_mpg_integer(n)	0
+#define iszero(n)		((n)->numbr == 0.0)
+#endif
+
+#define var_uninitialized(n)	((n)->var_value == Nnull_string)
+
+#define get_lhs(n, r)	 (n)->type == Node_var && ! var_uninitialized(n) ? \
+				&((n)->var_value) : r_get_lhs((n), (r))
+
+#define getblock(p, id, ty)  (void) ((p = (ty) nextfree[id].freep) ? \
+			(ty) (nextfree[id].freep = ((struct block_item *) p)->freep) \
+			: (p = (ty) more_blocks(id)))
+#define freeblock(p, id)	 (void) (((struct block_item *) p)->freep = nextfree[id].freep, \
+					nextfree[id].freep = (struct block_item *) p)
+
+#define getnode(n)	getblock(n, BLOCK_NODE, NODE *)
+#define freenode(n)	freeblock(n, BLOCK_NODE)
+
+#define getbucket(b) 	getblock(b, BLOCK_BUCKET, BUCKET *)
+#define freebucket(b)	freeblock(b, BLOCK_BUCKET)
+
+#define	make_string(s, l)	make_str_node((s), (l), 0)
+
+// Flags for making string nodes
+#define		SCAN			1
+#define		ALREADY_MALLOCED	2
+#define		ELIDE_BACK_NL		4
+
+#define	cant_happen()	r_fatal("internal error line %d, file: %s", \
+				__LINE__, __FILE__)
+
+#define	emalloc(var,ty,x,str)	(void) (var = (ty) emalloc_real((size_t)(x), str, #var, __FILE__, __LINE__))
+#define	ezalloc(var,ty,x,str)	(void) (var = (ty) ezalloc_real((size_t)(x), str, #var, __FILE__, __LINE__))
+#define	erealloc(var,ty,x,str)	(void) (var = (ty) erealloc_real((void *) var, (size_t)(x), str, #var, __FILE__, __LINE__))
+
+#define efree(p)	free(p)
+
+#define fatal		(*(set_loc(__FILE__, __LINE__), r_fatal))
+
+extern jmp_buf fatal_tag;
+extern int fatal_tag_valid;
+
+#define assoc_length(a)	((a)->table_size)
+#define assoc_empty(a)	(assoc_length(a) == 0)
+#define assoc_lookup(a, s)	((a)->alookup(a, s))
+
+/* assoc_clear --- flush all the values in symbol[] */
+#define assoc_clear(a)	(void) ((a)->aclear(a, NULL))
+
+/* assoc_remove --- remove an index from symbol[] */
+#define assoc_remove(a, s) ((a)->aremove(a, s) != NULL)
+
+
+/* ------------- Function prototypes or defs (as appropriate) ------------- */
+/* array.c */
+typedef enum { SORTED_IN = 1, ASORT, ASORTI } sort_context_t;
+typedef enum {
+	ANONE   = 0x00,		/* "unused" value */
+	AINDEX	= 0x001,	/* list of indices */
+	AVALUE	= 0x002,	/* list of values */
+	AINUM	= 0x004,	/* numeric index */
+	AISTR	= 0x008,	/* string index */
+	AVNUM	= 0x010,	/* numeric scalar value */
+	AVSTR	= 0x020,	/* string scalar value */
+	AASC	= 0x040,	/* ascending order */
+	ADESC	= 0x080,	/* descending order */
+	ADELETE = 0x100		/* need a single index; for use in do_delete_loop */
+} assoc_kind_t;
+
+extern NODE *make_array(void);
+extern void null_array(NODE *symbol);
+extern NODE *force_array(NODE *symbol, bool canfatal);
+extern const char *make_aname(const NODE *symbol);
+extern const char *array_vname(const NODE *symbol);
+extern void array_init(void);
+extern NODE **null_afunc(NODE *symbol, NODE *subs);
+extern void set_SUBSEP(void);
+extern NODE *concat_exp(int nargs, bool do_subsep);
+extern NODE *assoc_copy(NODE *symbol, NODE *newsymb);
+extern void assoc_dump(NODE *symbol, NODE *p);
+extern NODE **assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt);
+extern void assoc_info(NODE *subs, NODE *val, NODE *p, const char *aname);
+extern void do_delete(NODE *symbol, int nsubs);
+extern void do_delete_loop(NODE *symbol, NODE **lhs);
+extern NODE *do_adump(int nargs);
+extern NODE *do_aoption(int nargs);
+extern NODE *do_asort(int nargs);
+extern NODE *do_asorti(int nargs);
+extern unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t *code);
+extern void init_env_array(NODE *env_node);
+extern void init_argv_array(NODE *argv_node, NODE *shadow_node);
+/* awkgram.c */
+extern NODE *variable(int location, char *name, NODETYPE type);
+extern int parse_program(INSTRUCTION **pcode, bool from_eval);
+extern void track_ext_func(const char *name);
+extern void dump_funcs(void);
+extern void dump_vars(const char *fname);
+extern const char *getfname(NODE *(*)(int), bool prepend_awk);
+extern NODE *stopme(int nargs);
+extern void shadow_funcs(void);
+extern int check_special(const char *name);
+extern SRCFILE *add_srcfile(enum srctype stype, char *src, SRCFILE *curr, bool *already_included, int *errcode);
+extern void free_srcfile(SRCFILE *thisfile);
+extern int files_are_same(char *path, SRCFILE *src);
+extern void valinfo(NODE *n, Func_print print_func, FILE *fp);
+extern void negate_num(NODE *n);
+typedef NODE *(*builtin_func_t)(int);	/* function that implements a built-in */
+extern builtin_func_t lookup_builtin(const char *name);
+extern void install_builtins(void);
+extern bool is_alpha(int c);
+extern bool is_alnum(int c);
+extern bool is_letter(int c);
+extern bool is_identchar(int c);
+extern NODE *make_regnode(int type, NODE *exp);
+extern bool validate_qualified_name(char *token);
+/* builtin.c */
+extern double double_to_int(double d);
+extern NODE *do_exp(int nargs);
+extern NODE *do_fflush(int nargs);
+extern NODE *do_index(int nargs);
+extern NODE *do_int(int nargs);
+extern NODE *do_isarray(int nargs);
+extern NODE *do_length(int nargs);
+extern NODE *do_log(int nargs);
+extern NODE *do_mktime(int nargs);
+extern NODE *do_sprintf(int nargs);
+extern void do_printf(int nargs, int redirtype);
+extern void print_simple(NODE *tree, FILE *fp);
+extern NODE *do_sqrt(int nargs);
+extern NODE *do_substr(int nargs);
+extern NODE *do_strftime(int nargs);
+extern NODE *do_systime(int nargs);
+extern NODE *do_system(int nargs);
+extern void do_print(int nargs, int redirtype);
+extern void do_print_rec(int args, int redirtype);
+extern NODE *do_tolower(int nargs);
+extern NODE *do_toupper(int nargs);
+extern NODE *do_atan2(int nargs);
+extern NODE *do_sin(int nargs);
+extern NODE *do_cos(int nargs);
+extern NODE *do_rand(int nargs);
+extern NODE *do_srand(int nargs);
+extern NODE *do_match(int nargs);
+extern NODE *do_sub(int nargs, unsigned int flags);
+extern NODE *call_sub(const char *name, int nargs);
+extern NODE *call_match(int nargs);
+extern NODE *call_split_func(const char *name, int nargs);
+extern NODE *format_tree(const char *, size_t, NODE **, long);
+extern NODE *do_lshift(int nargs);
+extern NODE *do_rshift(int nargs);
+extern NODE *do_and(int nargs);
+extern NODE *do_or(int nargs);
+extern NODE *do_xor(int nargs);
+extern NODE *do_compl(int nargs);
+extern NODE *do_strtonum(int nargs);
+extern AWKNUM nondec2awknum(char *str, size_t len, char **endptr);
+extern NODE *do_dcgettext(int nargs);
+extern NODE *do_dcngettext(int nargs);
+extern NODE *do_bindtextdomain(int nargs);
+extern NODE *do_intdiv(int nargs);
+extern NODE *do_typeof(int nargs);
+extern int strncasecmpmbs(const unsigned char *,
+			  const unsigned char *, size_t);
+extern int sanitize_exit_status(int status);
+/* debug.c */
+extern void init_debug(void);
+extern int debug_prog(INSTRUCTION *pc);
+/* eval.c */
+extern void PUSH_CODE(INSTRUCTION *cp);
+extern INSTRUCTION *POP_CODE(void);
+extern void init_interpret(void);
+extern int cmp_nodes(NODE *t1, NODE *t2, bool use_strcmp);
+extern int cmp_awknums(const NODE *t1, const NODE *t2);
+extern void set_IGNORECASE(void);
+extern void set_OFS(void);
+extern void set_ORS(void);
+extern void set_OFMT(void);
+extern void set_CONVFMT(void);
+extern void set_BINMODE(void);
+extern void set_LINT(void);
+extern void set_TEXTDOMAIN(void);
+extern void update_ERRNO_int(int);
+extern void update_ERRNO_string(const char *string);
+extern void unset_ERRNO(void);
+extern void update_NR(void);
+extern void update_NF(void);
+extern void update_FNR(void);
+extern const char *redflags2str(int);
+extern const char *flags2str(int);
+extern const char *genflags2str(int flagval, const struct flagtab *tab);
+extern const char *nodetype2str(NODETYPE type);
+extern void load_casetable(void);
+extern AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
+extern const char *opcode2str(OPCODE type);
+extern const char *op2str(OPCODE type);
+extern NODE **r_get_lhs(NODE *n, bool reference);
+extern STACK_ITEM *grow_stack(void);
+extern void dump_fcall_stack(FILE *fp);
+extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth);
+extern NODE **r_get_field(NODE *n, Func_ptr *assign, bool reference);
+/* ext.c */
+extern NODE *do_ext(int nargs);
+void load_ext(const char *lib_name);	/* temporary */
+extern void close_extensions(void);
+extern bool is_valid_identifier(const char *name);
+#ifdef DYNAMIC
+extern awk_bool_t make_builtin(const char *name_space, const awk_ext_func_t *);
+extern NODE *get_argument(int);
+extern NODE *get_actual_argument(NODE *, int, bool);
+#define get_scalar_argument(n, i)  get_actual_argument((n), (i), false)
+#define get_array_argument(n, i)   get_actual_argument((n), (i), true)
+#endif
+/* field.c */
+extern void init_fields(void);
+extern void set_record(const char *buf, int cnt, const awk_fieldwidth_info_t *);
+extern void reset_record(void);
+extern void rebuild_record(void);
+extern void set_NF(void);
+extern NODE **get_field(long num, Func_ptr *assign);
+extern NODE *do_split(int nargs);
+extern NODE *do_patsplit(int nargs);
+extern void set_FS(void);
+extern void set_RS(void);
+extern void set_FIELDWIDTHS(void);
+extern void set_FPAT(void);
+extern void update_PROCINFO_str(const char *subscript, const char *str);
+extern void update_PROCINFO_num(const char *subscript, AWKNUM val);
+
+typedef enum {
+	Using_FS,
+	Using_FIELDWIDTHS,
+	Using_FPAT,
+	Using_API
+} field_sep_type;
+extern field_sep_type current_field_sep(void);
+extern const char *current_field_sep_str(void);
+
+/* gawkapi.c: */
+extern gawk_api_t api_impl;
+extern void init_ext_api(void);
+extern void update_ext_api(void);
+extern NODE *awk_value_to_node(const awk_value_t *);
+extern void run_ext_exit_handlers(int exitval);
+extern void print_ext_versions(void);
+extern void free_api_string_copies(void);
+
+/* gawkmisc.c */
+extern char *gawk_name(const char *filespec);
+extern void os_arg_fixup(int *argcp, char ***argvp);
+extern int os_devopen(const char *name, int flag);
+extern void os_close_on_exec(int fd, const char *name, const char *what, const char *dir);
+extern int os_isatty(int fd);
+extern int os_isdir(int fd);
+extern int os_isreadable(const awk_input_buf_t *iobuf, bool *isdir);
+extern int os_is_setuid(void);
+extern int os_setbinmode(int fd, int mode);
+extern void os_restore_mode(int fd);
+extern size_t optimal_bufsize(int fd, struct stat *sbuf);
+extern int ispath(const char *file);
+extern int isdirpunct(int c);
+
+/* io.c */
+extern void init_sockets(void);
+extern void init_io(void);
+extern void register_input_parser(awk_input_parser_t *input_parser);
+extern void register_output_wrapper(awk_output_wrapper_t *wrapper);
+extern void register_two_way_processor(awk_two_way_processor_t *processor);
+extern void set_FNR(void);
+extern void set_NR(void);
+
+extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal);
+extern struct redirect *redirect_string(const char *redir_exp_str,
+		size_t redir_exp_len, bool not_string_flag, int redirtype,
+		int *errflg, int extfd, bool failure_fatal);
+extern NODE *do_close(int nargs);
+extern int flush_io(void);
+extern int close_io(bool *stdio_problem, bool *got_EPIPE);
+typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type;
+extern int close_rp(struct redirect *rp, two_way_close_type how);
+extern int devopen_simple(const char *name, const char *mode, bool try_real_open);
+extern int devopen(const char *name, const char *mode);
+extern int srcopen(SRCFILE *s);
+extern char *find_source(const char *src, struct stat *stb, int *errcode, int is_extlib);
+extern NODE *do_getline_redir(int intovar, enum redirval redirtype);
+extern NODE *do_getline(int intovar, IOBUF *iop);
+extern struct redirect *getredirect(const char *str, int len);
+extern bool inrec(IOBUF *iop, int *errcode);
+extern int nextfile(IOBUF **curfile, bool skipping);
+extern bool is_non_fatal_std(FILE *fp);
+extern bool is_non_fatal_redirect(const char *str, size_t len);
+extern void ignore_sigpipe(void);
+extern void set_sigpipe_to_default(void);
+extern bool non_fatal_flush_std_file(FILE *fp);
+
+/* main.c */
+extern int arg_assign(char *arg, bool initing);
+extern int is_std_var(const char *var);
+extern int is_off_limits_var(const char *var);
+extern char *estrdup(const char *str, size_t len);
+extern void update_global_values();
+extern long getenv_long(const char *name);
+extern void after_beginfile(IOBUF **curfile);
+extern void set_current_namespace(const char *new_namespace);
+
+/* mpfr.c */
+extern void set_PREC(void);
+extern void set_ROUNDMODE(void);
+extern void mpfr_unset(NODE *n);
+#ifdef HAVE_MPFR
+extern int mpg_cmp(const NODE *, const NODE *);
+extern int format_ieee(mpfr_ptr, int);
+extern NODE *mpg_update_var(NODE *);
+extern long mpg_set_var(NODE *);
+extern NODE *do_mpfr_and(int);
+extern NODE *do_mpfr_atan2(int);
+extern NODE *do_mpfr_compl(int);
+extern NODE *do_mpfr_cos(int);
+extern NODE *do_mpfr_exp(int);
+extern NODE *do_mpfr_int(int);
+extern NODE *do_mpfr_intdiv(int);
+extern NODE *do_mpfr_log(int);
+extern NODE *do_mpfr_lshift(int);
+extern NODE *do_mpfr_or(int);
+extern NODE *do_mpfr_rand(int);
+extern NODE *do_mpfr_rshift(int);
+extern NODE *do_mpfr_sin(int);
+extern NODE *do_mpfr_sqrt(int);
+extern NODE *do_mpfr_srand(int);
+extern NODE *do_mpfr_strtonum(int);
+extern NODE *do_mpfr_xor(int);
+extern void init_mpfr(mpfr_prec_t, const char *);
+extern void cleanup_mpfr(void);
+extern NODE *mpg_node(unsigned int);
+extern const char *mpg_fmt(const char *, ...);
+extern int mpg_strtoui(mpz_ptr, char *, size_t, char **, int);
+#endif
+/* msg.c */
+extern void gawk_exit(int status);
+extern void final_exit(int status) ATTRIBUTE_NORETURN;
+extern void err(bool isfatal, const char *s, const char *emsg, va_list argp) ATTRIBUTE_PRINTF(3, 0);
+extern void msg (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
+extern void error (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
+extern void r_warning (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
+extern void set_loc (const char *file, int line);
+extern void r_fatal (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+extern void (*lintfunc)(const char *mesg, ...) ATTRIBUTE_PRINTF_1;
+#else
+extern void (*lintfunc)(const char *mesg, ...);
+#endif
+/* profile.c */
+extern void init_profiling_signals(void);
+extern void set_prof_file(const char *filename);
+extern void dump_prog(INSTRUCTION *code);
+extern char *pp_number(NODE *n);
+extern char *pp_string(const char *in_str, size_t len, int delim);
+extern char *pp_node(NODE *n);
+extern int pp_func(INSTRUCTION *pc, void *);
+extern void pp_string_fp(Func_print print_func, FILE *fp, const char *str,
+		size_t namelen, int delim, bool breaklines);
+/* node.c */
+extern NODE *r_force_number(NODE *n);
+extern NODE *r_format_val(const char *format, int index, NODE *s);
+extern NODE *r_dupnode(NODE *n);
+extern NODE *make_str_node(const char *s, size_t len, int flags);
+extern NODE *make_typed_regex(const char *re, size_t len);
+extern void *more_blocks(int id);
+extern int parse_escape(const char **string_ptr);
+extern NODE *str2wstr(NODE *n, size_t **ptr);
+extern NODE *wstr2str(NODE *n);
+#define force_wstring(n)	str2wstr(n, NULL)
+extern const wchar_t *wstrstr(const wchar_t *haystack, size_t hs_len,
+		const wchar_t *needle, size_t needle_len);
+extern const wchar_t *wcasestrstr(const wchar_t *haystack, size_t hs_len,
+		const wchar_t *needle, size_t needle_len);
+extern void r_free_wstr(NODE *n);
+#define free_wstr(n)	do { if ((n)->flags & WSTRCUR) r_free_wstr(n); } while(0)
+extern wint_t btowc_cache[];
+#define btowc_cache(x) btowc_cache[(x)&0xFF]
+extern void init_btowc_cache();
+#define is_valid_character(b)	(btowc_cache[(b)&0xFF] != WEOF)
+extern bool out_of_range(NODE *n);
+extern char *format_nan_inf(NODE *n, char format);
+/* re.c */
+extern Regexp *make_regexp(const char *s, size_t len, bool ignorecase, bool dfa, bool canfatal);
+extern int research(Regexp *rp, char *str, int start, size_t len, int flags);
+extern void refree(Regexp *rp);
+extern void reg_error(const char *s);
+extern Regexp *re_update(NODE *t);
+extern void resyntax(int syntax);
+extern void resetup(void);
+extern int reisstring(const char *text, size_t len, Regexp *re, const char *buf);
+extern int get_numbase(const char *str, size_t len, bool use_locale);
+extern bool using_utf8(void);
+
+/* symbol.c */
+extern void load_symbols();
+extern void init_symbol_table();
+extern NODE *symbol_table;
+extern NODE *func_table;
+extern NODE *install_symbol(const char *name, NODETYPE type);
+extern NODE *remove_symbol(NODE *r);
+extern void destroy_symbol(NODE *r);
+extern void release_symbols(NODE *symlist, int keep_globals);
+extern void append_symbol(NODE *r);
+extern NODE *lookup(const char *name);
+extern NODE *make_params(char **pnames, int pcount);
+extern void install_params(NODE *func);
+extern void remove_params(NODE *func);
+extern void release_all_vars(void);
+extern int foreach_func(NODE **table, int (*)(INSTRUCTION *, void *), void *);
+extern INSTRUCTION *bcalloc(OPCODE op, int size, int srcline);
+extern void bcfree(INSTRUCTION *);
+extern AWK_CONTEXT *new_context(void);
+extern void push_context(AWK_CONTEXT *ctxt);
+extern void pop_context();
+extern int in_main_context();
+extern void free_context(AWK_CONTEXT *ctxt, bool keep_globals);
+extern NODE **variable_list();
+extern NODE **function_list(bool sort);
+extern void print_vars(NODE **table, Func_print print_func, FILE *fp);
+extern bool check_param_names(void);
+extern bool is_all_upper(const char *name);
+
+/* floatcomp.c */
+#ifdef HAVE_UINTMAX_T
+extern uintmax_t adjust_uint(uintmax_t n);
+#else
+#define adjust_uint(n) (n)
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#if defined(VMS)
+#define WEXITSTATUS(stat_val) (stat_val)
+#else /* ! defined(VMS) */
+#define WEXITSTATUS(stat_val) ((((unsigned) (stat_val)) >> 8) & 0xFF)
+#endif /* ! defined(VMS)) */
+#endif /* WEXITSTATUS */
+
+/* For z/OS, from Dave Pitts. EXIT_FAILURE is normally 8, make it 1. */
+#if defined(EXIT_FAILURE) && EXIT_FAILURE == 8
+# undef EXIT_FAILURE
+#endif
+
+/* EXIT_SUCCESS and EXIT_FAILURE normally come from <stdlib.h> */
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+/* EXIT_FATAL is specific to gawk, not part of Standard C */
+#ifndef EXIT_FATAL
+# define EXIT_FATAL   2
+#endif
+
+/* ------------------ Inline Functions ------------------ */
+
+/*
+ * These must come last to get all the function declarations and
+ * macro definitions before their bodies.
+ *
+ * This is wasteful if the compiler doesn't support inline. We won't
+ * worry about it until someone complains.
+ */
+
+/* POP_ARRAY --- get the array at the top of the stack */
+
+static inline NODE *
+POP_ARRAY(bool check_for_untyped)
+{
+	NODE *t = POP();
+	static bool warned = false;
+
+	if (do_lint && ! warned && check_for_untyped && t->type == Node_var_new) {
+		warned = true;
+		lintwarn(_("behavior of `for' loop on untyped variable is not defined by POSIX"));
+	}
+
+	return (t->type == Node_var_array) ? t : force_array(t, true);
+}
+
+/* POP_PARAM --- get the top parameter, array or scalar */
+
+static inline NODE *
+POP_PARAM()
+{
+	NODE *t = POP();
+
+	return (t->type == Node_var_array) ? t : force_array(t, false);
+}
+
+/* POP_SCALAR --- pop the scalar at the top of the stack */
+
+static inline NODE *
+POP_SCALAR()
+{
+	NODE *t = POP();
+
+	if (t->type == Node_var_array)
+		fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t));
+
+	return t;
+}
+
+/* TOP_SCALAR --- get the scalar at the top of the stack */
+
+static inline NODE *
+TOP_SCALAR()
+{
+	NODE *t = TOP();
+
+	if (t->type == Node_var_array)
+		fatal(_("attempt to use array `%s' in a scalar context"), array_vname(t));
+
+	return t;
+}
+
+/* POP_STRING --- pop the string at the top of the stack */
+#define POP_STRING()	force_string(POP_SCALAR())
+
+/* TOP_STRING --- get the string at the top of the stack */
+#define TOP_STRING()	force_string(TOP_SCALAR())
+
+/* in_array --- return pointer to element in array if there */
+
+static inline NODE *
+in_array(NODE *a, NODE *s)
+{
+	NODE **ret;
+
+	ret = a->aexists(a, s);
+
+	return ret ? *ret : NULL;
+}
+
+#ifdef GAWKDEBUG
+#define dupnode	r_dupnode
+#else
+/* dupnode --- up the reference on a node */
+
+static inline NODE *
+dupnode(NODE *n)
+{
+	if ((n->flags & MALLOC) != 0) {
+		n->valref++;
+		return n;
+	}
+	return r_dupnode(n);
+}
+#endif
+
+/*
+ * force_string_fmt --- force a node to have a string value in a given format.
+ * The string representation of a number may change due to whether it was most
+ * recently rendered with CONVFMT or OFMT, or due to changes in the CONVFMT
+ * and OFMT values. But if the value entered gawk as a string or strnum, then
+ * stfmt should be set to STFMT_UNUSED, and the string representation should
+ * not change.
+ *
+ * Additional twist: If ROUNDMODE changed at some point we have to
+ * recompute also.
+ */
+
+static inline NODE *
+force_string_fmt(NODE *s, const char *fmtstr, int fmtidx)
+{
+	if ((s->flags & STRCUR) != 0
+		&& (s->stfmt == STFMT_UNUSED || (s->stfmt == fmtidx
+#ifdef HAVE_MPFR
+						&& s->strndmode == MPFR_round_mode
+#endif
+				)))
+		return s;
+	return format_val(fmtstr, fmtidx, s);
+}
+
+/* conceptually should be force_string_convfmt, but this is the typical case */
+#define force_string(s)		force_string_fmt((s), CONVFMT, CONVFMTidx)
+
+#define force_string_ofmt(s)	force_string_fmt((s), OFMT, OFMTidx)
+
+#ifdef GAWKDEBUG
+#define unref	r_unref
+#define	force_number	str2number
+#else /* not GAWKDEBUG */
+
+/* unref --- decrease the reference count and/or free a node */
+
+static inline void
+unref(NODE *r)
+{
+	if (r != NULL && --r->valref <= 0)
+		r_unref(r);
+}
+
+/* force_number --- force a  node to have a numeric value */
+
+static inline NODE *
+force_number(NODE *n)
+{
+	return (n->flags & NUMCUR) != 0 ? n : str2number(n);
+}
+
+#endif /* GAWKDEBUG */
+
+
+/* fixtype --- make a node decide if it's a number or a string */
+
+/*
+ * In certain contexts, the true type of a scalar value matters, and we
+ * must ascertain whether it is a NUMBER or a STRING. In such situations,
+ * please use this function to resolve the type.
+ *
+ * It is safe to assume that the return value will be the same NODE,
+ * since force_number on a USER_INPUT should always return the same NODE,
+ * and force_string on an INTIND should as well.
+ */
+
+static inline NODE *
+fixtype(NODE *n)
+{
+	assert(n->type == Node_val);
+	if ((n->flags & (NUMCUR|USER_INPUT)) == USER_INPUT)
+		return force_number(n);
+	if ((n->flags & INTIND) != 0)
+		return force_string(n);
+	return n;
+}
+
+/* boolval --- return true/false based on awk's criteria */
+
+/*
+ * In awk, a value is considered to be true if it is nonzero _or_
+ * non-null. Otherwise, the value is false.
+ */
+
+static inline bool
+boolval(NODE *t)
+{
+	(void) fixtype(t);
+	if ((t->flags & NUMBER) != 0)
+		return ! iszero(t);
+	return (t->stlen > 0);
+}
+
+/* emalloc_real --- malloc with error checking */
+
+static inline void *
+emalloc_real(size_t count, const char *where, const char *var, const char *file, int line)
+{
+	void *ret;
+
+	if (count == 0)
+		fatal("%s:%d: emalloc called with zero bytes", file, line);
+
+	ret = (void *) malloc(count);
+	if (ret == NULL)
+		fatal(_("%s:%d:%s: %s: can't allocate %ld bytes of memory (%s)"),
+			file, line, where, var, (long) count, strerror(errno));
+
+	return ret;
+}
+
+/* ezalloc_real --- malloc zero-filled bytes with error checking */
+
+static inline void *
+ezalloc_real(size_t count, const char *where, const char *var, const char *file, int line)
+{
+	void *ret;
+
+	if (count == 0)
+		fatal("%s:%d: ezalloc called with zero bytes", file, line);
+
+	ret = (void *) calloc(1, count);
+	if (ret == NULL)
+		fatal(_("%s:%d:%s: %s: can't allocate %ld bytes of memory (%s)"),
+			file, line, where, var, (long) count, strerror(errno));
+
+	return ret;
+}
+
+/* erealloc_real --- realloc with error checking */
+
+static inline void *
+erealloc_real(void *ptr, size_t count, const char *where, const char *var, const char *file, int line)
+{
+	void *ret;
+
+	if (count == 0)
+		fatal("%s:%d: erealloc called with zero bytes", file, line);
+
+	ret = (void *) realloc(ptr, count);
+	if (ret == NULL)
+		fatal(_("%s:%d:%s: %s: can't reallocate %ld bytes of memory (%s)"),
+			file, line, where, var, (long) count, strerror(errno));
+
+	return ret;
+}
+
+/* make_number_node --- make node with the given flags */
+
+static inline NODE *
+make_number_node(unsigned int flags)
+{
+	NODE *r;
+	getnode(r);
+	memset(r, 0, sizeof(*r));
+	r->type = Node_val;
+	r->valref = 1;
+	r->flags = (flags|MALLOC|NUMBER|NUMCUR);
+	return r;
+}
+
+/* assoc_set -- set an element in an array. Does unref(sub)! */
+
+static inline void
+assoc_set(NODE *array, NODE *sub, NODE *value)
+{
+
+	NODE **lhs = assoc_lookup(array, sub);
+	unref(*lhs);
+	*lhs = value;
+	if (array->astore != NULL)
+		(*array->astore)(array, sub);
+	unref(sub);
+}
+
+/*
+ * str_terminate_f, str_terminate, str_restore: function and macros to
+ * reduce chances of typos when terminating and restoring strings.
+ * This also helps to enforce that the NODE must be in scope when we restore.
+ */
+
+static inline void
+str_terminate_f(NODE *n, char *savep)
+{
+	*savep = n->stptr[n->stlen];
+	n->stptr[n->stlen] = '\0';
+}
+
+#define str_terminate(n, save) str_terminate_f((n), &save)
+#define str_restore(n, save) (n)->stptr[(n)->stlen] = save
+
+#ifdef SIGPIPE
+#define ignore_sigpipe() signal(SIGPIPE, SIG_IGN)
+#define set_sigpipe_to_default() signal(SIGPIPE, SIG_DFL)
+#define die_via_sigpipe() (signal(SIGPIPE, SIG_DFL), kill(getpid(), SIGPIPE))
+#else
+#define ignore_sigpipe()
+#define set_sigpipe_to_default()
+#ifdef __MINGW32__
+/* 0xC0000008 is EXCEPTION_INVALID_HANDLE, somewhat appropriate for EPIPE */
+#define die_via_sigpipe() exit(0xC0000008)
+#else  /* !__MINGW32__ */
+#define die_via_sigpipe() exit(EXIT_FATAL)
+#endif	/* !__MINGW32__ */
+#endif
diff --git a/gawk/awkgram.c b/gawk/awkgram.c
new file mode 100644
index 00000000000..68cee61abd8
--- /dev/null
+++ b/gawk/awkgram.c
@@ -0,0 +1,9365 @@
+/* A Bison parser, made by GNU Bison 3.4.  */
+
+/* Bison implementation for Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* 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.  */
+
+/* C LALR(1) parser skeleton 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.  */
+
+/* Undocumented macros, especially those whose name start with YY_,
+   are private implementation details.  Do not rely on them.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "3.4"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* First part of user prologue.  */
+#line 26 "awkgram.y"
+
+#ifdef GAWKDEBUG
+#define YYDEBUG 12
+#endif
+
+#include "awk.h"
+
+#if defined(__STDC__) && __STDC__ < 1	/* VMS weirdness, maybe elsewhere */
+#define signed /**/
+#endif
+
+static void yyerror(const char *m, ...) ATTRIBUTE_PRINTF_1;
+static void error_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
+static void lintwarn_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
+static void warning_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
+static char *get_src_buf(void);
+static int yylex(void);
+int	yyparse(void);
+static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
+static char **check_params(char *fname, int pcount, INSTRUCTION *list);
+static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist);
+static NODE *mk_rexp(INSTRUCTION *exp);
+static void param_sanity(INSTRUCTION *arglist);
+static int parms_shadow(INSTRUCTION *pc, bool *shadow);
+#ifndef NO_LINT
+static int isnoeffect(OPCODE type);
+#endif
+static INSTRUCTION *make_assignable(INSTRUCTION *ip);
+static void dumpintlstr(const char *str, size_t len);
+static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2);
+static bool include_source(INSTRUCTION *file, void **srcfile_p);
+static bool load_library(INSTRUCTION *file, void **srcfile_p);
+static void set_namespace(INSTRUCTION *ns, INSTRUCTION *comment);
+static void next_sourcefile(void);
+static char *tokexpand(void);
+static NODE *set_profile_text(NODE *n, const char *str, size_t len);
+static int check_qualified_special(char *token);
+static char *qualify_name(const char *name, size_t len);
+static INSTRUCTION *trailing_comment;
+static INSTRUCTION *outer_comment;
+static INSTRUCTION *interblock_comment;
+static INSTRUCTION *pending_comment;
+static INSTRUCTION *namespace_chain;
+
+#ifdef DEBUG_COMMENTS
+static void
+debug_print_comment_s(const char *name, INSTRUCTION *comment, int line)
+{
+	if (comment != NULL)
+		fprintf(stderr, "%d: %s: <%.*s>\n", line, name,
+				(int) (comment->memory->stlen - 1),
+				comment->memory->stptr);
+}
+#define debug_print_comment(comment) \
+	 debug_print_comment_s(# comment, comment, __LINE__)
+#endif
+
+#define instruction(t)	bcalloc(t, 1, 0)
+
+static INSTRUCTION *mk_program(void);
+static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action);
+static INSTRUCTION *mk_function(INSTRUCTION *fi, INSTRUCTION *def);
+static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
+		INSTRUCTION *elsep,	INSTRUCTION *false_branch);
+static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1);
+static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
+		INSTRUCTION *incr, INSTRUCTION *body);
+static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target);
+static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op);
+static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op);
+static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op);
+static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype);
+static int count_expressions(INSTRUCTION **list, bool isarg);
+static INSTRUCTION *optimize_assignment(INSTRUCTION *exp);
+static void add_lint(INSTRUCTION *list, LINTTYPE linttype);
+
+enum defref { FUNC_DEFINE, FUNC_USE, FUNC_EXT };
+static void func_use(const char *name, enum defref how);
+static void check_funcs(void);
+
+static ssize_t read_one_line(int fd, void *buffer, size_t count);
+static int one_line_close(int fd);
+static void merge_comments(INSTRUCTION *c1, INSTRUCTION *c2);
+static INSTRUCTION *make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace);
+static void add_sign_to_num(NODE *n, char sign);
+
+static bool at_seen = false;
+static bool want_source = false;
+static bool want_regexp = false;	/* lexical scanning kludge */
+static enum {
+	FUNC_HEADER,
+	FUNC_BODY,
+	DONT_CHECK
+} want_param_names = DONT_CHECK;	/* ditto */
+static bool in_function;		/* parsing kludge */
+static int rule = 0;
+
+const char *const ruletab[] = {
+	"?",
+	"BEGIN",
+	"Rule",
+	"END",
+	"BEGINFILE",
+	"ENDFILE",
+};
+
+static bool in_print = false;	/* lexical scanning kludge for print */
+static int in_parens = 0;	/* lexical scanning kludge for print */
+static int sub_counter = 0;	/* array dimension counter for use in delete */
+static char *lexptr;		/* pointer to next char during parsing */
+static char *lexend;		/* end of buffer */
+static char *lexptr_begin;	/* keep track of where we were for error msgs */
+static char *lexeme;		/* beginning of lexeme for debugging */
+static bool lexeof;		/* seen EOF for current source? */
+static char *thisline = NULL;
+static int in_braces = 0;	/* count braces for firstline, lastline in an 'action' */
+static int lastline = 0;
+static int firstline = 0;
+static SRCFILE *sourcefile = NULL;	/* current program source */
+static int lasttok = 0;
+static bool eof_warned = false;	/* GLOBAL: want warning for each file */
+static int break_allowed;	/* kludge for break */
+static int continue_allowed;	/* kludge for continue */
+
+#define END_FILE	-1000
+#define END_SRC  	-2000
+
+#define YYDEBUG_LEXER_TEXT (lexeme)
+static char *tokstart = NULL;
+static char *tok = NULL;
+static char *tokend;
+int errcount = 0;
+
+extern char *source;
+extern int sourceline;
+extern SRCFILE *srcfiles;
+extern INSTRUCTION *rule_list;
+extern int max_args;
+extern NODE **args_array;
+
+const char awk_namespace[] = "awk";
+const char *current_namespace = awk_namespace;
+bool namespace_changed = false;
+
+static INSTRUCTION *rule_block[sizeof(ruletab)];
+
+static INSTRUCTION *ip_rec;
+static INSTRUCTION *ip_newfile;
+static INSTRUCTION *ip_atexit = NULL;
+static INSTRUCTION *ip_end;
+static INSTRUCTION *ip_endfile;
+static INSTRUCTION *ip_beginfile;
+INSTRUCTION *main_beginfile;
+static bool called_from_eval = false;
+
+static inline INSTRUCTION *list_create(INSTRUCTION *x);
+static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x);
+static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x);
+static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2);
+
+extern double fmod(double x, double y);
+
+#define YYSTYPE INSTRUCTION *
+
+#line 235 "awkgram.c"
+
+# ifndef YY_NULLPTR
+#  if defined __cplusplus
+#   if 201103L <= __cplusplus
+#    define YY_NULLPTR nullptr
+#   else
+#    define YY_NULLPTR 0
+#   endif
+#  else
+#   define YY_NULLPTR ((void*)0)
+#  endif
+# endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+  enum yytokentype
+  {
+    FUNC_CALL = 258,
+    NAME = 259,
+    REGEXP = 260,
+    FILENAME = 261,
+    YNUMBER = 262,
+    YSTRING = 263,
+    TYPED_REGEXP = 264,
+    RELOP = 265,
+    IO_OUT = 266,
+    IO_IN = 267,
+    ASSIGNOP = 268,
+    ASSIGN = 269,
+    MATCHOP = 270,
+    CONCAT_OP = 271,
+    SUBSCRIPT = 272,
+    LEX_BEGIN = 273,
+    LEX_END = 274,
+    LEX_IF = 275,
+    LEX_ELSE = 276,
+    LEX_RETURN = 277,
+    LEX_DELETE = 278,
+    LEX_SWITCH = 279,
+    LEX_CASE = 280,
+    LEX_DEFAULT = 281,
+    LEX_WHILE = 282,
+    LEX_DO = 283,
+    LEX_FOR = 284,
+    LEX_BREAK = 285,
+    LEX_CONTINUE = 286,
+    LEX_PRINT = 287,
+    LEX_PRINTF = 288,
+    LEX_NEXT = 289,
+    LEX_EXIT = 290,
+    LEX_FUNCTION = 291,
+    LEX_BEGINFILE = 292,
+    LEX_ENDFILE = 293,
+    LEX_GETLINE = 294,
+    LEX_NEXTFILE = 295,
+    LEX_IN = 296,
+    LEX_AND = 297,
+    LEX_OR = 298,
+    INCREMENT = 299,
+    DECREMENT = 300,
+    LEX_BUILTIN = 301,
+    LEX_LENGTH = 302,
+    LEX_EOF = 303,
+    LEX_INCLUDE = 304,
+    LEX_EVAL = 305,
+    LEX_LOAD = 306,
+    LEX_NAMESPACE = 307,
+    NEWLINE = 308,
+    SLASH_BEFORE_EQUAL = 309,
+    UNARY = 310
+  };
+#endif
+/* Tokens.  */
+#define FUNC_CALL 258
+#define NAME 259
+#define REGEXP 260
+#define FILENAME 261
+#define YNUMBER 262
+#define YSTRING 263
+#define TYPED_REGEXP 264
+#define RELOP 265
+#define IO_OUT 266
+#define IO_IN 267
+#define ASSIGNOP 268
+#define ASSIGN 269
+#define MATCHOP 270
+#define CONCAT_OP 271
+#define SUBSCRIPT 272
+#define LEX_BEGIN 273
+#define LEX_END 274
+#define LEX_IF 275
+#define LEX_ELSE 276
+#define LEX_RETURN 277
+#define LEX_DELETE 278
+#define LEX_SWITCH 279
+#define LEX_CASE 280
+#define LEX_DEFAULT 281
+#define LEX_WHILE 282
+#define LEX_DO 283
+#define LEX_FOR 284
+#define LEX_BREAK 285
+#define LEX_CONTINUE 286
+#define LEX_PRINT 287
+#define LEX_PRINTF 288
+#define LEX_NEXT 289
+#define LEX_EXIT 290
+#define LEX_FUNCTION 291
+#define LEX_BEGINFILE 292
+#define LEX_ENDFILE 293
+#define LEX_GETLINE 294
+#define LEX_NEXTFILE 295
+#define LEX_IN 296
+#define LEX_AND 297
+#define LEX_OR 298
+#define INCREMENT 299
+#define DECREMENT 300
+#define LEX_BUILTIN 301
+#define LEX_LENGTH 302
+#define LEX_EOF 303
+#define LEX_INCLUDE 304
+#define LEX_EVAL 305
+#define LEX_LOAD 306
+#define LEX_NAMESPACE 307
+#define NEWLINE 308
+#define SLASH_BEFORE_EQUAL 309
+#define UNARY 310
+
+/* Value type.  */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && 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
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#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
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
+#     endif
+#    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 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+             && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  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
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* 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 (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* 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_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   1191
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  77
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  71
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  207
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  355
+
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   310
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, with out-of-bounds checking.  */
+#define YYTRANSLATE(YYX)                                                \
+  ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex.  */
+static const yytype_uint8 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,    65,     2,     2,    68,    64,     2,     2,
+      69,    70,    62,    60,    57,    61,     2,    63,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    56,    76,
+      58,     2,    59,    55,    71,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    72,     2,    73,    67,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    74,     2,    75,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     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,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      66
+};
+
+#if YYDEBUG
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   232,   232,   233,   238,   248,   252,   264,   272,   286,
+     297,   307,   317,   330,   340,   342,   347,   357,   359,   364,
+     366,   368,   374,   378,   383,   413,   425,   437,   443,   452,
+     470,   471,   482,   488,   496,   497,   501,   501,   535,   534,
+     568,   583,   585,   590,   591,   611,   616,   617,   621,   632,
+     637,   644,   752,   803,   853,   979,  1000,  1021,  1031,  1041,
+    1051,  1062,  1075,  1093,  1092,  1109,  1127,  1127,  1229,  1229,
+    1262,  1292,  1300,  1301,  1307,  1308,  1315,  1320,  1333,  1348,
+    1350,  1358,  1365,  1367,  1375,  1384,  1386,  1395,  1396,  1404,
+    1409,  1409,  1422,  1428,  1440,  1444,  1466,  1467,  1473,  1474,
+    1483,  1484,  1489,  1494,  1511,  1513,  1515,  1522,  1523,  1529,
+    1530,  1535,  1537,  1544,  1546,  1554,  1559,  1570,  1571,  1576,
+    1578,  1585,  1587,  1595,  1600,  1610,  1611,  1616,  1623,  1627,
+    1629,  1631,  1644,  1661,  1671,  1678,  1680,  1685,  1687,  1689,
+    1697,  1699,  1704,  1706,  1711,  1713,  1715,  1772,  1774,  1776,
+    1778,  1780,  1782,  1784,  1786,  1800,  1805,  1810,  1835,  1841,
+    1843,  1845,  1847,  1849,  1851,  1856,  1860,  1892,  1900,  1906,
+    1912,  1925,  1926,  1927,  1932,  1937,  1941,  1945,  1960,  1981,
+    1986,  2023,  2060,  2061,  2067,  2068,  2073,  2075,  2082,  2099,
+    2116,  2118,  2125,  2130,  2136,  2147,  2159,  2168,  2172,  2177,
+    2181,  2185,  2189,  2194,  2195,  2199,  2203,  2207
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* 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", "FUNC_CALL", "NAME", "REGEXP",
+  "FILENAME", "YNUMBER", "YSTRING", "TYPED_REGEXP", "RELOP", "IO_OUT",
+  "IO_IN", "ASSIGNOP", "ASSIGN", "MATCHOP", "CONCAT_OP", "SUBSCRIPT",
+  "LEX_BEGIN", "LEX_END", "LEX_IF", "LEX_ELSE", "LEX_RETURN", "LEX_DELETE",
+  "LEX_SWITCH", "LEX_CASE", "LEX_DEFAULT", "LEX_WHILE", "LEX_DO",
+  "LEX_FOR", "LEX_BREAK", "LEX_CONTINUE", "LEX_PRINT", "LEX_PRINTF",
+  "LEX_NEXT", "LEX_EXIT", "LEX_FUNCTION", "LEX_BEGINFILE", "LEX_ENDFILE",
+  "LEX_GETLINE", "LEX_NEXTFILE", "LEX_IN", "LEX_AND", "LEX_OR",
+  "INCREMENT", "DECREMENT", "LEX_BUILTIN", "LEX_LENGTH", "LEX_EOF",
+  "LEX_INCLUDE", "LEX_EVAL", "LEX_LOAD", "LEX_NAMESPACE", "NEWLINE",
+  "SLASH_BEFORE_EQUAL", "'?'", "':'", "','", "'<'", "'>'", "'+'", "'-'",
+  "'*'", "'/'", "'%'", "'!'", "UNARY", "'^'", "'$'", "'('", "')'", "'@'",
+  "'['", "']'", "'{'", "'}'", "';'", "$accept", "program", "rule",
+  "source", "library", "namespace", "pattern", "action", "func_name",
+  "lex_builtin", "function_prologue", "$@1", "regexp", "$@2",
+  "typed_regexp", "a_slash", "statements", "statement_term", "statement",
+  "non_compound_stmt", "$@3", "simple_stmt", "$@4", "$@5",
+  "opt_simple_stmt", "case_statements", "case_statement", "case_value",
+  "print", "print_expression_list", "output_redir", "$@6", "if_statement",
+  "nls", "opt_nls", "input_redir", "opt_param_list", "param_list",
+  "opt_exp", "opt_expression_list", "expression_list",
+  "opt_fcall_expression_list", "fcall_expression_list", "fcall_exp", "exp",
+  "assign_operator", "relop_or_less", "a_relop", "common_exp", "simp_exp",
+  "simp_exp_nc", "non_post_simp_exp", "func_call", "direct_func_call",
+  "opt_variable", "delete_subscript_list", "delete_subscript",
+  "delete_exp_list", "bracketed_exp_list", "subscript", "subscript_list",
+  "simple_variable", "variable", "opt_incdec", "l_brace", "r_brace",
+  "r_paren", "opt_semi", "semi", "colon", "comma", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
+static const yytype_uint16 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,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,   306,   307,   308,   309,    63,    58,    44,    60,    62,
+      43,    45,    42,    47,    37,    33,   310,    94,    36,    40,
+      41,    64,    91,    93,   123,   125,    59
+};
+# endif
+
+#define YYPACT_NINF -283
+
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-283)))
+
+#define YYTABLE_NINF -119
+
+#define yytable_value_is_error(Yytable_value) \
+  (!!((Yytable_value) == (-119)))
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int16 yypact[] =
+{
+    -283,   316,  -283,  -283,   -45,   -28,  -283,  -283,  -283,  -283,
+     160,  -283,  -283,    23,    23,    23,   -39,   -18,  -283,  -283,
+    -283,  1047,  1047,  -283,  1047,  1075,   818,   257,  -283,    99,
+     -20,  -283,  -283,    11,  1017,   974,   378,   415,  -283,  -283,
+    -283,  -283,   329,   742,   818,  -283,     0,  -283,  -283,  -283,
+    -283,  -283,    25,     9,  -283,    22,  -283,  -283,  -283,   742,
+     742,    79,    46,    18,    46,    46,  1047,   114,  -283,  -283,
+      13,   286,    44,    47,    60,  -283,    94,  -283,  -283,  -283,
+      11,  -283,    94,  -283,   151,  -283,  -283,  1002,   162,  1047,
+    1047,  1047,    94,  -283,  -283,  -283,  1047,  1047,   132,   378,
+    1047,  1047,  1047,  1047,  1047,  1047,  1047,  1047,  1047,  1047,
+    1047,  1047,  -283,   170,  -283,  -283,   168,  1047,  -283,  -283,
+    -283,   116,    14,  -283,  1132,    76,  1132,  -283,  -283,  -283,
+    -283,  1047,  -283,   116,   116,   286,  -283,  -283,  -283,  1047,
+    -283,   144,   846,  -283,  -283,    34,    91,  -283,    39,    91,
+    -283,    59,    91,    11,  -283,   542,  -283,  -283,  -283,   145,
+    -283,   135,   580,  1113,  -283,   189,  1132,    23,   230,   230,
+      46,    46,    46,    46,   230,   230,    46,    46,    46,    46,
+    -283,  -283,  1132,  -283,  1002,   770,  -283,    27,   378,  -283,
+    -283,  1132,   162,  -283,  1132,  -283,  -283,  -283,  -283,  -283,
+    -283,  -283,   119,  -283,    12,   123,   126,    94,   128,    91,
+      91,  -283,  -283,    91,  1047,    91,    94,  -283,  -283,    91,
+    -283,  -283,  1132,  -283,   122,    94,  1047,  -283,  -283,  -283,
+    -283,  -283,  -283,   116,    73,  -283,  1047,  1047,  -283,   198,
+    1047,  1047,   660,   895,  -283,  -283,  -283,    91,  1132,  -283,
+    -283,  -283,   590,   542,    94,  -283,  -283,  1132,    94,  -283,
+      28,   286,    91,   -28,   141,   286,   286,   190,   -23,  -283,
+     122,  -283,   818,   205,  -283,   325,  -283,  -283,  -283,  -283,
+    -283,    94,  -283,  -283,   115,  -283,  -283,  -283,    94,    94,
+     153,   162,    94,    13,  -283,  -283,   660,  -283,  -283,   -20,
+     660,  1047,   116,   694,   144,  1047,   209,  -283,  -283,   286,
+      94,  1090,    94,   974,    94,   152,    94,   660,    94,   929,
+     660,  -283,   342,   176,  -283,   158,  -283,  -283,   929,   116,
+    -283,  -283,  -283,   236,   243,  -283,  -283,   176,  -283,    94,
+    -283,   116,    94,  -283,  -283,    94,  -283,    94,   660,  -283,
+     390,   660,  -283,   466,  -283
+};
+
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,     0,     1,     6,     0,   193,   175,   176,    25,    26,
+       0,    27,    28,   182,     0,     0,     0,   170,     5,    94,
+      42,     0,     0,    41,     0,     0,     0,     0,     3,     0,
+       0,   165,    38,     4,    23,   136,   144,   145,   147,   171,
+     179,   195,   172,     0,     0,   190,     0,   194,    31,    30,
+      34,    35,     0,     0,    32,    98,   183,   173,   174,     0,
+       0,     0,   178,   172,   177,   166,     0,   199,   172,   113,
+       0,   111,     0,     0,     0,   180,    96,   205,     7,     8,
+      46,    43,    96,     9,     0,    95,   140,     0,     0,     0,
+       0,     0,    96,   141,   143,   142,     0,     0,     0,   146,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   138,   137,   155,   156,     0,     0,   121,    40,
+     126,     0,     0,   119,   125,     0,   111,   192,   191,    33,
+      36,     0,   154,     0,     0,     0,   197,   198,   196,   114,
+     202,     0,     0,   167,    15,     0,     0,    18,     0,     0,
+      21,     0,     0,    97,   200,     0,    47,    39,   131,   132,
+     133,   129,   130,     0,   207,   134,    24,   182,   152,   153,
+     149,   150,   151,   148,   163,   164,   160,   161,   162,   159,
+     128,   139,   127,   181,   122,     0,   189,     0,    99,   168,
+     169,   115,     0,   116,   112,    14,    10,    17,    11,    20,
+      12,    45,     0,    63,     0,     0,     0,    96,     0,     0,
+       0,    85,    86,     0,   107,     0,    96,    44,    57,     0,
+      66,    50,    71,    43,   203,    96,     0,   158,   123,   124,
+     120,   104,   102,     0,     0,   157,     0,   107,    68,     0,
+       0,     0,     0,    72,    58,    59,    60,     0,   108,    61,
+     201,    65,     0,     0,    96,   204,    48,   135,    96,   105,
+       0,     0,     0,   184,     0,     0,     0,     0,   193,    73,
+       0,    62,     0,    89,    87,     0,    49,    29,    37,   106,
+     103,    96,    64,    69,     0,   186,   188,    70,    96,    96,
+       0,     0,    96,     0,    90,    67,     0,   185,   187,     0,
+       0,     0,     0,     0,    88,     0,    92,    74,    52,     0,
+      96,     0,    96,    91,    96,     0,    96,     0,    96,    72,
+       0,    76,     0,     0,    75,     0,    53,    54,    72,     0,
+      93,    79,    82,     0,     0,    83,    84,     0,   206,    96,
+      51,     0,    96,    81,    80,    96,    43,    96,     0,    43,
+       0,     0,    56,     0,    55
+};
+
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -283,  -283,  -283,  -283,  -283,  -283,  -283,   226,  -283,  -283,
+    -283,  -283,   -63,  -283,   -77,  -283,  -215,   -73,   -30,  -283,
+    -283,  -234,  -283,  -283,  -282,  -283,  -283,  -283,  -283,  -283,
+    -283,  -283,  -283,     5,   -35,  -283,  -283,  -283,    24,  -283,
+     -43,   101,  -283,   -15,    -1,  -283,  -283,  -283,   -40,    17,
+    -283,   237,  -283,    -6,    96,  -283,  -283,   -16,   -42,  -283,
+    -283,   -81,    -2,  -283,   -27,  -186,   -65,  -283,   -62,   -68,
+      -8
+};
+
+  /* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,    28,   146,   149,   152,    29,    78,    53,    54,
+      30,   187,    31,    84,   120,    32,   155,    79,   217,   218,
+     237,   219,   252,   263,   270,   315,   324,   337,   220,   273,
+     295,   305,   221,   153,   154,   132,   233,   234,   247,   274,
+      70,   121,   122,   123,   222,   117,    95,    96,    35,    36,
+      37,    38,    39,    40,    55,   283,   284,   285,    45,    46,
+      47,    41,    42,   138,   223,   224,   143,   254,    82,   339,
+     142
+};
+
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
+static const yytype_int16 yytable[] =
+{
+      34,   125,    81,    81,   128,   141,    33,   160,   253,   269,
+     158,    56,    57,    58,   139,   184,   238,   127,   291,    63,
+      63,    75,    63,    68,    43,    71,    97,     5,   231,   279,
+      59,   232,   280,    63,    80,   195,   180,   329,    62,    64,
+     197,    65,   124,   126,    44,   144,   341,   156,   147,    44,
+     145,    60,    99,   148,    76,    75,   183,   164,   124,   124,
+     199,   150,   114,   115,    85,   135,   151,   276,   189,   190,
+      92,    92,    44,   196,   259,   129,   198,   139,   130,   200,
+     131,   239,     4,   140,  -118,   269,   159,   -13,   161,   162,
+     163,    25,   -16,   225,   269,   165,   166,  -100,    63,    63,
+      63,    63,    63,    63,    63,    63,    63,    63,    63,    63,
+     -13,   235,   -19,   105,   185,   -16,   182,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,    63,
+      92,   350,   297,    92,   353,   -19,   244,   245,   191,   340,
+     246,   194,   249,  -101,    19,    86,   251,    19,   188,   186,
+      87,    80,    19,   321,    80,    86,   157,    80,   136,   137,
+     133,   134,   255,    48,    49,    56,     5,    77,   258,   228,
+     230,   167,   242,    76,   271,    77,    88,   322,   323,   119,
+     225,   250,   181,   124,   124,   192,   140,    44,   236,   282,
+     256,   225,   240,    93,    94,   241,   281,   243,    77,  -119,
+     288,   289,   264,    93,    94,    19,    50,    51,   292,   275,
+     302,   287,   267,   248,    80,    80,   294,   290,    80,   277,
+      80,   286,   301,   278,    80,   257,   260,   -96,   304,   293,
+     314,    52,   338,   216,   225,   261,   248,   310,   225,   265,
+     266,   312,   286,   343,   316,   336,   296,  -119,  -119,   318,
+     344,   126,    80,   299,   300,   225,    83,   303,   225,   335,
+       4,   262,    67,   227,   342,   313,   306,    80,   298,   345,
+     308,    71,   307,     0,     0,   317,   347,   319,     0,   320,
+     325,   326,     0,   328,     0,     0,   225,   327,   225,   225,
+     330,   225,   102,   103,   104,     0,    86,   105,     0,     0,
+     309,    87,   311,    63,   346,     0,    72,   348,    73,    74,
+     349,    63,   351,     0,     0,     0,     2,     3,   352,     4,
+       5,   354,     0,     6,     7,     0,   139,    88,    89,    90,
+      99,     0,     0,     0,     8,     9,  -110,     0,     0,     0,
+       0,    91,   112,   113,    93,    94,     0,     0,     0,   331,
+     332,   119,    10,    11,    12,    13,   140,     0,     0,     0,
+      14,    15,    16,    17,    18,     0,     0,     0,     0,    19,
+      20,     0,     0,   114,   115,     0,    21,    22,  -110,    23,
+       0,    24,    92,   116,    25,    26,     0,    27,     0,     0,
+     -22,   201,   -22,     4,     5,  -110,    20,     6,     7,     0,
+       0,  -110,   333,   334,     0,    23,     0,     0,     0,     0,
+     202,     0,   203,   204,   205,   -78,   -78,   206,   207,   208,
+     209,   210,   211,   212,   213,   214,     0,     0,     0,    13,
+     215,     0,     0,     0,    14,    15,    16,    17,   100,   101,
+     102,   103,   104,   -78,    20,   105,     0,     0,     0,     0,
+      21,    22,     0,    23,     0,    24,     0,     0,    25,    26,
+       0,    61,     0,     0,    76,   -78,    77,   201,     0,     4,
+       5,     0,     0,     6,     7,   106,   107,   108,   109,   110,
+       0,     0,   111,     0,     0,     0,   202,     0,   203,   204,
+     205,   -77,   -77,   206,   207,   208,   209,   210,   211,   212,
+     213,   214,     0,     0,     0,    13,   215,     0,     0,     0,
+      14,    15,    16,    17,     0,     0,     0,     0,     0,   -77,
+      20,     0,     0,     0,     0,     0,    21,    22,     0,    23,
+       0,    24,     0,     0,    25,    26,     0,    61,     0,     0,
+      76,   -77,    77,   201,     0,     4,     5,     0,     0,     6,
+       7,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   202,     0,   203,   204,   205,     0,     0,   206,
+     207,   208,   209,   210,   211,   212,   213,   214,     0,     0,
+       0,    13,   215,     0,     0,     0,    14,    15,    16,    17,
+      86,    69,     0,     4,     5,    87,    20,     6,     7,     0,
+       0,  -109,    21,    22,     0,    23,     0,    24,     0,     0,
+      25,    26,     0,    61,     0,     0,    76,   216,    77,     0,
+       0,    88,    89,     0,     0,     0,     0,     0,     0,    13,
+       0,     0,     0,     0,    14,    15,    16,    17,    93,    94,
+       0,     0,     0,  -109,    20,     0,     0,     0,     0,     0,
+      21,    22,     0,    23,     0,    24,     0,     0,    25,   272,
+    -109,    61,     0,     4,     5,     0,  -109,     6,     7,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     202,     0,   203,   204,   205,     0,     0,   206,   207,   208,
+     209,   210,   211,   212,   213,   214,     0,     4,     5,    13,
+     215,     6,     7,     0,    14,    15,    16,    17,     0,     0,
+       0,     0,     0,     0,    20,     0,     0,     0,     0,     0,
+      21,    22,     0,    23,     0,    24,     0,     0,    25,    26,
+       0,    61,     0,    13,    76,     0,    77,     0,    14,    15,
+      16,    17,     0,   118,     0,     4,     5,     0,    20,     6,
+       7,   119,     0,     0,    21,    22,     0,    23,     0,    24,
+       0,     0,    25,    26,     0,    61,     0,     0,     0,     0,
+      77,   229,     0,     4,     5,     0,     0,     6,     7,   119,
+       0,    13,     0,     0,     0,     0,    14,    15,    16,    17,
+       0,     0,     0,     0,     0,     0,    20,     0,     0,     0,
+       0,     0,    21,    22,     0,    23,     0,    24,     0,    13,
+      25,    26,  -117,    61,    14,    15,    16,    17,     0,    69,
+       0,     4,     5,     0,    20,     6,     7,     0,     0,     0,
+      21,    22,     0,    23,     0,    24,     0,     0,    25,    26,
+       0,    61,     0,     0,     0,     0,     0,   193,     0,     4,
+       5,     0,     0,     6,     7,     0,     0,    13,     0,     0,
+       0,     0,    14,    15,    16,    17,     0,     0,     0,     0,
+       0,     0,    20,     0,     0,     0,     0,     0,    21,    22,
+       0,    23,     0,    24,     0,    13,    25,    26,     0,    61,
+      14,    15,    16,    17,     0,     0,     0,     0,     4,   268,
+      20,     0,     6,     7,     0,     0,    21,    22,     0,    23,
+       0,    24,     0,     0,    25,    26,     0,    61,   204,     0,
+       0,     0,     0,     0,     0,     0,     0,   211,   212,     0,
+       0,     0,     4,     5,    13,     0,     6,     7,     0,    14,
+      15,    16,    17,     0,     0,     0,     0,     0,     0,    20,
+       0,     0,   204,     0,     0,    21,    22,     0,    23,     0,
+      24,   211,   212,    25,    26,     0,    61,     0,    13,     0,
+       0,     0,     0,    14,    15,    16,    17,     4,     5,     0,
+       0,     6,     7,    20,     0,     0,    98,     0,     0,    21,
+      22,     0,    23,     0,    24,     0,     0,    25,    26,     0,
+      61,     0,     0,     0,     0,     4,     5,     0,     0,     6,
+       7,   119,     0,    13,     0,     0,     0,     0,    14,    15,
+      16,    17,     0,     0,     0,     0,     0,    86,    20,     0,
+       0,     0,    87,     0,    21,    22,     0,    23,     0,    24,
+       0,    13,    25,    26,     0,    61,    14,    15,    16,    17,
+       4,     5,     0,     0,     6,     7,    20,     0,    88,    89,
+      90,     0,    21,    22,     0,    23,     0,    24,     0,     0,
+      25,    26,    91,    61,    92,    93,    94,     0,     4,     5,
+       0,     0,     6,     7,     0,     0,    13,     0,     0,     0,
+       0,    14,    15,    16,    17,     0,     0,     0,     0,     0,
+      86,    20,     0,     0,     0,    87,     0,    21,    22,     0,
+      23,     0,    24,     0,     0,    25,    26,     0,    61,    14,
+      15,    16,    17,    86,     0,     0,     0,     0,    87,    20,
+       0,    88,    89,    90,     0,    21,    22,     0,    23,     0,
+      24,     0,    86,    25,    66,    91,    61,    87,    93,    94,
+       0,     0,     0,     0,    88,    89,    90,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    77,     0,    91,   226,
+       0,    93,    94,    88,    89,    90,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    91,     0,     0,
+      93,    94
+};
+
+static const yytype_int16 yycheck[] =
+{
+       1,    44,    29,    30,    46,    70,     1,    88,   223,   243,
+      87,    13,    14,    15,     1,     1,     4,    17,    41,    21,
+      22,    27,    24,    25,    69,    26,    34,     4,     1,     1,
+      69,     4,     4,    35,    29,     1,   113,   319,    21,    22,
+       1,    24,    43,    44,    72,     1,   328,    82,     1,    72,
+       6,    69,    35,     6,    74,    61,   121,    92,    59,    60,
+       1,     1,    44,    45,    53,    66,     6,   253,   133,   134,
+      57,    57,    72,   146,     1,    50,   149,     1,    69,   152,
+      58,    69,     3,    70,    70,   319,    87,    53,    89,    90,
+      91,    68,    53,   155,   328,    96,    97,    70,   100,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   111,
+      76,   192,    53,    67,   122,    76,   117,   100,   101,   102,
+     103,   104,   105,   106,   107,   108,   109,   110,   111,   131,
+      57,   346,    17,    57,   349,    76,   209,   210,   139,   325,
+     213,   142,   215,    70,    53,    10,   219,    53,   131,    73,
+      15,   146,    53,     1,   149,    10,     5,   152,    44,    45,
+      59,    60,   224,     3,     4,   167,     4,    76,   233,   184,
+     185,    39,   207,    74,   247,    76,    41,    25,    26,     9,
+     242,   216,    14,   184,   185,    41,    70,    72,    69,   262,
+     225,   253,    69,    58,    59,    69,   261,    69,    76,    10,
+     265,   266,     4,    58,    59,    53,    46,    47,   270,   252,
+     291,    70,   242,   214,   209,   210,    11,    27,   213,   254,
+     215,   263,    69,   258,   219,   226,   234,    75,   293,   272,
+      21,    71,    56,    75,   296,   236,   237,   302,   300,   240,
+     241,   303,   284,     7,   309,   322,   281,    58,    59,   311,
+       7,   252,   247,   288,   289,   317,    30,   292,   320,   322,
+       3,   237,    25,   167,   329,   305,   296,   262,   284,   337,
+     300,   272,   299,    -1,    -1,   310,   341,   312,    -1,   314,
+     315,   316,    -1,   318,    -1,    -1,   348,   317,   350,   351,
+     320,   353,    62,    63,    64,    -1,    10,    67,    -1,    -1,
+     301,    15,   303,   305,   339,    -1,    49,   342,    51,    52,
+     345,   313,   347,    -1,    -1,    -1,     0,     1,   348,     3,
+       4,   351,    -1,     7,     8,    -1,     1,    41,    42,    43,
+     313,    -1,    -1,    -1,    18,    19,    11,    -1,    -1,    -1,
+      -1,    55,    13,    14,    58,    59,    -1,    -1,    -1,     7,
+       8,     9,    36,    37,    38,    39,    70,    -1,    -1,    -1,
+      44,    45,    46,    47,    48,    -1,    -1,    -1,    -1,    53,
+      54,    -1,    -1,    44,    45,    -1,    60,    61,    53,    63,
+      -1,    65,    57,    54,    68,    69,    -1,    71,    -1,    -1,
+      74,     1,    76,     3,     4,    70,    54,     7,     8,    -1,
+      -1,    76,    60,    61,    -1,    63,    -1,    -1,    -1,    -1,
+      20,    -1,    22,    23,    24,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    -1,    -1,    -1,    39,
+      40,    -1,    -1,    -1,    44,    45,    46,    47,    60,    61,
+      62,    63,    64,    53,    54,    67,    -1,    -1,    -1,    -1,
+      60,    61,    -1,    63,    -1,    65,    -1,    -1,    68,    69,
+      -1,    71,    -1,    -1,    74,    75,    76,     1,    -1,     3,
+       4,    -1,    -1,     7,     8,    60,    61,    62,    63,    64,
+      -1,    -1,    67,    -1,    -1,    -1,    20,    -1,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
+      34,    35,    -1,    -1,    -1,    39,    40,    -1,    -1,    -1,
+      44,    45,    46,    47,    -1,    -1,    -1,    -1,    -1,    53,
+      54,    -1,    -1,    -1,    -1,    -1,    60,    61,    -1,    63,
+      -1,    65,    -1,    -1,    68,    69,    -1,    71,    -1,    -1,
+      74,    75,    76,     1,    -1,     3,     4,    -1,    -1,     7,
+       8,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    20,    -1,    22,    23,    24,    -1,    -1,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    -1,    -1,
+      -1,    39,    40,    -1,    -1,    -1,    44,    45,    46,    47,
+      10,     1,    -1,     3,     4,    15,    54,     7,     8,    -1,
+      -1,    11,    60,    61,    -1,    63,    -1,    65,    -1,    -1,
+      68,    69,    -1,    71,    -1,    -1,    74,    75,    76,    -1,
+      -1,    41,    42,    -1,    -1,    -1,    -1,    -1,    -1,    39,
+      -1,    -1,    -1,    -1,    44,    45,    46,    47,    58,    59,
+      -1,    -1,    -1,    53,    54,    -1,    -1,    -1,    -1,    -1,
+      60,    61,    -1,    63,    -1,    65,    -1,    -1,    68,    69,
+      70,    71,    -1,     3,     4,    -1,    76,     7,     8,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      20,    -1,    22,    23,    24,    -1,    -1,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    -1,     3,     4,    39,
+      40,     7,     8,    -1,    44,    45,    46,    47,    -1,    -1,
+      -1,    -1,    -1,    -1,    54,    -1,    -1,    -1,    -1,    -1,
+      60,    61,    -1,    63,    -1,    65,    -1,    -1,    68,    69,
+      -1,    71,    -1,    39,    74,    -1,    76,    -1,    44,    45,
+      46,    47,    -1,     1,    -1,     3,     4,    -1,    54,     7,
+       8,     9,    -1,    -1,    60,    61,    -1,    63,    -1,    65,
+      -1,    -1,    68,    69,    -1,    71,    -1,    -1,    -1,    -1,
+      76,     1,    -1,     3,     4,    -1,    -1,     7,     8,     9,
+      -1,    39,    -1,    -1,    -1,    -1,    44,    45,    46,    47,
+      -1,    -1,    -1,    -1,    -1,    -1,    54,    -1,    -1,    -1,
+      -1,    -1,    60,    61,    -1,    63,    -1,    65,    -1,    39,
+      68,    69,    70,    71,    44,    45,    46,    47,    -1,     1,
+      -1,     3,     4,    -1,    54,     7,     8,    -1,    -1,    -1,
+      60,    61,    -1,    63,    -1,    65,    -1,    -1,    68,    69,
+      -1,    71,    -1,    -1,    -1,    -1,    -1,     1,    -1,     3,
+       4,    -1,    -1,     7,     8,    -1,    -1,    39,    -1,    -1,
+      -1,    -1,    44,    45,    46,    47,    -1,    -1,    -1,    -1,
+      -1,    -1,    54,    -1,    -1,    -1,    -1,    -1,    60,    61,
+      -1,    63,    -1,    65,    -1,    39,    68,    69,    -1,    71,
+      44,    45,    46,    47,    -1,    -1,    -1,    -1,     3,     4,
+      54,    -1,     7,     8,    -1,    -1,    60,    61,    -1,    63,
+      -1,    65,    -1,    -1,    68,    69,    -1,    71,    23,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    32,    33,    -1,
+      -1,    -1,     3,     4,    39,    -1,     7,     8,    -1,    44,
+      45,    46,    47,    -1,    -1,    -1,    -1,    -1,    -1,    54,
+      -1,    -1,    23,    -1,    -1,    60,    61,    -1,    63,    -1,
+      65,    32,    33,    68,    69,    -1,    71,    -1,    39,    -1,
+      -1,    -1,    -1,    44,    45,    46,    47,     3,     4,    -1,
+      -1,     7,     8,    54,    -1,    -1,    12,    -1,    -1,    60,
+      61,    -1,    63,    -1,    65,    -1,    -1,    68,    69,    -1,
+      71,    -1,    -1,    -1,    -1,     3,     4,    -1,    -1,     7,
+       8,     9,    -1,    39,    -1,    -1,    -1,    -1,    44,    45,
+      46,    47,    -1,    -1,    -1,    -1,    -1,    10,    54,    -1,
+      -1,    -1,    15,    -1,    60,    61,    -1,    63,    -1,    65,
+      -1,    39,    68,    69,    -1,    71,    44,    45,    46,    47,
+       3,     4,    -1,    -1,     7,     8,    54,    -1,    41,    42,
+      43,    -1,    60,    61,    -1,    63,    -1,    65,    -1,    -1,
+      68,    69,    55,    71,    57,    58,    59,    -1,     3,     4,
+      -1,    -1,     7,     8,    -1,    -1,    39,    -1,    -1,    -1,
+      -1,    44,    45,    46,    47,    -1,    -1,    -1,    -1,    -1,
+      10,    54,    -1,    -1,    -1,    15,    -1,    60,    61,    -1,
+      63,    -1,    65,    -1,    -1,    68,    69,    -1,    71,    44,
+      45,    46,    47,    10,    -1,    -1,    -1,    -1,    15,    54,
+      -1,    41,    42,    43,    -1,    60,    61,    -1,    63,    -1,
+      65,    -1,    10,    68,    69,    55,    71,    15,    58,    59,
+      -1,    -1,    -1,    -1,    41,    42,    43,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    76,    -1,    55,    56,
+      -1,    58,    59,    41,    42,    43,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    55,    -1,    -1,
+      58,    59
+};
+
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    78,     0,     1,     3,     4,     7,     8,    18,    19,
+      36,    37,    38,    39,    44,    45,    46,    47,    48,    53,
+      54,    60,    61,    63,    65,    68,    69,    71,    79,    83,
+      87,    89,    92,   110,   121,   125,   126,   127,   128,   129,
+     130,   138,   139,    69,    72,   135,   136,   137,     3,     4,
+      46,    47,    71,    85,    86,   131,   139,   139,   139,    69,
+      69,    71,   126,   139,   126,   126,    69,   128,   139,     1,
+     117,   121,    49,    51,    52,   130,    74,    76,    84,    94,
+     110,   141,   145,    84,    90,    53,    10,    15,    41,    42,
+      43,    55,    57,    58,    59,   123,   124,   147,    12,   126,
+      60,    61,    62,    63,    64,    67,    60,    61,    62,    63,
+      64,    67,    13,    14,    44,    45,    54,   122,     1,     9,
+      91,   118,   119,   120,   121,   117,   121,    17,   135,    50,
+      69,    58,   112,   118,   118,   121,    44,    45,   140,     1,
+      70,   143,   147,   143,     1,     6,    80,     1,     6,    81,
+       1,     6,    82,   110,   111,    93,   111,     5,    91,   121,
+     138,   121,   121,   121,   111,   121,   121,    39,   126,   126,
+     126,   126,   126,   126,   126,   126,   126,   126,   126,   126,
+      91,    14,   121,   143,     1,   147,    73,    88,   126,   143,
+     143,   121,    41,     1,   121,     1,    94,     1,    94,     1,
+      94,     1,    20,    22,    23,    24,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    40,    75,    95,    96,    98,
+     105,   109,   121,   141,   142,   145,    56,   131,   120,     1,
+     120,     1,     4,   113,   114,   138,    69,    97,     4,    69,
+      69,    69,   111,    69,    94,    94,    94,   115,   121,    94,
+     111,    94,    99,    93,   144,   145,   111,   121,   143,     1,
+     147,   121,   115,   100,     4,   121,   121,    95,     4,    98,
+     101,    94,    69,   106,   116,   117,   142,   111,   111,     1,
+       4,   143,    94,   132,   133,   134,   135,    70,   143,   143,
+      27,    41,   145,   117,    11,   107,   111,    17,   134,   111,
+     111,    69,   138,   111,   143,   108,    95,   141,    95,   121,
+     143,   121,   145,   125,    21,   102,   143,   111,   145,   111,
+     111,     1,    25,    26,   103,   111,   111,    95,   111,   101,
+      95,     7,     8,    60,    61,    89,    91,   104,    56,   146,
+     142,   101,   143,     7,     7,   146,   111,   143,   111,   111,
+      93,   111,    95,    93,    95
+};
+
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    77,    78,    78,    78,    78,    78,    79,    79,    79,
+      79,    79,    79,    80,    80,    80,    81,    81,    81,    82,
+      82,    82,    83,    83,    83,    83,    83,    83,    83,    84,
+      85,    85,    85,    85,    86,    86,    88,    87,    90,    89,
+      91,    92,    92,    93,    93,    93,    94,    94,    95,    95,
+      95,    95,    95,    95,    95,    95,    95,    95,    96,    96,
+      96,    96,    96,    97,    96,    96,    99,    98,   100,    98,
+      98,    98,   101,   101,   102,   102,   102,   103,   103,   104,
+     104,   104,   104,   104,   104,   105,   105,   106,   106,   107,
+     108,   107,   109,   109,   110,   110,   111,   111,   112,   112,
+     113,   113,   114,   114,   114,   114,   114,   115,   115,   116,
+     116,   117,   117,   117,   117,   117,   117,   118,   118,   119,
+     119,   119,   119,   119,   119,   120,   120,   121,   121,   121,
+     121,   121,   121,   121,   121,   121,   121,   122,   122,   122,
+     123,   123,   124,   124,   125,   125,   125,   126,   126,   126,
+     126,   126,   126,   126,   126,   126,   126,   126,   127,   127,
+     127,   127,   127,   127,   127,   128,   128,   128,   128,   128,
+     128,   128,   128,   128,   128,   128,   128,   128,   128,   129,
+     129,   130,   131,   131,   132,   132,   133,   133,   134,   135,
+     136,   136,   137,   138,   138,   139,   139,   140,   140,   140,
+     141,   142,   143,   144,   144,   145,   146,   147
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     2,     2,     2,     2,     2,
+       4,     4,     4,     1,     2,     1,     1,     2,     1,     1,
+       2,     1,     0,     1,     3,     1,     1,     1,     1,     5,
+       1,     1,     1,     2,     1,     1,     0,     7,     0,     3,
+       1,     1,     1,     0,     2,     2,     1,     2,     2,     3,
+       1,     9,     6,     8,     8,    12,    11,     1,     2,     2,
+       2,     2,     3,     0,     4,     2,     0,     4,     0,     4,
+       4,     1,     0,     1,     0,     2,     2,     5,     4,     1,
+       2,     2,     1,     1,     1,     1,     1,     1,     3,     0,
+       0,     3,     6,     9,     1,     2,     0,     1,     0,     2,
+       0,     1,     1,     3,     1,     2,     3,     0,     1,     0,
+       1,     1,     3,     1,     2,     3,     3,     0,     1,     1,
+       3,     1,     2,     3,     3,     1,     1,     3,     3,     3,
+       3,     3,     3,     3,     3,     5,     1,     1,     1,     2,
+       1,     1,     1,     1,     1,     1,     2,     1,     3,     3,
+       3,     3,     3,     3,     3,     2,     2,     5,     4,     3,
+       3,     3,     3,     3,     3,     1,     2,     3,     4,     4,
+       1,     1,     1,     2,     2,     1,     1,     2,     2,     1,
+       2,     4,     0,     1,     0,     2,     1,     2,     1,     3,
+       1,     2,     2,     1,     2,     1,     3,     1,     1,     0,
+       2,     2,     1,     0,     1,     1,     1,     2
+};
+
+
+#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
+
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                    \
+  do                                                              \
+    if (yychar == YYEMPTY)                                        \
+      {                                                           \
+        yychar = (Token);                                         \
+        yylval = (Value);                                         \
+        YYPOPSTACK (yylen);                                       \
+        yystate = *yyssp;                                         \
+        goto yybackup;                                            \
+      }                                                           \
+    else                                                          \
+      {                                                           \
+        yyerror (YY_("syntax error: cannot back up")); \
+        YYERROR;                                                  \
+      }                                                           \
+  while (0)
+
+/* Error token number */
+#define YYTERROR        1
+#define YYERRCODE       256
+
+
+
+/* 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)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO.  |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep)
+{
+  FILE *yyoutput = yyo;
+  YYUSE (yyoutput);
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyo, yytoknum[yytype], *yyvaluep);
+# endif
+  YYUSE (yytype);
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO.  |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep)
+{
+  YYFPRINTF (yyo, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+  yy_symbol_value_print (yyo, yytype, yyvaluep);
+  YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  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.  |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
+{
+  unsigned long yylno = yyrline[yyrule];
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+             yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &yyvsp[(yyi + 1) - (yynrhs)]
+                                              );
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, 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
+yystrlen (const char *yystr)
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  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 *
+yystpcpy (char *yydest, const char *yysrc)
+{
+  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 == '"')
+    {
+      YYSIZE_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;
+            else
+              goto append;
+
+          append:
+          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 (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres);
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
+
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = YY_NULLPTR;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
+    {
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                {
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+                  if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+                    yysize = yysize1;
+                  else
+                    return 2;
+                }
+              }
+        }
+    }
+
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+    default: /* Avoid compiler warnings. */
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
+
+  {
+    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+    if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+      yysize = yysize1;
+    else
+      return 2;
+  }
+
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
+    }
+
+  /* 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 = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+{
+  YYUSE (yyvaluep);
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+int
+yyparse (void)
+{
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
+
+    /* The stacks and their tools:
+       'yyss': related to states.
+       'yyvs': related to semantic values.
+
+       Refer to the stacks through separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
+
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
+
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
+
+    YYSIZE_T yystacksize;
+
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yyssp = yyss = yyssa;
+  yyvsp = yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+  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++;
+
+
+/*--------------------------------------------------------------------.
+| yynewstate -- set current state (the top of the stack) to yystate.  |
+`--------------------------------------------------------------------*/
+yysetstate:
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+  YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+  *yyssp = (yytype_int16) yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+    goto yyexhaustedlab;
+#else
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1);
+
+# if defined 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;
+        yytype_int16 *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 /* defined YYSTACK_RELOCATE */
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                  (unsigned long) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead 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 (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+  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 232 "awkgram.y"
+    { yyval = NULL; }
+#line 1917 "awkgram.c"
+    break;
+
+  case 3:
+#line 234 "awkgram.y"
+    {
+		rule = 0;
+		yyerrok;
+	  }
+#line 1926 "awkgram.c"
+    break;
+
+  case 4:
+#line 239 "awkgram.y"
+    {
+		if (yyvsp[0] != NULL) {
+			if (yyvsp[-1] == NULL)
+				outer_comment = yyvsp[0];
+			else
+				interblock_comment = yyvsp[0];
+		}
+		yyval = yyvsp[-1];
+	  }
+#line 1940 "awkgram.c"
+    break;
+
+  case 5:
+#line 249 "awkgram.y"
+    {
+		next_sourcefile();
+	  }
+#line 1948 "awkgram.c"
+    break;
+
+  case 6:
+#line 253 "awkgram.y"
+    {
+		rule = 0;
+		/*
+		 * If errors, give up, don't produce an infinite
+		 * stream of syntax error messages.
+		 */
+  		/* yyerrok; */
+	  }
+#line 1961 "awkgram.c"
+    break;
+
+  case 7:
+#line 265 "awkgram.y"
+    {
+		(void) append_rule(yyvsp[-1], yyvsp[0]);
+		if (pending_comment != NULL) {
+			interblock_comment = pending_comment;
+			pending_comment = NULL;
+		}
+	  }
+#line 1973 "awkgram.c"
+    break;
+
+  case 8:
+#line 273 "awkgram.y"
+    {
+		if (rule != Rule) {
+			msg(_("%s blocks must have an action part"), ruletab[rule]);
+			errcount++;
+		} else if (yyvsp[-1] == NULL) {
+			msg(_("each rule must have a pattern or an action part"));
+			errcount++;
+		} else {	/* pattern rule with non-empty pattern */
+			if (yyvsp[0] != NULL)
+				list_append(yyvsp[-1], yyvsp[0]);
+			(void) append_rule(yyvsp[-1], NULL);
+		}
+	  }
+#line 1991 "awkgram.c"
+    break;
+
+  case 9:
+#line 287 "awkgram.y"
+    {
+		in_function = false;
+		(void) mk_function(yyvsp[-1], yyvsp[0]);
+		want_param_names = DONT_CHECK;
+		if (pending_comment != NULL) {
+			interblock_comment = pending_comment;
+			pending_comment = NULL;
+		}
+		yyerrok;
+	  }
+#line 2006 "awkgram.c"
+    break;
+
+  case 10:
+#line 298 "awkgram.y"
+    {
+		want_source = false;
+		at_seen = false;
+		if (yyvsp[-1] != NULL && yyvsp[0] != NULL) {
+			SRCFILE *s = (SRCFILE *) yyvsp[-1];
+			s->comment = yyvsp[0];
+		}
+		yyerrok;
+	  }
+#line 2020 "awkgram.c"
+    break;
+
+  case 11:
+#line 308 "awkgram.y"
+    {
+		want_source = false;
+		at_seen = false;
+		if (yyvsp[-1] != NULL && yyvsp[0] != NULL) {
+			SRCFILE *s = (SRCFILE *) yyvsp[-1];
+			s->comment = yyvsp[0];
+		}
+		yyerrok;
+	  }
+#line 2034 "awkgram.c"
+    break;
+
+  case 12:
+#line 318 "awkgram.y"
+    {
+		want_source = false;
+		at_seen = false;
+
+		// this frees $3 storage in all cases
+		set_namespace(yyvsp[-1], yyvsp[0]);
+
+		yyerrok;
+	  }
+#line 2048 "awkgram.c"
+    break;
+
+  case 13:
+#line 331 "awkgram.y"
+    {
+		void *srcfile = NULL;
+
+		if (! include_source(yyvsp[0], & srcfile))
+			YYABORT;
+		efree(yyvsp[0]->lextok);
+		bcfree(yyvsp[0]);
+		yyval = (INSTRUCTION *) srcfile;
+	  }
+#line 2062 "awkgram.c"
+    break;
+
+  case 14:
+#line 341 "awkgram.y"
+    { yyval = NULL; }
+#line 2068 "awkgram.c"
+    break;
+
+  case 15:
+#line 343 "awkgram.y"
+    { yyval = NULL; }
+#line 2074 "awkgram.c"
+    break;
+
+  case 16:
+#line 348 "awkgram.y"
+    {
+		void *srcfile;
+
+		if (! load_library(yyvsp[0], & srcfile))
+			YYABORT;
+		efree(yyvsp[0]->lextok);
+		bcfree(yyvsp[0]);
+		yyval = (INSTRUCTION *) srcfile;
+	  }
+#line 2088 "awkgram.c"
+    break;
+
+  case 17:
+#line 358 "awkgram.y"
+    { yyval = NULL; }
+#line 2094 "awkgram.c"
+    break;
+
+  case 18:
+#line 360 "awkgram.y"
+    { yyval = NULL; }
+#line 2100 "awkgram.c"
+    break;
+
+  case 19:
+#line 365 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 2106 "awkgram.c"
+    break;
+
+  case 20:
+#line 367 "awkgram.y"
+    { yyval = NULL; }
+#line 2112 "awkgram.c"
+    break;
+
+  case 21:
+#line 369 "awkgram.y"
+    { yyval = NULL; }
+#line 2118 "awkgram.c"
+    break;
+
+  case 22:
+#line 374 "awkgram.y"
+    {
+		rule = Rule;
+		yyval = NULL;
+	  }
+#line 2127 "awkgram.c"
+    break;
+
+  case 23:
+#line 379 "awkgram.y"
+    {
+		rule = Rule;
+	  }
+#line 2135 "awkgram.c"
+    break;
+
+  case 24:
+#line 384 "awkgram.y"
+    {
+		INSTRUCTION *tp;
+
+		add_lint(yyvsp[-2], LINT_assign_in_cond);
+		add_lint(yyvsp[0], LINT_assign_in_cond);
+
+		tp = instruction(Op_no_op);
+		list_prepend(yyvsp[-2], bcalloc(Op_line_range, !!do_pretty_print + 1, 0));
+		yyvsp[-2]->nexti->triggered = false;
+		yyvsp[-2]->nexti->target_jmp = yyvsp[0]->nexti;
+
+		list_append(yyvsp[-2], instruction(Op_cond_pair));
+		yyvsp[-2]->lasti->line_range = yyvsp[-2]->nexti;
+		yyvsp[-2]->lasti->target_jmp = tp;
+
+		list_append(yyvsp[0], instruction(Op_cond_pair));
+		yyvsp[0]->lasti->line_range = yyvsp[-2]->nexti;
+		yyvsp[0]->lasti->target_jmp = tp;
+		if (do_pretty_print) {
+			(yyvsp[-2]->nexti + 1)->condpair_left = yyvsp[-2]->lasti;
+			(yyvsp[-2]->nexti + 1)->condpair_right = yyvsp[0]->lasti;
+		}
+		/* Put any comments in front of the range expression */
+		if (yyvsp[-1] != NULL)
+			yyval = list_append(list_merge(list_prepend(yyvsp[-2], yyvsp[-1]), yyvsp[0]), tp);
+		else
+			yyval = list_append(list_merge(yyvsp[-2], yyvsp[0]), tp);
+		rule = Rule;
+	  }
+#line 2169 "awkgram.c"
+    break;
+
+  case 25:
+#line 414 "awkgram.y"
+    {
+		static int begin_seen = 0;
+
+		if (do_lint_old && ++begin_seen == 2)
+			warning_ln(yyvsp[0]->source_line,
+				_("old awk does not support multiple `BEGIN' or `END' rules"));
+
+		yyvsp[0]->in_rule = rule = BEGIN;
+		yyvsp[0]->source_file = source;
+		yyval = yyvsp[0];
+	  }
+#line 2185 "awkgram.c"
+    break;
+
+  case 26:
+#line 426 "awkgram.y"
+    {
+		static int end_seen = 0;
+
+		if (do_lint_old && ++end_seen == 2)
+			warning_ln(yyvsp[0]->source_line,
+				_("old awk does not support multiple `BEGIN' or `END' rules"));
+
+		yyvsp[0]->in_rule = rule = END;
+		yyvsp[0]->source_file = source;
+		yyval = yyvsp[0];
+	  }
+#line 2201 "awkgram.c"
+    break;
+
+  case 27:
+#line 438 "awkgram.y"
+    {
+		yyvsp[0]->in_rule = rule = BEGINFILE;
+		yyvsp[0]->source_file = source;
+		yyval = yyvsp[0];
+	  }
+#line 2211 "awkgram.c"
+    break;
+
+  case 28:
+#line 444 "awkgram.y"
+    {
+		yyvsp[0]->in_rule = rule = ENDFILE;
+		yyvsp[0]->source_file = source;
+		yyval = yyvsp[0];
+	  }
+#line 2221 "awkgram.c"
+    break;
+
+  case 29:
+#line 453 "awkgram.y"
+    {
+		INSTRUCTION *ip = make_braced_statements(yyvsp[-4], yyvsp[-3], yyvsp[-2]);
+
+		if (yyvsp[-2] != NULL && yyvsp[0] != NULL) {
+			merge_comments(yyvsp[-2], yyvsp[0]);
+			pending_comment = yyvsp[-2];
+		} else if (yyvsp[-2] != NULL) {
+			pending_comment = yyvsp[-2];
+		} else if (yyvsp[0] != NULL) {
+			pending_comment = yyvsp[0];
+		}
+
+		yyval = ip;
+	  }
+#line 2240 "awkgram.c"
+    break;
+
+  case 31:
+#line 472 "awkgram.y"
+    {
+		const char *name = yyvsp[0]->lextok;
+		char *qname = qualify_name(name, strlen(name));
+
+		if (qname != name) {
+			efree((void *)name);
+			yyvsp[0]->lextok = qname;
+		}
+		yyval = yyvsp[0];
+	  }
+#line 2255 "awkgram.c"
+    break;
+
+  case 32:
+#line 483 "awkgram.y"
+    {
+		yyerror(_("`%s' is a built-in function, it cannot be redefined"),
+					tokstart);
+		YYABORT;
+	  }
+#line 2265 "awkgram.c"
+    break;
+
+  case 33:
+#line 489 "awkgram.y"
+    {
+		yyval = yyvsp[0];
+		at_seen = false;
+	  }
+#line 2274 "awkgram.c"
+    break;
+
+  case 36:
+#line 501 "awkgram.y"
+    { want_param_names = FUNC_HEADER; }
+#line 2280 "awkgram.c"
+    break;
+
+  case 37:
+#line 502 "awkgram.y"
+    {
+		INSTRUCTION *func_comment = NULL;
+		// Merge any comments found in the parameter list with those
+		// following the function header, associate the whole shebang
+		// with the function as one block comment.
+		if (yyvsp[-2] != NULL && yyvsp[-2]->comment != NULL) {
+			if (yyvsp[0] != NULL) {
+				merge_comments(yyvsp[-2]->comment, yyvsp[0]);
+			}
+			func_comment = yyvsp[-2]->comment;
+		} else if (yyvsp[0] != NULL) {
+			func_comment = yyvsp[0];
+		}
+
+		yyvsp[-6]->source_file = source;
+		yyvsp[-6]->comment = func_comment;
+		if (install_function(yyvsp[-5]->lextok, yyvsp[-6], yyvsp[-2]) < 0)
+			YYABORT;
+		in_function = true;
+		yyvsp[-5]->lextok = NULL;
+		bcfree(yyvsp[-5]);
+		/* $5 already free'd in install_function */
+		yyval = yyvsp[-6];
+		want_param_names = FUNC_BODY;
+	  }
+#line 2310 "awkgram.c"
+    break;
+
+  case 38:
+#line 535 "awkgram.y"
+    { want_regexp = true; }
+#line 2316 "awkgram.c"
+    break;
+
+  case 39:
+#line 537 "awkgram.y"
+    {
+		  NODE *n, *exp;
+		  char *re;
+		  size_t len;
+
+		  re = yyvsp[0]->lextok;
+		  yyvsp[0]->lextok = NULL;
+		  len = strlen(re);
+		  if (do_lint) {
+			if (len == 0)
+				lintwarn_ln(yyvsp[0]->source_line,
+					_("regexp constant `//' looks like a C++ comment, but is not"));
+			else if (re[0] == '*' && re[len-1] == '*')
+				/* possible C comment */
+				lintwarn_ln(yyvsp[0]->source_line,
+					_("regexp constant `/%s/' looks like a C comment, but is not"), re);
+		  }
+
+		  exp = make_str_node(re, len, ALREADY_MALLOCED);
+		  n = make_regnode(Node_regex, exp);
+		  if (n == NULL) {
+			unref(exp);
+			YYABORT;
+		  }
+		  yyval = yyvsp[0];
+		  yyval->opcode = Op_match_rec;
+		  yyval->memory = n;
+		}
+#line 2349 "awkgram.c"
+    break;
+
+  case 40:
+#line 569 "awkgram.y"
+    {
+		  char *re;
+		  size_t len;
+
+		  re = yyvsp[0]->lextok;
+		  yyvsp[0]->lextok = NULL;
+		  len = strlen(re);
+
+		  yyval = yyvsp[0];
+		  yyval->opcode = Op_push_re;
+		  yyval->memory = make_typed_regex(re, len);
+		}
+#line 2366 "awkgram.c"
+    break;
+
+  case 41:
+#line 584 "awkgram.y"
+    { bcfree(yyvsp[0]); }
+#line 2372 "awkgram.c"
+    break;
+
+  case 43:
+#line 590 "awkgram.y"
+    { yyval = NULL; }
+#line 2378 "awkgram.c"
+    break;
+
+  case 44:
+#line 592 "awkgram.y"
+    {
+		if (yyvsp[0] == NULL) {
+			yyval = yyvsp[-1];
+		} else {
+			add_lint(yyvsp[0], LINT_no_effect);
+			if (yyvsp[-1] == NULL) {
+				yyval = yyvsp[0];
+			} else {
+				yyval = list_merge(yyvsp[-1], yyvsp[0]);
+			}
+		}
+
+		if (trailing_comment != NULL) {
+			yyval = list_append(yyval, trailing_comment);
+			trailing_comment = NULL;
+		}
+
+		yyerrok;
+	  }
+#line 2402 "awkgram.c"
+    break;
+
+  case 45:
+#line 612 "awkgram.y"
+    {	yyval = NULL; }
+#line 2408 "awkgram.c"
+    break;
+
+  case 46:
+#line 616 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 2414 "awkgram.c"
+    break;
+
+  case 47:
+#line 617 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 2420 "awkgram.c"
+    break;
+
+  case 48:
+#line 622 "awkgram.y"
+    {
+		if (yyvsp[0] != NULL) {
+			INSTRUCTION *ip;
+
+			merge_comments(yyvsp[0], NULL);
+			ip = list_create(instruction(Op_no_op));
+			yyval = list_append(ip, yyvsp[0]); 
+		} else
+			yyval = NULL;
+	  }
+#line 2435 "awkgram.c"
+    break;
+
+  case 49:
+#line 633 "awkgram.y"
+    {
+		trailing_comment = yyvsp[0];	// NULL or comment
+		yyval = make_braced_statements(yyvsp[-2], yyvsp[-1], yyvsp[0]);
+	  }
+#line 2444 "awkgram.c"
+    break;
+
+  case 50:
+#line 638 "awkgram.y"
+    {
+		if (do_pretty_print)
+			yyval = list_prepend(yyvsp[0], instruction(Op_exec_count));
+		else
+			yyval = yyvsp[0];
+ 	  }
+#line 2455 "awkgram.c"
+    break;
+
+  case 51:
+#line 645 "awkgram.y"
+    {
+		INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
+		INSTRUCTION *ip, *nextc, *tbreak;
+		const char **case_values = NULL;
+		int maxcount = 128;
+		int case_count = 0;
+		int i;
+
+		tbreak = instruction(Op_no_op);
+		cstmt = list_create(tbreak);
+		cexp = list_create(instruction(Op_pop));
+		dflt = instruction(Op_jmp);
+		dflt->target_jmp = tbreak;	/* if no case match and no explicit default */
+
+		if (yyvsp[-2] != NULL) {
+			curr = yyvsp[-2]->nexti;
+			bcfree(yyvsp[-2]);	/* Op_list */
+		}
+		/*  else
+			curr = NULL; */
+
+		for (; curr != NULL; curr = nextc) {
+			INSTRUCTION *caseexp = curr->case_exp;
+			INSTRUCTION *casestmt = curr->case_stmt;
+
+			nextc = curr->nexti;
+			if (curr->opcode == Op_K_case) {
+				if (caseexp->opcode == Op_push_i) {
+					/* a constant scalar */
+					char *caseval;
+					caseval = force_string(caseexp->memory)->stptr;
+					for (i = 0; i < case_count; i++) {
+						if (strcmp(caseval, case_values[i]) == 0)
+							error_ln(curr->source_line,
+								_("duplicate case values in switch body: %s"), caseval);
+					}
+
+					if (case_values == NULL)
+						emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement");
+					else if (case_count >= maxcount) {
+						maxcount += 128;
+						erealloc(case_values, const char **, sizeof(char*) * maxcount, "statement");
+					}
+					case_values[case_count++] = caseval;
+				} else {
+					/* match a constant regex against switch expression. */
+					(curr + 1)->match_exp = true;
+				}
+				curr->stmt_start = casestmt->nexti;
+				curr->stmt_end	= casestmt->lasti;
+				(void) list_prepend(cexp, curr);
+				(void) list_prepend(cexp, caseexp);
+			} else {
+				if (dflt->target_jmp != tbreak)
+					error_ln(curr->source_line,
+						_("duplicate `default' detected in switch body"));
+				else
+					dflt->target_jmp = casestmt->nexti;
+
+				if (do_pretty_print) {
+					curr->stmt_start = casestmt->nexti;
+					curr->stmt_end = casestmt->lasti;
+					(void) list_prepend(cexp, curr);
+				} else
+					bcfree(curr);
+			}
+
+			cstmt = list_merge(casestmt, cstmt);
+		}
+
+		if (case_values != NULL)
+			efree(case_values);
+
+		ip = yyvsp[-6];
+		if (do_pretty_print) {
+			// first merge comments
+			INSTRUCTION *head_comment = NULL;
+
+			if (yyvsp[-4] != NULL && yyvsp[-3] != NULL) {
+				merge_comments(yyvsp[-4], yyvsp[-3]);
+				head_comment = yyvsp[-4];
+			} else if (yyvsp[-4] != NULL)
+				head_comment = yyvsp[-4];
+			else
+				head_comment = yyvsp[-3];
+
+			yyvsp[-8]->comment = head_comment;
+
+			(void) list_prepend(ip, yyvsp[-8]);
+			(void) list_prepend(ip, instruction(Op_exec_count));
+			yyvsp[-8]->target_break = tbreak;
+			(yyvsp[-8] + 1)->switch_start = cexp->nexti;
+			(yyvsp[-8] + 1)->switch_end = cexp->lasti;
+			(yyvsp[-8] + 1)->switch_end->comment = yyvsp[0];
+		}
+		/* else
+			$1 is NULL */
+
+		(void) list_append(cexp, dflt);
+		(void) list_merge(ip, cexp);
+		if (yyvsp[-1] != NULL)
+			(void) list_append(cstmt, yyvsp[-1]);
+		yyval = list_merge(ip, cstmt);
+
+		break_allowed--;
+		fix_break_continue(ip, tbreak, NULL);
+	  }
+#line 2567 "awkgram.c"
+    break;
+
+  case 52:
+#line 753 "awkgram.y"
+    {
+		/*
+		 *    -----------------
+		 * tc:
+		 *         cond
+		 *    -----------------
+		 *    [Op_jmp_false tb   ]
+		 *    -----------------
+		 *         body
+		 *    -----------------
+		 *    [Op_jmp      tc    ]
+		 * tb:[Op_no_op          ]
+		 */
+
+		INSTRUCTION *ip, *tbreak, *tcont;
+
+		tbreak = instruction(Op_no_op);
+		add_lint(yyvsp[-3], LINT_assign_in_cond);
+		tcont = yyvsp[-3]->nexti;
+		ip = list_append(yyvsp[-3], instruction(Op_jmp_false));
+		ip->lasti->target_jmp = tbreak;
+
+		if (do_pretty_print) {
+			(void) list_append(ip, instruction(Op_exec_count));
+			yyvsp[-5]->target_break = tbreak;
+			yyvsp[-5]->target_continue = tcont;
+			(yyvsp[-5] + 1)->while_body = ip->lasti;
+			(void) list_prepend(ip, yyvsp[-5]);
+		}
+		/* else
+			$1 is NULL */
+
+		if (yyvsp[-1] != NULL) {
+			if (yyvsp[0] == NULL)
+				yyvsp[0] = list_create(instruction(Op_no_op));
+
+			yyvsp[-1]->memory->comment_type = BLOCK_COMMENT;
+			yyvsp[0] = list_prepend(yyvsp[0], yyvsp[-1]);
+		}
+
+		if (yyvsp[0] != NULL)
+			(void) list_merge(ip, yyvsp[0]);
+		(void) list_append(ip, instruction(Op_jmp));
+		ip->lasti->target_jmp = tcont;
+		yyval = list_append(ip, tbreak);
+
+		break_allowed--;
+		continue_allowed--;
+		fix_break_continue(ip, tbreak, tcont);
+	  }
+#line 2622 "awkgram.c"
+    break;
+
+  case 53:
+#line 804 "awkgram.y"
+    {
+		/*
+		 *    -----------------
+		 * z:
+		 *         body
+		 *    -----------------
+		 * tc:
+		 *         cond
+		 *    -----------------
+		 *    [Op_jmp_true | z  ]
+		 * tb:[Op_no_op         ]
+		 */
+
+		INSTRUCTION *ip, *tbreak, *tcont;
+
+		tbreak = instruction(Op_no_op);
+		tcont = yyvsp[-2]->nexti;
+		add_lint(yyvsp[-2], LINT_assign_in_cond);
+		if (yyvsp[-5] != NULL)
+			ip = list_merge(yyvsp[-5], yyvsp[-2]);
+		else
+			ip = list_prepend(yyvsp[-2], instruction(Op_no_op));
+
+		if (yyvsp[-6] != NULL)
+			(void) list_prepend(ip, yyvsp[-6]);
+
+		if (do_pretty_print)
+			(void) list_prepend(ip, instruction(Op_exec_count));
+
+		(void) list_append(ip, instruction(Op_jmp_true));
+		ip->lasti->target_jmp = ip->nexti;
+		yyval = list_append(ip, tbreak);
+
+		break_allowed--;
+		continue_allowed--;
+		fix_break_continue(ip, tbreak, tcont);
+
+		if (do_pretty_print) {
+			yyvsp[-7]->target_break = tbreak;
+			yyvsp[-7]->target_continue = tcont;
+			(yyvsp[-7] + 1)->doloop_cond = tcont;
+			yyval = list_prepend(ip, yyvsp[-7]);
+			bcfree(yyvsp[-4]);
+			if (yyvsp[0] != NULL)
+				yyvsp[-7]->comment = yyvsp[0];
+		}
+		/* else
+			$1 and $4 are NULLs */
+	  }
+#line 2676 "awkgram.c"
+    break;
+
+  case 54:
+#line 854 "awkgram.y"
+    {
+		INSTRUCTION *ip;
+		char *var_name = yyvsp[-5]->lextok;
+
+		if (yyvsp[0] != NULL
+				&& yyvsp[0]->lasti->opcode == Op_K_delete
+				&& yyvsp[0]->lasti->expr_count == 1
+				&& yyvsp[0]->nexti->opcode == Op_push
+				&& (yyvsp[0]->nexti->memory->type != Node_var || !(yyvsp[0]->nexti->memory->var_update))
+				&& strcmp(yyvsp[0]->nexti->memory->vname, var_name) == 0
+		) {
+
+		/*
+		 * Efficiency hack.  Recognize the special case of
+		 *
+		 * 	for (iggy in foo)
+		 * 		delete foo[iggy]
+		 *
+		 * and treat it as if it were
+		 *
+		 * 	delete foo
+		 *
+		 * Check that the body is a `delete a[i]' statement,
+		 * and that both the loop var and array names match.
+		 */
+			NODE *arr = NULL;
+
+			ip = yyvsp[0]->nexti->nexti;
+			if (yyvsp[-3]->nexti->opcode == Op_push && yyvsp[-3]->lasti == yyvsp[-3]->nexti)
+				arr = yyvsp[-3]->nexti->memory;
+			if (arr != NULL
+					&& ip->opcode == Op_no_op
+					&& ip->nexti->opcode == Op_push_array
+					&& strcmp(ip->nexti->memory->vname, arr->vname) == 0
+					&& ip->nexti->nexti == yyvsp[0]->lasti
+			) {
+				(void) make_assignable(yyvsp[0]->nexti);
+				yyvsp[0]->lasti->opcode = Op_K_delete_loop;
+				yyvsp[0]->lasti->expr_count = 0;
+				if (yyvsp[-7] != NULL)
+					bcfree(yyvsp[-7]);
+				efree(var_name);
+				bcfree(yyvsp[-5]);
+				bcfree(yyvsp[-4]);
+				bcfree(yyvsp[-3]);
+				if (yyvsp[-1] != NULL) {
+					merge_comments(yyvsp[-1], NULL);
+					yyvsp[0] = list_prepend(yyvsp[0], yyvsp[-1]);
+				}
+				yyval = yyvsp[0];
+			} else
+				goto regular_loop;
+		} else {
+			INSTRUCTION *tbreak, *tcont;
+
+			/*    [ Op_push_array a       ]
+			 *    [ Op_arrayfor_init | ib ]
+			 * ic:[ Op_arrayfor_incr | ib ]
+			 *    [ Op_var_assign if any  ]
+			 *
+			 *              body
+			 *
+			 *    [Op_jmp | ic            ]
+			 * ib:[Op_arrayfor_final      ]
+			 */
+regular_loop:
+			ip = yyvsp[-3];
+			ip->nexti->opcode = Op_push_array;
+
+			tbreak = instruction(Op_arrayfor_final);
+			yyvsp[-4]->opcode = Op_arrayfor_incr;
+			yyvsp[-4]->array_var = variable(yyvsp[-5]->source_line, var_name, Node_var);
+			yyvsp[-4]->target_jmp = tbreak;
+			tcont = yyvsp[-4];
+			yyvsp[-5]->opcode = Op_arrayfor_init;
+			yyvsp[-5]->target_jmp = tbreak;
+			(void) list_append(ip, yyvsp[-5]);
+
+			if (do_pretty_print) {
+				yyvsp[-7]->opcode = Op_K_arrayfor;
+				yyvsp[-7]->target_continue = tcont;
+				yyvsp[-7]->target_break = tbreak;
+				(void) list_append(ip, yyvsp[-7]);
+			}
+			/* else
+				$1 is NULL */
+
+			/* add update_FOO instruction if necessary */
+			if (yyvsp[-4]->array_var->type == Node_var && yyvsp[-4]->array_var->var_update) {
+				(void) list_append(ip, instruction(Op_var_update));
+				ip->lasti->update_var = yyvsp[-4]->array_var->var_update;
+			}
+			(void) list_append(ip, yyvsp[-4]);
+
+			/* add set_FOO instruction if necessary */
+			if (yyvsp[-4]->array_var->type == Node_var && yyvsp[-4]->array_var->var_assign) {
+				(void) list_append(ip, instruction(Op_var_assign));
+				ip->lasti->assign_var = yyvsp[-4]->array_var->var_assign;
+			}
+
+			if (do_pretty_print) {
+				(void) list_append(ip, instruction(Op_exec_count));
+				(yyvsp[-7] + 1)->forloop_cond = yyvsp[-4];
+				(yyvsp[-7] + 1)->forloop_body = ip->lasti;
+			}
+
+			if (yyvsp[-1] != NULL)
+				merge_comments(yyvsp[-1], NULL);
+
+			if (yyvsp[0] != NULL) {
+				if (yyvsp[-1] != NULL)
+					yyvsp[0] = list_prepend(yyvsp[0], yyvsp[-1]);
+				(void) list_merge(ip, yyvsp[0]);
+			} else if (yyvsp[-1] != NULL)
+				(void) list_append(ip, yyvsp[-1]);
+
+			(void) list_append(ip, instruction(Op_jmp));
+			ip->lasti->target_jmp = yyvsp[-4];
+			yyval = list_append(ip, tbreak);
+			fix_break_continue(ip, tbreak, tcont);
+		}
+
+		break_allowed--;
+		continue_allowed--;
+	  }
+#line 2806 "awkgram.c"
+    break;
+
+  case 55:
+#line 980 "awkgram.y"
+    {
+		if (yyvsp[-7] != NULL) {
+			merge_comments(yyvsp[-7], NULL);
+			yyvsp[-11]->comment = yyvsp[-7];
+		}
+		if (yyvsp[-4] != NULL) {
+			merge_comments(yyvsp[-4], NULL);
+			if (yyvsp[-11]->comment == NULL) {
+				yyvsp[-4]->memory->comment_type = FOR_COMMENT;
+				yyvsp[-11]->comment = yyvsp[-4];
+			} else
+				yyvsp[-11]->comment->comment = yyvsp[-4];
+		}
+		if (yyvsp[-1] != NULL)
+			yyvsp[0] = list_prepend(yyvsp[0], yyvsp[-1]);
+		yyval = mk_for_loop(yyvsp[-11], yyvsp[-9], yyvsp[-6], yyvsp[-3], yyvsp[0]);
+
+		break_allowed--;
+		continue_allowed--;
+	  }
+#line 2831 "awkgram.c"
+    break;
+
+  case 56:
+#line 1001 "awkgram.y"
+    {
+		if (yyvsp[-6] != NULL) {
+			merge_comments(yyvsp[-6], NULL);
+			yyvsp[-10]->comment = yyvsp[-6];
+		}
+		if (yyvsp[-4] != NULL) {
+			merge_comments(yyvsp[-4], NULL);
+			if (yyvsp[-10]->comment == NULL) {
+				yyvsp[-4]->memory->comment_type = FOR_COMMENT;
+				yyvsp[-10]->comment = yyvsp[-4];
+			} else
+				yyvsp[-10]->comment->comment = yyvsp[-4];
+		}
+		if (yyvsp[-1] != NULL)
+			yyvsp[0] = list_prepend(yyvsp[0], yyvsp[-1]);
+		yyval = mk_for_loop(yyvsp[-10], yyvsp[-8], (INSTRUCTION *) NULL, yyvsp[-3], yyvsp[0]);
+
+		break_allowed--;
+		continue_allowed--;
+	  }
+#line 2856 "awkgram.c"
+    break;
+
+  case 57:
+#line 1022 "awkgram.y"
+    {
+		if (do_pretty_print)
+			yyval = list_prepend(yyvsp[0], instruction(Op_exec_count));
+		else
+			yyval = yyvsp[0];
+	  }
+#line 2867 "awkgram.c"
+    break;
+
+  case 58:
+#line 1032 "awkgram.y"
+    {
+		if (! break_allowed)
+			error_ln(yyvsp[-1]->source_line,
+				_("`break' is not allowed outside a loop or switch"));
+		yyvsp[-1]->target_jmp = NULL;
+		yyval = list_create(yyvsp[-1]);
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyval, yyvsp[0]);
+	  }
+#line 2881 "awkgram.c"
+    break;
+
+  case 59:
+#line 1042 "awkgram.y"
+    {
+		if (! continue_allowed)
+			error_ln(yyvsp[-1]->source_line,
+				_("`continue' is not allowed outside a loop"));
+		yyvsp[-1]->target_jmp = NULL;
+		yyval = list_create(yyvsp[-1]);
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyval, yyvsp[0]);
+	  }
+#line 2895 "awkgram.c"
+    break;
+
+  case 60:
+#line 1052 "awkgram.y"
+    {
+		/* if inside function (rule = 0), resolve context at run-time */
+		if (rule && rule != Rule)
+			error_ln(yyvsp[-1]->source_line,
+				_("`next' used in %s action"), ruletab[rule]);
+		yyvsp[-1]->target_jmp = ip_rec;
+		yyval = list_create(yyvsp[-1]);
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyval, yyvsp[0]);
+	  }
+#line 2910 "awkgram.c"
+    break;
+
+  case 61:
+#line 1063 "awkgram.y"
+    {
+		/* if inside function (rule = 0), resolve context at run-time */
+		if (rule == BEGIN || rule == END || rule == ENDFILE)
+			error_ln(yyvsp[-1]->source_line,
+				_("`nextfile' used in %s action"), ruletab[rule]);
+
+		yyvsp[-1]->target_newfile = ip_newfile;
+		yyvsp[-1]->target_endfile = ip_endfile;
+		yyval = list_create(yyvsp[-1]);
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyval, yyvsp[0]);
+	  }
+#line 2927 "awkgram.c"
+    break;
+
+  case 62:
+#line 1076 "awkgram.y"
+    {
+		/* Initialize the two possible jump targets, the actual target
+		 * is resolved at run-time.
+		 */
+		yyvsp[-2]->target_end = ip_end;	/* first instruction in end_block */
+		yyvsp[-2]->target_atexit = ip_atexit;	/* cleanup and go home */
+
+		if (yyvsp[-1] == NULL) {
+			yyval = list_create(yyvsp[-2]);
+			(void) list_prepend(yyval, instruction(Op_push_i));
+			yyval->nexti->memory = dupnode(Nnull_string);
+		} else
+			yyval = list_append(yyvsp[-1], yyvsp[-2]);
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyval, yyvsp[0]);
+	  }
+#line 2948 "awkgram.c"
+    break;
+
+  case 63:
+#line 1093 "awkgram.y"
+    {
+		if (! in_function)
+			yyerror(_("`return' used outside function context"));
+	  }
+#line 2957 "awkgram.c"
+    break;
+
+  case 64:
+#line 1096 "awkgram.y"
+    {
+		if (called_from_eval)
+			yyvsp[-3]->opcode = Op_K_return_from_eval;
+
+		if (yyvsp[-1] == NULL) {
+			yyval = list_create(yyvsp[-3]);
+			(void) list_prepend(yyval, instruction(Op_push_i));
+			yyval->nexti->memory = dupnode(Nnull_string);
+		} else
+			yyval = list_append(yyvsp[-1], yyvsp[-3]);
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyval, yyvsp[0]);
+	  }
+#line 2975 "awkgram.c"
+    break;
+
+  case 65:
+#line 1110 "awkgram.y"
+    {
+		if (yyvsp[0] != NULL)
+			yyval = list_append(yyvsp[-1], yyvsp[0]);
+		else
+			yyval = yyvsp[-1];
+	  }
+#line 2986 "awkgram.c"
+    break;
+
+  case 66:
+#line 1127 "awkgram.y"
+    { in_print = true; in_parens = 0; }
+#line 2992 "awkgram.c"
+    break;
+
+  case 67:
+#line 1128 "awkgram.y"
+    {
+		/*
+		 * Optimization: plain `print' has no expression list, so $3 is null.
+		 * If $3 is NULL or is a bytecode list for $0 use Op_K_print_rec,
+		 * which is faster for these two cases.
+		 */
+
+		if (do_optimize && yyvsp[-3]->opcode == Op_K_print &&
+			(yyvsp[-1] == NULL
+				|| (yyvsp[-1]->lasti->opcode == Op_field_spec
+					&& yyvsp[-1]->nexti->nexti->nexti == yyvsp[-1]->lasti
+					&& yyvsp[-1]->nexti->nexti->opcode == Op_push_i
+					&& yyvsp[-1]->nexti->nexti->memory->type == Node_val)
+			)
+		) {
+			static bool warned = false;
+			/*   -----------------
+			 *      output_redir
+			 *    [ redirect exp ]
+			 *   -----------------
+			 *     expression_list
+			 *   ------------------
+			 *    [Op_K_print_rec | NULL | redir_type | expr_count]
+			 */
+
+			if (yyvsp[-1] != NULL) {
+				NODE *n = yyvsp[-1]->nexti->nexti->memory;
+
+				if (! iszero(n))
+					goto regular_print;
+
+				bcfree(yyvsp[-1]->lasti);			/* Op_field_spec */
+				unref(n);				/* Node_val */
+				bcfree(yyvsp[-1]->nexti->nexti);		/* Op_push_i */
+				bcfree(yyvsp[-1]->nexti);			/* Op_list */
+				bcfree(yyvsp[-1]);				/* Op_list */
+			} else {
+				if (do_lint && (rule == BEGIN || rule == END) && ! warned) {
+					warned = true;
+					lintwarn_ln(yyvsp[-3]->source_line,
+		_("plain `print' in BEGIN or END rule should probably be `print \"\"'"));
+				}
+			}
+
+			yyvsp[-3]->expr_count = 0;
+			yyvsp[-3]->opcode = Op_K_print_rec;
+			if (yyvsp[0] == NULL) {    /* no redircetion */
+				yyvsp[-3]->redir_type = redirect_none;
+				yyval = list_create(yyvsp[-3]);
+			} else {
+				INSTRUCTION *ip;
+				ip = yyvsp[0]->nexti;
+				yyvsp[-3]->redir_type = ip->redir_type;
+				yyvsp[0]->nexti = ip->nexti;
+				bcfree(ip);
+				yyval = list_append(yyvsp[0], yyvsp[-3]);
+			}
+		} else {
+			/*   -----------------
+			 *    [ output_redir    ]
+			 *    [ redirect exp    ]
+			 *   -----------------
+			 *    [ expression_list ]
+			 *   ------------------
+			 *    [$1 | NULL | redir_type | expr_count]
+			 *
+			 */
+regular_print:
+			if (yyvsp[0] == NULL) {		/* no redirection */
+				if (yyvsp[-1] == NULL)	{	/* print/printf without arg */
+					yyvsp[-3]->expr_count = 0;
+					if (yyvsp[-3]->opcode == Op_K_print)
+						yyvsp[-3]->opcode = Op_K_print_rec;
+					yyvsp[-3]->redir_type = redirect_none;
+					yyval = list_create(yyvsp[-3]);
+				} else {
+					INSTRUCTION *t = yyvsp[-1];
+					yyvsp[-3]->expr_count = count_expressions(&t, false);
+					yyvsp[-3]->redir_type = redirect_none;
+					yyval = list_append(t, yyvsp[-3]);
+				}
+			} else {
+				INSTRUCTION *ip;
+				ip = yyvsp[0]->nexti;
+				yyvsp[-3]->redir_type = ip->redir_type;
+				yyvsp[0]->nexti = ip->nexti;
+				bcfree(ip);
+				if (yyvsp[-1] == NULL) {
+					yyvsp[-3]->expr_count = 0;
+					if (yyvsp[-3]->opcode == Op_K_print)
+						yyvsp[-3]->opcode = Op_K_print_rec;
+					yyval = list_append(yyvsp[0], yyvsp[-3]);
+				} else {
+					INSTRUCTION *t = yyvsp[-1];
+					yyvsp[-3]->expr_count = count_expressions(&t, false);
+					yyval = list_append(list_merge(yyvsp[0], t), yyvsp[-3]);
+				}
+			}
+		}
+	  }
+#line 3097 "awkgram.c"
+    break;
+
+  case 68:
+#line 1229 "awkgram.y"
+    { sub_counter = 0; }
+#line 3103 "awkgram.c"
+    break;
+
+  case 69:
+#line 1230 "awkgram.y"
+    {
+		char *arr = yyvsp[-2]->lextok;
+
+		yyvsp[-2]->opcode = Op_push_array;
+		yyvsp[-2]->memory = variable(yyvsp[-2]->source_line, arr, Node_var_new);
+
+		if (! do_posix && ! do_traditional) {
+			if (yyvsp[-2]->memory == symbol_table)
+				fatal(_("`delete' is not allowed with SYMTAB"));
+			else if (yyvsp[-2]->memory == func_table)
+				fatal(_("`delete' is not allowed with FUNCTAB"));
+		}
+
+		if (yyvsp[0] == NULL) {
+			/*
+			 * As of September 2012, POSIX has added support
+			 * for `delete array'. See:
+			 * http://austingroupbugs.net/view.php?id=544
+			 *
+			 * Thanks to Nathan Weeks for the initiative.
+			 *
+			 * Thus we no longer warn or check do_posix.
+			 * Also, since BWK awk supports it, we don't have to
+			 * check do_traditional either.
+			 */
+			yyvsp[-3]->expr_count = 0;
+			yyval = list_append(list_create(yyvsp[-2]), yyvsp[-3]);
+		} else {
+			yyvsp[-3]->expr_count = sub_counter;
+			yyval = list_append(list_append(yyvsp[0], yyvsp[-2]), yyvsp[-3]);
+		}
+	  }
+#line 3140 "awkgram.c"
+    break;
+
+  case 70:
+#line 1267 "awkgram.y"
+    {
+		static bool warned = false;
+		char *arr = yyvsp[-1]->lextok;
+
+		if (do_lint && ! warned) {
+			warned = true;
+			lintwarn_ln(yyvsp[-3]->source_line,
+				_("`delete(array)' is a non-portable tawk extension"));
+		}
+		if (do_traditional) {
+			error_ln(yyvsp[-3]->source_line,
+				_("`delete(array)' is a non-portable tawk extension"));
+		}
+		yyvsp[-1]->memory = variable(yyvsp[-1]->source_line, arr, Node_var_new);
+		yyvsp[-1]->opcode = Op_push_array;
+		yyvsp[-3]->expr_count = 0;
+		yyval = list_append(list_create(yyvsp[-1]), yyvsp[-3]);
+
+		if (! do_posix && ! do_traditional) {
+			if (yyvsp[-1]->memory == symbol_table)
+				fatal(_("`delete' is not allowed with SYMTAB"));
+			else if (yyvsp[-1]->memory == func_table)
+				fatal(_("`delete' is not allowed with FUNCTAB"));
+		}
+	  }
+#line 3170 "awkgram.c"
+    break;
+
+  case 71:
+#line 1293 "awkgram.y"
+    {
+		yyval = optimize_assignment(yyvsp[0]);
+	  }
+#line 3178 "awkgram.c"
+    break;
+
+  case 72:
+#line 1300 "awkgram.y"
+    { yyval = NULL; }
+#line 3184 "awkgram.c"
+    break;
+
+  case 73:
+#line 1302 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3190 "awkgram.c"
+    break;
+
+  case 74:
+#line 1307 "awkgram.y"
+    { yyval = NULL; }
+#line 3196 "awkgram.c"
+    break;
+
+  case 75:
+#line 1309 "awkgram.y"
+    {
+		if (yyvsp[-1] == NULL)
+			yyval = list_create(yyvsp[0]);
+		else
+			yyval = list_prepend(yyvsp[-1], yyvsp[0]);
+	  }
+#line 3207 "awkgram.c"
+    break;
+
+  case 76:
+#line 1316 "awkgram.y"
+    { yyval = NULL; }
+#line 3213 "awkgram.c"
+    break;
+
+  case 77:
+#line 1321 "awkgram.y"
+    {
+		INSTRUCTION *casestmt = yyvsp[0];
+		if (yyvsp[0] == NULL)
+			casestmt = list_create(instruction(Op_no_op));
+		if (do_pretty_print)
+			(void) list_prepend(casestmt, instruction(Op_exec_count));
+		yyvsp[-4]->case_exp = yyvsp[-3];
+		yyvsp[-4]->case_stmt = casestmt;
+		yyvsp[-4]->comment = yyvsp[-1];
+		bcfree(yyvsp[-2]);
+		yyval = yyvsp[-4];
+	  }
+#line 3230 "awkgram.c"
+    break;
+
+  case 78:
+#line 1334 "awkgram.y"
+    {
+		INSTRUCTION *casestmt = yyvsp[0];
+		if (yyvsp[0] == NULL)
+			casestmt = list_create(instruction(Op_no_op));
+		if (do_pretty_print)
+			(void) list_prepend(casestmt, instruction(Op_exec_count));
+		bcfree(yyvsp[-2]);
+		yyvsp[-3]->case_stmt = casestmt;
+		yyvsp[-3]->comment = yyvsp[-1];
+		yyval = yyvsp[-3];
+	  }
+#line 3246 "awkgram.c"
+    break;
+
+  case 79:
+#line 1349 "awkgram.y"
+    {	yyval = yyvsp[0]; }
+#line 3252 "awkgram.c"
+    break;
+
+  case 80:
+#line 1351 "awkgram.y"
+    {
+		NODE *n = yyvsp[0]->memory;
+		(void) force_number(n);
+		negate_num(n);
+		bcfree(yyvsp[-1]);
+		yyval = yyvsp[0];
+	  }
+#line 3264 "awkgram.c"
+    break;
+
+  case 81:
+#line 1359 "awkgram.y"
+    {
+		NODE *n = yyvsp[0]->lasti->memory;
+		bcfree(yyvsp[-1]);
+		add_sign_to_num(n, '+');
+		yyval = yyvsp[0];
+	  }
+#line 3275 "awkgram.c"
+    break;
+
+  case 82:
+#line 1366 "awkgram.y"
+    {	yyval = yyvsp[0]; }
+#line 3281 "awkgram.c"
+    break;
+
+  case 83:
+#line 1368 "awkgram.y"
+    {
+		if (yyvsp[0]->memory->type == Node_regex)
+			yyvsp[0]->opcode = Op_push_re;
+		else
+			yyvsp[0]->opcode = Op_push;
+		yyval = yyvsp[0];
+	  }
+#line 3293 "awkgram.c"
+    break;
+
+  case 84:
+#line 1376 "awkgram.y"
+    {
+		assert((yyvsp[0]->memory->flags & REGEX) == REGEX);
+		yyvsp[0]->opcode = Op_push_re;
+		yyval = yyvsp[0];
+	  }
+#line 3303 "awkgram.c"
+    break;
+
+  case 85:
+#line 1385 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3309 "awkgram.c"
+    break;
+
+  case 86:
+#line 1387 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3315 "awkgram.c"
+    break;
+
+  case 88:
+#line 1397 "awkgram.y"
+    {
+		yyval = yyvsp[-1];
+	  }
+#line 3323 "awkgram.c"
+    break;
+
+  case 89:
+#line 1404 "awkgram.y"
+    {
+		in_print = false;
+		in_parens = 0;
+		yyval = NULL;
+	  }
+#line 3333 "awkgram.c"
+    break;
+
+  case 90:
+#line 1409 "awkgram.y"
+    { in_print = false; in_parens = 0; }
+#line 3339 "awkgram.c"
+    break;
+
+  case 91:
+#line 1410 "awkgram.y"
+    {
+		if (yyvsp[-2]->redir_type == redirect_twoway
+		    	&& yyvsp[0]->lasti->opcode == Op_K_getline_redir
+		   	 	&& yyvsp[0]->lasti->redir_type == redirect_twoway)
+			yyerror(_("multistage two-way pipelines don't work"));
+		if (do_lint && yyvsp[-2]->redir_type == redirect_output && yyvsp[0]->lasti->opcode == Op_concat)
+			lintwarn(_("concatenation as I/O `>' redirection target is ambiguous"));
+		yyval = list_prepend(yyvsp[0], yyvsp[-2]);
+	  }
+#line 3353 "awkgram.c"
+    break;
+
+  case 92:
+#line 1423 "awkgram.y"
+    {
+		if (yyvsp[-1] != NULL)
+			yyvsp[-5]->comment = yyvsp[-1];
+		yyval = mk_condition(yyvsp[-3], yyvsp[-5], yyvsp[0], NULL, NULL);
+	  }
+#line 3363 "awkgram.c"
+    break;
+
+  case 93:
+#line 1430 "awkgram.y"
+    {
+		if (yyvsp[-4] != NULL)
+			yyvsp[-8]->comment = yyvsp[-4];
+		if (yyvsp[-1] != NULL)
+			yyvsp[-2]->comment = yyvsp[-1];
+		yyval = mk_condition(yyvsp[-6], yyvsp[-8], yyvsp[-3], yyvsp[-2], yyvsp[0]);
+	  }
+#line 3375 "awkgram.c"
+    break;
+
+  case 94:
+#line 1441 "awkgram.y"
+    {
+		yyval = yyvsp[0];
+	  }
+#line 3383 "awkgram.c"
+    break;
+
+  case 95:
+#line 1445 "awkgram.y"
+    {
+		if (yyvsp[-1] != NULL && yyvsp[0] != NULL) {
+			if (yyvsp[-1]->memory->comment_type == EOL_COMMENT) {
+				assert(yyvsp[0]->memory->comment_type == BLOCK_COMMENT);
+				yyvsp[-1]->comment = yyvsp[0];	// chain them
+			} else {
+				merge_comments(yyvsp[-1], yyvsp[0]);
+			}
+
+			yyval = yyvsp[-1];
+		} else if (yyvsp[-1] != NULL) {
+			yyval = yyvsp[-1];
+		} else if (yyvsp[0] != NULL) {
+			yyval = yyvsp[0];
+		} else
+			yyval = NULL;
+	  }
+#line 3405 "awkgram.c"
+    break;
+
+  case 96:
+#line 1466 "awkgram.y"
+    { yyval = NULL; }
+#line 3411 "awkgram.c"
+    break;
+
+  case 97:
+#line 1468 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3417 "awkgram.c"
+    break;
+
+  case 98:
+#line 1473 "awkgram.y"
+    { yyval = NULL; }
+#line 3423 "awkgram.c"
+    break;
+
+  case 99:
+#line 1475 "awkgram.y"
+    {
+		bcfree(yyvsp[-1]);
+		yyval = yyvsp[0];
+	  }
+#line 3432 "awkgram.c"
+    break;
+
+  case 100:
+#line 1483 "awkgram.y"
+    { yyval = NULL; }
+#line 3438 "awkgram.c"
+    break;
+
+  case 101:
+#line 1485 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3444 "awkgram.c"
+    break;
+
+  case 102:
+#line 1490 "awkgram.y"
+    {
+		yyvsp[0]->param_count = 0;
+		yyval = list_create(yyvsp[0]);
+	  }
+#line 3453 "awkgram.c"
+    break;
+
+  case 103:
+#line 1495 "awkgram.y"
+    {
+		if (yyvsp[-2] != NULL && yyvsp[0] != NULL) {
+			yyvsp[0]->param_count = yyvsp[-2]->lasti->param_count + 1;
+			yyval = list_append(yyvsp[-2], yyvsp[0]);
+			yyerrok;
+
+			// newlines are allowed after commas, catch any comments
+			if (yyvsp[-1] != NULL) {
+				if (yyvsp[-2]->comment != NULL)
+					merge_comments(yyvsp[-2]->comment, yyvsp[-1]);
+				else
+					yyvsp[-2]->comment = yyvsp[-1];
+			}
+		} else
+			yyval = NULL;
+	  }
+#line 3474 "awkgram.c"
+    break;
+
+  case 104:
+#line 1512 "awkgram.y"
+    { yyval = NULL; }
+#line 3480 "awkgram.c"
+    break;
+
+  case 105:
+#line 1514 "awkgram.y"
+    { yyval = yyvsp[-1]; }
+#line 3486 "awkgram.c"
+    break;
+
+  case 106:
+#line 1516 "awkgram.y"
+    { yyval = yyvsp[-2]; }
+#line 3492 "awkgram.c"
+    break;
+
+  case 107:
+#line 1522 "awkgram.y"
+    { yyval = NULL; }
+#line 3498 "awkgram.c"
+    break;
+
+  case 108:
+#line 1524 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3504 "awkgram.c"
+    break;
+
+  case 109:
+#line 1529 "awkgram.y"
+    { yyval = NULL; }
+#line 3510 "awkgram.c"
+    break;
+
+  case 110:
+#line 1531 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3516 "awkgram.c"
+    break;
+
+  case 111:
+#line 1536 "awkgram.y"
+    {	yyval = mk_expression_list(NULL, yyvsp[0]); }
+#line 3522 "awkgram.c"
+    break;
+
+  case 112:
+#line 1538 "awkgram.y"
+    {
+		if (yyvsp[-1] != NULL)
+			yyvsp[-2]->lasti->comment = yyvsp[-1];
+		yyval = mk_expression_list(yyvsp[-2], yyvsp[0]);
+		yyerrok;
+	  }
+#line 3533 "awkgram.c"
+    break;
+
+  case 113:
+#line 1545 "awkgram.y"
+    { yyval = NULL; }
+#line 3539 "awkgram.c"
+    break;
+
+  case 114:
+#line 1547 "awkgram.y"
+    {
+		/*
+		 * Returning the expression list instead of NULL lets
+		 * snode get a list of arguments that it can count.
+		 */
+		yyval = yyvsp[-1];
+	  }
+#line 3551 "awkgram.c"
+    break;
+
+  case 115:
+#line 1555 "awkgram.y"
+    {
+		/* Ditto */
+		yyval = mk_expression_list(yyvsp[-2], yyvsp[0]);
+	  }
+#line 3560 "awkgram.c"
+    break;
+
+  case 116:
+#line 1560 "awkgram.y"
+    {
+		/* Ditto */
+		if (yyvsp[-1] != NULL)
+			yyvsp[-2]->lasti->comment = yyvsp[-1];
+		yyval = yyvsp[-2];
+	  }
+#line 3571 "awkgram.c"
+    break;
+
+  case 117:
+#line 1570 "awkgram.y"
+    { yyval = NULL; }
+#line 3577 "awkgram.c"
+    break;
+
+  case 118:
+#line 1572 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3583 "awkgram.c"
+    break;
+
+  case 119:
+#line 1577 "awkgram.y"
+    {	yyval = mk_expression_list(NULL, yyvsp[0]); }
+#line 3589 "awkgram.c"
+    break;
+
+  case 120:
+#line 1579 "awkgram.y"
+    {
+		if (yyvsp[-1] != NULL)
+			yyvsp[-2]->lasti->comment = yyvsp[-1];
+		yyval = mk_expression_list(yyvsp[-2], yyvsp[0]);
+		yyerrok;
+	  }
+#line 3600 "awkgram.c"
+    break;
+
+  case 121:
+#line 1586 "awkgram.y"
+    { yyval = NULL; }
+#line 3606 "awkgram.c"
+    break;
+
+  case 122:
+#line 1588 "awkgram.y"
+    {
+		/*
+		 * Returning the expression list instead of NULL lets
+		 * snode get a list of arguments that it can count.
+		 */
+		yyval = yyvsp[-1];
+	  }
+#line 3618 "awkgram.c"
+    break;
+
+  case 123:
+#line 1596 "awkgram.y"
+    {
+		/* Ditto */
+		yyval = mk_expression_list(yyvsp[-2], yyvsp[0]);
+	  }
+#line 3627 "awkgram.c"
+    break;
+
+  case 124:
+#line 1601 "awkgram.y"
+    {
+		/* Ditto */
+		if (yyvsp[-1] != NULL)
+			yyvsp[-2]->comment = yyvsp[-1];
+		yyval = yyvsp[-2];
+	  }
+#line 3638 "awkgram.c"
+    break;
+
+  case 125:
+#line 1610 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3644 "awkgram.c"
+    break;
+
+  case 126:
+#line 1611 "awkgram.y"
+    { yyval = list_create(yyvsp[0]); }
+#line 3650 "awkgram.c"
+    break;
+
+  case 127:
+#line 1617 "awkgram.y"
+    {
+		if (do_lint && yyvsp[0]->lasti->opcode == Op_match_rec)
+			lintwarn_ln(yyvsp[-1]->source_line,
+				_("regular expression on right of assignment"));
+		yyval = mk_assignment(yyvsp[-2], yyvsp[0], yyvsp[-1]);
+	  }
+#line 3661 "awkgram.c"
+    break;
+
+  case 128:
+#line 1624 "awkgram.y"
+    {
+		yyval = mk_assignment(yyvsp[-2], list_create(yyvsp[0]), yyvsp[-1]);
+	  }
+#line 3669 "awkgram.c"
+    break;
+
+  case 129:
+#line 1628 "awkgram.y"
+    {	yyval = mk_boolean(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3675 "awkgram.c"
+    break;
+
+  case 130:
+#line 1630 "awkgram.y"
+    {	yyval = mk_boolean(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3681 "awkgram.c"
+    break;
+
+  case 131:
+#line 1632 "awkgram.y"
+    {
+		if (yyvsp[-2]->lasti->opcode == Op_match_rec)
+			warning_ln(yyvsp[-1]->source_line,
+				_("regular expression on left of `~' or `!~' operator"));
+
+		assert(yyvsp[0]->opcode == Op_push_re
+			&& (yyvsp[0]->memory->flags & REGEX) != 0);
+		/* RHS is @/.../ */
+		yyvsp[-1]->memory = yyvsp[0]->memory;
+		bcfree(yyvsp[0]);
+		yyval = list_append(yyvsp[-2], yyvsp[-1]);
+	  }
+#line 3698 "awkgram.c"
+    break;
+
+  case 132:
+#line 1645 "awkgram.y"
+    {
+		if (yyvsp[-2]->lasti->opcode == Op_match_rec)
+			warning_ln(yyvsp[-1]->source_line,
+				_("regular expression on left of `~' or `!~' operator"));
+
+		if (yyvsp[0]->lasti == yyvsp[0]->nexti && yyvsp[0]->nexti->opcode == Op_match_rec) {
+			/* RHS is /.../ */
+			yyvsp[-1]->memory = yyvsp[0]->nexti->memory;
+			bcfree(yyvsp[0]->nexti);	/* Op_match_rec */
+			bcfree(yyvsp[0]);			/* Op_list */
+			yyval = list_append(yyvsp[-2], yyvsp[-1]);
+		} else {
+			yyvsp[-1]->memory = make_regnode(Node_dynregex, NULL);
+			yyval = list_append(list_merge(yyvsp[-2], yyvsp[0]), yyvsp[-1]);
+		}
+	  }
+#line 3719 "awkgram.c"
+    break;
+
+  case 133:
+#line 1662 "awkgram.y"
+    {
+		if (do_lint_old)
+			warning_ln(yyvsp[-1]->source_line,
+				_("old awk does not support the keyword `in' except after `for'"));
+		yyvsp[0]->nexti->opcode = Op_push_array;
+		yyvsp[-1]->opcode = Op_in_array;
+		yyvsp[-1]->expr_count = 1;
+		yyval = list_append(list_merge(yyvsp[-2], yyvsp[0]), yyvsp[-1]);
+	  }
+#line 3733 "awkgram.c"
+    break;
+
+  case 134:
+#line 1672 "awkgram.y"
+    {
+		if (do_lint && yyvsp[0]->lasti->opcode == Op_match_rec)
+			lintwarn_ln(yyvsp[-1]->source_line,
+				_("regular expression on right of comparison"));
+		yyval = list_append(list_merge(yyvsp[-2], yyvsp[0]), yyvsp[-1]);
+	  }
+#line 3744 "awkgram.c"
+    break;
+
+  case 135:
+#line 1679 "awkgram.y"
+    { yyval = mk_condition(yyvsp[-4], yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); }
+#line 3750 "awkgram.c"
+    break;
+
+  case 136:
+#line 1681 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3756 "awkgram.c"
+    break;
+
+  case 137:
+#line 1686 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3762 "awkgram.c"
+    break;
+
+  case 138:
+#line 1688 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3768 "awkgram.c"
+    break;
+
+  case 139:
+#line 1690 "awkgram.y"
+    {
+		yyvsp[0]->opcode = Op_assign_quotient;
+		yyval = yyvsp[0];
+	  }
+#line 3777 "awkgram.c"
+    break;
+
+  case 140:
+#line 1698 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3783 "awkgram.c"
+    break;
+
+  case 141:
+#line 1700 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3789 "awkgram.c"
+    break;
+
+  case 142:
+#line 1705 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3795 "awkgram.c"
+    break;
+
+  case 143:
+#line 1707 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3801 "awkgram.c"
+    break;
+
+  case 144:
+#line 1712 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3807 "awkgram.c"
+    break;
+
+  case 145:
+#line 1714 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 3813 "awkgram.c"
+    break;
+
+  case 146:
+#line 1716 "awkgram.y"
+    {
+		int count = 2;
+		bool is_simple_var = false;
+
+		if (yyvsp[-1]->lasti->opcode == Op_concat) {
+			/* multiple (> 2) adjacent strings optimization */
+			is_simple_var = (yyvsp[-1]->lasti->concat_flag & CSVAR) != 0;
+			count = yyvsp[-1]->lasti->expr_count + 1;
+			yyvsp[-1]->lasti->opcode = Op_no_op;
+		} else {
+			is_simple_var = (yyvsp[-1]->nexti->opcode == Op_push
+					&& yyvsp[-1]->lasti == yyvsp[-1]->nexti); /* first exp. is a simple
+					                             * variable?; kludge for use
+					                             * in Op_assign_concat.
+		 			                             */
+		}
+
+		if (do_optimize
+			&& yyvsp[-1]->nexti == yyvsp[-1]->lasti && yyvsp[-1]->nexti->opcode == Op_push_i
+			&& yyvsp[0]->nexti == yyvsp[0]->lasti && yyvsp[0]->nexti->opcode == Op_push_i
+		) {
+			NODE *n1 = yyvsp[-1]->nexti->memory;
+			NODE *n2 = yyvsp[0]->nexti->memory;
+			size_t nlen;
+
+			// 1.5 ""   # can't fold this if program mucks with CONVFMT.
+			// See test #12 in test/posix.awk.
+			// Also can't fold if one or the other is translatable.
+			if ((n1->flags & (NUMBER|NUMINT|INTLSTR)) != 0 || (n2->flags & (NUMBER|NUMINT|INTLSTR)) != 0)
+				goto plain_concat;
+
+			n1 = force_string(n1);
+			n2 = force_string(n2);
+			nlen = n1->stlen + n2->stlen;
+			erealloc(n1->stptr, char *, nlen + 1, "constant fold");
+			memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
+			n1->stlen = nlen;
+			n1->stptr[nlen] = '\0';
+			n1->flags &= ~(NUMCUR|NUMBER|NUMINT);
+			n1->flags |= (STRING|STRCUR);
+			unref(n2);
+			bcfree(yyvsp[0]->nexti);
+			bcfree(yyvsp[0]);
+			yyval = yyvsp[-1];
+		} else {
+	plain_concat:
+			yyval = list_append(list_merge(yyvsp[-1], yyvsp[0]), instruction(Op_concat));
+			yyval->lasti->concat_flag = (is_simple_var ? CSVAR : 0);
+			yyval->lasti->expr_count = count;
+			if (count > max_args)
+				max_args = count;
+		}
+	  }
+#line 3871 "awkgram.c"
+    break;
+
+  case 148:
+#line 1775 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3877 "awkgram.c"
+    break;
+
+  case 149:
+#line 1777 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3883 "awkgram.c"
+    break;
+
+  case 150:
+#line 1779 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3889 "awkgram.c"
+    break;
+
+  case 151:
+#line 1781 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3895 "awkgram.c"
+    break;
+
+  case 152:
+#line 1783 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3901 "awkgram.c"
+    break;
+
+  case 153:
+#line 1785 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3907 "awkgram.c"
+    break;
+
+  case 154:
+#line 1787 "awkgram.y"
+    {
+		/*
+		 * In BEGINFILE/ENDFILE, allow `getline [var] < file'
+		 */
+
+		if ((rule == BEGINFILE || rule == ENDFILE) && yyvsp[0] == NULL)
+			error_ln(yyvsp[-2]->source_line,
+				 _("non-redirected `getline' invalid inside `%s' rule"), ruletab[rule]);
+		if (do_lint && rule == END && yyvsp[0] == NULL)
+			lintwarn_ln(yyvsp[-2]->source_line,
+				_("non-redirected `getline' undefined inside END action"));
+		yyval = mk_getline(yyvsp[-2], yyvsp[-1], yyvsp[0], redirect_input);
+	  }
+#line 3925 "awkgram.c"
+    break;
+
+  case 155:
+#line 1801 "awkgram.y"
+    {
+		yyvsp[0]->opcode = Op_postincrement;
+		yyval = mk_assignment(yyvsp[-1], NULL, yyvsp[0]);
+	  }
+#line 3934 "awkgram.c"
+    break;
+
+  case 156:
+#line 1806 "awkgram.y"
+    {
+		yyvsp[0]->opcode = Op_postdecrement;
+		yyval = mk_assignment(yyvsp[-1], NULL, yyvsp[0]);
+	  }
+#line 3943 "awkgram.c"
+    break;
+
+  case 157:
+#line 1811 "awkgram.y"
+    {
+		if (do_lint_old) {
+		    warning_ln(yyvsp[-1]->source_line,
+				_("old awk does not support the keyword `in' except after `for'"));
+		    warning_ln(yyvsp[-1]->source_line,
+				_("old awk does not support multidimensional arrays"));
+		}
+		yyvsp[0]->nexti->opcode = Op_push_array;
+		yyvsp[-1]->opcode = Op_in_array;
+		if (yyvsp[-3] == NULL) {	/* error */
+			errcount++;
+			yyvsp[-1]->expr_count = 0;
+			yyval = list_merge(yyvsp[0], yyvsp[-1]);
+		} else {
+			INSTRUCTION *t = yyvsp[-3];
+			yyvsp[-1]->expr_count = count_expressions(&t, false);
+			yyval = list_append(list_merge(t, yyvsp[0]), yyvsp[-1]);
+		}
+	  }
+#line 3967 "awkgram.c"
+    break;
+
+  case 158:
+#line 1836 "awkgram.y"
+    {
+		  yyval = mk_getline(yyvsp[-1], yyvsp[0], yyvsp[-3], yyvsp[-2]->redir_type);
+		  bcfree(yyvsp[-2]);
+		}
+#line 3976 "awkgram.c"
+    break;
+
+  case 159:
+#line 1842 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3982 "awkgram.c"
+    break;
+
+  case 160:
+#line 1844 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3988 "awkgram.c"
+    break;
+
+  case 161:
+#line 1846 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 3994 "awkgram.c"
+    break;
+
+  case 162:
+#line 1848 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 4000 "awkgram.c"
+    break;
+
+  case 163:
+#line 1850 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 4006 "awkgram.c"
+    break;
+
+  case 164:
+#line 1852 "awkgram.y"
+    { yyval = mk_binary(yyvsp[-2], yyvsp[0], yyvsp[-1]); }
+#line 4012 "awkgram.c"
+    break;
+
+  case 165:
+#line 1857 "awkgram.y"
+    {
+		yyval = list_create(yyvsp[0]);
+	  }
+#line 4020 "awkgram.c"
+    break;
+
+  case 166:
+#line 1861 "awkgram.y"
+    {
+		if (yyvsp[0]->opcode == Op_match_rec) {
+			yyvsp[0]->opcode = Op_nomatch;
+			yyvsp[-1]->opcode = Op_push_i;
+			yyvsp[-1]->memory = set_profile_text(make_number(0.0), "0", 1);
+			yyval = list_append(list_append(list_create(yyvsp[-1]),
+						instruction(Op_field_spec)), yyvsp[0]);
+		} else {
+			if (do_optimize && yyvsp[0]->nexti == yyvsp[0]->lasti
+					&& yyvsp[0]->nexti->opcode == Op_push_i
+					&& (yyvsp[0]->nexti->memory->flags & (MPFN|MPZN|INTLSTR)) == 0
+			) {
+				NODE *n = yyvsp[0]->nexti->memory;
+				if ((n->flags & STRING) != 0) {
+					n->numbr = (AWKNUM) (n->stlen == 0);
+					n->flags &= ~(STRCUR|STRING);
+					n->flags |= (NUMCUR|NUMBER);
+					efree(n->stptr);
+					n->stptr = NULL;
+					n->stlen = 0;
+				} else
+					n->numbr = (AWKNUM) (n->numbr == 0.0);
+				bcfree(yyvsp[-1]);
+				yyval = yyvsp[0];
+			} else {
+				yyvsp[-1]->opcode = Op_not;
+				add_lint(yyvsp[0], LINT_assign_in_cond);
+				yyval = list_append(yyvsp[0], yyvsp[-1]);
+			}
+		}
+	   }
+#line 4056 "awkgram.c"
+    break;
+
+  case 167:
+#line 1893 "awkgram.y"
+    {
+		// Always include. Allows us to lint warn on
+		// print "foo" > "bar" 1
+		// but not warn on
+		// print "foo" > ("bar" 1)
+		yyval = list_append(yyvsp[-1], bcalloc(Op_parens, 1, sourceline));
+	  }
+#line 4068 "awkgram.c"
+    break;
+
+  case 168:
+#line 1901 "awkgram.y"
+    {
+		yyval = snode(yyvsp[-1], yyvsp[-3]);
+		if (yyval == NULL)
+			YYABORT;
+	  }
+#line 4078 "awkgram.c"
+    break;
+
+  case 169:
+#line 1907 "awkgram.y"
+    {
+		yyval = snode(yyvsp[-1], yyvsp[-3]);
+		if (yyval == NULL)
+			YYABORT;
+	  }
+#line 4088 "awkgram.c"
+    break;
+
+  case 170:
+#line 1913 "awkgram.y"
+    {
+		static bool warned = false;
+
+		if (do_lint && ! warned) {
+			warned = true;
+			lintwarn_ln(yyvsp[0]->source_line,
+				_("call of `length' without parentheses is not portable"));
+		}
+		yyval = snode(NULL, yyvsp[0]);
+		if (yyval == NULL)
+			YYABORT;
+	  }
+#line 4105 "awkgram.c"
+    break;
+
+  case 173:
+#line 1928 "awkgram.y"
+    {
+		yyvsp[-1]->opcode = Op_preincrement;
+		yyval = mk_assignment(yyvsp[0], NULL, yyvsp[-1]);
+	  }
+#line 4114 "awkgram.c"
+    break;
+
+  case 174:
+#line 1933 "awkgram.y"
+    {
+		yyvsp[-1]->opcode = Op_predecrement;
+		yyval = mk_assignment(yyvsp[0], NULL, yyvsp[-1]);
+	  }
+#line 4123 "awkgram.c"
+    break;
+
+  case 175:
+#line 1938 "awkgram.y"
+    {
+		yyval = list_create(yyvsp[0]);
+	  }
+#line 4131 "awkgram.c"
+    break;
+
+  case 176:
+#line 1942 "awkgram.y"
+    {
+		yyval = list_create(yyvsp[0]);
+	  }
+#line 4139 "awkgram.c"
+    break;
+
+  case 177:
+#line 1946 "awkgram.y"
+    {
+		if (yyvsp[0]->lasti->opcode == Op_push_i
+			&& (yyvsp[0]->lasti->memory->flags & STRING) == 0
+		) {
+			NODE *n = yyvsp[0]->lasti->memory;
+			(void) force_number(n);
+			negate_num(n);
+			yyval = yyvsp[0];
+			bcfree(yyvsp[-1]);
+		} else {
+			yyvsp[-1]->opcode = Op_unary_minus;
+			yyval = list_append(yyvsp[0], yyvsp[-1]);
+		}
+	  }
+#line 4158 "awkgram.c"
+    break;
+
+  case 178:
+#line 1961 "awkgram.y"
+    {
+		if (yyvsp[0]->lasti->opcode == Op_push_i
+			&& (yyvsp[0]->lasti->memory->flags & STRING) == 0
+			&& (yyvsp[0]->lasti->memory->flags & NUMCONSTSTR) != 0) {
+			NODE *n = yyvsp[0]->lasti->memory;
+			add_sign_to_num(n, '+');
+			yyval = yyvsp[0];
+			bcfree(yyvsp[-1]);
+		} else {
+			/*
+			 * was: $$ = $2
+			 * POSIX semantics: force a conversion to numeric type
+			 */
+			yyvsp[-1]->opcode = Op_unary_plus;
+			yyval = list_append(yyvsp[0], yyvsp[-1]);
+		}
+	  }
+#line 4180 "awkgram.c"
+    break;
+
+  case 179:
+#line 1982 "awkgram.y"
+    {
+		func_use(yyvsp[0]->lasti->func_name, FUNC_USE);
+		yyval = yyvsp[0];
+	  }
+#line 4189 "awkgram.c"
+    break;
+
+  case 180:
+#line 1987 "awkgram.y"
+    {
+		/* indirect function call */
+		INSTRUCTION *f, *t;
+		char *name;
+		NODE *indirect_var;
+		static bool warned = false;
+		const char *msg = _("indirect function calls are a gawk extension");
+
+		if (do_traditional || do_posix)
+			yyerror("%s", msg);
+		else if (do_lint && ! warned) {
+			warned = true;
+			lintwarn("%s", msg);
+		}
+
+		f = yyvsp[0]->lasti;
+		f->opcode = Op_indirect_func_call;
+		name = estrdup(f->func_name, strlen(f->func_name));
+		if (is_std_var(name))
+			yyerror(_("can not use special variable `%s' for indirect function call"), name);
+		indirect_var = variable(f->source_line, name, Node_var_new);
+		t = instruction(Op_push);
+		t->memory = indirect_var;
+
+		/* prepend indirect var instead of appending to arguments (opt_expression_list),
+		 * and pop it off in setup_frame (eval.c) (left to right evaluation order); Test case:
+		 *		f = "fun"
+		 *		@f(f="real_fun")
+		 */
+
+		yyval = list_prepend(yyvsp[0], t);
+		at_seen = false;
+	  }
+#line 4227 "awkgram.c"
+    break;
+
+  case 181:
+#line 2024 "awkgram.y"
+    {
+		NODE *n;
+		char *name = yyvsp[-3]->func_name;
+		char *qname = qualify_name(name, strlen(name));
+
+		if (qname != name) {
+			efree((char *) name);
+			yyvsp[-3]->func_name = qname;
+		}
+
+		if (! at_seen) {
+			n = lookup(yyvsp[-3]->func_name);
+			if (n != NULL && n->type != Node_func
+			    && n->type != Node_ext_func) {
+				error_ln(yyvsp[-3]->source_line,
+					_("attempt to use non-function `%s' in function call"),
+						yyvsp[-3]->func_name);
+			}
+		}
+
+		param_sanity(yyvsp[-1]);
+		yyvsp[-3]->opcode = Op_func_call;
+		yyvsp[-3]->func_body = NULL;
+		if (yyvsp[-1] == NULL) {	/* no argument or error */
+			(yyvsp[-3] + 1)->expr_count = 0;
+			yyval = list_create(yyvsp[-3]);
+		} else {
+			INSTRUCTION *t = yyvsp[-1];
+			(yyvsp[-3] + 1)->expr_count = count_expressions(&t, true);
+			yyval = list_append(t, yyvsp[-3]);
+		}
+	  }
+#line 4264 "awkgram.c"
+    break;
+
+  case 182:
+#line 2060 "awkgram.y"
+    { yyval = NULL; }
+#line 4270 "awkgram.c"
+    break;
+
+  case 183:
+#line 2062 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 4276 "awkgram.c"
+    break;
+
+  case 184:
+#line 2067 "awkgram.y"
+    { yyval = NULL; }
+#line 4282 "awkgram.c"
+    break;
+
+  case 185:
+#line 2069 "awkgram.y"
+    { yyval = yyvsp[-1]; }
+#line 4288 "awkgram.c"
+    break;
+
+  case 186:
+#line 2074 "awkgram.y"
+    {	yyval = yyvsp[0]; }
+#line 4294 "awkgram.c"
+    break;
+
+  case 187:
+#line 2076 "awkgram.y"
+    {
+		yyval = list_merge(yyvsp[-1], yyvsp[0]);
+	  }
+#line 4302 "awkgram.c"
+    break;
+
+  case 188:
+#line 2083 "awkgram.y"
+    {
+		INSTRUCTION *ip = yyvsp[0]->lasti;
+		int count = ip->sub_count;	/* # of SUBSEP-seperated expressions */
+		if (count > 1) {
+			/* change Op_subscript or Op_sub_array to Op_concat */
+			ip->opcode = Op_concat;
+			ip->concat_flag = CSUBSEP;
+			ip->expr_count = count;
+		} else
+			ip->opcode = Op_no_op;
+		sub_counter++;	/* count # of dimensions */
+		yyval = yyvsp[0];
+	  }
+#line 4320 "awkgram.c"
+    break;
+
+  case 189:
+#line 2100 "awkgram.y"
+    {
+		INSTRUCTION *t = yyvsp[-1];
+		if (yyvsp[-1] == NULL) {
+			error_ln(yyvsp[0]->source_line,
+				_("invalid subscript expression"));
+			/* install Null string as subscript. */
+			t = list_create(instruction(Op_push_i));
+			t->nexti->memory = dupnode(Nnull_string);
+			yyvsp[0]->sub_count = 1;
+		} else
+			yyvsp[0]->sub_count = count_expressions(&t, false);
+		yyval = list_append(t, yyvsp[0]);
+	  }
+#line 4338 "awkgram.c"
+    break;
+
+  case 190:
+#line 2117 "awkgram.y"
+    {	yyval = yyvsp[0]; }
+#line 4344 "awkgram.c"
+    break;
+
+  case 191:
+#line 2119 "awkgram.y"
+    {
+		yyval = list_merge(yyvsp[-1], yyvsp[0]);
+	  }
+#line 4352 "awkgram.c"
+    break;
+
+  case 192:
+#line 2126 "awkgram.y"
+    { yyval = yyvsp[-1]; }
+#line 4358 "awkgram.c"
+    break;
+
+  case 193:
+#line 2131 "awkgram.y"
+    {
+		yyvsp[0]->opcode = Op_push;
+		yyvsp[0]->memory = variable(yyvsp[0]->source_line, yyvsp[0]->lextok, Node_var_new);
+		yyval = list_create(yyvsp[0]);
+	  }
+#line 4368 "awkgram.c"
+    break;
+
+  case 194:
+#line 2137 "awkgram.y"
+    {
+		char *arr = yyvsp[-1]->lextok;
+
+		yyvsp[-1]->memory = variable(yyvsp[-1]->source_line, arr, Node_var_new);
+		yyvsp[-1]->opcode = Op_push_array;
+		yyval = list_prepend(yyvsp[0], yyvsp[-1]);
+	  }
+#line 4380 "awkgram.c"
+    break;
+
+  case 195:
+#line 2148 "awkgram.y"
+    {
+		INSTRUCTION *ip = yyvsp[0]->nexti;
+		if (ip->opcode == Op_push
+			&& ip->memory->type == Node_var
+			&& ip->memory->var_update
+		) {
+			yyval = list_prepend(yyvsp[0], instruction(Op_var_update));
+			yyval->nexti->update_var = ip->memory->var_update;
+		} else
+			yyval = yyvsp[0];
+	  }
+#line 4396 "awkgram.c"
+    break;
+
+  case 196:
+#line 2160 "awkgram.y"
+    {
+		yyval = list_append(yyvsp[-1], yyvsp[-2]);
+		if (yyvsp[0] != NULL)
+			mk_assignment(yyvsp[-1], NULL, yyvsp[0]);
+	  }
+#line 4406 "awkgram.c"
+    break;
+
+  case 197:
+#line 2169 "awkgram.y"
+    {
+		yyvsp[0]->opcode = Op_postincrement;
+	  }
+#line 4414 "awkgram.c"
+    break;
+
+  case 198:
+#line 2173 "awkgram.y"
+    {
+		yyvsp[0]->opcode = Op_postdecrement;
+	  }
+#line 4422 "awkgram.c"
+    break;
+
+  case 199:
+#line 2177 "awkgram.y"
+    { yyval = NULL; }
+#line 4428 "awkgram.c"
+    break;
+
+  case 200:
+#line 2181 "awkgram.y"
+    { yyval = yyvsp[0]; }
+#line 4434 "awkgram.c"
+    break;
+
+  case 201:
+#line 2185 "awkgram.y"
+    { yyval = yyvsp[0]; yyerrok; }
+#line 4440 "awkgram.c"
+    break;
+
+  case 202:
+#line 2189 "awkgram.y"
+    { yyerrok; }
+#line 4446 "awkgram.c"
+    break;
+
+  case 203:
+#line 2194 "awkgram.y"
+    { yyval = NULL; }
+#line 4452 "awkgram.c"
+    break;
+
+  case 205:
+#line 2199 "awkgram.y"
+    { yyerrok; }
+#line 4458 "awkgram.c"
+    break;
+
+  case 206:
+#line 2203 "awkgram.y"
+    { yyval = yyvsp[0]; yyerrok; }
+#line 4464 "awkgram.c"
+    break;
+
+  case 207:
+#line 2207 "awkgram.y"
+    { yyval = yyvsp[0]; yyerrok; }
+#line 4470 "awkgram.c"
+    break;
+
+
+#line 4474 "awkgram.c"
+
+      default: break;
+    }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  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.  */
+  {
+    const int yylhs = yyr1[yyn] - YYNTOKENS;
+    const int yyi = yypgoto[yylhs] + *yyssp;
+    yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+               ? yytable[yyi]
+               : yydefgoto[yylhs]);
+  }
+
+  goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error.  |
+`--------------------------------------*/
+yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
+      {
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead 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 lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+  /* Pacify compilers when the user code never invokes YYERROR and the
+     label yyerrorlab therefore never appears in user code.  */
+  if (0)
+    YYERROR;
+
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  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 (!yypact_value_is_default (yyn))
+        {
+          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 (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* 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;
+
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+
+/*-----------------------------------------------------.
+| yyreturn -- parsing is finished, return the result.  |
+`-----------------------------------------------------*/
+yyreturn:
+  if (yychar != YYEMPTY)
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
+  /* Do not reclaim the symbols of the rule whose action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  return yyresult;
+}
+#line 2209 "awkgram.y"
+
+
+struct token {
+	const char *operator;	/* text to match */
+	OPCODE value;			/*  type */
+	int class;				/* lexical class */
+	unsigned flags;			/* # of args. allowed and compatability */
+#	define	ARGS	0xFF	/* 0, 1, 2, 3 args allowed (any combination */
+#	define	A(n)	(1<<(n))
+#	define	VERSION_MASK	0xFF00	/* old awk is zero */
+#	define	NOT_OLD		0x0100	/* feature not in old awk */
+#	define	NOT_POSIX	0x0200	/* feature not in POSIX */
+#	define	GAWKX		0x0400	/* gawk extension */
+#	define	BREAK		0x0800	/* break allowed inside */
+#	define	CONTINUE	0x1000	/* continue allowed inside */
+#	define	DEBUG_USE	0x2000	/* for use by developers */
+
+	NODE *(*ptr)(int);	/* function that implements this keyword */
+	NODE *(*ptr2)(int);	/* alternate arbitrary-precision function */
+};
+
+#ifdef USE_EBCDIC
+/* tokcompare --- lexicographically compare token names for sorting */
+
+static int
+tokcompare(const void *l, const void *r)
+{
+	struct token *lhs, *rhs;
+
+	lhs = (struct token *) l;
+	rhs = (struct token *) r;
+
+	return strcmp(lhs->operator, rhs->operator);
+}
+#endif
+
+/*
+ * Tokentab is sorted ASCII ascending order, so it can be binary searched.
+ * See check_special(), which sorts the table on EBCDIC systems.
+ * Function pointers come from declarations in awk.h.
+ */
+
+#ifdef HAVE_MPFR
+#define MPF(F) do_mpfr_##F
+#else
+#define MPF(F) 0
+#endif
+
+static const struct token tokentab[] = {
+{"BEGIN",	Op_rule,	 LEX_BEGIN,	0,		0,	0},
+{"BEGINFILE",	Op_rule,	 LEX_BEGINFILE,	GAWKX,		0,	0},
+{"END",		Op_rule,	 LEX_END,	0,		0,	0},
+{"ENDFILE",	Op_rule,	 LEX_ENDFILE,	GAWKX,		0,	0},
+#ifdef ARRAYDEBUG
+{"adump",	Op_builtin,    LEX_BUILTIN,	GAWKX|A(1)|A(2)|DEBUG_USE,	do_adump,	0},
+#endif
+{"and",		Op_builtin,    LEX_BUILTIN,	GAWKX,		do_and,	MPF(and)},
+{"asort",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2)|A(3),	do_asort,	0},
+{"asorti",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2)|A(3),	do_asorti,	0},
+{"atan2",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(2),	do_atan2,	MPF(atan2)},
+{"bindtextdomain",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2),	do_bindtextdomain,	0},
+{"break",	Op_K_break,	 LEX_BREAK,	0,		0,	0},
+{"case",	Op_K_case,	 LEX_CASE,	GAWKX,		0,	0},
+{"close",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(1)|A(2),	do_close,	0},
+{"compl",	Op_builtin,    LEX_BUILTIN,	GAWKX|A(1),	do_compl,	MPF(compl)},
+{"continue",	Op_K_continue, LEX_CONTINUE,	0,		0,	0},
+{"cos",		Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(1),	do_cos,	MPF(cos)},
+{"dcgettext",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2)|A(3),	do_dcgettext,	0},
+{"dcngettext",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2)|A(3)|A(4)|A(5),	do_dcngettext,	0},
+{"default",	Op_K_default,	 LEX_DEFAULT,	GAWKX,		0,	0},
+{"delete",	Op_K_delete,	 LEX_DELETE,	NOT_OLD,	0,	0},
+{"do",		Op_K_do,	 LEX_DO,	NOT_OLD|BREAK|CONTINUE,	0,	0},
+{"else",	Op_K_else,	 LEX_ELSE,	0,		0,	0},
+{"eval",	Op_symbol,	 LEX_EVAL,	0,		0,	0},
+{"exit",	Op_K_exit,	 LEX_EXIT,	0,		0,	0},
+{"exp",		Op_builtin,	 LEX_BUILTIN,	A(1),		do_exp,	MPF(exp)},
+{"fflush",	Op_builtin,	 LEX_BUILTIN,	A(0)|A(1), do_fflush,	0},
+{"for",		Op_K_for,	 LEX_FOR,	BREAK|CONTINUE,	0,	0},
+{"func",	Op_func, 	LEX_FUNCTION,	NOT_POSIX|NOT_OLD,	0,	0},
+{"function",	Op_func, 	LEX_FUNCTION,	NOT_OLD,	0,	0},
+{"gensub",	Op_sub_builtin,	 LEX_BUILTIN,	GAWKX|A(3)|A(4), 0,	0},
+{"getline",	Op_K_getline_redir,	 LEX_GETLINE,	NOT_OLD,	0,	0},
+{"gsub",	Op_sub_builtin,	 LEX_BUILTIN,	NOT_OLD|A(2)|A(3), 0,	0},
+{"if",		Op_K_if,	 LEX_IF,	0,		0,	0},
+{"in",		Op_symbol,	 LEX_IN,	0,		0,	0},
+{"include",	Op_symbol,	 LEX_INCLUDE,	GAWKX,	0,	0},
+{"index",	Op_builtin,	 LEX_BUILTIN,	A(2),		do_index,	0},
+{"int",		Op_builtin,	 LEX_BUILTIN,	A(1),		do_int,	MPF(int)},
+#ifdef SUPPLY_INTDIV
+{"intdiv0",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(3),	do_intdiv,	MPF(intdiv)},
+#endif
+{"isarray",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1),	do_isarray,	0},
+{"length",	Op_builtin,	 LEX_LENGTH,	A(0)|A(1),	do_length,	0},
+{"load",  	Op_symbol,	 LEX_LOAD,	GAWKX,		0,	0},
+{"log",		Op_builtin,	 LEX_BUILTIN,	A(1),		do_log,	MPF(log)},
+{"lshift",	Op_builtin,    LEX_BUILTIN,	GAWKX|A(2),	do_lshift,	MPF(lshift)},
+{"match",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(2)|A(3), do_match,	0},
+{"mktime",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2), do_mktime, 0},
+{"namespace",  	Op_symbol,	 LEX_NAMESPACE,	GAWKX,		0,	0},
+{"next",	Op_K_next,	 LEX_NEXT,	0,		0,	0},
+{"nextfile",	Op_K_nextfile, LEX_NEXTFILE,	0,		0,	0},
+{"or",		Op_builtin,    LEX_BUILTIN,	GAWKX,		do_or,	MPF(or)},
+{"patsplit",	Op_builtin,    LEX_BUILTIN,	GAWKX|A(2)|A(3)|A(4), do_patsplit,	0},
+{"print",	Op_K_print,	 LEX_PRINT,	0,		0,	0},
+{"printf",	Op_K_printf,	 LEX_PRINTF,	0,		0,	0},
+{"rand",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(0),	do_rand,	MPF(rand)},
+{"return",	Op_K_return,	 LEX_RETURN,	NOT_OLD,	0,	0},
+{"rshift",	Op_builtin,    LEX_BUILTIN,	GAWKX|A(2),	do_rshift,	MPF(rshift)},
+{"sin",		Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(1),	do_sin,	MPF(sin)},
+{"split",	Op_builtin,	 LEX_BUILTIN,	A(2)|A(3)|A(4),	do_split,	0},
+{"sprintf",	Op_builtin,	 LEX_BUILTIN,	0,		do_sprintf,	0},
+{"sqrt",	Op_builtin,	 LEX_BUILTIN,	A(1),		do_sqrt,	MPF(sqrt)},
+{"srand",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(0)|A(1), do_srand,	MPF(srand)},
+#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
+{"stopme",	Op_builtin,	LEX_BUILTIN,	GAWKX|A(0)|DEBUG_USE,	stopme,		0},
+#endif
+{"strftime",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime,	0},
+{"strtonum",	Op_builtin,    LEX_BUILTIN,	GAWKX|A(1),	do_strtonum, MPF(strtonum)},
+{"sub",		Op_sub_builtin,	 LEX_BUILTIN,	NOT_OLD|A(2)|A(3), 0,	0},
+{"substr",	Op_builtin,	 LEX_BUILTIN,	A(2)|A(3),	do_substr,	0},
+{"switch",	Op_K_switch,	 LEX_SWITCH,	GAWKX|BREAK,	0,	0},
+{"system",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(1),	do_system,	0},
+{"systime",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(0),	do_systime,	0},
+{"tolower",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(1),	do_tolower,	0},
+{"toupper",	Op_builtin,	 LEX_BUILTIN,	NOT_OLD|A(1),	do_toupper,	0},
+{"typeof",	Op_builtin,	 LEX_BUILTIN,	GAWKX|A(1)|A(2), do_typeof,	0},
+{"while",	Op_K_while,	 LEX_WHILE,	BREAK|CONTINUE,	0,	0},
+{"xor",		Op_builtin,    LEX_BUILTIN,	GAWKX,		do_xor,	MPF(xor)},
+};
+
+/* Variable containing the current shift state.  */
+static mbstate_t cur_mbstate;
+/* Ring buffer containing current characters.  */
+#define MAX_CHAR_IN_RING_BUFFER 8
+#define RING_BUFFER_SIZE (MAX_CHAR_IN_RING_BUFFER * MB_LEN_MAX)
+static char cur_char_ring[RING_BUFFER_SIZE];
+/* Index for ring buffers.  */
+static int cur_ring_idx;
+/* This macro means that last nextc() return a singlebyte character
+   or 1st byte of a multibyte character.  */
+#define nextc_is_1stbyte (cur_char_ring[cur_ring_idx] == 1)
+
+/* getfname --- return name of a builtin function (for pretty printing) */
+
+const char *
+getfname(NODE *(*fptr)(int), bool prepend_awk)
+{
+	int i, j;
+	static char buf[100];
+
+	j = sizeof(tokentab) / sizeof(tokentab[0]);
+	/* linear search, no other way to do it */
+	for (i = 0; i < j; i++) {
+		if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr) {
+			if (prepend_awk && (tokentab[i].flags & GAWKX) != 0) {
+				sprintf(buf, "awk::%s", tokentab[i].operator);
+				return buf;
+			}
+			return tokentab[i].operator;
+		}
+	}
+
+	return NULL;
+}
+
+/* negate_num --- negate a number in NODE */
+
+void
+negate_num(NODE *n)
+{
+#ifdef HAVE_MPFR
+	int tval = 0;
+#endif
+
+	add_sign_to_num(n, '-');
+
+	if (! is_mpg_number(n)) {
+		n->numbr = -n->numbr;
+		return;
+	}
+
+#ifdef HAVE_MPFR
+	if (is_mpg_integer(n)) {
+		if (! iszero(n)) {
+			mpz_neg(n->mpg_i, n->mpg_i);
+			return;
+		}
+
+		/*
+		 * 0 --> -0 conversion. Requires turning the MPG integer
+		 * into an MPFR float.
+		 */
+
+		mpz_clear(n->mpg_i);	/* release the integer storage */
+
+		/* Convert and fall through. */
+		tval = mpfr_set_d(n->mpg_numbr, 0.0, ROUND_MODE);
+		IEEE_FMT(n->mpg_numbr, tval);
+		n->flags &= ~MPZN;
+		n->flags |= MPFN;
+	}
+
+	/* mpfr float case */
+	tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
+	IEEE_FMT(n->mpg_numbr, tval);
+#endif
+}
+
+/* add_sign_to_num --- make a constant unary plus or minus for profiling */
+
+static void
+add_sign_to_num(NODE *n, char sign)
+{
+	if ((n->flags & NUMCONSTSTR) != 0) {
+		char *s;
+
+		s = n->stptr;
+		memmove(& s[1], & s[0], n->stlen + 1);
+		s[0] = sign;
+		n->stlen++;
+	}
+}
+
+/* print_included_from --- print `Included from ..' file names and locations */
+
+static void
+print_included_from()
+{
+	int saveline, line;
+	SRCFILE *s;
+
+	/* suppress current file name, line # from `.. included from ..' msgs */
+	saveline = sourceline;
+	sourceline = 0;
+
+	for (s = sourcefile; s != NULL && s->stype == SRC_INC; ) {
+		s = s->next;
+		if (s == NULL || s->fd <= INVALID_HANDLE)
+			continue;
+		line = s->srclines;
+
+		/* if last token is NEWLINE, line number is off by 1. */
+		if (s->lasttok == NEWLINE)
+			line--;
+		msg("%s %s:%d%c",
+			s->prev == sourcefile ? "In file included from"
+					  : "                 from",
+			(s->stype == SRC_INC ||
+				 s->stype == SRC_FILE) ? s->src : "cmd. line",
+			line,
+			s->stype == SRC_INC ? ',' : ':'
+		);
+	}
+	sourceline = saveline;
+}
+
+/* warning_ln --- print a warning message with location */
+
+static void
+warning_ln(int line, const char *mesg, ...)
+{
+	va_list args;
+	int saveline;
+
+	saveline = sourceline;
+	sourceline = line;
+	print_included_from();
+	va_start(args, mesg);
+	err(false, _("warning: "), mesg, args);
+	va_end(args);
+	sourceline = saveline;
+}
+
+/* lintwarn_ln --- print a lint warning and location */
+
+static void
+lintwarn_ln(int line, const char *mesg, ...)
+{
+	va_list args;
+	int saveline;
+
+	saveline = sourceline;
+	sourceline = line;
+	print_included_from();
+	va_start(args, mesg);
+	if (lintfunc == r_fatal)
+		err(true, _("fatal: "), mesg, args);
+	else
+		err(false, _("warning: "), mesg, args);
+	va_end(args);
+	sourceline = saveline;
+	if (lintfunc == r_fatal)
+		gawk_exit(EXIT_FATAL);
+}
+
+/* error_ln --- print an error message and location */
+
+static void
+error_ln(int line, const char *m, ...)
+{
+	va_list args;
+	int saveline;
+
+	saveline = sourceline;
+	sourceline = line;
+	print_included_from();
+	errcount++;
+	va_start(args, m);
+	err(false, "error: ", m, args);
+	va_end(args);
+	sourceline = saveline;
+}
+
+/* yyerror --- print a syntax error message, show where */
+
+static void
+yyerror(const char *m, ...)
+{
+	va_list args;
+	const char *mesg = NULL;
+	char *bp, *cp;
+	char *scan;
+	char *buf;
+	int count;
+	static char end_of_file_line[] = "(END OF FILE)";
+	static char syntax_error[] = "syntax error";
+	static size_t syn_err_len = sizeof(syntax_error) - 1;
+	bool generic_error = (strncmp(m, syntax_error, syn_err_len) == 0);
+
+	print_included_from();
+
+	errcount++;
+	/* Find the current line in the input file */
+	if (lexptr && lexeme) {
+		if (thisline == NULL) {
+			cp = lexeme;
+			if (*cp == '\n') {
+				if (cp > lexptr_begin)
+					cp--;
+				mesg = _("unexpected newline or end of string");
+			}
+			for (; cp != lexptr_begin && *cp != '\n'; --cp)
+				continue;
+			if (*cp == '\n')
+				cp++;
+			thisline = cp;
+		}
+		/* NL isn't guaranteed */
+		bp = lexeme;
+		if (bp < thisline)
+			bp = thisline + 1;
+		while (bp < lexend && *bp && *bp != '\n')
+			bp++;
+	} else {
+		thisline = end_of_file_line;
+		bp = thisline + strlen(thisline);
+	}
+
+	if (lexeof && mesg == NULL && generic_error) {
+		msg("%s", end_of_file_line);
+		mesg = _("source files / command-line arguments must contain complete functions or rules");
+	} else
+		msg("%.*s", (int) (bp - thisline), thisline);
+
+	va_start(args, m);
+	if (mesg == NULL)
+		mesg = m;
+
+	count = strlen(mesg) + 1;
+	if (lexptr != NULL)
+		count += (lexeme - thisline) + 2;
+	ezalloc(buf, char *, count+1, "yyerror");
+
+	bp = buf;
+
+	if (lexptr != NULL) {
+		scan = thisline;
+		while (scan < lexeme)
+			if (*scan++ == '\t')
+				*bp++ = '\t';
+			else
+				*bp++ = ' ';
+		*bp++ = '^';
+		*bp++ = ' ';
+	}
+	strcpy(bp, mesg);
+	err(false, "", buf, args);
+	va_end(args);
+	efree(buf);
+}
+
+/* mk_program --- create a single list of instructions */
+
+static INSTRUCTION *
+mk_program()
+{
+	INSTRUCTION *cp, *tmp;
+
+#define begin_block         rule_block[BEGIN]
+#define end_block           rule_block[END]
+#define prog_block          rule_block[Rule]
+#define beginfile_block     rule_block[BEGINFILE]
+#define endfile_block       rule_block[ENDFILE]
+
+	if (end_block == NULL)
+		end_block = list_create(ip_end);
+	else
+		(void) list_prepend(end_block, ip_end);
+
+	if (! in_main_context()) {
+		if (begin_block != NULL && prog_block != NULL)
+			cp = list_merge(begin_block, prog_block);
+		else
+			cp = (begin_block != NULL) ? begin_block : prog_block;
+
+		if (cp != NULL)
+			(void) list_merge(cp, end_block);
+		else
+			cp = end_block;
+
+		(void) list_append(cp, instruction(Op_stop));
+		goto out;
+	}
+
+	if (endfile_block == NULL)
+		endfile_block = list_create(ip_endfile);
+	else {
+		ip_rec->has_endfile = true;
+		(void) list_prepend(endfile_block, ip_endfile);
+	}
+
+	if (beginfile_block == NULL)
+		beginfile_block = list_create(ip_beginfile);
+	else
+		(void) list_prepend(beginfile_block, ip_beginfile);
+
+	if (prog_block == NULL) {
+		if (end_block->nexti == end_block->lasti
+				&& beginfile_block->nexti == beginfile_block->lasti
+				&& endfile_block->nexti == endfile_block->lasti
+		) {
+			/* no pattern-action and (real) end, beginfile or endfile blocks */
+			bcfree(ip_rec);
+			bcfree(ip_newfile);
+			ip_rec = ip_newfile = NULL;
+
+			list_append(beginfile_block, instruction(Op_after_beginfile));
+			(void) list_append(endfile_block, instruction(Op_after_endfile));
+
+			if (begin_block == NULL)     /* no program at all */
+				cp = end_block;
+			else
+				cp = list_merge(begin_block, end_block);
+
+			if (interblock_comment != NULL) {
+				(void) list_append(cp, interblock_comment);
+				interblock_comment = NULL;
+			}
+
+			(void) list_append(cp, ip_atexit);
+			(void) list_append(cp, instruction(Op_stop));
+
+			/* append beginfile_block and endfile_block for sole use
+			 * in getline without redirection (Op_K_getline).
+			 */
+
+			(void) list_merge(cp, beginfile_block);
+			(void) list_merge(cp, endfile_block);
+
+			if (outer_comment != NULL) {
+				cp = list_merge(list_create(outer_comment), cp);
+				outer_comment = NULL;
+			}
+
+			if (interblock_comment != NULL) {
+				(void) list_append(cp, interblock_comment);
+				interblock_comment = NULL;
+			}
+
+			goto out;
+
+		} else {
+			/* install a do-nothing prog block */
+			prog_block = list_create(instruction(Op_no_op));
+		}
+	}
+
+	(void) list_append(endfile_block, instruction(Op_after_endfile));
+	(void) list_prepend(prog_block, ip_rec);
+	(void) list_append(prog_block, instruction(Op_jmp));
+	prog_block->lasti->target_jmp = ip_rec;
+
+	list_append(beginfile_block, instruction(Op_after_beginfile));
+
+	cp = list_merge(beginfile_block, prog_block);
+	(void) list_prepend(cp, ip_newfile);
+	(void) list_merge(cp, endfile_block);
+	(void) list_merge(cp, end_block);
+	if (begin_block != NULL)
+		cp = list_merge(begin_block, cp);
+
+	if (outer_comment != NULL) {
+		cp = list_merge(list_create(outer_comment), cp);
+		outer_comment = NULL;
+	}
+
+	if (interblock_comment != NULL) {
+		(void) list_append(cp, interblock_comment);
+		interblock_comment = NULL;
+	}
+
+	(void) list_append(cp, ip_atexit);
+	(void) list_append(cp, instruction(Op_stop));
+
+out:
+	/* delete the Op_list, not needed */
+	tmp = cp->nexti;
+	bcfree(cp);
+	return tmp;
+
+#undef begin_block
+#undef end_block
+#undef prog_block
+#undef beginfile_block
+#undef endfile_block
+}
+
+/* parse_program --- read in the program and convert into a list of instructions */
+
+int
+parse_program(INSTRUCTION **pcode, bool from_eval)
+{
+	int ret;
+
+	called_from_eval = from_eval;
+
+	/* pre-create non-local jump targets
+	 * ip_end (Op_no_op) -- used as jump target for `exit'
+	 * outside an END block.
+	 */
+	ip_end = instruction(Op_no_op);
+
+	if (! in_main_context())
+		ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL;
+	else {
+		ip_endfile = instruction(Op_no_op);
+		main_beginfile = ip_beginfile = instruction(Op_no_op);
+		ip_rec = instruction(Op_get_record); /* target for `next', also ip_newfile */
+		ip_newfile = bcalloc(Op_newfile, 2, 0); /* target for `nextfile' */
+		ip_newfile->target_jmp = ip_end;
+		ip_newfile->target_endfile = ip_endfile;
+		(ip_newfile + 1)->target_get_record = ip_rec;
+		ip_rec->target_newfile = ip_newfile;
+		ip_atexit = instruction(Op_atexit);	/* target for `exit' in END block */
+	}
+
+	for (sourcefile = srcfiles->next; sourcefile->stype == SRC_EXTLIB;
+			sourcefile = sourcefile->next)
+		;
+
+	lexeof = false;
+	lexptr = NULL;
+	lasttok = 0;
+	memset(rule_block, 0, sizeof(ruletab) * sizeof(INSTRUCTION *));
+	errcount = 0;
+	tok = tokstart != NULL ? tokstart : tokexpand();
+
+	ret = yyparse();
+	*pcode = mk_program();
+
+	/* avoid false source indications */
+	source = NULL;
+	sourceline = 0;
+	if (ret == 0)	/* avoid spurious warning if parser aborted with YYABORT */
+		check_funcs();
+
+	if (do_posix && ! check_param_names())
+		errcount++;
+
+	if (args_array == NULL)
+		emalloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program");
+	else
+		erealloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program");
+
+	return (ret || errcount);
+}
+
+/* free_srcfile --- free a SRCFILE struct */
+
+void
+free_srcfile(SRCFILE *thisfile)
+{
+	efree(thisfile->src);
+	efree(thisfile);
+}
+
+/* do_add_srcfile --- add one item to srcfiles */
+
+static SRCFILE *
+do_add_srcfile(enum srctype stype, char *src, char *path, SRCFILE *thisfile)
+{
+	SRCFILE *s;
+
+	ezalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile");
+	s->src = estrdup(src, strlen(src));
+	s->fullpath = path;
+	s->stype = stype;
+	s->fd = INVALID_HANDLE;
+	s->next = thisfile;
+	s->prev = thisfile->prev;
+	thisfile->prev->next = s;
+	thisfile->prev = s;
+	return s;
+}
+
+/* add_srcfile --- add one item to srcfiles after checking if
+ *				a source file exists and not already in list.
+ */
+
+SRCFILE *
+add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_included, int *errcode)
+{
+	SRCFILE *s;
+	struct stat sbuf;
+	char *path;
+	int errno_val = 0;
+
+	if (already_included)
+		*already_included = false;
+	if (errcode)
+		*errcode = 0;
+	if (stype == SRC_CMDLINE || stype == SRC_STDIN)
+		return do_add_srcfile(stype, src, NULL, thisfile);
+
+	path = find_source(src, & sbuf, & errno_val, stype == SRC_EXTLIB);
+	if (path == NULL) {
+		if (errcode) {
+			*errcode = errno_val;
+			return NULL;
+		}
+		/* use full messages to ease translation */
+		fatal(stype != SRC_EXTLIB
+			? _("can't open source file `%s' for reading (%s)")
+			: _("can't open shared library `%s' for reading (%s)"),
+				src,
+				errno_val ? strerror(errno_val) : _("reason unknown"));
+	}
+
+	/* N.B. We do not eliminate duplicate SRC_FILE (-f) programs. */
+	for (s = srcfiles->next; s != srcfiles; s = s->next) {
+		if ((s->stype == SRC_FILE || s->stype == SRC_INC || s->stype == SRC_EXTLIB) && files_are_same(path, s)) {
+			if (stype == SRC_INC || stype == SRC_EXTLIB) {
+				/* eliminate duplicates */
+				if ((stype == SRC_INC) && (s->stype == SRC_FILE))
+					fatal(_("can't include `%s' and use it as a program file"), src);
+
+				if (do_lint) {
+					int line = sourceline;
+					/* Kludge: the line number may be off for `@include file'.
+					 * Since, this function is also used for '-f file' in main.c,
+					 * sourceline > 1 check ensures that the call is at
+					 * parse time.
+					 */
+					if (sourceline > 1 && lasttok == NEWLINE)
+						line--;
+					lintwarn_ln(line,
+						    stype != SRC_EXTLIB
+						      ? _("already included source file `%s'")
+						      : _("already loaded shared library `%s'"),
+						    src);
+				}
+				efree(path);
+				if (already_included)
+					*already_included = true;
+				return NULL;
+			} else {
+				/* duplicates are allowed for -f */
+				if (s->stype == SRC_INC)
+					fatal(_("can't include `%s' and use it as a program file"), src);
+				/* no need to scan for further matches, since
+				 * they must be of homogeneous type */
+				break;
+			}
+		}
+	}
+
+	s = do_add_srcfile(stype, src, path, thisfile);
+	s->sbuf = sbuf;
+	s->mtime = sbuf.st_mtime;
+	return s;
+}
+
+/* include_source --- read program from source included using `@include' */
+
+static bool
+include_source(INSTRUCTION *file, void **srcfile_p)
+{
+	SRCFILE *s;
+	char *src = file->lextok;
+	int errcode;
+	bool already_included;
+
+	*srcfile_p = NULL;
+
+	if (do_traditional || do_posix) {
+		error_ln(file->source_line, _("@include is a gawk extension"));
+		return false;
+	}
+
+	if (strlen(src) == 0) {
+		if (do_lint)
+			lintwarn_ln(file->source_line, _("empty filename after @include"));
+		return true;
+	}
+
+	s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode);
+	if (s == NULL) {
+		if (already_included)
+			return true;
+		error_ln(file->source_line,
+			_("can't open source file `%s' for reading (%s)"),
+			src, errcode ? strerror(errcode) : _("reason unknown"));
+		return false;
+	}
+
+	/* save scanner state for the current sourcefile */
+	sourcefile->srclines = sourceline;
+	sourcefile->lexptr = lexptr;
+	sourcefile->lexend = lexend;
+	sourcefile->lexptr_begin = lexptr_begin;
+	sourcefile->lexeme = lexeme;
+	sourcefile->lasttok = lasttok;
+	sourcefile->namespace = current_namespace;
+
+	/* included file becomes the current source */
+	sourcefile = s;
+	lexptr = NULL;
+	sourceline = 0;
+	source = NULL;
+	lasttok = 0;
+	lexeof = false;
+	eof_warned = false;
+	current_namespace = awk_namespace;
+	*srcfile_p = (void *) s;
+	return true;
+}
+
+/* load_library --- load a shared library */
+
+static bool
+load_library(INSTRUCTION *file, void **srcfile_p)
+{
+	SRCFILE *s;
+	char *src = file->lextok;
+	int errcode;
+	bool already_included;
+
+	*srcfile_p = NULL;
+
+	if (do_traditional || do_posix) {
+		error_ln(file->source_line, _("@load is a gawk extension"));
+		return false;
+	}
+
+
+	if (strlen(src) == 0) {
+		if (do_lint)
+			lintwarn_ln(file->source_line, _("empty filename after @load"));
+		return true;
+	}
+
+	if (do_pretty_print && ! do_profile) {
+		// create a fake one, don't try to open the file
+		s = do_add_srcfile(SRC_EXTLIB, src, src, sourcefile);
+	} else {
+		s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode);
+		if (s == NULL) {
+			if (already_included)
+				return true;
+			error_ln(file->source_line,
+				_("can't open shared library `%s' for reading (%s)"),
+				src, errcode ? strerror(errcode) : _("reason unknown"));
+			return false;
+		}
+
+		load_ext(s->fullpath);
+	}
+
+	*srcfile_p = (void *) s;
+	return true;
+}
+
+/* next_sourcefile --- read program from the next source in srcfiles */
+
+static void
+next_sourcefile()
+{
+	static int (*closefunc)(int fd) = NULL;
+
+	if (closefunc == NULL) {
+		char *cp = getenv("AWKREADFUNC");
+
+		/* If necessary, one day, test value for different functions.  */
+		if (cp == NULL)
+			closefunc = close;
+		else
+			closefunc = one_line_close;
+	}
+
+	/*
+	 * This won't be true if there's an invalid character in
+	 * the source file or source string (e.g., user typo).
+	 * Previous versions of gawk did not core dump in such a
+	 * case.
+	 *
+	 * assert(lexeof == true);
+	 */
+
+	lexeof = false;
+	eof_warned = false;
+	sourcefile->srclines = sourceline;	/* total no of lines in current file */
+	if (sourcefile->fd > INVALID_HANDLE) {
+		if (sourcefile->fd != fileno(stdin))  /* safety */
+			(*closefunc)(sourcefile->fd);
+		sourcefile->fd = INVALID_HANDLE;
+	}
+	if (sourcefile->buf != NULL) {
+		efree(sourcefile->buf);
+		sourcefile->buf = NULL;
+		sourcefile->lexptr_begin = NULL;
+	}
+
+	while ((sourcefile = sourcefile->next) != NULL) {
+		if (sourcefile == srcfiles)
+			return;
+		if (sourcefile->stype != SRC_EXTLIB)
+			break;
+	}
+
+	if (sourcefile->lexptr_begin != NULL) {
+		/* resume reading from already opened file (postponed to process '@include') */
+		lexptr = sourcefile->lexptr;
+		lexend = sourcefile->lexend;
+		lasttok = sourcefile->lasttok;
+		lexptr_begin = sourcefile->lexptr_begin;
+		lexeme = sourcefile->lexeme;
+		sourceline = sourcefile->srclines;
+		source = sourcefile->src;
+		set_current_namespace(sourcefile->namespace);
+	} else {
+		lexptr = NULL;
+		sourceline = 0;
+		source = NULL;
+		lasttok = 0;
+		set_current_namespace(awk_namespace);
+	}
+}
+
+/* get_src_buf --- read the next buffer of source program */
+
+static char *
+get_src_buf()
+{
+	int n;
+	char *scan;
+	bool newfile;
+	int savelen;
+	struct stat sbuf;
+
+	/*
+	 * No argument prototype on readfunc on purpose,
+	 * avoids problems with some ancient systems where
+	 * the types of arguments to read() aren't up to date.
+	 */
+	static ssize_t (*readfunc)() = 0;
+
+	if (readfunc == NULL) {
+		char *cp = getenv("AWKREADFUNC");
+
+		/* If necessary, one day, test value for different functions.  */
+		if (cp == NULL)
+			/*
+			 * cast is to remove warnings on systems with
+			 * different return types for read.
+			 */
+			readfunc = ( ssize_t(*)() ) read;
+		else
+			readfunc = read_one_line;
+	}
+
+	newfile = false;
+	if (sourcefile == srcfiles)
+		return NULL;
+
+	if (sourcefile->stype == SRC_CMDLINE) {
+		if (sourcefile->bufsize == 0) {
+			sourcefile->bufsize = strlen(sourcefile->src);
+			lexptr = lexptr_begin = lexeme = sourcefile->src;
+			lexend = lexptr + sourcefile->bufsize;
+			sourceline = 1;
+			if (sourcefile->bufsize == 0) {
+				/*
+				 * Yet Another Special case:
+				 *	gawk '' /path/name
+				 * Sigh.
+				 */
+				static bool warned = false;
+
+				if (do_lint && ! warned) {
+					warned = true;
+					lintwarn(_("empty program text on command line"));
+				}
+				lexeof = true;
+			}
+		} else if (sourcefile->buf == NULL  && *(lexptr-1) != '\n') {
+			/*
+			 * The following goop is to ensure that the source
+			 * ends with a newline and that the entire current
+			 * line is available for error messages.
+			 */
+			int offset;
+			char *buf;
+
+			offset = lexptr - lexeme;
+			for (scan = lexeme; scan > lexptr_begin; scan--)
+				if (*scan == '\n') {
+					scan++;
+					break;
+				}
+			savelen = lexptr - scan;
+			emalloc(buf, char *, savelen + 1, "get_src_buf");
+			memcpy(buf, scan, savelen);
+			thisline = buf;
+			lexptr = buf + savelen;
+			*lexptr = '\n';
+			lexeme = lexptr - offset;
+			lexptr_begin = buf;
+			lexend = lexptr + 1;
+			sourcefile->buf = buf;
+		} else
+			lexeof = true;
+		return lexptr;
+	}
+
+	if (sourcefile->fd <= INVALID_HANDLE) {
+		int fd;
+		int l;
+
+		source = sourcefile->src;
+		if (source == NULL)
+			return NULL;
+		fd = srcopen(sourcefile);
+		if (fd <= INVALID_HANDLE) {
+			char *in;
+
+			/* suppress file name and line no. in error mesg */
+			in = source;
+			source = NULL;
+			error(_("can't open source file `%s' for reading (%s)"),
+				in, strerror(errno));
+			errcount++;
+			lexeof = true;
+			return sourcefile->src;
+		}
+
+		sourcefile->fd = fd;
+		l = optimal_bufsize(fd, &sbuf);
+		/*
+		 * Make sure that something silly like
+		 * 	AWKBUFSIZE=8 make check
+		 * works ok.
+		 */
+#define A_DECENT_BUFFER_SIZE	128
+		if (l < A_DECENT_BUFFER_SIZE)
+			l = A_DECENT_BUFFER_SIZE;
+#undef A_DECENT_BUFFER_SIZE
+		sourcefile->bufsize = l;
+		newfile = true;
+		emalloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf");
+		lexptr = lexptr_begin = lexeme = sourcefile->buf;
+		savelen = 0;
+		sourceline = 1;
+		thisline = NULL;
+	} else {
+		/*
+		 * Here, we retain the current source line in the beginning of the buffer.
+		 */
+		int offset;
+		for (scan = lexeme; scan > lexptr_begin; scan--)
+			if (*scan == '\n') {
+				scan++;
+				break;
+			}
+
+		savelen = lexptr - scan;
+		offset = lexptr - lexeme;
+
+		if (savelen > 0) {
+			/*
+			 * Need to make sure we have room left for reading new text;
+			 * grow the buffer (by doubling, an arbitrary choice), if the retained line
+			 * takes up more than a certain percentage (50%, again an arbitrary figure)
+			 * of the available space.
+			 */
+
+			if (savelen > sourcefile->bufsize / 2) { /* long line or token  */
+				sourcefile->bufsize *= 2;
+				erealloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf");
+				scan = sourcefile->buf + (scan - lexptr_begin);
+				lexptr_begin = sourcefile->buf;
+			}
+
+			thisline = lexptr_begin;
+			memmove(thisline, scan, savelen);
+			lexptr = thisline + savelen;
+			lexeme = lexptr - offset;
+		} else {
+			savelen = 0;
+			lexptr = lexeme = lexptr_begin;
+			thisline = NULL;
+		}
+	}
+
+	n = (*readfunc)(sourcefile->fd, lexptr, sourcefile->bufsize - savelen);
+	if (n == -1) {
+		error(_("can't read sourcefile `%s' (%s)"),
+				source, strerror(errno));
+		errcount++;
+		lexeof = true;
+	} else {
+		lexend = lexptr + n;
+		if (n == 0) {
+			static bool warned = false;
+			if (do_lint && newfile && ! warned) {
+				warned = true;
+				sourceline = 0;
+				lintwarn(_("source file `%s' is empty"), source);
+			}
+			lexeof = true;
+		}
+	}
+	return sourcefile->buf;
+}
+
+/* tokadd --- add a character to the token buffer */
+
+#define	tokadd(x) (*tok++ = (x), tok == tokend ? tokexpand() : tok)
+
+/* tokexpand --- grow the token buffer */
+
+static char *
+tokexpand()
+{
+	static int toksize;
+	int tokoffset;
+
+	if (tokstart != NULL) {
+		tokoffset = tok - tokstart;
+		toksize *= 2;
+		erealloc(tokstart, char *, toksize, "tokexpand");
+		tok = tokstart + tokoffset;
+	} else {
+		toksize = 60;
+		emalloc(tokstart, char *, toksize, "tokexpand");
+		tok = tokstart;
+	}
+	tokend = tokstart + toksize;
+	return tok;
+}
+
+/* check_bad_char --- fatal if c isn't allowed in gawk source code */
+
+/*
+ * The error message was inspired by someone who decided to put
+ * a physical \0 byte into the source code to see what would
+ * happen and then filed a bug report about it.  Sigh.
+ */
+
+static void
+check_bad_char(int c)
+{
+	/* allow escapes. needed for autoconf. bleah. */
+	switch (c) {
+	case '\a':
+	case '\b':
+	case '\f':
+	case '\n':
+	case '\r':
+	case '\t':
+		return;
+	default:
+		break;
+	}
+
+	if (iscntrl(c) && ! isspace(c))
+		fatal(_("PEBKAC error: invalid character '\\%03o' in source code"), c & 0xFF);
+}
+
+/* nextc --- get the next input character */
+
+// For namespaces, -e chunks must be syntactic units.
+#define NO_CONTINUE_SOURCE_STRINGS	1
+
+static int
+nextc(bool check_for_bad)
+{
+	if (gawk_mb_cur_max > 1) {
+again:
+#ifdef NO_CONTINUE_SOURCE_STRINGS
+		if (lexeof)
+			return END_FILE;
+#else
+		if (lexeof) {
+			if (sourcefile->next == srcfiles)
+				return END_FILE;
+			else
+				next_sourcefile();
+		}
+#endif
+		if (lexptr == NULL || lexptr >= lexend) {
+			if (get_src_buf())
+				goto again;
+			return END_SRC;
+		}
+
+		/* Update the buffer index.  */
+		cur_ring_idx = (cur_ring_idx == RING_BUFFER_SIZE - 1)? 0 :
+			cur_ring_idx + 1;
+
+		/* Did we already check the current character?  */
+		if (cur_char_ring[cur_ring_idx] == 0) {
+			/* No, we need to check the next character on the buffer.  */
+			int idx, work_ring_idx = cur_ring_idx;
+			mbstate_t tmp_state;
+			size_t mbclen;
+
+			for (idx = 0; lexptr + idx < lexend; idx++) {
+				tmp_state = cur_mbstate;
+				mbclen = mbrlen(lexptr, idx + 1, &tmp_state);
+
+				if (mbclen == 1 || mbclen == (size_t)-1 || mbclen == 0) {
+					/* It is a singlebyte character, non-complete multibyte
+					   character or EOF.  We treat it as a singlebyte
+					   character.  */
+					cur_char_ring[work_ring_idx] = 1;
+					break;
+				} else if (mbclen == (size_t)-2) {
+					/* It is not a complete multibyte character.  */
+					cur_char_ring[work_ring_idx] = idx + 1;
+				} else {
+					/* mbclen > 1 */
+					cur_char_ring[work_ring_idx] = mbclen;
+					break;
+				}
+				work_ring_idx = (work_ring_idx == RING_BUFFER_SIZE - 1)?
+					0 : work_ring_idx + 1;
+			}
+			cur_mbstate = tmp_state;
+
+			/* Put a mark on the position on which we write next character.  */
+			work_ring_idx = (work_ring_idx == RING_BUFFER_SIZE - 1)?
+				0 : work_ring_idx + 1;
+			cur_char_ring[work_ring_idx] = 0;
+		}
+		if (check_for_bad || *lexptr == '\0')
+			check_bad_char(*lexptr);
+
+		return (int) (unsigned char) *lexptr++;
+	} else {
+		do {
+#ifdef NO_CONTINUE_SOURCE_STRINGS
+			if (lexeof)
+				return END_FILE;
+#else
+			if (lexeof) {
+				if (sourcefile->next == srcfiles)
+					return END_FILE;
+				else
+					next_sourcefile();
+			}
+#endif
+			if (lexptr && lexptr < lexend) {
+				if (check_for_bad || *lexptr == '\0')
+					check_bad_char(*lexptr);
+				return ((int) (unsigned char) *lexptr++);
+			}
+		} while (get_src_buf());
+		return END_SRC;
+	}
+}
+#undef NO_CONTINUE_SOURCE_STRINGS
+
+/* pushback --- push a character back on the input */
+
+static inline void
+pushback(void)
+{
+	if (gawk_mb_cur_max > 1)
+		cur_ring_idx = (cur_ring_idx == 0)? RING_BUFFER_SIZE - 1 :
+			cur_ring_idx - 1;
+	(! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr);
+}
+
+/*
+ * get_comment --- collect comment text.
+ * 	Flag = EOL_COMMENT for end-of-line comments.
+ * 	Flag = BLOCK_COMMENT for self-contained comments.
+ */
+
+static int
+get_comment(enum commenttype flag, INSTRUCTION **comment_instruction)
+{
+	int c;
+	int sl;
+	char *p1;
+	char *p2;
+
+	tok = tokstart;
+	tokadd('#');
+	sl = sourceline;
+
+	while (true) {
+		while ((c = nextc(false)) != '\n' && c != END_FILE) {
+			/* ignore \r characters */
+			if (c != '\r')
+				tokadd(c);
+		}
+		if (flag == EOL_COMMENT) {
+			/* comment at end of line.  */
+			if (c == '\n')
+				tokadd(c);
+			break;
+		}
+		if (c == '\n') {
+			tokadd(c);
+			sourceline++;
+			do {
+				c = nextc(false);
+				if (c == '\n') {
+					sourceline++;
+					tokadd(c);
+				}
+			} while (isspace(c) && c != END_FILE);
+			if (c == END_FILE)
+				break;
+			else if (c != '#') {
+				pushback();
+				sourceline--;
+				break;
+			} else
+				tokadd(c);
+		} else
+			break;
+	}
+
+	/* remove any trailing blank lines (consecutive \n) from comment */
+	p1 = tok - 1;
+	p2 = tok - 2;
+	while (*p1 == '\n' && *p2 == '\n') {
+		p1--;
+		p2--;
+		tok--;
+	}
+
+	(*comment_instruction) = bcalloc(Op_comment, 1, sl);
+	(*comment_instruction)->source_file = source;
+	(*comment_instruction)->memory = make_str_node(tokstart, tok - tokstart, 0);
+	(*comment_instruction)->memory->comment_type = flag;
+
+	return c;
+}
+
+/* allow_newline --- allow newline after &&, ||, ? and : */
+
+static void
+allow_newline(INSTRUCTION **new_comment)
+{
+	int c;
+
+	for (;;) {
+		c = nextc(true);
+		if (c == END_FILE) {
+			pushback();
+			break;
+		}
+		if (c == '#') {
+			if (do_pretty_print && ! do_profile) {
+				/* collect comment byte code iff doing pretty print but not profiling.  */
+				c = get_comment(EOL_COMMENT, new_comment);
+			} else {
+				while ((c = nextc(false)) != '\n' && c != END_FILE)
+					continue;
+			}
+			if (c == END_FILE) {
+				pushback();
+				break;
+			}
+		}
+		if (c == '\n')
+			sourceline++;
+		if (! isspace(c)) {
+			pushback();
+			break;
+		}
+	}
+}
+
+/* newline_eof --- return newline or EOF as needed and adjust variables */
+
+/*
+ * This routine used to be a macro, however GCC 4.6.2 warned about
+ * the result of a computation not being used.  Converting to a function
+ * removes the warnings.
+ */
+
+static int
+newline_eof()
+{
+	/* NB: a newline at end does not start a source line. */
+	if (lasttok != NEWLINE) {
+                pushback();
+		if (do_lint && ! eof_warned) {
+        		lintwarn(_("source file does not end in newline"));
+			eof_warned = true;
+		}
+		sourceline++;
+		return NEWLINE;
+	}
+
+	sourceline--;
+	eof_warned = false;
+	return LEX_EOF;
+}
+
+/* yylex --- Read the input and turn it into tokens. */
+
+static int
+#ifdef USE_EBCDIC
+yylex_ebcdic(void)
+#else
+yylex(void)
+#endif
+{
+	int c;
+	bool seen_e = false;		/* These are for numbers */
+	bool seen_point = false;
+	bool esc_seen;		/* for literal strings */
+	int mid;
+	int base;
+	static bool did_newline = false;
+	char *tokkey;
+	bool inhex = false;
+	bool intlstr = false;
+	AWKNUM d;
+	bool collecting_typed_regexp = false;
+	static int qm_col_count = 0;
+
+#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
+
+#define NEWLINE_EOF newline_eof()
+
+	yylval = (INSTRUCTION *) NULL;
+	if (lasttok == SUBSCRIPT) {
+		lasttok = 0;
+		return SUBSCRIPT;
+	}
+
+	if (lasttok == LEX_EOF)		/* error earlier in current source, must give up !! */
+		return 0;
+
+	c = nextc(! want_regexp);
+	if (c == END_SRC)
+		return 0;
+	if (c == END_FILE)
+		return lasttok = NEWLINE_EOF;
+	pushback();
+
+#if defined __EMX__
+	/*
+	 * added for OS/2's extproc feature of cmd.exe
+	 * (like #! in BSD sh)
+	 */
+	if (strncasecmp(lexptr, "extproc ", 8) == 0) {
+		while (*lexptr && *lexptr != '\n')
+			lexptr++;
+	}
+#endif
+
+	lexeme = lexptr;
+	thisline = NULL;
+
+collect_regexp:
+	if (want_regexp) {
+		int in_brack = 0;	/* count brackets, [[:alnum:]] allowed */
+		int b_index = -1;
+		int cur_index = 0;
+
+		/*
+		 * Here is what's ok with brackets:
+		 *
+		 * [..[..] []] [^]] [.../...]
+		 * [...\[...] [...\]...] [...\/...]
+		 *
+		 * (Remember that all of the above are inside /.../)
+		 *
+		 * The code for \ handles \[, \] and \/.
+		 *
+		 * Otherwise, track the first open [ position, and if
+		 * an embedded ] occurs, allow it to pass through
+		 * if it's right after the first [ or after [^.
+		 *
+		 * Whew!
+		 */
+
+		want_regexp = false;
+		tok = tokstart;
+		for (;;) {
+			c = nextc(false);
+
+			cur_index = tok - tokstart;
+			if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) switch (c) {
+			case '[':
+				if (nextc(false) == ':' || in_brack == 0) {
+					in_brack++;
+					if (in_brack == 1)
+						b_index = tok - tokstart;
+				}
+				pushback();
+				break;
+			case ']':
+				if (in_brack > 0
+				    && (cur_index == b_index + 1
+					|| (cur_index == b_index + 2 && tok[-1] == '^')))
+					; /* do nothing */
+				else {
+					in_brack--;
+					if (in_brack == 0)
+						b_index = -1;
+				}
+				break;
+			case '\\':
+				if ((c = nextc(false)) == END_FILE) {
+					pushback();
+					yyerror(_("unterminated regexp ends with `\\' at end of file"));
+					goto end_regexp; /* kludge */
+				}
+				if (c == '\r')	/* allow MS-DOS files. bleah */
+					c = nextc(true);
+				if (c == '\n') {
+					sourceline++;
+					continue;
+				} else {
+					tokadd('\\');
+					tokadd(c);
+					continue;
+				}
+				break;
+			case '/':	/* end of the regexp */
+				if (in_brack > 0)
+					break;
+end_regexp:
+				yylval = GET_INSTRUCTION(Op_token);
+				yylval->lextok = estrdup(tokstart, tok - tokstart);
+				if (do_lint) {
+					int peek = nextc(true);
+
+					pushback();
+					if (peek == 'i' || peek == 's') {
+						if (source)
+							lintwarn(
+						_("%s: %d: tawk regex modifier `/.../%c' doesn't work in gawk"),
+								source, sourceline, peek);
+						else
+							lintwarn(
+						_("tawk regex modifier `/.../%c' doesn't work in gawk"),
+								peek);
+					}
+				}
+				if (collecting_typed_regexp) {
+					collecting_typed_regexp = false;
+					lasttok = TYPED_REGEXP;
+				} else
+					lasttok = REGEXP;
+
+				return lasttok;
+			case '\n':
+				pushback();
+				yyerror(_("unterminated regexp"));
+				goto end_regexp;	/* kludge */
+			case END_FILE:
+				pushback();
+				yyerror(_("unterminated regexp at end of file"));
+				goto end_regexp;	/* kludge */
+			}
+			tokadd(c);
+		}
+	}
+retry:
+
+	/* skipping \r is a hack, but windows is just too pervasive. sigh. */
+	while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r')
+		continue;
+
+	lexeme = lexptr ? lexptr - 1 : lexptr;
+	thisline = NULL;
+	tok = tokstart;
+
+	if (gawk_mb_cur_max == 1 || nextc_is_1stbyte)
+	switch (c) {
+	case END_SRC:
+		return 0;
+
+	case END_FILE:
+		return lasttok = NEWLINE_EOF;
+
+	case '\n':
+		sourceline++;
+		return lasttok = NEWLINE;
+
+	case '#':		/* it's a comment */
+		yylval = NULL;
+		if (do_pretty_print && ! do_profile) {
+			/*
+			 * Collect comment byte code iff doing pretty print
+			 * but not profiling.
+			 */
+			INSTRUCTION *new_comment;
+
+			if (lasttok == NEWLINE || lasttok == 0)
+				c = get_comment(BLOCK_COMMENT, & new_comment);
+			else
+				c = get_comment(EOL_COMMENT, & new_comment);
+
+			yylval = new_comment;
+
+			if (c == END_FILE) {
+				pushback();
+				return lasttok = NEWLINE;
+			}
+		} else {
+			while ((c = nextc(false)) != '\n') {
+				if (c == END_FILE)
+					return lasttok = NEWLINE_EOF;
+			}
+		}
+		sourceline++;
+		return lasttok = NEWLINE;
+
+	case '@':
+		c = nextc(true);
+		if (c == '/') {
+			want_regexp = true;
+			collecting_typed_regexp = true;
+			goto collect_regexp;
+		}
+		pushback();
+		at_seen = true;
+		return lasttok = '@';
+
+	case '\\':
+#ifdef RELAXED_CONTINUATION
+		/*
+		 * This code purports to allow comments and/or whitespace
+		 * after the `\' at the end of a line used for continuation.
+		 * Use it at your own risk. We think it's a bad idea, which
+		 * is why it's not on by default.
+		 */
+		yylval = NULL;
+		if (! do_traditional) {
+			INSTRUCTION *new_comment;
+
+			/* strip trailing white-space and/or comment */
+			while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r')
+				continue;
+			if (c == '#') {
+				static bool warned = false;
+
+				if (do_lint && ! warned) {
+					warned = true;
+					lintwarn(
+		_("use of `\\ #...' line continuation is not portable"));
+				}
+				if (do_pretty_print && ! do_profile) {
+					c = get_comment(EOL_COMMENT, & new_comment);
+					yylval = new_comment;
+					return lasttok = c;
+				} else {
+					while ((c = nextc(false)) != '\n')
+						if (c == END_FILE)
+							break;
+				}
+			}
+			pushback();
+		}
+#endif /* RELAXED_CONTINUATION */
+		c = nextc(true);
+		if (c == '\r')	/* allow MS-DOS files. bleah */
+			c = nextc(true);
+		if (c == '\n') {
+			sourceline++;
+			goto retry;
+		} else {
+			yyerror(_("backslash not last character on line"));
+			return lasttok = LEX_EOF;
+		}
+		break;
+
+	case '?':
+		qm_col_count++;
+		// fall through
+	case ':':
+		yylval = GET_INSTRUCTION(Op_cond_exp);
+		if (qm_col_count > 0) {
+			if (! do_posix) {
+				INSTRUCTION *new_comment = NULL;
+				allow_newline(& new_comment);
+				yylval->comment = new_comment;
+			}
+			if (c == ':')
+				qm_col_count--;
+		}
+		return lasttok = c;
+
+		/*
+		 * in_parens is undefined unless we are parsing a print
+		 * statement (in_print), but why bother with a check?
+		 */
+	case ')':
+		in_parens--;
+		return lasttok = c;
+
+	case '(':
+		in_parens++;
+		return lasttok = c;
+	case '$':
+		yylval = GET_INSTRUCTION(Op_field_spec);
+		return lasttok = c;
+	case '{':
+		if (++in_braces == 1)
+			firstline = sourceline;
+	case ';':
+	case ',':
+	case '[':
+			return lasttok = c;
+	case ']':
+		c = nextc(true);
+		pushback();
+		if (c == '[') {
+			if (do_traditional)
+				fatal(_("multidimensional arrays are a gawk extension"));
+			if (do_lint)
+				lintwarn(_("multidimensional arrays are a gawk extension"));
+			yylval = GET_INSTRUCTION(Op_sub_array);
+			lasttok = ']';
+		} else {
+			yylval = GET_INSTRUCTION(Op_subscript);
+			lasttok = SUBSCRIPT;	/* end of subscripts */
+		}
+		return ']';
+
+	case '*':
+		if ((c = nextc(true)) == '=') {
+			yylval = GET_INSTRUCTION(Op_assign_times);
+			return lasttok = ASSIGNOP;
+		} else if (do_posix) {
+			pushback();
+			yylval = GET_INSTRUCTION(Op_times);
+			return lasttok = '*';
+		} else if (c == '*') {
+			/* make ** and **= aliases for ^ and ^= */
+			static bool did_warn_op = false, did_warn_assgn = false;
+
+			if (nextc(true) == '=') {
+				if (! did_warn_assgn) {
+					did_warn_assgn = true;
+					if (do_lint)
+						lintwarn(_("POSIX does not allow operator `**='"));
+					if (do_lint_old)
+						warning(_("old awk does not support operator `**='"));
+				}
+				yylval = GET_INSTRUCTION(Op_assign_exp);
+				return ASSIGNOP;
+			} else {
+				pushback();
+				if (! did_warn_op) {
+					did_warn_op = true;
+					if (do_lint)
+						lintwarn(_("POSIX does not allow operator `**'"));
+					if (do_lint_old)
+						warning(_("old awk does not support operator `**'"));
+				}
+				yylval = GET_INSTRUCTION(Op_exp);
+				return lasttok = '^';
+			}
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_times);
+		return lasttok = '*';
+
+	case '/':
+		if (nextc(false) == '=') {
+			pushback();
+			return lasttok = SLASH_BEFORE_EQUAL;
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_quotient);
+		return lasttok = '/';
+
+	case '%':
+		if (nextc(true) == '=') {
+			yylval = GET_INSTRUCTION(Op_assign_mod);
+			return lasttok = ASSIGNOP;
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_mod);
+		return lasttok = '%';
+
+	case '^':
+	{
+		static bool did_warn_op = false, did_warn_assgn = false;
+
+		if (nextc(true) == '=') {
+			if (do_lint_old && ! did_warn_assgn) {
+				did_warn_assgn = true;
+				warning(_("operator `^=' is not supported in old awk"));
+			}
+			yylval = GET_INSTRUCTION(Op_assign_exp);
+			return lasttok = ASSIGNOP;
+		}
+		pushback();
+		if (do_lint_old && ! did_warn_op) {
+			did_warn_op = true;
+			warning(_("operator `^' is not supported in old awk"));
+		}
+		yylval = GET_INSTRUCTION(Op_exp);
+		return lasttok = '^';
+	}
+
+	case '+':
+		if ((c = nextc(true)) == '=') {
+			yylval = GET_INSTRUCTION(Op_assign_plus);
+			return lasttok = ASSIGNOP;
+		}
+		if (c == '+') {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			return lasttok = INCREMENT;
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_plus);
+		return lasttok = '+';
+
+	case '!':
+		if ((c = nextc(true)) == '=') {
+			yylval = GET_INSTRUCTION(Op_notequal);
+			return lasttok = RELOP;
+		}
+		if (c == '~') {
+			yylval = GET_INSTRUCTION(Op_nomatch);
+			return lasttok = MATCHOP;
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_symbol);
+		return lasttok = '!';
+
+	case '<':
+		if (nextc(true) == '=') {
+			yylval = GET_INSTRUCTION(Op_leq);
+			return lasttok = RELOP;
+		}
+		yylval = GET_INSTRUCTION(Op_less);
+		pushback();
+		return lasttok = '<';
+
+	case '=':
+		if (nextc(true) == '=') {
+			yylval = GET_INSTRUCTION(Op_equal);
+			return lasttok = RELOP;
+		}
+		yylval = GET_INSTRUCTION(Op_assign);
+		pushback();
+		return lasttok = ASSIGN;
+
+	case '>':
+		if ((c = nextc(true)) == '=') {
+			yylval = GET_INSTRUCTION(Op_geq);
+			return lasttok = RELOP;
+		} else if (c == '>') {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			yylval->redir_type = redirect_append;
+			return lasttok = IO_OUT;
+		}
+		pushback();
+		if (in_print && in_parens == 0) {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			yylval->redir_type = redirect_output;
+			return lasttok = IO_OUT;
+		}
+		yylval = GET_INSTRUCTION(Op_greater);
+		return lasttok = '>';
+
+	case '~':
+		yylval = GET_INSTRUCTION(Op_match);
+		return lasttok = MATCHOP;
+
+	case '}':
+		/*
+		 * Added did newline stuff.  Easier than
+		 * hacking the grammar.
+		 */
+		if (did_newline) {
+			did_newline = false;
+			if (--in_braces == 0)
+				lastline = sourceline;
+			return lasttok = c;
+		}
+		did_newline = true;
+		--lexptr;	/* pick up } next time */
+		return lasttok = NEWLINE;
+
+	case '"':
+	string:
+		esc_seen = false;
+		/*
+		 * Allow any kind of junk in quoted string,
+		 * so pass false to nextc().
+		 */
+		while ((c = nextc(false)) != '"') {
+			if (c == '\n') {
+				pushback();
+				yyerror(_("unterminated string"));
+				return lasttok = LEX_EOF;
+			}
+			if ((gawk_mb_cur_max == 1 || nextc_is_1stbyte) &&
+			    c == '\\') {
+				c = nextc(true);
+				if (c == '\r')	/* allow MS-DOS files. bleah */
+					c = nextc(true);
+				if (c == '\n') {
+					if (do_posix)
+						fatal(_("POSIX does not allow physical newlines in string values"));
+					else if (do_lint)
+						lintwarn(_("backslash string continuation is not portable"));
+					sourceline++;
+					continue;
+				}
+				esc_seen = true;
+				if (! want_source || c != '"')
+					tokadd('\\');
+			}
+			if (c == END_FILE) {
+				pushback();
+				yyerror(_("unterminated string"));
+				return lasttok = LEX_EOF;
+			}
+			tokadd(c);
+		}
+		yylval = GET_INSTRUCTION(Op_token);
+		if (want_source) {
+			yylval->lextok = estrdup(tokstart, tok - tokstart);
+			return lasttok = FILENAME;
+		}
+
+		yylval->opcode = Op_push_i;
+		yylval->memory = make_str_node(tokstart,
+					tok - tokstart, esc_seen ? SCAN : 0);
+		if (intlstr) {
+			yylval->memory->flags |= INTLSTR;
+			intlstr = false;
+			if (do_intl)
+				dumpintlstr(yylval->memory->stptr, yylval->memory->stlen);
+		}
+		return lasttok = YSTRING;
+
+	case '-':
+		if ((c = nextc(true)) == '=') {
+			yylval = GET_INSTRUCTION(Op_assign_minus);
+			return lasttok = ASSIGNOP;
+		}
+		if (c == '-') {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			return lasttok = DECREMENT;
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_minus);
+		return lasttok = '-';
+
+	case '.':
+		c = nextc(true);
+		pushback();
+		if (! isdigit(c))
+			return lasttok = '.';
+		else
+			c = '.';
+		/* FALL THROUGH */
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+		/* It's a number */
+		for (;;) {
+			bool gotnumber = false;
+
+			tokadd(c);
+			switch (c) {
+			case 'x':
+			case 'X':
+				if (do_traditional)
+					goto done;
+				if (tok == tokstart + 2) {
+					int peek = nextc(true);
+
+					if (isxdigit(peek)) {
+						inhex = true;
+						pushback();	/* following digit */
+					} else {
+						pushback();	/* x or X */
+						goto done;
+					}
+				}
+				break;
+			case '.':
+				/* period ends exponent part of floating point number */
+				if (seen_point || seen_e) {
+					gotnumber = true;
+					break;
+				}
+				seen_point = true;
+				break;
+			case 'e':
+			case 'E':
+				if (inhex)
+					break;
+				if (seen_e) {
+					gotnumber = true;
+					break;
+				}
+				seen_e = true;
+				if ((c = nextc(true)) == '-' || c == '+') {
+					int c2 = nextc(true);
+
+					if (isdigit(c2)) {
+						tokadd(c);
+						tokadd(c2);
+					} else {
+						pushback();	/* non-digit after + or - */
+						pushback();	/* + or - */
+						pushback();	/* e or E */
+					}
+				} else if (! isdigit(c)) {
+					pushback();	/* character after e or E */
+					pushback();	/* e or E */
+				} else {
+					pushback();	/* digit */
+				}
+				break;
+			case 'a':
+			case 'A':
+			case 'b':
+			case 'B':
+			case 'c':
+			case 'C':
+			case 'D':
+			case 'd':
+			case 'f':
+			case 'F':
+				if (do_traditional || ! inhex)
+					goto done;
+				/* fall through */
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				break;
+			default:
+			done:
+				gotnumber = true;
+			}
+			if (gotnumber)
+				break;
+			c = nextc(true);
+		}
+		pushback();
+
+		tokadd('\0');
+		yylval = GET_INSTRUCTION(Op_push_i);
+
+		base = 10;
+		if (! do_traditional) {
+			base = get_numbase(tokstart, strlen(tokstart)-1, false);
+			if (do_lint) {
+				if (base == 8)
+					lintwarn("numeric constant `%.*s' treated as octal",
+						(int) strlen(tokstart)-1, tokstart);
+				else if (base == 16)
+					lintwarn("numeric constant `%.*s' treated as hexadecimal",
+						(int) strlen(tokstart)-1, tokstart);
+			}
+		}
+
+#ifdef HAVE_MPFR
+		if (do_mpfr) {
+			NODE *r;
+
+			if (! seen_point && ! seen_e) {
+				r = mpg_integer();
+				mpg_strtoui(r->mpg_i, tokstart, strlen(tokstart), NULL, base);
+				errno = 0;
+			} else {
+				int tval;
+				r = mpg_float();
+				tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base, ROUND_MODE);
+				errno = 0;
+				IEEE_FMT(r->mpg_numbr, tval);
+			}
+			yylval->memory = set_profile_text(r, tokstart, strlen(tokstart)-1);
+			return lasttok = YNUMBER;
+		}
+#endif
+		if (base != 10)
+			d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL);
+		else
+			d = atof(tokstart);
+		yylval->memory = set_profile_text(make_number(d), tokstart, strlen(tokstart) - 1);
+		if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+			yylval->memory->flags |= NUMINT;
+		return lasttok = YNUMBER;
+
+	case '&':
+		if ((c = nextc(true)) == '&') {
+			yylval = GET_INSTRUCTION(Op_and);
+			INSTRUCTION *new_comment = NULL;
+			allow_newline(& new_comment);
+			yylval->comment = new_comment;
+
+			return lasttok = LEX_AND;
+		}
+		pushback();
+		yylval = GET_INSTRUCTION(Op_symbol);
+		return lasttok = '&';
+
+	case '|':
+		if ((c = nextc(true)) == '|') {
+			yylval = GET_INSTRUCTION(Op_or);
+			INSTRUCTION *new_comment = NULL;
+			allow_newline(& new_comment);
+			yylval->comment = new_comment;
+
+			return lasttok = LEX_OR;
+		} else if (! do_traditional && c == '&') {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			yylval->redir_type = redirect_twoway;
+
+			return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN);
+		}
+		pushback();
+		if (in_print && in_parens == 0) {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			yylval->redir_type = redirect_pipe;
+			return lasttok = IO_OUT;
+		} else {
+			yylval = GET_INSTRUCTION(Op_symbol);
+			yylval->redir_type = redirect_pipein;
+			return lasttok = IO_IN;
+		}
+	}
+
+	if (! is_letter(c)) {
+		yyerror(_("invalid char '%c' in expression"), c);
+		return lasttok = LEX_EOF;
+	}
+
+	/*
+	 * Lots of fog here.  Consider:
+	 *
+	 * print "xyzzy"$_"foo"
+	 *
+	 * Without the check for ` lasttok != '$' ', this is parsed as
+	 *
+	 * print "xxyzz" $(_"foo")
+	 *
+	 * With the check, it is "correctly" parsed as three
+	 * string concatenations.  Sigh.  This seems to be
+	 * "more correct", but this is definitely one of those
+	 * occasions where the interactions are funny.
+	 */
+	if (! do_traditional && c == '_' && lasttok != '$') {
+		if ((c = nextc(true)) == '"') {
+			intlstr = true;
+			goto string;
+		}
+		pushback();
+		c = '_';
+	}
+
+	/* it's some type of name-type-thing.  Find its length. */
+	tok = tokstart;
+	while (c != END_FILE && is_identchar(c)) {
+		tokadd(c);
+		c = nextc(true);
+
+		if (! do_traditional && c == ':') {
+			int peek = nextc(true);
+
+			if (peek == ':') {	// saw identifier::
+				tokadd(c);
+				tokadd(c);
+				c = nextc(true);
+			} else
+				pushback();
+				// then continue around the loop, c == ':'
+		}
+	}
+	tokadd('\0');
+	pushback();
+
+	(void) validate_qualified_name(tokstart);
+
+	/* See if it is a special token. */
+	if ((mid = check_qualified_special(tokstart)) >= 0) {
+		static int warntab[sizeof(tokentab) / sizeof(tokentab[0])];
+		int class = tokentab[mid].class;
+
+		switch (class) {
+		case LEX_EVAL:
+		case LEX_INCLUDE:
+		case LEX_LOAD:
+		case LEX_NAMESPACE:
+			if (lasttok != '@')
+				goto out;
+		default:
+			break;
+		}
+
+		/* allow parameter names to shadow the names of gawk extension built-ins */
+		if ((tokentab[mid].flags & GAWKX) != 0) {
+			NODE *f;
+
+			switch (want_param_names) {
+			case FUNC_HEADER:
+				/* in header, defining parameter names */
+				goto out;
+			case FUNC_BODY:
+				/* in body, name must be in symbol table for it to be a parameter */
+				if ((f = lookup(tokstart)) != NULL) {
+					if (f->type == Node_builtin_func)
+						break;
+					else
+						goto out;
+				}
+				/* else
+					fall through */
+			case DONT_CHECK:
+				/* regular code */
+				break;
+			default:
+				cant_happen();
+				break;
+			}
+		}
+
+		if (do_lint) {
+			if (do_lint_extensions && (tokentab[mid].flags & GAWKX) != 0 && (warntab[mid] & GAWKX) == 0) {
+				lintwarn(_("`%s' is a gawk extension"),
+					tokentab[mid].operator);
+				warntab[mid] |= GAWKX;
+			}
+			if ((tokentab[mid].flags & NOT_POSIX) != 0 && (warntab[mid] & NOT_POSIX) == 0) {
+				lintwarn(_("POSIX does not allow `%s'"),
+					tokentab[mid].operator);
+				warntab[mid] |= NOT_POSIX;
+			}
+		}
+		if (do_lint_old && (tokentab[mid].flags & NOT_OLD) != 0
+				 && (warntab[mid] & NOT_OLD) == 0
+		) {
+			warning(_("`%s' is not supported in old awk"),
+					tokentab[mid].operator);
+			warntab[mid] |= NOT_OLD;
+		}
+
+		if ((tokentab[mid].flags & BREAK) != 0)
+			break_allowed++;
+		if ((tokentab[mid].flags & CONTINUE) != 0)
+			continue_allowed++;
+
+		switch (class) {
+		case LEX_NAMESPACE:
+		case LEX_INCLUDE:
+		case LEX_LOAD:
+			want_source = true;
+			break;
+		case LEX_EVAL:
+			if (in_main_context())
+				goto out;
+			emalloc(tokkey, char *, tok - tokstart + 1, "yylex");
+			tokkey[0] = '@';
+			memcpy(tokkey + 1, tokstart, tok - tokstart);
+			yylval = GET_INSTRUCTION(Op_token);
+			yylval->lextok = tokkey;
+			break;
+
+		case LEX_FUNCTION:
+		case LEX_BEGIN:
+		case LEX_END:
+		case LEX_BEGINFILE:
+		case LEX_ENDFILE:
+			yylval = bcalloc(tokentab[mid].value, 4, sourceline);
+			break;
+
+		case LEX_FOR:
+		case LEX_WHILE:
+		case LEX_DO:
+		case LEX_SWITCH:
+			if (! do_pretty_print)
+				return lasttok = class;
+			/* fall through */
+		case LEX_CASE:
+			yylval = bcalloc(tokentab[mid].value, 2, sourceline);
+			break;
+
+		/*
+		 * These must be checked here, due to the LALR nature of the parser,
+		 * the rules for continue and break may not be reduced until after
+		 * a token that increments the xxx_allowed varibles is seen. Bleah.
+		 */
+		case LEX_CONTINUE:
+			if (! continue_allowed) {
+				error_ln(sourceline,
+					_("`continue' is not allowed outside a loop"));
+				errcount++;
+			}
+			goto make_instruction;
+
+		case LEX_BREAK:
+			if (! break_allowed) {
+				error_ln(sourceline,
+					_("`break' is not allowed outside a loop or switch"));
+				errcount++;
+			}
+			goto make_instruction;
+
+		default:
+make_instruction:
+			yylval = GET_INSTRUCTION(tokentab[mid].value);
+			if (class == LEX_BUILTIN || class == LEX_LENGTH)
+				yylval->builtin_idx = mid;
+			break;
+		}
+		return lasttok = class;
+	}
+out:
+	if (want_param_names == FUNC_HEADER)
+		tokkey = estrdup(tokstart, tok - tokstart - 1);
+	else
+		tokkey = qualify_name(tokstart, tok - tokstart - 1);
+
+	if (*lexptr == '(') {
+		yylval = bcalloc(Op_token, 2, sourceline);
+		yylval->lextok = tokkey;
+		return lasttok = FUNC_CALL;
+	} else {
+		static bool goto_warned = false;
+
+		yylval = GET_INSTRUCTION(Op_token);
+		yylval->lextok = tokkey;
+
+#define SMART_ALECK	1
+		if (SMART_ALECK
+		    && do_lint
+		    && ! goto_warned
+		    && tolower(tokkey[0]) == 'g'
+		    && strcasecmp(tokkey, "goto") == 0) {
+			goto_warned = true;
+			lintwarn(_("`goto' considered harmful!"));
+		}
+		return lasttok = NAME;
+	}
+
+#undef GET_INSTRUCTION
+#undef NEWLINE_EOF
+}
+
+/* It's EBCDIC in a Bison grammar, run for the hills!
+
+   Or, convert single-character tokens coming out of yylex() from EBCDIC to
+   ASCII values on-the-fly so that the parse tables need not be regenerated
+   for EBCDIC systems.  */
+#ifdef USE_EBCDIC
+static int
+yylex(void)
+{
+	static char etoa_xlate[256];
+	static bool do_etoa_init = true;
+	int tok;
+
+	if (do_etoa_init)
+	{
+		for (tok = 0; tok < 256; tok++)
+			etoa_xlate[tok] = (char) tok;
+#ifdef HAVE___ETOA_L
+		/* IBM helpfully provides this function.  */
+		__etoa_l(etoa_xlate, sizeof(etoa_xlate));
+#else
+# error "An EBCDIC-to-ASCII translation function is needed for this system"
+#endif
+		do_etoa_init = false;
+	}
+
+	tok = yylex_ebcdic();
+
+	if (tok >= 0 && tok <= 0xFF)
+		tok = etoa_xlate[tok];
+
+	return tok;
+}
+#endif /* USE_EBCDIC */
+
+/* snode --- instructions for builtin functions. Checks for arg. count
+             and supplies defaults where possible. */
+
+static INSTRUCTION *
+snode(INSTRUCTION *subn, INSTRUCTION *r)
+{
+	INSTRUCTION *arg;
+	INSTRUCTION *ip;
+	NODE *n;
+	int nexp = 0;
+	int args_allowed;
+	int idx = r->builtin_idx;
+
+	if (subn != NULL) {
+		INSTRUCTION *tp;
+		for (tp = subn->nexti; tp; tp = tp->nexti) {
+			tp = tp->lasti;
+			nexp++;
+		}
+		assert(nexp > 0);
+	}
+
+	/* check against how many args. are allowed for this builtin */
+	args_allowed = tokentab[idx].flags & ARGS;
+	if (args_allowed && (args_allowed & A(nexp)) == 0) {
+		yyerror(_("%d is invalid as number of arguments for %s"),
+				nexp, tokentab[idx].operator);
+		return NULL;
+	}
+
+	/* special processing for sub, gsub and gensub */
+
+	if (tokentab[idx].value == Op_sub_builtin) {
+		const char *operator = tokentab[idx].operator;
+
+		r->sub_flags = 0;
+
+		arg = subn->nexti;		/* first arg list */
+		(void) mk_rexp(arg);
+
+		if (strcmp(operator, "gensub") != 0) {
+			/* sub and gsub */
+
+			if (strcmp(operator, "gsub") == 0)
+				r->sub_flags |= GSUB;
+
+			arg = arg->lasti->nexti;	/* 2nd arg list */
+			if (nexp == 2) {
+				INSTRUCTION *expr;
+
+				expr = list_create(instruction(Op_push_i));
+				expr->nexti->memory = set_profile_text(make_number(0.0), "0", 1);
+				(void) mk_expression_list(subn,
+						list_append(expr, instruction(Op_field_spec)));
+			}
+
+			arg = arg->lasti->nexti; 	/* third arg list */
+			ip = arg->lasti;
+			if (ip->opcode == Op_push_i) {
+				if (do_lint)
+					lintwarn(_("%s: string literal as last arg of substitute has no effect"),
+						operator);
+				r->sub_flags |=	LITERAL;
+			} else {
+				if (make_assignable(ip) == NULL)
+					yyerror(_("%s third parameter is not a changeable object"),
+						operator);
+				else
+					ip->do_reference = true;
+			}
+
+			r->expr_count = count_expressions(&subn, false);
+			ip = subn->lasti;
+
+			(void) list_append(subn, r);
+
+			/* add after_assign code */
+			if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) {
+				(void) list_append(subn, instruction(Op_var_assign));
+				subn->lasti->assign_ctxt = Op_sub_builtin;
+				subn->lasti->assign_var = ip->memory->var_assign;
+			} else if (ip->opcode == Op_field_spec_lhs) {
+				(void) list_append(subn, instruction(Op_field_assign));
+				subn->lasti->assign_ctxt = Op_sub_builtin;
+				subn->lasti->field_assign = (Func_ptr) 0;
+				ip->target_assign = subn->lasti;
+			} else if (ip->opcode == Op_subscript_lhs) {
+				(void) list_append(subn, instruction(Op_subscript_assign));
+				subn->lasti->assign_ctxt = Op_sub_builtin;
+			}
+
+			return subn;
+
+		} else {
+			/* gensub */
+
+			r->sub_flags |= GENSUB;
+			if (nexp == 3) {
+				ip = instruction(Op_push_i);
+				ip->memory = set_profile_text(make_number(0.0), "0", 1);
+				(void) mk_expression_list(subn,
+						list_append(list_create(ip), instruction(Op_field_spec)));
+			}
+
+			r->expr_count = count_expressions(&subn, false);
+			return list_append(subn, r);
+		}
+	}
+
+#ifdef HAVE_MPFR
+	/* N.B.: If necessary, add special processing for alternate builtin, below */
+	if (do_mpfr && tokentab[idx].ptr2)
+		r->builtin =  tokentab[idx].ptr2;
+	else
+#endif
+		r->builtin = tokentab[idx].ptr;
+
+	/* special case processing for a few builtins */
+
+	if (r->builtin == do_length) {
+		if (nexp == 0) {
+		    /* no args. Use $0 */
+
+			INSTRUCTION *list;
+			r->expr_count = 1;
+			list = list_create(r);
+			(void) list_prepend(list, instruction(Op_field_spec));
+			(void) list_prepend(list, instruction(Op_push_i));
+			list->nexti->memory = set_profile_text(make_number(0.0), "0", 1);
+			return list;
+		} else {
+			arg = subn->nexti;
+			if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
+				arg->nexti->opcode = Op_push_arg;	/* argument may be array */
+ 		}
+	} else if (r->builtin == do_isarray) {
+		arg = subn->nexti;
+		if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
+			arg->nexti->opcode = Op_push_arg_untyped;	/* argument may be untyped */
+	} else if (r->builtin == do_typeof) {
+		arg = subn->nexti;
+		if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
+			arg->nexti->opcode = Op_push_arg_untyped;	/* argument may be untyped */
+		if (nexp == 2) {	/* 2nd argument there */
+			arg = subn->nexti->lasti->nexti;	/* 2nd arg list */
+			ip = arg->lasti;
+			if (ip->opcode == Op_push)
+				ip->opcode = Op_push_array;
+		}
+#ifdef SUPPLY_INTDIV
+	} else if (r->builtin == do_intdiv
+#ifdef HAVE_MPFR
+		   || r->builtin == MPF(intdiv)
+#endif
+			) {
+		arg = subn->nexti->lasti->nexti->lasti->nexti;	/* 3rd arg list */
+		ip = arg->lasti;
+		if (ip->opcode == Op_push)
+			ip->opcode = Op_push_array;
+#endif /* SUPPLY_INTDIV */
+	} else if (r->builtin == do_match) {
+		static bool warned = false;
+
+		arg = subn->nexti->lasti->nexti;	/* 2nd arg list */
+		(void) mk_rexp(arg);
+
+		if (nexp == 3) {	/* 3rd argument there */
+			if (do_lint_extensions && ! warned) {
+				warned = true;
+				lintwarn(_("match: third argument is a gawk extension"));
+			}
+			if (do_traditional) {
+				yyerror(_("match: third argument is a gawk extension"));
+				return NULL;
+			}
+
+			arg = arg->lasti->nexti; 	/* third arg list */
+			ip = arg->lasti;
+			if (/*ip == arg->nexti  && */ ip->opcode == Op_push)
+				ip->opcode = Op_push_array;
+		}
+	} else if (r->builtin == do_split) {
+		arg = subn->nexti->lasti->nexti;	/* 2nd arg list */
+		ip = arg->lasti;
+		if (ip->opcode == Op_push)
+			ip->opcode = Op_push_array;
+		if (nexp == 2) {
+			INSTRUCTION *expr;
+			expr = list_create(instruction(Op_push));
+			expr->nexti->memory = FS_node;
+			(void) mk_expression_list(subn, expr);
+		}
+		arg = arg->lasti->nexti;
+		n = mk_rexp(arg);
+		if (nexp == 2)
+			n->re_flags |= FS_DFLT;
+		if (nexp == 4) {
+			arg = arg->lasti->nexti;
+			ip = arg->lasti;
+			if (ip->opcode == Op_push)
+				ip->opcode = Op_push_array;
+		}
+	} else if (r->builtin == do_patsplit) {
+		arg = subn->nexti->lasti->nexti;	/* 2nd arg list */
+		ip = arg->lasti;
+		if (ip->opcode == Op_push)
+			ip->opcode = Op_push_array;
+		if (nexp == 2) {
+			INSTRUCTION *expr;
+			expr = list_create(instruction(Op_push));
+			expr->nexti->memory = FPAT_node;
+			(void) mk_expression_list(subn, expr);
+		}
+		arg = arg->lasti->nexti;
+		n = mk_rexp(arg);
+		if (nexp == 4) {
+			arg = arg->lasti->nexti;
+			ip = arg->lasti;
+			if (ip->opcode == Op_push)
+				ip->opcode = Op_push_array;
+		}
+	} else if (r->builtin == do_close) {
+		static bool warned = false;
+		if (nexp == 2) {
+			if (do_lint_extensions && ! warned) {
+				warned = true;
+				lintwarn(_("close: second argument is a gawk extension"));
+			}
+			if (do_traditional) {
+				yyerror(_("close: second argument is a gawk extension"));
+				return NULL;
+			}
+		}
+	} else if (do_intl					/* --gen-po */
+			&& r->builtin == do_dcgettext		/* dcgettext(...) */
+			&& subn->nexti->lasti->opcode == Op_push_i	/* 1st arg is constant */
+			&& (subn->nexti->lasti->memory->flags & STRING) != 0) {	/* it's a string constant */
+		/* ala xgettext, dcgettext("some string" ...) dumps the string */
+		NODE *str = subn->nexti->lasti->memory;
+
+		if ((str->flags & INTLSTR) != 0)
+			warning(_("use of dcgettext(_\"...\") is incorrect: remove leading underscore"));
+			/* don't dump it, the lexer already did */
+		else
+			dumpintlstr(str->stptr, str->stlen);
+	} else if (do_intl					/* --gen-po */
+			&& r->builtin == do_dcngettext		/* dcngettext(...) */
+			&& subn->nexti->lasti->opcode == Op_push_i	/* 1st arg is constant */
+			&& (subn->nexti->lasti->memory->flags & STRING) != 0	/* it's a string constant */
+			&& subn->nexti->lasti->nexti->lasti->opcode == Op_push_i	/* 2nd arg is constant too */
+			&& (subn->nexti->lasti->nexti->lasti->memory->flags & STRING) != 0) {	/* it's a string constant */
+		/* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */
+		NODE *str1 = subn->nexti->lasti->memory;
+		NODE *str2 = subn->nexti->lasti->nexti->lasti->memory;
+
+		if (((str1->flags | str2->flags) & INTLSTR) != 0)
+			warning(_("use of dcngettext(_\"...\") is incorrect: remove leading underscore"));
+		else
+			dumpintlstr2(str1->stptr, str1->stlen, str2->stptr, str2->stlen);
+	} else if (r->builtin == do_asort || r->builtin == do_asorti) {
+		arg = subn->nexti;	/* 1st arg list */
+		ip = arg->lasti;
+		if (ip->opcode == Op_push)
+			ip->opcode = Op_push_array;
+		if (nexp >= 2) {
+			arg = ip->nexti;
+			ip = arg->lasti;
+			if (ip->opcode == Op_push)
+				ip->opcode = Op_push_array;
+		}
+	}
+	else if (r->builtin == do_index) {
+		arg = subn->nexti->lasti->nexti;	/* 2nd arg list */
+		ip = arg->lasti;
+		if (ip->opcode == Op_match_rec || ip->opcode == Op_push_re)
+			fatal(_("index: regexp constant as second argument is not allowed"));
+	}
+#ifdef ARRAYDEBUG
+	else if (r->builtin == do_adump) {
+		ip = subn->nexti->lasti;
+		if (ip->opcode == Op_push)
+			ip->opcode = Op_push_array;
+	}
+#endif
+
+	if (subn != NULL) {
+		r->expr_count = count_expressions(&subn, false);
+		return list_append(subn, r);
+	}
+
+	r->expr_count = 0;
+	return list_create(r);
+}
+
+
+/* parms_shadow --- check if parameters shadow globals */
+
+static int
+parms_shadow(INSTRUCTION *pc, bool *shadow)
+{
+	int pcount, i;
+	bool ret = false;
+	NODE *func, *fp;
+	char *fname;
+
+	func = pc->func_body;
+	fname = func->vname;
+	fp = func->fparms;
+
+#if 0	/* can't happen, already exited if error ? */
+	if (fname == NULL || func == NULL)	/* error earlier */
+		return false;
+#endif
+
+	pcount = func->param_cnt;
+
+	if (pcount == 0)		/* no args, no problem */
+		return 0;
+
+	source = pc->source_file;
+	sourceline = pc->source_line;
+	/*
+	 * Use warning() and not lintwarn() so that can warn
+	 * about all shadowed parameters.
+	 */
+	for (i = 0; i < pcount; i++) {
+		if (lookup(fp[i].param) != NULL) {
+			warning(
+	_("function `%s': parameter `%s' shadows global variable"),
+					fname, fp[i].param);
+			ret = true;
+		}
+	}
+
+	*shadow |= ret;
+	return 0;
+}
+
+/* valinfo --- dump var info */
+
+void
+valinfo(NODE *n, Func_print print_func, FILE *fp)
+{
+	if (n == Nnull_string)
+		print_func(fp, "uninitialized scalar\n");
+	else if ((n->flags & REGEX) != 0)
+		print_func(fp, "@/%.*s/\n", n->stlen, n->stptr);
+	else if ((n->flags & STRING) != 0) {
+		pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
+		print_func(fp, "\n");
+	} else if ((n->flags & NUMBER) != 0) {
+#ifdef HAVE_MPFR
+		if (is_mpg_float(n))
+			print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
+		else if (is_mpg_integer(n))
+			print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
+		else
+#endif
+		print_func(fp, "%.17g\n", n->numbr);
+	} else
+		print_func(fp, "?? flags %s\n", flags2str(n->flags));
+}
+
+
+/* dump_vars --- dump the symbol table */
+
+void
+dump_vars(const char *fname)
+{
+	FILE *fp;
+	NODE **vars;
+
+	if (fname == NULL)
+		fp = stderr;
+	else if (strcmp(fname, "-") == 0)
+		fp = stdout;
+	else if ((fp = fopen(fname, "w")) == NULL) {
+		warning(_("could not open `%s' for writing (%s)"), fname, strerror(errno));
+		warning(_("sending variable list to standard error"));
+		fp = stderr;
+	}
+
+	vars = variable_list();
+	print_vars(vars, fprintf, fp);
+	efree(vars);
+	if (fp != stdout && fp != stderr && fclose(fp) != 0)
+		warning(_("%s: close failed (%s)"), fname, strerror(errno));
+}
+
+/* dump_funcs --- print all functions */
+
+void
+dump_funcs()
+{
+	NODE **funcs;
+	funcs = function_list(true);
+	(void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, (void *) 0);
+	efree(funcs);
+}
+
+
+/* shadow_funcs --- check all functions for parameters that shadow globals */
+
+void
+shadow_funcs()
+{
+	static int calls = 0;
+	bool shadow = false;
+	NODE **funcs;
+
+	if (calls++ != 0)
+		fatal(_("shadow_funcs() called twice!"));
+
+	funcs = function_list(true);
+	(void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) parms_shadow, & shadow);
+	efree(funcs);
+
+	/* End with fatal if the user requested it.  */
+	if (shadow && lintfunc == r_fatal)
+		lintwarn(_("there were shadowed variables."));
+}
+
+
+/* mk_function --- finalize function definition node; remove parameters
+ *	out of the symbol table.
+ */
+
+static INSTRUCTION *
+mk_function(INSTRUCTION *fi, INSTRUCTION *def)
+{
+	NODE *thisfunc;
+
+	thisfunc = fi->func_body;
+	assert(thisfunc != NULL);
+
+	/* add any pre-function comment to start of action for profile.c  */
+
+	if (interblock_comment != NULL) {
+		interblock_comment->source_line = 0;
+		merge_comments(interblock_comment, fi->comment);
+		fi->comment = interblock_comment;
+		interblock_comment = NULL;
+	}
+
+	/*
+	 * Add an implicit return at end;
+	 * also used by 'return' command in debugger
+	 */
+
+	(void) list_append(def, instruction(Op_push_i));
+	def->lasti->memory = dupnode(Nnull_string);
+	(void) list_append(def, instruction(Op_K_return));
+
+	if (trailing_comment != NULL) {
+		(void) list_append(def, trailing_comment);
+		trailing_comment = NULL;
+	}
+
+	if (do_pretty_print) {
+		fi[3].nexti = namespace_chain;
+		namespace_chain = NULL;
+		(void) list_prepend(def, instruction(Op_exec_count));
+	}
+
+	/* fi->opcode = Op_func */
+	(fi + 1)->firsti = def->nexti;
+	(fi + 1)->lasti = def->lasti;
+	(fi + 2)->first_line = fi->source_line;
+	(fi + 2)->last_line = lastline;
+	fi->nexti = def->nexti;
+	bcfree(def);
+
+	(void) list_append(rule_list, fi + 1);	/* debugging */
+
+	/* update lint table info */
+	func_use(thisfunc->vname, FUNC_DEFINE);
+
+	/* remove params from symbol table */
+	remove_params(thisfunc);
+	return fi;
+}
+
+/*
+ * install_function:
+ * install function name in the symbol table.
+ * Extra work, build up and install a list of the parameter names.
+ */
+
+static int
+install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
+{
+	NODE *r, *f;
+	int pcount = 0;
+
+	r = lookup(fname);
+	if (r != NULL) {
+		error_ln(fi->source_line, _("function name `%s' previously defined"), fname);
+		return -1;
+	}
+
+	if (plist != NULL)
+		pcount = plist->lasti->param_count + 1;
+	f = install_symbol(fname, Node_func);
+	if (f->vname != fname) {
+		// DON'T free fname, it's done later
+		fname = f->vname;
+	}
+
+	fi->func_body = f;
+	f->param_cnt = pcount;
+	f->code_ptr = fi;
+	f->fparms = NULL;
+	if (pcount > 0) {
+		char **pnames;
+		pnames = check_params(fname, pcount, plist);	/* frees plist */
+		f->fparms = make_params(pnames, pcount);
+		efree(pnames);
+		install_params(f);
+	}
+	return 0;
+}
+
+
+/* check_params --- build a list of function parameter names after
+ *	making sure that the names are valid and there are no duplicates.
+ */
+
+static char **
+check_params(char *fname, int pcount, INSTRUCTION *list)
+{
+	INSTRUCTION *p, *np;
+	int i, j;
+	char *name;
+	char **pnames;
+
+	assert(pcount > 0);
+
+	emalloc(pnames, char **, pcount * sizeof(char *), "check_params");
+
+	for (i = 0, p = list->nexti; p != NULL; i++, p = np) {
+		np = p->nexti;
+		name = p->lextok;
+		p->lextok = NULL;
+
+		if (strcmp(name, fname) == 0) {
+			/* check for function foo(foo) { ... }.  bleah. */
+			error_ln(p->source_line,
+				_("function `%s': can't use function name as parameter name"), fname);
+		} else if (is_std_var(name)) {
+			error_ln(p->source_line,
+				_("function `%s': can't use special variable `%s' as a function parameter"),
+					fname, name);
+		} else if (strchr(name, ':') != NULL)
+			error_ln(p->source_line,
+				_("function `%s': parameter `%s' cannot contain a namespace"),
+					fname, name);
+
+		/* check for duplicate parameters */
+		for (j = 0; j < i; j++) {
+			if (strcmp(name, pnames[j]) == 0) {
+				error_ln(p->source_line,
+					_("function `%s': parameter #%d, `%s', duplicates parameter #%d"),
+					fname, i + 1, name, j + 1);
+			}
+		}
+
+		pnames[i] = name;
+		bcfree(p);
+	}
+	bcfree(list);
+
+	return pnames;
+}
+
+
+#ifdef HASHSIZE
+undef HASHSIZE
+#endif
+#define HASHSIZE 1021
+
+static struct fdesc {
+	char *name;
+	short used;
+	short defined;
+	short extension;
+	struct fdesc *next;
+} *ftable[HASHSIZE];
+
+/* func_use --- track uses and definitions of functions */
+
+static void
+func_use(const char *name, enum defref how)
+{
+	struct fdesc *fp;
+	int len;
+	int ind;
+
+	len = strlen(name);
+	ind = hash(name, len, HASHSIZE, NULL);
+
+	for (fp = ftable[ind]; fp != NULL; fp = fp->next)
+		if (strcmp(fp->name, name) == 0)
+			goto update_value;
+
+	/* not in the table, fall through to allocate a new one */
+
+	ezalloc(fp, struct fdesc *, sizeof(struct fdesc), "func_use");
+	emalloc(fp->name, char *, len + 1, "func_use");
+	strcpy(fp->name, name);
+	fp->next = ftable[ind];
+	ftable[ind] = fp;
+
+update_value:
+	if (how == FUNC_DEFINE)
+		fp->defined++;
+	else if (how == FUNC_EXT) {
+		fp->defined++;
+		fp->extension++;
+	} else
+		fp->used++;
+}
+
+/* track_ext_func --- add an extension function to the table */
+
+void
+track_ext_func(const char *name)
+{
+	func_use(name, FUNC_EXT);
+}
+
+/* check_funcs --- verify functions that are called but not defined */
+
+static void
+check_funcs()
+{
+	struct fdesc *fp, *next;
+	int i;
+
+	if (! in_main_context())
+		goto free_mem;
+
+	for (i = 0; i < HASHSIZE; i++) {
+		for (fp = ftable[i]; fp != NULL; fp = fp->next) {
+			if (do_lint && ! fp->extension) {
+				/*
+				 * Making this not a lint check and
+				 * incrementing * errcount breaks old code.
+				 * Sigh.
+				 */
+				if (fp->defined == 0)
+					lintwarn(_("function `%s' called but never defined"),
+						fp->name);
+
+				if (fp->used == 0)
+					lintwarn(_("function `%s' defined but never called directly"),
+						fp->name);
+			}
+		}
+	}
+
+free_mem:
+	/* now let's free all the memory */
+	for (i = 0; i < HASHSIZE; i++) {
+		for (fp = ftable[i]; fp != NULL; fp = next) {
+			next = fp->next;
+			efree(fp->name);
+			efree(fp);
+		}
+		ftable[i] = NULL;
+	}
+}
+
+/* param_sanity --- look for parameters that are regexp constants */
+
+static void
+param_sanity(INSTRUCTION *arglist)
+{
+	INSTRUCTION *argl, *arg;
+	int i = 1;
+
+	if (arglist == NULL)
+		return;
+	for (argl = arglist->nexti; argl; ) {
+		arg = argl->lasti;
+		if (arg->opcode == Op_match_rec)
+			warning_ln(arg->source_line,
+				_("regexp constant for parameter #%d yields boolean value"), i);
+		argl = arg->nexti;
+		i++;
+	}
+}
+
+/* variable --- make sure NAME is in the symbol table */
+
+NODE *
+variable(int location, char *name, NODETYPE type)
+{
+	NODE *r;
+
+	if ((r = lookup(name)) != NULL) {
+		if (r->type == Node_func || r->type == Node_ext_func )
+			error_ln(location, _("function `%s' called with space between name and `(',\nor used as a variable or an array"),
+				r->vname);
+	} else {
+		/* not found */
+		return install_symbol(name, type);
+	}
+	efree(name);
+	return r;
+}
+
+/* make_regnode --- make a regular expression node */
+
+NODE *
+make_regnode(int type, NODE *exp)
+{
+	NODE *n;
+
+	assert(type == Node_regex || type == Node_dynregex);
+	getnode(n);
+	memset(n, 0, sizeof(NODE));
+	n->type = type;
+	n->re_cnt = 1;
+
+	if (type == Node_regex) {
+		n->re_reg[0] = make_regexp(exp->stptr, exp->stlen, false, true, false);
+		if (n->re_reg[0] == NULL) {
+			freenode(n);
+			return NULL;
+		}
+		n->re_reg[1] = make_regexp(exp->stptr, exp->stlen, true, true, false);
+		if (n->re_reg[1] == NULL) {
+			refree(n->re_reg[0]);
+			freenode(n);
+			return NULL;
+		}
+		n->re_exp = exp;
+		n->re_flags = CONSTANT;
+	}
+	return n;
+}
+
+
+/* mk_rexp --- make a regular expression constant */
+
+static NODE *
+mk_rexp(INSTRUCTION *list)
+{
+	INSTRUCTION *ip;
+
+	ip = list->nexti;
+	if (ip == list->lasti && ip->opcode == Op_match_rec)
+		ip->opcode = Op_push_re;
+	else if (ip == list->lasti && ip->opcode == Op_push_re)
+		; /* do nothing --- @/.../ */
+	else {
+		ip = instruction(Op_push_re);
+		ip->memory = make_regnode(Node_dynregex, NULL);
+		ip->nexti = list->lasti->nexti;
+		list->lasti->nexti = ip;
+		list->lasti = ip;
+	}
+	return ip->memory;
+}
+
+#ifndef NO_LINT
+/* isnoeffect --- when used as a statement, has no side effects */
+
+static int
+isnoeffect(OPCODE type)
+{
+	switch (type) {
+	case Op_times:
+	case Op_times_i:
+	case Op_quotient:
+	case Op_quotient_i:
+	case Op_mod:
+	case Op_mod_i:
+	case Op_plus:
+	case Op_plus_i:
+	case Op_minus:
+	case Op_minus_i:
+	case Op_subscript:
+	case Op_concat:
+	case Op_exp:
+	case Op_exp_i:
+	case Op_unary_minus:
+	case Op_field_spec:
+	case Op_and_final:
+	case Op_or_final:
+	case Op_equal:
+	case Op_notequal:
+	case Op_less:
+	case Op_greater:
+	case Op_leq:
+	case Op_geq:
+	case Op_match:
+	case Op_nomatch:
+	case Op_match_rec:
+	case Op_not:
+	case Op_in_array:
+		return true;
+	default:
+		break;	/* keeps gcc -Wall happy */
+	}
+
+	return false;
+}
+#endif /* NO_LINT */
+
+
+/* make_assignable --- make this operand an assignable one if posiible */
+
+static INSTRUCTION *
+make_assignable(INSTRUCTION *ip)
+{
+	switch (ip->opcode) {
+	case Op_push:
+		ip->opcode = Op_push_lhs;
+		return ip;
+	case Op_field_spec:
+		ip->opcode = Op_field_spec_lhs;
+		return ip;
+	case Op_subscript:
+		ip->opcode = Op_subscript_lhs;
+		return ip;
+	default:
+		break;	/* keeps gcc -Wall happy */
+	}
+	return NULL;
+}
+
+/* stopme --- for debugging */
+
+NODE *
+stopme(int nargs ATTRIBUTE_UNUSED)
+{
+	return make_number(0.0);
+}
+
+/* dumpintlstr --- write out an initial .po file entry for the string */
+
+static void
+dumpintlstr(const char *str, size_t len)
+{
+	char *cp;
+
+	/* See the GNU gettext distribution for details on the file format */
+
+	if (source != NULL) {
+		/* ala the gettext sources, remove leading `./'s */
+		for (cp = source; cp[0] == '.' && cp[1] == '/'; cp += 2)
+			continue;
+		printf("#: %s:%d\n", cp, sourceline);
+	}
+
+	printf("msgid ");
+	pp_string_fp(fprintf, stdout, str, len, '"', true);
+	putchar('\n');
+	printf("msgstr \"\"\n\n");
+	fflush(stdout);
+}
+
+/* dumpintlstr2 --- write out an initial .po file entry for the string and its plural */
+
+static void
+dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2)
+{
+	char *cp;
+
+	/* See the GNU gettext distribution for details on the file format */
+
+	if (source != NULL) {
+		/* ala the gettext sources, remove leading `./'s */
+		for (cp = source; cp[0] == '.' && cp[1] == '/'; cp += 2)
+			continue;
+		printf("#: %s:%d\n", cp, sourceline);
+	}
+
+	printf("msgid ");
+	pp_string_fp(fprintf, stdout, str1, len1, '"', true);
+	putchar('\n');
+	printf("msgid_plural ");
+	pp_string_fp(fprintf, stdout, str2, len2, '"', true);
+	putchar('\n');
+	printf("msgstr[0] \"\"\nmsgstr[1] \"\"\n\n");
+	fflush(stdout);
+}
+
+/* mk_binary --- instructions for binary operators */
+
+static INSTRUCTION *
+mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
+{
+	INSTRUCTION *ip1,*ip2;
+	AWKNUM res;
+
+	ip2 = s2->nexti;
+	if (s2->lasti == ip2 && ip2->opcode == Op_push_i) {
+	/* do any numeric constant folding */
+		ip1 = s1->nexti;
+		if (do_optimize
+				&& ip1 == s1->lasti && ip1->opcode == Op_push_i
+				&& (ip1->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0
+				&& (ip2->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0
+		) {
+			NODE *n1 = ip1->memory, *n2 = ip2->memory;
+			res = force_number(n1)->numbr;
+			(void) force_number(n2);
+			switch (op->opcode) {
+			case Op_times:
+				res *= n2->numbr;
+				break;
+			case Op_quotient:
+				if (n2->numbr == 0.0) {
+					/* don't fatalize, allow parsing rest of the input */
+					error_ln(op->source_line, _("division by zero attempted"));
+					goto regular;
+				}
+
+				res /= n2->numbr;
+				break;
+			case Op_mod:
+				if (n2->numbr == 0.0) {
+					/* don't fatalize, allow parsing rest of the input */
+					error_ln(op->source_line, _("division by zero attempted in `%%'"));
+					goto regular;
+				}
+#ifdef HAVE_FMOD
+				res = fmod(res, n2->numbr);
+#else	/* ! HAVE_FMOD */
+				(void) modf(res / n2->numbr, &res);
+				res = n1->numbr - res * n2->numbr;
+#endif	/* ! HAVE_FMOD */
+				break;
+			case Op_plus:
+				res += n2->numbr;
+				break;
+			case Op_minus:
+				res -= n2->numbr;
+				break;
+			case Op_exp:
+				res = calc_exp(res, n2->numbr);
+				break;
+			default:
+				goto regular;
+			}
+
+			op->opcode = Op_push_i;
+			// We don't need to call set_profile_text() here since
+			// optimizing is disabled when doing pretty printing.
+			op->memory = make_number(res);
+			unref(n1);
+			unref(n2);
+			bcfree(ip1);
+			bcfree(ip2);
+			bcfree(s1);
+			bcfree(s2);
+			return list_create(op);
+		} else {
+		/* do basic arithmetic optimisation */
+		/* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i Node_val) */
+			switch (op->opcode) {
+			case Op_times:
+				op->opcode = Op_times_i;
+				break;
+			case Op_quotient:
+				op->opcode = Op_quotient_i;
+				break;
+			case Op_mod:
+				op->opcode = Op_mod_i;
+				break;
+			case Op_plus:
+				op->opcode = Op_plus_i;
+				break;
+			case Op_minus:
+				op->opcode = Op_minus_i;
+				break;
+			case Op_exp:
+				op->opcode = Op_exp_i;
+				break;
+			default:
+				goto regular;
+			}
+
+			op->memory = ip2->memory;
+			bcfree(ip2);
+			bcfree(s2);	/* Op_list */
+			return list_append(s1, op);
+		}
+	}
+
+regular:
+	/* append lists s1, s2 and add `op' bytecode */
+	(void) list_merge(s1, s2);
+	return list_append(s1, op);
+}
+
+/* mk_boolean --- instructions for boolean and, or */
+
+static INSTRUCTION *
+mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
+{
+	INSTRUCTION *tp;
+	OPCODE opc, final_opc;
+
+	opc = op->opcode;		/* Op_and or Op_or */
+	final_opc = (opc == Op_or) ? Op_or_final : Op_and_final;
+
+	add_lint(right, LINT_assign_in_cond);
+
+	tp = left->lasti;
+
+	if (tp->opcode != final_opc) {	/* x || y */
+		list_append(right, instruction(final_opc));
+		add_lint(left, LINT_assign_in_cond);
+		(void) list_append(left, op);
+		left->lasti->target_jmp = right->lasti;
+
+		/* NB: target_stmt points to previous Op_and(Op_or) in a chain;
+		 *     target_stmt only used in the parser (see below).
+		 */
+
+		left->lasti->target_stmt = left->lasti;
+		right->lasti->target_stmt = left->lasti;
+	} else {		/* optimization for x || y || z || ... */
+		INSTRUCTION *ip;
+
+		op->opcode = final_opc;
+		(void) list_append(right, op);
+		op->target_stmt = tp;
+		tp->opcode = opc;
+		tp->target_jmp = op;
+
+		/* update jump targets */
+		for (ip = tp->target_stmt; ; ip = ip->target_stmt) {
+			assert(ip->opcode == opc);
+			assert(ip->target_jmp == tp);
+			/* if (ip->opcode == opc &&  ip->target_jmp == tp) */
+			ip->target_jmp = op;
+			if (ip->target_stmt == ip)
+				break;
+		}
+	}
+
+	return list_merge(left, right);
+}
+
+/* mk_condition --- if-else and conditional */
+
+static INSTRUCTION *
+mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
+		INSTRUCTION *elsep, INSTRUCTION *false_branch)
+{
+	/*
+	 *    ----------------
+	 *       cond
+	 *    ----------------
+	 * t: [Op_jmp_false f ]
+	 *    ----------------
+	 *       true_branch
+	 *
+	 *    ----------------
+	 *    [Op_jmp y]
+	 *    ----------------
+	 * f:
+	 *      false_branch
+	 *    ----------------
+	 * y: [Op_no_op]
+	 *    ----------------
+	 */
+
+	INSTRUCTION *ip;
+	bool setup_else_part = true;
+
+	if (false_branch == NULL) {
+		false_branch = list_create(instruction(Op_no_op));
+		if (elsep == NULL) {		/* else { } */
+			setup_else_part = false;
+		}
+	} else {
+		/* assert(elsep != NULL); */
+
+		/* avoid a series of no_op's: if .. else if .. else if .. */
+		if (false_branch->lasti->opcode != Op_no_op)
+			(void) list_append(false_branch, instruction(Op_no_op));
+	}
+
+	if (setup_else_part) {
+		if (do_pretty_print) {
+			(void) list_prepend(false_branch, elsep);
+			false_branch->nexti->branch_end = false_branch->lasti;
+			(void) list_prepend(false_branch, instruction(Op_exec_count));
+		} else
+			bcfree(elsep);
+	}
+
+	(void) list_prepend(false_branch, instruction(Op_jmp));
+	false_branch->nexti->target_jmp = false_branch->lasti;
+
+	add_lint(cond, LINT_assign_in_cond);
+	ip = list_append(cond, instruction(Op_jmp_false));
+	ip->lasti->target_jmp = false_branch->nexti->nexti;
+
+	if (do_pretty_print) {
+		(void) list_prepend(ip, ifp);
+		(void) list_append(ip, instruction(Op_exec_count));
+		ip->nexti->branch_if = ip->lasti;
+		ip->nexti->branch_else = false_branch->nexti;
+	} else
+		bcfree(ifp);
+
+	if (true_branch != NULL)
+		list_merge(ip, true_branch);
+	return list_merge(ip, false_branch);
+}
+
+enum defline { FIRST_LINE, LAST_LINE };
+
+/* find_line -- find the first(last) line in a list of (pattern) instructions */
+
+static int
+find_line(INSTRUCTION *pattern, enum defline what)
+{
+	INSTRUCTION *ip;
+	int lineno = 0;
+
+	for (ip = pattern->nexti; ip; ip = ip->nexti) {
+		if (what == LAST_LINE) {
+			if (ip->source_line > lineno)
+				lineno = ip->source_line;
+		} else {	/* FIRST_LINE */
+			if (ip->source_line > 0
+					&& (lineno == 0 || ip->source_line < lineno))
+				lineno = ip->source_line;
+		}
+		if (ip == pattern->lasti)
+			break;
+	}
+	assert(lineno > 0);
+	return lineno;
+}
+
+/* append_rule --- pattern-action instructions */
+
+static INSTRUCTION *
+append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
+{
+	/*
+	 *    ----------------
+	 *       pattern
+	 *    ----------------
+	 *    [Op_jmp_false f ]
+	 *    ----------------
+	 *       action
+	 *    ----------------
+	 * f: [Op_no_op       ]
+	 *    ----------------
+	 */
+
+	INSTRUCTION *rp;
+	INSTRUCTION *tp;
+	INSTRUCTION *ip;
+
+	if (rule != Rule) {
+		rp = pattern;
+		if (do_pretty_print) {
+			rp[3].nexti = namespace_chain;
+			namespace_chain = NULL;
+			(void) list_append(action, instruction(Op_no_op));
+		}
+		(rp + 1)->firsti = action->nexti;
+		(rp + 1)->lasti = action->lasti;
+		(rp + 2)->first_line = pattern->source_line;
+		(rp + 2)->last_line = lastline;
+		ip = list_prepend(action, rp);
+		if (interblock_comment != NULL) {
+			ip = list_prepend(ip, interblock_comment);
+			interblock_comment = NULL;
+		}
+	} else {
+		rp = bcalloc(Op_rule, 4, 0);
+		rp->in_rule = Rule;
+		rp->source_file = source;
+		tp = instruction(Op_no_op);
+
+		if (do_pretty_print) {
+			rp[3].nexti = namespace_chain;
+			namespace_chain = NULL;
+		}
+
+		if (pattern == NULL) {
+			/* assert(action != NULL); */
+			if (do_pretty_print)
+				(void) list_prepend(action, instruction(Op_exec_count));
+			(rp + 1)->firsti = action->nexti;
+			(rp + 1)->lasti = tp;
+			(rp + 2)->first_line = firstline;
+			(rp + 2)->last_line = lastline;
+			rp->source_line = firstline;
+			ip = list_prepend(list_append(action, tp), rp);
+		} else {
+			(void) list_append(pattern, instruction(Op_jmp_false));
+			pattern->lasti->target_jmp = tp;
+			(rp + 2)->first_line = find_line(pattern, FIRST_LINE);
+			rp->source_line = (rp + 2)->first_line;
+			if (action == NULL) {
+				(rp + 2)->last_line = find_line(pattern, LAST_LINE);
+				action = list_create(instruction(Op_K_print_rec));
+				if (do_pretty_print)
+					action = list_prepend(action, instruction(Op_exec_count));
+			} else
+				(rp + 2)->last_line = lastline;
+
+			if (interblock_comment != NULL) {	// was after previous action
+				pattern = list_prepend(pattern, interblock_comment);
+				interblock_comment = NULL;
+			}
+
+			if (do_pretty_print) {
+				pattern = list_prepend(pattern, instruction(Op_exec_count));
+				action = list_prepend(action, instruction(Op_exec_count));
+			}
+
+ 			(rp + 1)->firsti = action->nexti;
+			(rp + 1)->lasti = tp;
+			ip = list_append(
+					list_merge(list_prepend(pattern, rp),
+						action),
+					tp);
+		}
+	}
+
+	list_append(rule_list, rp + 1);
+
+	if (rule_block[rule] == NULL)
+		rule_block[rule] = ip;
+	else
+		(void) list_merge(rule_block[rule], ip);
+
+	return rule_block[rule];
+}
+
+/* mk_assignment --- assignment bytecodes */
+
+static INSTRUCTION *
+mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op)
+{
+	INSTRUCTION *tp;
+	INSTRUCTION *ip;
+
+	tp = lhs->lasti;
+	switch (tp->opcode) {
+	case Op_field_spec:
+		tp->opcode = Op_field_spec_lhs;
+		break;
+	case Op_subscript:
+		tp->opcode = Op_subscript_lhs;
+		break;
+	case Op_push:
+	case Op_push_array:
+		tp->opcode = Op_push_lhs;
+		break;
+	case Op_field_assign:
+		yyerror(_("cannot assign a value to the result of a field post-increment expression"));
+		break;
+	default:
+		yyerror(_("invalid target of assignment (opcode %s)"),
+				opcode2str(tp->opcode));
+		break;
+	}
+
+	tp->do_reference = (op->opcode != Op_assign);	/* check for uninitialized reference */
+
+	if (rhs != NULL)
+		ip = list_merge(rhs, lhs);
+	else
+		ip = lhs;
+
+	(void) list_append(ip, op);
+
+	if (tp->opcode == Op_push_lhs
+			&& tp->memory->type == Node_var
+			&& tp->memory->var_assign
+	) {
+		tp->do_reference = false; /* no uninitialized reference checking
+		                           * for a special variable.
+		                           */
+		(void) list_append(ip, instruction(Op_var_assign));
+		ip->lasti->assign_var = tp->memory->var_assign;
+	} else if (tp->opcode == Op_field_spec_lhs) {
+		(void) list_append(ip, instruction(Op_field_assign));
+		ip->lasti->field_assign = (Func_ptr) 0;
+		tp->target_assign = ip->lasti;
+	} else if (tp->opcode == Op_subscript_lhs) {
+		(void) list_append(ip, instruction(Op_subscript_assign));
+	}
+
+	return ip;
+}
+
+/* optimize_assignment --- peephole optimization for assignment */
+
+static INSTRUCTION *
+optimize_assignment(INSTRUCTION *exp)
+{
+	INSTRUCTION *i1, *i2, *i3;
+
+	/*
+	 * Optimize assignment statements array[subs] = x; var = x; $n = x;
+	 * string concatenation of the form s = s t.
+	 *
+	 * 1) Array element assignment array[subs] = x:
+	 *   Replaces Op_push_array + Op_subscript_lhs + Op_assign + Op_pop
+	 *   with single instruction Op_store_sub.
+	 *	 Limitation: 1 dimension and sub is simple var/value.
+	 *
+	 * 2) Simple variable assignment var = x:
+	 *   Replaces Op_push_lhs + Op_assign + Op_pop with Op_store_var.
+	 *
+	 * 3) Field assignment $n = x:
+	 *   Replaces Op_field_spec_lhs + Op_assign + Op_field_assign + Op_pop
+	 *   with Op_store_field.
+	 *
+	 * 4) Optimization for string concatenation:
+	 *   For cases like x = x y, uses realloc to include y in x;
+	 *   also eliminates instructions Op_push_lhs and Op_pop.
+	 */
+
+	/*
+	 * N.B.: do not append Op_pop instruction to the returned
+	 * instruction list if optimized. None of these
+	 * optimized instructions pushes the r-value of assignment
+	 * onto the runtime stack.
+	 */
+
+	i2 = NULL;
+	i1 = exp->lasti;
+
+	if (   i1->opcode != Op_assign
+	    && i1->opcode != Op_field_assign)
+		return list_append(exp, instruction(Op_pop));
+
+	for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {
+		switch (i2->opcode) {
+		case Op_concat:
+			if (i2->nexti->opcode == Op_push_lhs    /* l.h.s is a simple variable */
+				&& (i2->concat_flag & CSVAR) != 0   /* 1st exp in r.h.s is a simple variable;
+				                                     * see Op_concat in the grammer above.
+				                                     */
+				&& i2->nexti->memory == exp->nexti->memory	 /* and the same as in l.h.s */
+				&& i2->nexti->nexti == i1
+				&& i1->opcode == Op_assign
+			) {
+				/* s = s ... optimization */
+
+				/* avoid stuff like x = x (x = y) or x = x gsub(/./, "b", x);
+				 * check for l-value reference to this variable in the r.h.s.
+				 * Also, avoid function calls in general to guard against
+				 * global variable assignment.
+				 */
+
+				for (i3 = exp->nexti->nexti; i3 != i2; i3 = i3->nexti) {
+					if ((i3->opcode == Op_push_lhs && i3->memory == i2->nexti->memory)
+							|| i3->opcode == Op_func_call)
+						return list_append(exp, instruction(Op_pop)); /* no optimization */
+				}
+
+				/* remove the variable from r.h.s */
+				i3 = exp->nexti;
+				exp->nexti = i3->nexti;
+				bcfree(i3);
+
+				if (--i2->expr_count == 1)	/* one less expression in Op_concat */
+					i2->opcode = Op_no_op;
+
+				i3 = i2->nexti;
+				assert(i3->opcode == Op_push_lhs);
+				i3->opcode = Op_assign_concat;	/* change Op_push_lhs to Op_assign_concat */
+				i3->nexti = NULL;
+				bcfree(i1);          /* Op_assign */
+				exp->lasti = i3;     /* update Op_list */
+				return exp;
+			}
+			break;
+
+		case Op_field_spec_lhs:
+			if (i2->nexti->opcode == Op_assign
+					&& i2->nexti->nexti == i1
+					&& i1->opcode == Op_field_assign
+			) {
+				/* $n = .. */
+				i2->opcode = Op_store_field;
+				bcfree(i2->nexti);  /* Op_assign */
+				i2->nexti = NULL;
+				bcfree(i1);          /* Op_field_assign */
+				exp->lasti = i2;    /* update Op_list */
+				return exp;
+			}
+			break;
+
+		case Op_push_array:
+			if (i2->nexti->nexti->opcode == Op_subscript_lhs) {
+				i3 = i2->nexti->nexti;
+				if (i3->sub_count == 1
+						&& i3->nexti == i1
+						&& i1->opcode == Op_assign
+				) {
+					/* array[sub] = .. */
+					i3->opcode = Op_store_sub;
+					i3->memory = i2->memory;
+					i3->expr_count = 1;  /* sub_count shadows memory,
+                                          * so use expr_count instead.
+				                          */
+					i3->nexti = NULL;
+					i2->opcode = Op_no_op;
+					bcfree(i1);          /* Op_assign */
+					exp->lasti = i3;     /* update Op_list */
+					return exp;
+				}
+			}
+			break;
+
+		case Op_push_lhs:
+			if (i2->nexti == i1
+					&& i1->opcode == Op_assign
+			) {
+				/* var = .. */
+				i2->opcode = Op_store_var;
+				i2->nexti = NULL;
+				bcfree(i1);          /* Op_assign */
+				exp->lasti = i2;     /* update Op_list */
+
+				i3 = exp->nexti;
+				if (i3->opcode == Op_push_i
+					&& (i3->memory->flags & INTLSTR) == 0
+					&& i3->nexti == i2
+				) {
+					/* constant initializer */
+					i2->initval = i3->memory;
+					bcfree(i3);
+					exp->nexti = i2;
+				} else
+					i2->initval = NULL;
+
+				return exp;
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	/* no optimization  */
+	return list_append(exp, instruction(Op_pop));
+}
+
+
+/* mk_getline --- make instructions for getline */
+
+static INSTRUCTION *
+mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
+{
+	INSTRUCTION *ip;
+	INSTRUCTION *tp;
+	INSTRUCTION *asgn = NULL;
+
+	/*
+	 *  getline [var] < [file]
+	 *
+	 *  [ file (simp_exp)]
+	 *  [ [ var ] ]
+	 *  [ Op_K_getline_redir|NULL|redir_type|into_var]
+	 *  [ [var_assign] ]
+	 *
+	 */
+
+	if (redir == NULL) {
+		int sline = op->source_line;
+		bcfree(op);
+		op = bcalloc(Op_K_getline, 2, sline);
+		(op + 1)->target_endfile = ip_endfile;
+		(op + 1)->target_beginfile = ip_beginfile;
+	}
+
+	if (var != NULL) {
+		tp = make_assignable(var->lasti);
+		assert(tp != NULL);
+
+		/* check if we need after_assign bytecode */
+		if (tp->opcode == Op_push_lhs
+				&& tp->memory->type == Node_var
+				&& tp->memory->var_assign
+		) {
+			asgn = instruction(Op_var_assign);
+			asgn->assign_ctxt = op->opcode;
+			asgn->assign_var = tp->memory->var_assign;
+		} else if (tp->opcode == Op_field_spec_lhs) {
+			asgn = instruction(Op_field_assign);
+			asgn->assign_ctxt = op->opcode;
+			asgn->field_assign = (Func_ptr) 0;   /* determined at run time */
+			tp->target_assign = asgn;
+		} else if (tp->opcode == Op_subscript_lhs) {
+			asgn = instruction(Op_subscript_assign);
+			asgn->assign_ctxt = op->opcode;
+		}
+
+		if (redir != NULL) {
+			ip = list_merge(redir, var);
+			(void) list_append(ip, op);
+		} else
+			ip = list_append(var, op);
+	} else if (redir != NULL)
+		ip = list_append(redir, op);
+	else
+		ip = list_create(op);
+	op->into_var = (var != NULL);
+	op->redir_type = (redir != NULL) ? redirtype : redirect_none;
+
+	return (asgn == NULL ? ip : list_append(ip, asgn));
+}
+
+
+/* mk_for_loop --- for loop bytecodes */
+
+static INSTRUCTION *
+mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
+				INSTRUCTION *incr, INSTRUCTION *body)
+{
+	/*
+	 *   ------------------------
+	 *        init                 (may be NULL)
+	 *   ------------------------
+	 * x:
+	 *        cond                 (Op_no_op if NULL)
+	 *   ------------------------
+	 *    [ Op_jmp_false tb      ]
+	 *   ------------------------
+	 *        body                 (may be NULL)
+	 *   ------------------------
+	 * tc:
+	 *    incr                      (may be NULL)
+	 *    [ Op_jmp x             ]
+	 *   ------------------------
+	 * tb:[ Op_no_op             ]
+	 */
+
+	INSTRUCTION *ip, *tbreak, *tcont;
+	INSTRUCTION *jmp;
+	INSTRUCTION *pp_cond;
+	INSTRUCTION *ret;
+
+	tbreak = instruction(Op_no_op);
+
+	if (cond != NULL) {
+		add_lint(cond, LINT_assign_in_cond);
+		pp_cond = cond->nexti;
+		ip = cond;
+		(void) list_append(ip, instruction(Op_jmp_false));
+		ip->lasti->target_jmp = tbreak;
+	} else {
+		pp_cond = instruction(Op_no_op);
+		ip = list_create(pp_cond);
+	}
+
+	if (init != NULL)
+		ip = list_merge(init, ip);
+
+	if (do_pretty_print) {
+		(void) list_append(ip, instruction(Op_exec_count));
+		(forp + 1)->forloop_cond = pp_cond;
+		(forp + 1)->forloop_body = ip->lasti;
+	}
+
+	if (body != NULL)
+		(void) list_merge(ip, body);
+
+	jmp = instruction(Op_jmp);
+	jmp->target_jmp = pp_cond;
+	if (incr == NULL)
+		tcont = jmp;
+	else {
+		tcont = incr->nexti;
+		(void) list_merge(ip, incr);
+	}
+
+	(void) list_append(ip, jmp);
+	ret = list_append(ip, tbreak);
+	fix_break_continue(ret, tbreak, tcont);
+
+	if (do_pretty_print) {
+		forp->target_break = tbreak;
+		forp->target_continue = tcont;
+		ret = list_prepend(ret, forp);
+	}
+	/* else
+		forp is NULL */
+
+	return ret;
+}
+
+/* add_lint --- add lint warning bytecode if needed */
+
+static void
+add_lint(INSTRUCTION *list, LINTTYPE linttype)
+{
+#ifndef NO_LINT
+	INSTRUCTION *ip;
+
+	switch (linttype) {
+	case LINT_assign_in_cond:
+		ip = list->lasti;
+		if (ip->opcode == Op_var_assign || ip->opcode == Op_field_assign) {
+			assert(ip != list->nexti);
+			for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti)
+				;
+		}
+
+		if (ip->opcode == Op_assign || ip->opcode == Op_assign_concat) {
+			list_append(list, instruction(Op_lint));
+			list->lasti->lint_type = linttype;
+		}
+		break;
+
+	case LINT_no_effect:
+		if (list->lasti->opcode == Op_pop && list->nexti != list->lasti) {
+			int line = 0;
+
+			// Get down to the last instruction (FIXME: why?)
+			for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) {
+				// along the way track line numbers, we will use the line
+				// closest to the opcode if that opcode doesn't have one
+				if (ip->source_line != 0)
+					line = ip->source_line;
+			}
+
+			if (do_lint) {		/* compile-time warning */
+				if (isnoeffect(ip->opcode)) {
+					if (ip->source_line != 0)
+						line = ip->source_line;
+					lintwarn_ln(line, ("statement may have no effect"));
+				}
+			}
+
+			if (ip->opcode == Op_push || ip->opcode == Op_push_i) {		/* run-time warning */
+				list_append(list, instruction(Op_lint));
+				list->lasti->lint_type = linttype;
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+#endif
+}
+
+/* mk_expression_list --- list of bytecode lists */
+
+static INSTRUCTION *
+mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1)
+{
+	INSTRUCTION *r;
+
+	/* we can't just combine all bytecodes, since we need to
+	 * process individual expressions for a few builtins in snode() (-:
+	 */
+
+	/* -- list of lists     */
+	/* [Op_list| ... ]------
+	 *                       |
+	 * [Op_list| ... ]   --  |
+	 *  ...               |  |
+	 *  ...       <-------   |
+	 * [Op_list| ... ]   --  |
+	 *  ...               |  |
+	 *  ...               |  |
+	 *  ...       <------- --
+	 */
+
+	assert(s1 != NULL && s1->opcode == Op_list);
+	if (list == NULL) {
+		list = instruction(Op_list);
+		list->nexti = s1;
+		list->lasti = s1->lasti;
+		return list;
+	}
+
+	/* append expression to the end of the list */
+
+	r = list->lasti;
+	r->nexti = s1;
+	list->lasti = s1->lasti;
+	return list;
+}
+
+/* count_expressions --- fixup expression_list from mk_expression_list.
+ *                       returns no of expressions in list. isarg is true
+ *                       for function arguments.
+ */
+
+static int
+count_expressions(INSTRUCTION **list, bool isarg)
+{
+	INSTRUCTION *expr;
+	INSTRUCTION *r = NULL;
+	int count = 0;
+
+	if (*list == NULL)	/* error earlier */
+		return 0;
+
+	for (expr = (*list)->nexti; expr; ) {
+		INSTRUCTION *t1, *t2;
+		t1 = expr->nexti;
+		t2 = expr->lasti;
+		if (isarg && t1 == t2 && t1->opcode == Op_push)
+			t1->opcode = Op_push_param;
+		if (++count == 1)
+			r = expr;
+		else
+			(void) list_merge(r, expr);
+		expr = t2->nexti;
+	}
+
+	assert(count > 0);
+	if (! isarg && count > max_args)
+		max_args = count;
+	bcfree(*list);
+	*list = r;
+	return count;
+}
+
+/* fix_break_continue --- fix up break & continue codes in loop bodies */
+
+static void
+fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target)
+{
+	INSTRUCTION *ip;
+
+	list->lasti->nexti = NULL;	/* just to make sure */
+
+	for (ip = list->nexti; ip != NULL; ip = ip->nexti) {
+		switch (ip->opcode) {
+		case Op_K_break:
+			if (ip->target_jmp == NULL)
+				ip->target_jmp = b_target;
+			break;
+
+		case Op_K_continue:
+			if (ip->target_jmp == NULL)
+				ip->target_jmp = c_target;
+			break;
+
+		default:
+			/* this is to keep the compiler happy. sheesh. */
+			break;
+		}
+	}
+}
+
+static inline INSTRUCTION *
+list_create(INSTRUCTION *x)
+{
+	INSTRUCTION *l;
+
+	l = instruction(Op_list);
+	l->nexti = x;
+	l->lasti = x;
+	return l;
+}
+
+static inline INSTRUCTION *
+list_append(INSTRUCTION *l, INSTRUCTION *x)
+{
+#ifdef GAWKDEBUG
+	if (l->opcode != Op_list)
+		cant_happen();
+#endif
+	l->lasti->nexti = x;
+	l->lasti = x;
+	return l;
+}
+
+static inline INSTRUCTION *
+list_prepend(INSTRUCTION *l, INSTRUCTION *x)
+{
+#ifdef GAWKDEBUG
+	if (l->opcode != Op_list)
+		cant_happen();
+#endif
+	x->nexti = l->nexti;
+	l->nexti = x;
+	return l;
+}
+
+static inline INSTRUCTION *
+list_merge(INSTRUCTION *l1, INSTRUCTION *l2)
+{
+#ifdef GAWKDEBUG
+	if (l1->opcode != Op_list)
+		cant_happen();
+	if (l2->opcode != Op_list)
+		cant_happen();
+#endif
+	l1->lasti->nexti = l2->nexti;
+	l1->lasti = l2->lasti;
+	bcfree(l2);
+	return l1;
+}
+
+/* See if name is a special token. */
+
+int
+check_special(const char *name)
+{
+	int low, high, mid;
+	int i;
+	int non_standard_flags = 0;
+#ifdef USE_EBCDIC
+	static bool did_sort = false;
+
+	if (! did_sort) {
+		qsort((void *) tokentab,
+				sizeof(tokentab) / sizeof(tokentab[0]),
+				sizeof(tokentab[0]), tokcompare);
+		did_sort = true;
+	}
+#endif
+
+	if (do_traditional)
+		non_standard_flags |= GAWKX;
+	if (do_posix)
+		non_standard_flags |= NOT_POSIX;
+
+	low = 0;
+	high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1;
+	while (low <= high) {
+		mid = (low + high) / 2;
+		i = *name - tokentab[mid].operator[0];
+		if (i == 0)
+			i = strcmp(name, tokentab[mid].operator);
+
+		if (i < 0)		/* token < mid */
+			high = mid - 1;
+		else if (i > 0)		/* token > mid */
+			low = mid + 1;
+		else {
+			if ((tokentab[mid].flags & non_standard_flags) != 0)
+				return -1;
+			return mid;
+		}
+	}
+	return -1;
+}
+
+/*
+ * This provides a private version of functions that act like VMS's
+ * variable-length record filesystem, where there was a bug on
+ * certain source files.
+ */
+
+static FILE *fp = NULL;
+
+/* read_one_line --- return one input line at a time. mainly for debugging. */
+
+static ssize_t
+read_one_line(int fd, void *buffer, size_t count)
+{
+	char buf[BUFSIZ];
+
+	/* Minor potential memory leak here. Too bad. */
+	if (fp == NULL) {
+		fp = fdopen(fd, "r");
+		if (fp == NULL) {
+			fprintf(stderr, "ugh. fdopen: %s\n", strerror(errno));
+			gawk_exit(EXIT_FAILURE);
+		}
+	}
+
+	if (fgets(buf, sizeof buf, fp) == NULL)
+		return 0;
+
+	memcpy(buffer, buf, strlen(buf));
+	return strlen(buf);
+}
+
+/* one_line_close --- close the open file being read with read_one_line() */
+
+static int
+one_line_close(int fd)
+{
+	int ret;
+
+	if (fp == NULL || fd != fileno(fp))
+		fatal("debugging read/close screwed up!");
+
+	ret = fclose(fp);
+	fp = NULL;
+	return ret;
+}
+
+
+/* lookup_builtin --- find a builtin function or return NULL */
+
+builtin_func_t
+lookup_builtin(const char *name)
+{
+	if (strncmp(name, "awk::", 5) == 0)
+		name += 5;
+
+	int mid = check_special(name);
+
+	if (mid == -1)
+		return NULL;
+
+	switch (tokentab[mid].class) {
+	case LEX_BUILTIN:
+	case LEX_LENGTH:
+		break;
+	default:
+		return NULL;
+	}
+
+	/* And another special case... */
+	if (tokentab[mid].value == Op_sub_builtin)
+		return (builtin_func_t) do_sub;
+
+#ifdef HAVE_MPFR
+	if (do_mpfr)
+		return tokentab[mid].ptr2;
+#endif
+
+	return tokentab[mid].ptr;
+}
+
+/* install_builtins --- add built-in functions to FUNCTAB */
+
+void
+install_builtins(void)
+{
+	int i, j;
+	int flags_that_must_be_clear = DEBUG_USE;
+
+	if (do_traditional)
+		flags_that_must_be_clear |= GAWKX;
+
+	if (do_posix)
+		flags_that_must_be_clear |= NOT_POSIX;
+
+
+	j = sizeof(tokentab) / sizeof(tokentab[0]);
+	for (i = 0; i < j; i++) {
+		if (   (tokentab[i].class == LEX_BUILTIN
+		        || tokentab[i].class == LEX_LENGTH)
+		    && (tokentab[i].flags & flags_that_must_be_clear) == 0) {
+			(void) install_symbol(tokentab[i].operator, Node_builtin_func);
+		}
+	}
+}
+
+/*
+ * 9/2014: Gawk cannot use <ctype.h> isalpha or isalnum when
+ * parsing the program since that can let through non-English
+ * letters.  So, we supply our own. !@#$%^&*()-ing locales!
+ */
+
+/* is_alpha --- return true if c is an English letter */
+
+/*
+ * The scene of the murder was grisly to look upon.  When the inspector
+ * arrived, the sergeant turned to him and said, "Another programmer stabbed
+ * in the back. He never knew what happened."
+ *
+ * The inspector replied, "Looks like the MO of isalpha, and his even meaner
+ * big brother, isalnum. The Locale brothers."  The sergeant merely
+ * shuddered in horror.
+ */
+
+bool
+is_alpha(int c)
+{
+	switch (c) {
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+	case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+	case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+	case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+	case 'y': case 'z':
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+	case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+	case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+	case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+	case 'Y': case 'Z':
+		return true;
+	}
+	return false;
+}
+
+/* is_alnum --- return true for alphanumeric, English only letters */
+
+bool
+is_alnum(int c)
+{
+	/* digit test is good for EBCDIC too. so there. */
+	return (is_alpha(c) || ('0' <= c && c <= '9'));
+}
+
+
+/*
+ * is_letter --- function to check letters
+ *	isalpha() isn't good enough since it can look at the locale.
+ * Underscore counts as a letter in awk identifiers
+ */
+
+bool
+is_letter(int c)
+{
+	return (is_alpha(c) || c == '_');
+}
+
+/* is_identchar --- return true if c can be in an identifier */
+
+bool
+is_identchar(int c)
+{
+	return (is_alnum(c) || c == '_');
+}
+
+/* set_profile_text --- make a number that can be printed when profiling */
+
+static NODE *
+set_profile_text(NODE *n, const char *str, size_t len)
+{
+	if (do_pretty_print) {
+		// two extra bytes: one for NUL termination, and another in
+		// case we need to add a leading minus sign in add_sign_to_num
+		emalloc(n->stptr, char *, len + 2, "set_profile_text");
+		memcpy(n->stptr, str, len);
+		n->stptr[len] = '\0';
+		n->stlen = len;
+		// Set STRCUR and n->stfmt for use when profiling
+		// (i.e., actually running the program) so that
+		// force_string() on this item will work ok.
+		// Thanks and a tip of the hatlo to valgrind.
+		n->flags |= (NUMCONSTSTR|STRCUR);
+		n->stfmt = STFMT_UNUSED;
+#ifdef HAVE_MPFR
+		n->strndmode = MPFR_round_mode;
+#endif
+	}
+
+	return n;
+}
+
+/*
+ * merge_comments --- merge c2 into c1 and free c2 if successful.
+ *	Allow c2 to be NULL, in which case just merged chained
+ *	comments in c1.
+ */
+
+static void
+merge_comments(INSTRUCTION *c1, INSTRUCTION *c2)
+{
+	assert(c1->opcode == Op_comment);
+
+	if (c1->comment == NULL && c2 == NULL)	// nothing to do
+		return;
+
+	size_t total = c1->memory->stlen;
+	if (c1->comment != NULL)
+		total += 1 /* \n */ + c1->comment->memory->stlen;
+
+	if (c2 != NULL) {
+		assert(c2->opcode == Op_comment);
+		total += 1 /* \n */ + c2->memory->stlen;
+		if (c2->comment != NULL)
+			total += c2->comment->memory->stlen + 1;
+	}
+
+	char *buffer;
+	emalloc(buffer, char *, total + 1, "merge_comments");
+
+	strcpy(buffer, c1->memory->stptr);
+	if (c1->comment != NULL) {
+		strcat(buffer, "\n");
+		strcat(buffer, c1->comment->memory->stptr);
+	}
+
+	if (c2 != NULL) {
+		strcat(buffer, "\n");
+		strcat(buffer, c2->memory->stptr);
+		if (c2->comment != NULL) {
+			strcat(buffer, "\n");
+			strcat(buffer, c2->comment->memory->stptr);
+		}
+
+		unref(c2->memory);
+		if (c2->comment != NULL) {
+			unref(c2->comment->memory);
+			bcfree(c2->comment);
+			c2->comment = NULL;
+		}
+		bcfree(c2);
+	}
+
+	c1->memory->comment_type = BLOCK_COMMENT;
+	free(c1->memory->stptr);
+	c1->memory->stptr = buffer;
+	c1->memory->stlen = strlen(buffer);
+
+	// now free everything else
+	if (c1->comment != NULL) {
+		unref(c1->comment->memory);
+		bcfree(c1->comment);
+		c1->comment = NULL;
+	}
+}
+
+/* make_braced_statements --- handle `l_brace statements r_brace' with comments */
+
+static INSTRUCTION *
+make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace)
+{
+	INSTRUCTION *ip;
+
+	if (stmts == NULL)
+		ip = list_create(instruction(Op_no_op));
+	else
+		ip = stmts;
+
+	if (lbrace != NULL) {
+		INSTRUCTION *comment2 = lbrace->comment;
+		if (comment2 != NULL) {
+			ip = list_prepend(ip, comment2);
+			lbrace->comment = NULL;
+		}
+		ip = list_prepend(ip, lbrace);
+	}
+
+	return ip;
+}
+
+/* validate_qualified_name --- make sure that a qualified name is built correctly */
+
+/*
+ * This routine returns upon first error, no need to produce multiple, possibly
+ * conflicting / confusing error messages.
+ */
+
+bool
+validate_qualified_name(char *token)
+{
+	char *cp, *cp2;
+
+	// no colon, by definition it's well formed
+	if ((cp = strchr(token, ':')) == NULL)
+		return true;
+
+	if (do_traditional || do_posix) {
+		error_ln(sourceline, _("identifier %s: qualified names not allowed in traditional / POSIX mode"), token);
+		return false;
+	}
+
+	if (cp[1] != ':') {	// could happen from command line
+		error_ln(sourceline, _("identifier %s: namespace separator is two colons, not one"), token);
+		return false;
+	}
+
+	if (! is_letter(cp[2])) {
+		error_ln(sourceline,
+				_("qualified identifier `%s' is badly formed"),
+				token);
+		return false;
+	}
+
+	if ((cp2 = strchr(cp+2, ':')) != NULL) {
+		error_ln(sourceline,
+			_("identifier `%s': namespace separator can only appear once in a qualified name"),
+			token);
+		return false;
+	}
+
+	return true;
+}
+
+/* check_qualified_special --- decide if a name is special or not */
+
+static int
+check_qualified_special(char *token)
+{
+	char *cp;
+
+	if ((cp = strchr(token, ':')) == NULL && current_namespace == awk_namespace)
+		return check_special(token);
+
+	/*
+	 * Now it's more complicated.  Here are the rules.
+	 *
+	 * 1. Namespace name cannot be a standard awk reserved word or function.
+	 * 2. Subordinate part of the name cannot be standard awk reserved word or function.
+	 * 3. If namespace part is explicitly "awk", return result of check_special().
+	 * 4. Else return -1 (gawk extensions allowed, we check standard awk in step 2).
+	 */
+
+	const struct token *tok;
+	int i;
+	if (cp == NULL) {	// namespace not awk, but a simple identifier
+		i = check_special(token);
+		if (i < 0)
+			return i;
+
+		tok = & tokentab[i];
+		if ((tok->flags & GAWKX) != 0 && tok->class == LEX_BUILTIN)
+			return -1;
+		else
+			return i;
+	}
+
+	char *ns, *end, *subname;
+	ns = token;
+	*(end = cp) = '\0';	// temporarily turn it into standalone string
+	subname = end + 2;
+
+	// First check the namespace part
+	i = check_special(ns);
+	if (i >= 0 && (tokentab[i].flags & GAWKX) == 0) {
+		error_ln(sourceline, _("using reserved identifier `%s' as a namespace is not allowed"), ns);
+		goto done;
+	}
+
+	// Now check the subordinate part
+	i = check_special(subname);
+	if (i >= 0 && (tokentab[i].flags & GAWKX) == 0 && strcmp(ns, "awk") != 0) {
+		error_ln(sourceline, _("using reserved identifier `%s' as second component of a qualified name is not allowed"), subname);
+		goto done;
+	}
+
+	if (strcmp(ns, "awk") == 0) {
+		i = check_special(subname);
+		if (i >= 0) {
+			if ((tokentab[i].flags & GAWKX) != 0 && tokentab[i].class == LEX_BUILTIN)
+				;	// gawk additional builtin function, is ok
+			else
+				error_ln(sourceline, _("using reserved identifier `%s' as second component of a qualified name is not allowed"), subname);
+		}
+	} else
+		i = -1;
+done:
+	*end = ':';
+	return i;
+}
+
+/* set_namespace --- change the current namespace */
+
+static void
+set_namespace(INSTRUCTION *ns, INSTRUCTION *comment)
+{
+	if (ns == NULL)
+		return;
+
+	if (do_traditional || do_posix) {
+		error_ln(ns->source_line, _("@namespace is a gawk extension"));
+		efree(ns->lextok);
+		bcfree(ns);
+		return;
+	}
+
+	if (! is_valid_identifier(ns->lextok)) {
+		error_ln(ns->source_line, _("namespace name `%s' must meet identifier naming rules"), ns->lextok);
+		efree(ns->lextok);
+		bcfree(ns);
+		return;
+	}
+
+	int mid = check_special(ns->lextok);
+
+	if (mid >= 0) {
+		error_ln(ns->source_line, _("using reserved identifier `%s' as a namespace is not allowed"), ns->lextok);
+		efree(ns->lextok);
+		bcfree(ns);
+		return;
+	}
+
+	if (strcmp(ns->lextok, current_namespace) == 0)
+		;	// nothing to do
+	else if (strcmp(ns->lextok, awk_namespace) == 0) {
+		set_current_namespace(awk_namespace);
+	} else {
+		set_current_namespace(estrdup(ns->lextok, strlen(ns->lextok)));
+	}
+	efree(ns->lextok);
+
+	// save info and push on front of list of namespaces seen
+	INSTRUCTION *new_ns = instruction(Op_K_namespace);
+	new_ns->comment = comment;
+	new_ns->ns_name = estrdup(current_namespace, strlen(current_namespace));
+	new_ns->nexti = namespace_chain;
+	namespace_chain = new_ns;
+
+	ns->lextok = NULL;
+	bcfree(ns);
+
+	namespace_changed = true;
+
+	return;
+}
+
+/* qualify_name --- put name into namespace */
+
+static char *
+qualify_name(const char *name, size_t len)
+{
+	if (strchr(name, ':') != NULL)	// already qualified
+		return estrdup(name, len);
+
+	NODE *p = lookup(name);
+	if (p != NULL && p->type == Node_param_list)
+		return estrdup(name, len);
+
+	if (current_namespace != awk_namespace && ! is_all_upper(name)) {
+		size_t length = strlen(current_namespace) + 2 + len + 1;
+		char *buf;
+
+		emalloc(buf, char *, length, "qualify_name");
+		sprintf(buf, "%s::%s", current_namespace, name);
+
+		return buf;
+	}
+
+	return estrdup(name, len);
+}
diff --git a/gawk/custom.h b/gawk/custom.h
new file mode 100644
index 00000000000..7dfc140f97e
--- /dev/null
+++ b/gawk/custom.h
@@ -0,0 +1,82 @@
+/*
+ * custom.h
+ *
+ * This file is for use on systems where Autoconf isn't quite able to
+ * get things right. It is appended to the bottom of config.h by configure,
+ * in order to override definitions from Autoconf that are erroneous. See
+ * the manual for more information.
+ *
+ * If you make additions to this file for your system, please send me
+ * the information, to arnold@skeeve.com.
+ */
+
+/*
+ * Copyright (C) 1995-2004, 2008, 2009, 2011, 2016, 2018
+ * the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK 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
+ */
+
+/* for VMS POSIX, from Pat Rankin, r.pat.rankin@gmail.com */
+#ifdef VMS_POSIX
+#undef VMS
+#include "vms/redirect.h"
+#endif
+
+/* OpenVMS has some definitions in fp.h that should be in math.h */
+/* From John Malmberg, wb8tyw@qsl.net */
+#ifdef __VMS
+#include <fp.h>
+/* isnan () macro is broken */
+#undef isnan
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#ifndef SIZE_MAX
+#define SIZE_MAX __INT32_MAX
+#endif
+#endif
+
+/* For QNX, based on submission from Michael Hunter, mphunter@qnx.com */
+#ifdef __QNX__
+#define GETPGRP_VOID	1
+#endif
+
+/* For MacOS X, which is almost BSD Unix */
+#ifdef __APPLE__
+#define HAVE_MKTIME	1
+#endif
+
+/* For HP/UX with gcc */
+#if defined(hpux) || defined(_HPUX_SOURCE)
+#undef HAVE_TZSET
+#define HAVE_TZSET 1
+#define _TZSET 1
+#endif
+
+#if defined(_AIX)
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+/* Junk for dfa.[ch] */
+/* The __pure__ attribute was added in gcc 2.96.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define _GL_ATTRIBUTE_PURE /* empty */
+#endif
diff --git a/gawk/gettext.h b/gawk/gettext.h
new file mode 100644
index 00000000000..bfc6148834e
--- /dev/null
+++ b/gawk/gettext.h
@@ -0,0 +1,301 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+   Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2016 Free Software
+   Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option.  */
+#if ENABLE_NLS
+
+/* ADR: Need this so gcc -g without -O works. */
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif /* HAVE_LOCALE_H */
+
+/* Get declarations of GNU message catalog functions.  */
+# include <libintl.h>
+
+/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
+   the gettext() and ngettext() macros.  This is an alternative to calling
+   textdomain(), and is useful for libraries.  */
+# ifdef DEFAULT_TEXT_DOMAIN
+#  undef gettext
+#  define gettext(Msgid) \
+     dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
+#  undef ngettext
+#  define ngettext(Msgid1, Msgid2, N) \
+     dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
+# endif
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+   chokes if dcgettext is defined as a macro.  So include it now, to make
+   later inclusions of <locale.h> a NOP.  We don't include <libintl.h>
+   as well because people using "gettext.h" will not include <libintl.h>,
+   and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+   is OK.  */
+/* ADR: Include <locale.h> even if not ENABLE_NLS so can pay attention
+ * to locale number formats, etc.
+ */
+#if defined(__sun) || defined(HAVE_LOCALE_H)
+# include <locale.h>
+#endif
+
+/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
+   <libintl.h>, which chokes if dcgettext is defined as a macro.  So include
+   it now, to make later inclusions of <libintl.h> a NOP.  */
+#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
+# include <cstdlib>
+# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
+#  include <libintl.h>
+# endif
+#endif
+
+/* Disabled NLS.
+   The casts to 'const char *' serve the purpose of producing warnings
+   for invalid uses of the value returned from these functions.
+   On pre-ANSI systems without 'const', the config.h file is supposed to
+   contain "#define const".  */
+/* ADR: BOGUS. Remove const. 19 Feb 2002 */
+# undef gettext
+# define gettext(Msgid) ((char *) (Msgid))
+# undef dgettext
+# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
+# undef dcgettext
+# define dcgettext(Domainname, Msgid, Category) \
+    ((void) (Category), dgettext (Domainname, Msgid))
+# undef ngettext
+# define ngettext(Msgid1, Msgid2, N) \
+    ((N) == 1 \
+     ? ((void) (Msgid2), (const char *) (Msgid1)) \
+     : ((void) (Msgid1), (const char *) (Msgid2)))
+# undef dngettext
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+    ((void) (Domainname), ngettext (Msgid1, Msgid2, N))
+# undef dcngettext
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+    ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N))
+# undef textdomain
+# define textdomain(Domainname) ((const char *) (Domainname))
+# undef bindtextdomain
+# define bindtextdomain(Domainname, Dirname) \
+    ((void) (Domainname), (const char *) (Dirname))
+# undef bind_textdomain_codeset
+# define bind_textdomain_codeset(Domainname, Codeset) \
+    ((void) (Domainname), (const char *) (Codeset))
+
+#endif
+
+/* Prefer gnulib's setlocale override over libintl's setlocale override.  */
+#ifdef GNULIB_defined_setlocale
+# undef setlocale
+# define setlocale rpl_setlocale
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+   extraction of messages, but does not call gettext().  The run-time
+   translation is done at a different place in the code.
+   The argument, String, should be a literal string.  Concatenated strings
+   and other string expressions won't work.
+   The macro's expansion is not parenthesized, so that it is suitable as
+   initializer for static 'char[]' or 'const char[]' variables.  */
+#define gettext_noop(String) String
+
+/* The separator between msgctxt and msgid in a .mo file.  */
+#define GETTEXT_CONTEXT_GLUE "\004"
+
+/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
+   MSGID.  MSGCTXT and MSGID must be string literals.  MSGCTXT should be
+   short and rarely need to change.
+   The letter 'p' stands for 'particular' or 'special'.  */
+#ifdef DEFAULT_TEXT_DOMAIN
+# define pgettext(Msgctxt, Msgid) \
+   pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#else
+# define pgettext(Msgctxt, Msgid) \
+   pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#endif
+#define dpgettext(Domainname, Msgctxt, Msgid) \
+  pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
+#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
+  pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
+#ifdef DEFAULT_TEXT_DOMAIN
+# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
+   npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#else
+# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
+   npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#endif
+#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
+  npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
+#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
+  npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+pgettext_aux (const char *domain,
+              const char *msg_ctxt_id, const char *msgid,
+              int category)
+{
+  const char *translation = dcgettext (domain, msg_ctxt_id, category);
+  if (translation == msg_ctxt_id)
+    return msgid;
+  else
+    return translation;
+}
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+npgettext_aux (const char *domain,
+               const char *msg_ctxt_id, const char *msgid,
+               const char *msgid_plural, unsigned long int n,
+               int category)
+{
+  const char *translation =
+    dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+  if (translation == msg_ctxt_id || translation == msgid_plural)
+    return (n == 1 ? msgid : msgid_plural);
+  else
+    return translation;
+}
+
+/* The same thing extended for non-constant arguments.  Here MSGCTXT and MSGID
+   can be arbitrary expressions.  But for string literals these macros are
+   less efficient than those above.  */
+
+#include <string.h>
+
+#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
+     /* || __STDC_VERSION__ >= 199901L */ )
+# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
+#else
+# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
+#endif
+
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+#include <stdlib.h>
+#endif
+
+#define pgettext_expr(Msgctxt, Msgid) \
+  dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
+#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
+  dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+dcpgettext_expr (const char *domain,
+                 const char *msgctxt, const char *msgid,
+                 int category)
+{
+  size_t msgctxt_len = strlen (msgctxt) + 1;
+  size_t msgid_len = strlen (msgid) + 1;
+  const char *translation;
+#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+  char msg_ctxt_id[msgctxt_len + msgid_len];
+#else
+  char buf[1024];
+  char *msg_ctxt_id =
+    (msgctxt_len + msgid_len <= sizeof (buf)
+     ? buf
+     : (char *) malloc (msgctxt_len + msgid_len));
+  if (msg_ctxt_id != NULL)
+#endif
+    {
+      int found_translation;
+      memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+      msg_ctxt_id[msgctxt_len - 1] = '\004';
+      memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+      translation = dcgettext (domain, msg_ctxt_id, category);
+      found_translation = (translation != msg_ctxt_id);
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+      if (msg_ctxt_id != buf)
+        free (msg_ctxt_id);
+#endif
+      if (found_translation)
+        return translation;
+    }
+  return msgid;
+}
+
+#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
+  dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
+#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
+  dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static const char *
+dcnpgettext_expr (const char *domain,
+                  const char *msgctxt, const char *msgid,
+                  const char *msgid_plural, unsigned long int n,
+                  int category)
+{
+  size_t msgctxt_len = strlen (msgctxt) + 1;
+  size_t msgid_len = strlen (msgid) + 1;
+  const char *translation;
+#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+  char msg_ctxt_id[msgctxt_len + msgid_len];
+#else
+  char buf[1024];
+  char *msg_ctxt_id =
+    (msgctxt_len + msgid_len <= sizeof (buf)
+     ? buf
+     : (char *) malloc (msgctxt_len + msgid_len));
+  if (msg_ctxt_id != NULL)
+#endif
+    {
+      int found_translation;
+      memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+      msg_ctxt_id[msgctxt_len - 1] = '\004';
+      memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+      translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
+      found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
+#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
+      if (msg_ctxt_id != buf)
+        free (msg_ctxt_id);
+#endif
+      if (found_translation)
+        return translation;
+    }
+  return (n == 1 ? msgid : msgid_plural);
+}
+
+#endif /* _LIBGETTEXT_H */
diff --git a/gawk/mbsupport.h b/gawk/mbsupport.h
new file mode 100644
index 00000000000..51cec3c7345
--- /dev/null
+++ b/gawk/mbsupport.h
@@ -0,0 +1,58 @@
+/*
+ * mbsupport.h --- Localize determination of whether we have multibyte stuff.
+ */
+
+/*
+ * Copyright (C) 2004, 2005, 2011, 2012, 2015, 2016
+ * the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK 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
+ */
+
+
+#ifdef __DJGPP__
+# undef MB_CUR_MAX
+# define MB_CUR_MAX 1
+
+/* All this glop is for DGJPP */
+
+#define towupper	toupper
+#define towlower	tolower
+#define iswalnum	isalnum
+#define iswalpha	isalpha
+#define iswupper	isupper
+#define iswlower	islower
+
+#define mbrtowc(wcp, s, e, mbs)	(-1)
+#define mbrlen(s, e, mbs)	strlen(s)
+#define wcrtomb(wc, b, mbs)	(-1)
+#define wcslen		strlen
+#define wctob(wc)	(EOF)
+
+#if (__DJGPP__ > 2 || __DJGPP_MINOR__ >= 3)
+# include <ctype.h>
+# include <wchar.h>
+# include <wctype.h>
+#else
+# define mbstate_t	int
+#endif
+
+extern wctype_t wctype(const char *name);
+extern int iswctype(wint_t wc, wctype_t desc);
+extern int wcscoll(const wchar_t *ws1, const wchar_t *ws2);
+#endif
diff --git a/gawk/protos.h b/gawk/protos.h
new file mode 100644
index 00000000000..4dd4a221390
--- /dev/null
+++ b/gawk/protos.h
@@ -0,0 +1,152 @@
+/*
+ * protos.h -- function prototypes for when the headers don't have them.
+ */
+
+/*
+ * Copyright (C) 1991 - 2002, 2011 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK 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
+ */
+
+#ifndef STDC_HEADERS
+
+#define aptr_t void *	/* arbitrary pointer type */
+extern aptr_t malloc(size_t);
+extern aptr_t realloc(aptr_t, size_t);
+extern aptr_t calloc(size_t, size_t);
+
+extern void free(aptr_t);
+extern char *getenv(const char *);
+
+#if ! defined(HAVE_STRING_H) && ! defined(HAVE_STRINGS_H)
+extern char *strcpy(char *, const char *);
+extern char *strcat(char *, const char *);
+extern char *strncpy(char *, const char *, size_t);
+extern int strcmp(const char *, const char *);
+extern int strncmp(const char *, const char *, size_t);
+extern char *strchr(const char *, int);
+extern char *strrchr(const char *, int);
+extern char *strstr(const char *s1, const char *s2);
+extern size_t strlen(const char *);
+extern long strtol(const char *, char **, int);
+
+extern aptr_t memset(aptr_t, int, size_t);
+extern aptr_t memcpy(aptr_t, const aptr_t, size_t);
+extern aptr_t memmove(aptr_t, const aptr_t, size_t);
+extern aptr_t memchr(const aptr_t, int, size_t);
+extern int memcmp(const aptr_t, const aptr_t, size_t);
+#endif /* ! defined(HAVE_STRING_H) && ! defined(HAVE_STRINGS_H) */
+
+#ifndef VMS
+extern char *strerror(int);
+#else
+extern char *strerror(int,...);
+#endif
+
+#if ! defined(__GNU_LIBRARY__)
+extern size_t strftime(char *, size_t, const char *, const struct tm *);
+#endif
+extern time_t time(time_t *);
+
+extern FILE *fdopen(int, const char *);
+extern int fprintf(FILE *, const char *, ...);
+#if ! defined(__GNU_LIBRARY__)
+extern size_t fwrite(const aptr_t, size_t, size_t, FILE *);
+#endif
+extern int fputs(const char *, FILE *);
+extern int unlink(const char *);
+extern int fflush(FILE *);
+extern int fclose(FILE *);
+extern FILE *popen(const char *, const char *);
+extern int pclose(FILE *);
+extern void abort();
+extern int isatty(int);
+extern void exit(int);
+extern int system(const char *);
+extern int sscanf(const char *, const char *, ...);
+#ifndef toupper
+extern int toupper(int);
+#endif
+#ifndef tolower
+extern int tolower(int);
+#endif
+
+extern double pow(double x, double y);
+extern double atof(const char *);
+extern double strtod(const char *, char **);
+extern int fstat(int, struct stat *);
+extern int stat(const char *, struct stat *);
+extern off_t lseek(int, off_t, int);
+extern int close(int);
+extern int creat(const char *, mode_t);
+extern int open(const char *, int, ...);
+extern int pipe(int *);
+extern int dup(int);
+extern int dup2(int,int);
+extern int fork();
+extern int execl(const char *, const char *, ...);
+#ifndef HAVE_SYS_WAIT_H
+extern int wait(int *);
+#endif
+extern void _exit(int);
+
+#undef aptr_t
+
+#endif /* STDC_HEADERS */
+
+
+/* prototypes for missing functions defined in missing_d/ */
+
+#ifndef HAVE_STRNCASECMP
+extern int strcasecmp(const char *s1, const char *s2);
+extern int strncasecmp(const char *s1, const char *s2, register size_t n);
+#endif
+
+#ifndef HAVE_STRTOUL
+extern unsigned long int strtoul(const char *, char **endptr, int base);
+#endif
+
+#ifndef HAVE_TZSET
+extern void tzset();
+#endif
+
+#ifndef HAVE_MKTIME
+extern time_t mktime(struct tm *tp);
+#endif
+
+#ifndef HAVE_TIMEGM
+extern time_t timegm(struct tm *);
+#endif
+
+#ifndef HAVE_SNPRINTF
+extern int snprintf(char *restrict buf, size_t len, const char *restrict fmt, ...);
+#endif
+
+#ifndef HAVE_USLEEP
+extern int usleep(unsigned int);
+#endif
+
+#ifndef HAVE_SETENV
+extern int setenv(const char *, const char *, int);
+extern int unsetenv(const char *);
+#endif
+
+#if !defined(HAVE_STRCOLL)
+extern int strcoll(const char *, const char *);
+#endif
+
diff --git a/gawk/support/dfa.h b/gawk/support/dfa.h
new file mode 100644
index 00000000000..2e25ef9f1ae
--- /dev/null
+++ b/gawk/support/dfa.h
@@ -0,0 +1,122 @@
+/* dfa.h - declarations for GNU deterministic regexp compiler
+   Copyright (C) 1988, 1998, 2007, 2009-2019 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 3, 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 */
+
+/* Written June, 1988 by Mike Haertel */
+
+#include <regex.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct localeinfo; /* See localeinfo.h.  */
+
+/* Element of a list of strings, at least one of which is known to
+   appear in any R.E. matching the DFA. */
+struct dfamust
+{
+  bool exact;
+  bool begline;
+  bool endline;
+  char *must;
+};
+
+/* The dfa structure. It is completely opaque. */
+struct dfa;
+
+/* Entry points. */
+
+/* Allocate a struct dfa.  The struct dfa is completely opaque.
+   The returned pointer should be passed directly to free() after
+   calling dfafree() on it. */
+extern struct dfa *dfaalloc (void) /* _GL_ATTRIBUTE_MALLOC */;
+
+/* DFA options that can be ORed together, for dfasyntax's 4th arg.  */
+enum
+  {
+    /* ^ and $ match only the start and end of data, and do not match
+       end-of-line within data.  This is always false for grep, but
+       possibly true for other apps.  */
+    DFA_ANCHOR = 1 << 0,
+
+    /* '\0' in data is end-of-line, instead of the traditional '\n'.  */
+    DFA_EOL_NUL = 1 << 1
+  };
+
+/* Initialize or reinitialize a DFA.  This must be called before
+   any of the routines below.  The arguments are:
+   1. The DFA to operate on.
+   2. Information about the current locale.
+   3. Syntax bits described in regex.h.
+   4. Additional DFA options described above.  */
+extern void dfasyntax (struct dfa *, struct localeinfo const *,
+                       reg_syntax_t, int);
+
+/* Build and return the struct dfamust from the given struct dfa. */
+extern struct dfamust *dfamust (struct dfa const *);
+
+/* Free the storage held by the components of a struct dfamust. */
+extern void dfamustfree (struct dfamust *);
+
+/* Compile the given string of the given length into the given struct dfa.
+   Final argument is a flag specifying whether to build a searching or an
+   exact matcher. */
+extern void dfacomp (char const *, size_t, struct dfa *, bool);
+
+/* Search through a buffer looking for a match to the given struct dfa.
+   Find the first occurrence of a string matching the regexp in the
+   buffer, and the shortest possible version thereof.  Return a pointer to
+   the first character after the match, or NULL if none is found.  BEGIN
+   points to the beginning of the buffer, and END points to the first byte
+   after its end.  Note however that we store a sentinel byte (usually
+   newline) in *END, so the actual buffer must be one byte longer.
+   When ALLOW_NL is true, newlines may appear in the matching string.
+   If COUNT is non-NULL, increment *COUNT once for each newline processed.
+   Finally, if BACKREF is non-NULL set *BACKREF to indicate whether we
+   encountered a back-reference.  The caller can use this to decide
+   whether to fall back on a backtracking matcher.  */
+extern char *dfaexec (struct dfa *d, char const *begin, char *end,
+                      bool allow_nl, size_t *count, bool *backref);
+
+/* Return a superset for D.  The superset matches everything that D
+   matches, along with some other strings (though the latter should be
+   rare, for efficiency reasons).  Return a null pointer if no useful
+   superset is available.  */
+extern struct dfa *dfasuperset (struct dfa const *d) _GL_ATTRIBUTE_PURE;
+
+/* The DFA is likely to be fast.  */
+extern bool dfaisfast (struct dfa const *) _GL_ATTRIBUTE_PURE;
+
+/* Copy the syntax settings from one dfa instance to another.
+   Saves considerable computation time if compiling many regular expressions
+   based on the same setting.  */
+extern void dfacopysyntax (struct dfa *to, const struct dfa *from);
+
+/* Free the storage held by the components of a struct dfa. */
+extern void dfafree (struct dfa *);
+
+/* Error handling. */
+
+/* dfawarn() is called by the regexp routines whenever a regex is compiled
+   that likely doesn't do what the user wanted.  It takes a single
+   argument, a NUL-terminated string describing the situation.  The user
+   must supply a dfawarn.  */
+extern void dfawarn (const char *);
+
+/* dfaerror() is called by the regexp routines whenever an error occurs.  It
+   takes a single argument, a NUL-terminated string describing the error.
+   The user must supply a dfaerror.  */
+extern _Noreturn void dfaerror (const char *);
-- 
2.21.0

