aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore18
-rw-r--r--ChangeLog126
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.in20
-rw-r--r--README.git218
-rw-r--r--array.c1384
-rw-r--r--awk.h530
-rw-r--r--awkgram.c2700
-rw-r--r--awkgram.y1159
-rw-r--r--awklib/.gitignore8
-rw-r--r--builtin.c63
-rw-r--r--cint_array.c1232
-rw-r--r--cmd.h3
-rw-r--r--command.c254
-rw-r--r--command.y74
-rwxr-xr-xconfigure24
-rw-r--r--configure.ac6
-rw-r--r--debug.c317
-rw-r--r--doc/ChangeLog4
-rw-r--r--doc/gawk.info203
-rw-r--r--doc/gawk.texi29
-rw-r--r--eval.c522
-rw-r--r--ext.c150
-rw-r--r--extension/ChangeLog4
-rw-r--r--extension/arrayparm.c8
-rw-r--r--extension/filefuncs.c44
-rw-r--r--extension/fork.c8
-rw-r--r--extension/ordchr.c4
-rw-r--r--extension/readfile.c2
-rw-r--r--extension/rwarray.c6
-rw-r--r--extension/testarg.c8
-rw-r--r--field.c28
-rw-r--r--int_array.c826
-rw-r--r--io.c9
-rw-r--r--main.c137
-rw-r--r--node.c168
-rw-r--r--pc/ChangeLog4
-rw-r--r--pc/Makefile.tst43
-rw-r--r--po/.gitignore4
-rw-r--r--po/ast.gmobin37068 -> 0 bytes
-rw-r--r--po/ca.gmobin25787 -> 0 bytes
-rw-r--r--po/ga.gmobin33929 -> 0 bytes
-rw-r--r--po/he.gmobin24651 -> 0 bytes
-rw-r--r--po/id.gmobin35809 -> 0 bytes
-rw-r--r--po/pt_BR.gmobin29120 -> 0 bytes
-rw-r--r--po/ro.gmobin25383 -> 0 bytes
-rw-r--r--po/rw.gmobin487 -> 0 bytes
-rw-r--r--po/tr.gmobin33826 -> 0 bytes
-rw-r--r--po/vi.gmobin40445 -> 0 bytes
-rw-r--r--po/zh_CN.gmobin33717 -> 0 bytes
-rw-r--r--profile.c40
-rw-r--r--str_array.c759
-rw-r--r--symbol.c718
-rw-r--r--test/Makefile.am1
-rw-r--r--test/Makefile.in3
-rw-r--r--test/Maketests2
-rw-r--r--test/delfunc.ok5
-rw-r--r--test/fnamedat.ok5
-rw-r--r--test/fnarray.ok2
-rw-r--r--test/fnarray2.in1
-rw-r--r--test/fnarray2.ok4
-rw-r--r--test/fnarydel.ok10
-rw-r--r--test/fnasgnm.ok5
-rw-r--r--test/fnparydl.ok6
-rw-r--r--test/funsmnam.ok2
-rw-r--r--test/gsubasgn.ok8
-rw-r--r--test/match2.ok5
-rw-r--r--version.c2
68 files changed, 7125 insertions, 4804 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..e2ae74d3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+# Ignore files that are created by a build.
+# For example objects and archives.
+*.[oa]
+
+# Directories
+autom4te.cache
+.deps
+
+# Single files.
+Makefile
+config.h
+config.log
+config.status
+dgawk
+gawk
+pgawk
+stamp-h1
+
diff --git a/ChangeLog b/ChangeLog
index 075809d5..8945a6bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -57,6 +57,14 @@
2011-10-25 Arnold D. Robbins <arnold@skeeve.com>
+ Merge with gawk_performance branch done. Additionally:
+
+ * cint_array.c, int_array.c, str_array.c: Fix compiler complaints
+ about printf formats (signed / unsigned vs. %d / %u).
+ * eval.c (setup_frame): Add a missing return value.
+
+2011-10-25 Arnold D. Robbins <arnold@skeeve.com>
+
* Makefile.am (dist-hook): Use `cd $(srcdir)/pc' so that
`make distcheck' works completely.
* builtin.c (do_strftime): Add cast to long int in check
@@ -128,10 +136,25 @@
(remap_std_file): Per Eli's suggestion, removed the leading close
of oldfd and will let dup2 do the close for us.
+2011-10-11 John Haque <j.eh@mchsi.com>
+
+ * symbol.c: Add licence notice.
+ * array.c (PREC_NUM, PREC_STR): Define as macros.
+
2011-10-09 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c: Sync with GNU grep.
+2011-10-07 John Haque <j.eh@mchsi.com>
+
+ Tail recursion optimization.
+ * awkgram.y (grammar, mk_function): Recognize tail-recursive
+ calls.
+ * awk.h (tail_call, num_tail_calls): New defines.
+ * eval.c (setup_frame): Reuse function call stack for
+ tail-recursive calls.
+ (dump_fcall_stack): Reworked.
+
2011-10-04 Arnold D. Robbins <arnold@skeeve.com>
* awk.h, main.c (gawk_mb_cur_max): Make it a constant 1 when
@@ -168,10 +191,113 @@
* dfa.c: Sync with GNU grep.
+2011-09-08 John Haque <j.eh@mchsi.com>
+
+ Optimization for compound assignment, increment and
+ decrement operators; Avoid unref and make_number calls
+ when there is no extra references to the value NODE.
+
2011-09-03 Arnold D. Robbins <arnold@skeeve.com>
* dfa.c: Sync with GNU grep.
+2011-08-31 John Haque <j.eh@mchsi.com>
+
+ Grammar related changes: Simplify grammar for user-defined
+ functions and general cleanups.
+
+ * symbol.c: New file.
+ * awkgram.y: Move symbol table related routines to the
+ new file.
+ (rule, func_name, function_prologue, param_list): Reworked.
+ (install_function, check_params): Do all error checkings
+ for the function name and parameters before installing in
+ the symbol table.
+ (mk_function): Finalize function definition.
+ (func_install, append_param, dup_params): Nuked.
+ * symbol.c (make_params): allocate function parameter nodes
+ for the symbol table. Use the hash node as Node_param_list;
+ Saves a NODE for each parameter.
+ (install_params): Install function parameters into the symbol
+ table.
+ (remove_params): Remove parameters out of the symbol table.
+ * awk.h (parmlist, FUNC): Nuked.
+ (fparms): New define.
+
+
+ Dynamically loaded function parameters are now handled like
+ those for a builtin.
+
+ * awk.h (Node_ext_func, Op_ext_builtin): New types.
+ (Op_ext_func): Nuked.
+ * ext.c (make_builtin): Simplified.
+ (get_curfunc_arg_count): Nuked; Use the argument 'nargs' of
+ the extension function instead.
+ (get_argument, get_actual_argument): Adjust.
+ * eval.c (r_interpret): Update case Op_func_call for a dynamic
+ extension function. Handle the new opcode Op_ext_builtin.
+ * pprint (profile.c): Adjust.
+
+
+ Use a single variable to process gawk options.
+
+ * awk.h (do_flags): New variable.
+ (DO_LINT_INVALID, DO_LINT_ALL, DO_LINT_OLD, DO_TRADITIONAL,
+ DO_POSIX, DO_INTL, DO_NON_DEC_DATA, DO_INTERVALS,
+ DO_PROFILING, DO_DUMP_VARS, DO_TIDY_MEM,
+ DO_SANDBOX): New defines.
+ (do_traditional, do_posix, do_intervals, do_intl,
+ do_non_decimal_data, do_profiling, do_dump_vars,
+ do_tidy_mem, do_sandbox, do_lint,
+ do_lint_old): Defined as macros.
+ * main.c: Remove definitions of the do_XX variables. Add
+ do_flags definition.
+ * debug.c (execute_code, do_eval, parse_condition): Save
+ do_flags before executing/parsing and restore afterwards.
+
+
+ Nuke PERM flag. Always increment/decrement the reference
+ count for a Node_val. Simplifies macros and avoids
+ occassional memory leaks, specially in the debugger.
+
+ * awk.h (UPREF, DEREF, dupnode, unref): Simplified.
+ (mk_number): Nuked.
+ * (*.c): Increment the reference count of Nnull_string before
+ assigning as a value.
+
+
+ Revamped array handling mechanism for more speed and
+ less memory consumption.
+
+ * awk.h (union bucket_item, BUCKET): New definitions. Used as
+ bucket elements for the hash table implementations of arrays;
+ 40% space saving in 32 bit x86.
+ (buckets, nodes, array_funcs, array_base, array_capacity,
+ xarray, alookup, aexists, aclear, aremove, alist,
+ acopy, adump, NUM_AFUNCS): New defines.
+ (array_empty): New macro to test for an empty array.
+ (assoc_lookup, in_array): Defined as macros.
+ (enum assoc_list_flags): New declaration.
+ (Node_ahash, NUMIND): Nuked.
+ * eval.c (r_interpret): Adjust cases Op_subscript,
+ Op_subscript_lhs, Op_store_var and Op_arrayfor_incr.
+ * node.c (dupnode, unref): Removed code related to Node_ahash.
+ * str_array.c: New file to handle array with string indices.
+ * int_array.c: New file to handle array with integer indices.
+ * cint_array.c: New file. Special handling of arrays with
+ (mostly) consecutive integer indices.
+
+
+ Memory pool management reworked to handle NODE and BUCKET.
+
+ * awk.h (struct block_item, BLOCK, block_id): New definitions.
+ (getblock, freeblock): New macros.
+ (getbucket, freebucket): New macros to allocate and deallocate
+ a BUCKET.
+ (getnode, freenode): Adjusted.
+ * node.c (more_nodes): Nuked.
+ (more_blocks): New routine to allocate blocks of memory.
+
2011-08-24 Arnold D. Robbins <arnold@skeeve.com>
Fix pty co-process communication on Ubuntu GNU/Linux.
diff --git a/Makefile.am b/Makefile.am
index aeff42f5..e9248506 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,6 +87,7 @@ base_sources = \
awk.h \
awkgram.y \
builtin.c \
+ cint_array.c \
custom.h \
dfa.c \
dfa.h \
@@ -100,6 +101,7 @@ base_sources = \
getopt1.c \
getopt_int.h \
gettext.h \
+ int_array.c \
io.c \
mbsupport.h \
main.c \
@@ -112,6 +114,8 @@ base_sources = \
regex.c \
regex.h \
replace.c \
+ str_array.c \
+ symbol.c \
version.c \
xalloc.h
diff --git a/Makefile.in b/Makefile.in
index c8208d94..26d6017b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -88,11 +88,13 @@ CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
- dfa.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
- floatcomp.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \
- getopt1.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) msg.$(OBJEXT) \
- node.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
- replace.$(OBJEXT) version.$(OBJEXT)
+ cint_array.$(OBJEXT) dfa.$(OBJEXT) ext.$(OBJEXT) \
+ field.$(OBJEXT) floatcomp.$(OBJEXT) gawkmisc.$(OBJEXT) \
+ getopt.$(OBJEXT) getopt1.$(OBJEXT) int_array.$(OBJEXT) \
+ io.$(OBJEXT) main.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
+ random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
+ replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
+ version.$(OBJEXT)
am_dgawk_OBJECTS = $(am__objects_1) eval_d.$(OBJEXT) profile.$(OBJEXT) \
command.$(OBJEXT) debug.$(OBJEXT)
dgawk_OBJECTS = $(am_dgawk_OBJECTS)
@@ -361,6 +363,7 @@ base_sources = \
awk.h \
awkgram.y \
builtin.c \
+ cint_array.c \
custom.h \
dfa.c \
dfa.h \
@@ -374,6 +377,7 @@ base_sources = \
getopt1.c \
getopt_int.h \
gettext.h \
+ int_array.c \
io.c \
mbsupport.h \
main.c \
@@ -386,6 +390,8 @@ base_sources = \
regex.c \
regex.h \
replace.c \
+ str_array.c \
+ symbol.c \
version.c \
xalloc.h
@@ -518,6 +524,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awkgram.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builtin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cint_array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dfa.Po@am__quote@
@@ -530,6 +537,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gawkmisc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int_array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg.Po@am__quote@
@@ -540,6 +548,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/re.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/replace.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str_array.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
.c.o:
diff --git a/README.git b/README.git
index f14588e1..59079598 100644
--- a/README.git
+++ b/README.git
@@ -18,6 +18,224 @@ comp.lang.awk is generally a bad idea, no matter what the purpose, but
especially if you wish to report a gawk bug. Use the above email address.
Really.
+You can find gawk's GIT repository at Savannah
+https://savannah.gnu.org/git/?group=gawk
+Detailed instructions on using and contributing to gawk can also be
+found there
+http://savannah.gnu.org/maintenance/UsingGit
+
+
+- How can I check out the GIT repository ?
+
+Depending upon your working habits, there are several options.
+1. On the Linux command line use the git command (details see below)
+2. With Microsoft Windows, use TortoiseGIT
+3. On both platforms Eclipse with its EGIT plugin is an excellent choice
+
+On the Linux command line use git to check out the repository.
+With Microsoft Windows, use TortoiseGIT.
+
+
+- Where is TortoiseGIT and how do I install it ?
+
+Follow these instructions for installation:
+ https://github.com/multitheftauto/multitheftauto/wiki/how-to-use-tortoisegit
+
+Begin with installing Putty, then msysgit and finally TortoiseGIT.
+Find Putty at http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
+
+
+- What about the SSH keys needed when Windows is my primary environment ?
+
+On Windows you may use Puttygen for generating keys.
+Save both keys (public and private) in a local .ppk file.
+Notice that this file is highly confidential and even other
+team members are not supposed to see your keys.
+Finally you need to convert Putty's keys (.ppk file) so that they
+can also be used on Linux.
+ http://www.laszlomolnar.name/open-source/tips-and-tutorials/how-to-convert-puttys-private-key-ppk-into-opensshs-private-key-format-in-linux.html
+
+ puttygen my_keys.ppk -O private-openssh -o .ssh/id_rsa
+ puttygen my_keys.ppk -O public-openssh -o .ssh/id_rsa.pub
+
+
+- What about the SSH keys needed when Linux is my primary environment ?
+
+On Linux follow these instructions to generate keys:
+http://www.guyrutenberg.com/2007/10/05/ssh-keygen-tutorial-generating-rsa-and-dsa-keys/
+If you ever need these keys inside a Windows environment, use Puttygen
+to import the already existing keys.
+
+
+- I know Subversion, now what's different with git ?
+
+Read the "Git - SVN Crash Course". It lists the Subversion commands that
+are roughly equivalent to certain git commands:
+ http://www.pronego.com/helpdesk/knowledgebase.php?article=49
+This document is only one of many copies of the document on the Internet.
+You should read the original (which is currently offline and unreachable):
+ https://git.wiki.kernel.org/index.php/GitSvnCrashCourse
+
+
+- How can I check out this repository inside a clean subdirectory ?
+
+ mkdir -p workspace/git
+ cd workspace/git
+ git clone git://git.sv.gnu.org/project.git
+
+ git remote -v
+ origin ssh://jkahrs@git.sv.gnu.org/srv/git/gawk.git (fetch)
+ origin ssh://jkahrs@git.sv.gnu.org/srv/git/gawk.git (push)
+
+
+- How can I check out this repository with Eclipse ?
+
+Use the most recent version of Eclipse, it already comes with the
+EGIT plugin installed.
+ Select File -> Import -> Git -> Git Repository.
+ Press clone and maintain the git repository "ssh://jkahrs@git.sv.gnu.org/srv/git/gawk.git".
+ You only have to paste the URL to the first line of the dialog,
+ the rest will be filled out automatically.
+
+You can find details in the EGIT tutorial.
+ http://www.vogella.de/articles/EGit/article.html#respository_checkoutproject
+
+
+- Can I start adding new files to the repository right now ?
+Yes, you can, but you should not do so.
+Convention with branches.
+
+But first you should make sure some global settings identifying
+you are set. The global settings will be used every time you commit
+something to the repository.
+
+ git config --global user.name "First-Name Last-Name"
+ git config --global user.email email@address.site
+ git config --global color.ui auto
+
+
+- How can I inspect my settings ?
+
+
+ git config --list
+ giggle.main-window-maximized=false
+ giggle.main-window-geometry=1369x753+183+81
+ giggle.main-window-view=HistoryView
+ giggle.history-view-vpane-position=389
+ giggle.file-view-vpane-position=293
+ user.name=First-Name Last-Name
+ user.email=email@address.site
+ color.diff=auto
+ color.status=auto
+ color.branch=auto
+ gui.spellingdictionary=en_US
+ core.repositoryformatversion=0
+ core.filemode=true
+ core.bare=false
+ core.logallrefupdates=true
+ remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
+ remote.origin.url=ssh://jkahrs@git.sv.gnu.org/srv/git/gawk.git
+ branch.master.remote=origin
+ branch.master.merge=refs/heads/master
+ branch.xgawk_load.remote=origin
+ branch.xgawk_load.merge=refs/heads/xgawk_load
+
+
+- How can I get or set a specific variable of the settings ?
+
+ git config --get color.ui
+ git config --set color.ui auto
+
+
+- How can I create new files or directories to the repository ?
+
+ touch README
+ git add README
+ git commit -m "first commit"
+
+
+- What did I change since the last commit ?
+
+ git diff README
+ git diff
+
+
+- I have committed everything to my local repository, now how can I
+ "push" these changes up to gawk.git ?
+
+ git push -u origin master # push up to master branch
+ git push -u origin my_feature_branch # push up to my own branch
+
+
+- How can I inspect the list of branches of my repository ?
+
+ git branch # shows all local branches
+ git branch -r # shows all remote branches
+ git branch -a # shows all local and all remote branches
+
+
+- How can I change to a different branch ?
+
+ git checkout my_stuff # change to branch my_stuff
+ git checkout -b my_stuff # create new branch my_stuff and change to it
+
+- How can I create a branch ?
+
+For each new feature to be considered for inclusion into future
+releasses, a new branch shall be created. Upon creation, this new
+branch shall be based on the master branch.
+
+ # make master branch the base
+ git checkout master
+ git branch my_new_feature_branch
+ touch my_new_file.c
+ git add my_new_file.c
+ git status
+ git commit -m "Created new feature branch."
+ git push -u origin my_new_feature_branch
+ git checkout my_new_feature_branch
+
+- How can I throw away an obsolete branch ?
+
+ git push origin :newfeature # remove remote branch
+ git checkout -f master # switch back from newfeature to master, ignoring changes
+ git branch -D newfeature # remove local branch
+
+
+- I have made stupid changes to a file and want the original back, how ?
+
+ svn checkout file_name.ext
+
+ This will only work if the file was not yet committed.
+ If you have already committed the change and want back the
+ last pushed version, use "git reset" instead.
+
+
+- Who changed a specific line in my file ?
+
+Sometimes you need to find out whom to blame for a certain line of a change.
+git can tell you for each line who did the most recent change of the line.
+
+ git blame README
+
+
+- Who else has ever changed my file, when and why ?
+
+You can inspect the log history file-wise but also directory-wise.
+
+ git log README
+ git log
+
+
+- How to fix a broken repository ?
+
+ git fsck
+
+- How to clean up my repository (garbage collection) ?
+
+ git gc
+
+
Thanks,
Arnold Robbins
diff --git a/array.c b/array.c
index e814e976..90679b72 100644
--- a/array.c
+++ b/array.c
@@ -1,5 +1,5 @@
/*
- * array.c - routines for associative arrays.
+ * array.c - routines for awk arrays.
*/
/*
@@ -25,69 +25,193 @@
#include "awk.h"
+extern FILE *output_fp;
+extern NODE **fmt_list; /* declared in eval.c */
+extern array_ptr str_array_func[];
+extern array_ptr cint_array_func[];
+extern array_ptr int_array_func[];
+
+static size_t SUBSEPlen;
+static char *SUBSEP;
+static char indent_char[] = " ";
+
+static NODE **e_lookup(NODE *symbol, NODE *subs);
+static array_ptr empty_array_func[NUM_AFUNCS] = {
+ (array_ptr) 0,
+ (array_ptr) 0,
+ e_lookup,
+};
+
+#define MAX_ATYPE 10
+
+static array_ptr *atypes[MAX_ATYPE];
+static int num_atypes = 0;
+
/*
- * Tree walks (``for (iggy in foo)'') and array deletions use expensive
- * linear searching. So what we do is start out with small arrays and
- * grow them as needed, so that our arrays are hopefully small enough,
- * most of the time, that they're pretty full and we're not looking at
- * wasted space.
- *
- * The decision is made to grow the array if the average chain length is
- * ``too big''. This is defined as the total number of entries in the table
- * divided by the size of the array being greater than some constant.
+ * register_array_func --- add routines to handle arrays.
*
- * We make the constant a variable, so that it can be tweaked
- * via environment variable.
+ * index 0 : initialization.
+ * index 1 : check if index is compatible.
+ * index 8 : array dump, memory and other statistics (do_adump).
*/
+
+
+int
+register_array_func(array_ptr *afunc)
+{
+ if (afunc && num_atypes < MAX_ATYPE) {
+ if (afunc != str_array_func && ! afunc[1])
+ return FALSE;
+ atypes[num_atypes++] = afunc;
+ if (afunc[0]) /* execute init routine if any */
+ (void) (*afunc[0])(NULL, NULL);
+ return TRUE;
+ }
+ return FALSE;
+}
-static size_t AVG_CHAIN_MAX = 2; /* Modern machines are bigger, reduce this from 10. */
-static size_t SUBSEPlen;
-static char *SUBSEP;
+/* array_init --- register all builtin array types */
+
+void
+array_init()
+{
+ (void) register_array_func(str_array_func); /* the default */
+ (void) register_array_func(int_array_func);
+ (void) register_array_func(cint_array_func);
+}
-static NODE *assoc_find(NODE *symbol, NODE *subs, unsigned long hash1, NODE **last);
-static void grow_table(NODE *symbol);
-static unsigned long gst_hash_string(const char *str, size_t len, unsigned long hsize, size_t *code);
-static unsigned long scramble(unsigned long x);
-static unsigned long awk_hash(const char *s, size_t len, unsigned long hsize, size_t *code);
+/* make_array --- create an array node */
-unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t *code) = awk_hash;
+NODE *
+make_array()
+{
+ NODE *array;
+ getnode(array);
+ memset(array, '\0', sizeof(NODE));
+ array->type = Node_var_array;
+ array->array_funcs = empty_array_func;
+ /* vname, flags, and parent_array not set here */
-/* qsort comparison function */
-static int sort_up_index_string(const void *, const void *);
-static int sort_down_index_string(const void *, const void *);
-static int sort_up_index_number(const void *, const void *);
-static int sort_down_index_number(const void *, const void *);
-static int sort_up_value_string(const void *, const void *);
-static int sort_down_value_string(const void *, const void *);
-static int sort_up_value_number(const void *, const void *);
-static int sort_down_value_number(const void *, const void *);
-static int sort_up_value_type(const void *, const void *);
-static int sort_down_value_type(const void *, const void *);
+ return array;
+}
-/* array_init --- check relevant environment variables */
+
+/* init_array --- initialize an array node */
void
-array_init()
+init_array(NODE *symbol)
+{
+ symbol->type = Node_var_array;
+ symbol->array_funcs = empty_array_func;
+ symbol->buckets = NULL;
+ symbol->table_size = symbol->array_size = 0;
+ symbol->array_capacity = 0;
+
+ assert(symbol->xarray == NULL);
+ /* symbol->xarray = NULL; */
+
+ /* flags, vname, parent_array not (re)initialized */
+}
+
+
+/* e_lookup: assign type to an empty array. */
+
+static NODE **
+e_lookup(NODE *symbol, NODE *subs)
+{
+ int i;
+ array_ptr *afunc = NULL;
+
+ assert(array_empty(symbol) == TRUE);
+
+ /* Check which array type wants to accept this sub; traverse
+ * array type list in reverse order.
+ */
+ for (i = num_atypes - 1; i >= 1; i--) {
+ afunc = atypes[i];
+ if (afunc[1](symbol, subs) != NULL)
+ break;
+ }
+ if (i == 0 || afunc == NULL)
+ afunc = atypes[0]; /* default is str_array_func */
+ symbol->array_funcs = afunc;
+
+ /* We have the right type of array; install the subscript */
+ return symbol->alookup(symbol, subs);
+}
+
+
+/* assoc_clear --- flush all the values in symbol[] */
+
+void
+assoc_clear(NODE *symbol)
+{
+ if (! array_empty(symbol))
+ (void) symbol->aclear(symbol, NULL);
+}
+
+
+/* r_in_array --- test whether the array element symbol[subs] exists or not,
+ * return pointer to value if it does.
+ */
+
+NODE *
+r_in_array(NODE *symbol, NODE *subs)
+{
+ NODE **ret;
+
+ if (array_empty(symbol))
+ return NULL;
+ ret = symbol->aexists(symbol, subs);
+ return (ret ? *ret : NULL);
+}
+
+
+/* assoc_remove --- remove an index from symbol[] */
+
+int
+assoc_remove(NODE *symbol, NODE *subs)
{
- const char *val;
- char *endptr;
- size_t newval;
-
- if ((val = getenv("AVG_CHAIN_MAX")) != NULL && isdigit((unsigned char) *val)) {
- newval = strtoul(val, & endptr, 10);
- if (endptr != val && newval > 0)
- AVG_CHAIN_MAX = newval;
+ if (array_empty(symbol))
+ return FALSE;
+ return (symbol->aremove(symbol, subs) != NULL);
+}
+
+
+/* assoc_copy --- duplicate input array "symbol" */
+
+NODE *
+assoc_copy(NODE *symbol, NODE *newsymb)
+{
+ assert(newsymb->vname != NULL);
+
+ assoc_clear(newsymb);
+ if (! array_empty(symbol)) {
+ (void) symbol->acopy(symbol, newsymb);
+ newsymb->array_funcs = symbol->array_funcs;
+ newsymb->flags = symbol->flags;
}
+ return newsymb;
+}
+
+
+/* assoc_dump --- dump array */
- if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
- hash = gst_hash_string;
+void
+assoc_dump(NODE *symbol, NODE *ndump)
+{
+ if (array_empty(symbol))
+ fprintf(output_fp, "array `%s' is empty\n", array_vname(symbol));
+ else if (symbol->adump)
+ (void) symbol->adump(symbol, ndump);
}
+
/* make_aname --- construct a 'vname' for a (sub)array */
-static char *
+const char *
make_aname(const NODE *symbol)
{
static char *aname = NULL;
@@ -115,10 +239,11 @@ make_aname(const NODE *symbol)
erealloc(aname, char *, (max_alen + 1) * sizeof(char *), "make_aname");
}
memcpy(aname, symbol->vname, alen + 1);
- }
+ }
return aname;
-#undef SLEN
}
+#undef SLEN
+
/*
* array_vname --- print the name of the array
@@ -128,7 +253,7 @@ make_aname(const NODE *symbol)
* to save it, they have to make a copy.
*/
-char *
+const char *
array_vname(const NODE *symbol)
{
static char *message = NULL;
@@ -164,7 +289,6 @@ array_vname(const NODE *symbol)
else
aname = make_aname(symbol);
len += strlen(aname);
-
/*
* Each node contributes by strlen(from) minus the length
* of "%s" in the translation (which is at least 2)
@@ -218,7 +342,7 @@ get_array(NODE *symbol, int canfatal)
NODE *save_symbol = symbol;
int isparam = FALSE;
- if (symbol->type == Node_param_list && (symbol->flags & FUNC) == 0) {
+ if (symbol->type == Node_param_list) {
save_symbol = symbol = GET_PARAM(symbol->param_cnt);
isparam = TRUE;
if (symbol->type == Node_array_ref)
@@ -227,35 +351,24 @@ get_array(NODE *symbol, int canfatal)
switch (symbol->type) {
case Node_var_new:
- symbol->type = Node_var_array;
- symbol->var_array = NULL;
+ init_array(symbol);
symbol->parent_array = NULL; /* main array has no parent */
/* fall through */
case Node_var_array:
break;
case Node_array_ref:
- case Node_param_list:
- if ((symbol->flags & FUNC) == 0)
- cant_happen();
- /* else
- fall through */
-
default:
- /* notably Node_var but catches also e.g. FS[1] = "x" */
+ /* notably Node_var but catches also e.g. a[1] = "x"; a[1][1] = "y" */
if (canfatal) {
if (symbol->type == Node_val)
fatal(_("attempt to use a scalar value as array"));
-
- if ((symbol->flags & FUNC) != 0)
- fatal(_("attempt to use function `%s' as an array"),
- save_symbol->vname);
- else if (isparam)
+ if (isparam)
fatal(_("attempt to use scalar parameter `%s' as an array"),
- save_symbol->vname);
+ save_symbol->vname);
else
fatal(_("attempt to use scalar `%s' as an array"),
- save_symbol->vname);
+ save_symbol->vname);
} else
break;
}
@@ -269,16 +382,18 @@ get_array(NODE *symbol, int canfatal)
void
set_SUBSEP()
{
- SUBSEP = force_string(SUBSEP_node->var_value)->stptr;
+ SUBSEP_node->var_value = force_string(SUBSEP_node->var_value);
+ SUBSEP = SUBSEP_node->var_value->stptr;
SUBSEPlen = SUBSEP_node->var_value->stlen;
-}
+}
+
/* concat_exp --- concatenate expression list into a single string */
NODE *
concat_exp(int nargs, int do_subsep)
{
- /* do_subsep is false for Node-concat */
+ /* do_subsep is FALSE for Op_concat */
NODE *r;
char *str;
char *s;
@@ -295,13 +410,14 @@ concat_exp(int nargs, int do_subsep)
len = 0;
for (i = 1; i <= nargs; i++) {
- r = POP();
+ r = TOP();
if (r->type == Node_var_array) {
while (--i > 0)
DEREF(args_array[i]); /* avoid memory leak */
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(r));
- }
- args_array[i] = force_string(r);
+ }
+ r = POP_STRING();
+ args_array[i] = r;
len += r->stlen;
}
len += (nargs - 1) * subseplen;
@@ -329,246 +445,6 @@ concat_exp(int nargs, int do_subsep)
}
-/* assoc_clear --- flush all the values in symbol[] */
-
-void
-assoc_clear(NODE *symbol)
-{
- long i;
- NODE *bucket, *next;
-
- if (symbol->var_array == NULL)
- return;
-
- for (i = 0; i < symbol->array_size; i++) {
- for (bucket = symbol->var_array[i]; bucket != NULL; bucket = next) {
- next = bucket->ahnext;
- if (bucket->ahvalue->type == Node_var_array) {
- NODE *r = bucket->ahvalue;
- assoc_clear(r); /* recursively clear all sub-arrays */
- efree(r->vname);
- freenode(r);
- } else
- unref(bucket->ahvalue);
-
- unref(bucket); /* unref() will free the ahname_str */
- }
- symbol->var_array[i] = NULL;
- }
- efree(symbol->var_array);
- symbol->var_array = NULL;
- symbol->array_size = symbol->table_size = 0;
- symbol->flags &= ~ARRAYMAXED;
-}
-
-/* awk_hash --- calculate the hash function of the string in subs */
-
-static unsigned long
-awk_hash(const char *s, size_t len, unsigned long hsize, size_t *code)
-{
- unsigned long h = 0;
- unsigned long htmp;
-
- /*
- * Ozan Yigit's original sdbm hash, copied from Margo Seltzers
- * db package.
- *
- * This is INCREDIBLY ugly, but fast. We break the string up into
- * 8 byte units. On the first time through the loop we get the
- * "leftover bytes" (strlen % 8). On every other iteration, we
- * perform 8 HASHC's so we handle all 8 bytes. Essentially, this
- * saves us 7 cmp & branch instructions. If this routine is
- * heavily used enough, it's worth the ugly coding.
- */
-
- /*
- * Even more speed:
- * #define HASHC h = *s++ + 65599 * h
- * Because 65599 = pow(2, 6) + pow(2, 16) - 1 we multiply by shifts
- *
- * 4/2011: Force the results to 32 bits, to get the same
- * result on both 32- and 64-bit systems. This may be a
- * bad idea.
- */
-#define HASHC htmp = (h << 6); \
- h = *s++ + htmp + (htmp << 10) - h ; \
- htmp &= 0xFFFFFFFF; \
- h &= 0xFFFFFFFF
-
- h = 0;
-
- /* "Duff's Device" */
- if (len > 0) {
- size_t loop = (len + 8 - 1) >> 3;
-
- switch (len & (8 - 1)) {
- case 0:
- do { /* All fall throughs */
- HASHC;
- case 7: HASHC;
- case 6: HASHC;
- case 5: HASHC;
- case 4: HASHC;
- case 3: HASHC;
- case 2: HASHC;
- case 1: HASHC;
- } while (--loop);
- }
- }
-
- if (code != NULL)
- *code = h;
-
- if (h >= hsize)
- h %= hsize;
- return h;
-}
-
-/* assoc_find --- locate symbol[subs] */
-
-static NODE * /* NULL if not found */
-assoc_find(NODE *symbol, NODE *subs, unsigned long hash1, NODE **last)
-{
- NODE *bucket, *prev;
- const char *s1_str;
- size_t s1_len;
- NODE *s2;
-
- for (prev = NULL, bucket = symbol->var_array[hash1]; bucket != NULL;
- prev = bucket, bucket = bucket->ahnext) {
- /*
- * This used to use cmp_nodes() here. That's wrong.
- * Array indices are strings; compare as such, always!
- */
- s1_str = bucket->ahname_str;
- s1_len = bucket->ahname_len;
- s2 = subs;
-
- if (s1_len == s2->stlen) {
- if (s1_len == 0 /* "" is a valid index */
- || memcmp(s1_str, s2->stptr, s1_len) == 0)
- break;
- }
- }
- if (last != NULL)
- *last = prev;
- return bucket;
-}
-
-/* in_array --- test whether the array element symbol[subs] exists or not,
- * return pointer to value if it does.
- */
-
-NODE *
-in_array(NODE *symbol, NODE *subs)
-{
- unsigned long hash1;
- NODE *ret;
-
- assert(symbol->type == Node_var_array);
-
- if (symbol->var_array == NULL)
- return NULL;
-
- hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size, NULL);
- ret = assoc_find(symbol, subs, hash1, NULL);
- return (ret ? ret->ahvalue : NULL);
-}
-
-/*
- * assoc_lookup:
- * Find SYMBOL[SUBS] in the assoc array. Install it with value "" if it
- * isn't there. Returns a pointer ala get_lhs to where its value is stored.
- *
- * SYMBOL is the address of the node (or other pointer) being dereferenced.
- * SUBS is a number or string used as the subscript.
- */
-
-NODE **
-assoc_lookup(NODE *symbol, NODE *subs, int reference)
-{
- unsigned long hash1;
- NODE *bucket;
- size_t code;
-
- assert(symbol->type == Node_var_array);
-
- (void) force_string(subs);
-
- if (symbol->var_array == NULL) {
- symbol->array_size = symbol->table_size = 0; /* sanity */
- symbol->flags &= ~ARRAYMAXED;
- grow_table(symbol);
- hash1 = hash(subs->stptr, subs->stlen,
- (unsigned long) symbol->array_size, & code);
- } else {
- hash1 = hash(subs->stptr, subs->stlen,
- (unsigned long) symbol->array_size, & code);
- bucket = assoc_find(symbol, subs, hash1, NULL);
- if (bucket != NULL)
- return &(bucket->ahvalue);
- }
-
- if (do_lint && reference) {
- lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
- array_vname(symbol), (int)subs->stlen, subs->stptr);
- }
-
- /* It's not there, install it. */
- if (do_lint && subs->stlen == 0)
- lintwarn(_("subscript of array `%s' is null string"),
- array_vname(symbol));
-
- /* first see if we would need to grow the array, before installing */
- symbol->table_size++;
- if ((symbol->flags & ARRAYMAXED) == 0
- && (symbol->table_size / symbol->array_size) > AVG_CHAIN_MAX) {
- grow_table(symbol);
- /* have to recompute hash value for new size */
- hash1 = code % (unsigned long) symbol->array_size;
- }
-
- getnode(bucket);
- bucket->type = Node_ahash;
-
- /*
- * Freeze this string value --- it must never
- * change, no matter what happens to the value
- * that created it or to CONVFMT, etc.
- *
- * One day: Use an atom table to track array indices,
- * and avoid the extra memory overhead.
- */
- bucket->flags |= MALLOC;
- bucket->ahname_ref = 1;
-
- emalloc(bucket->ahname_str, char *, subs->stlen + 2, "assoc_lookup");
- bucket->ahname_len = subs->stlen;
- memcpy(bucket->ahname_str, subs->stptr, subs->stlen);
- bucket->ahname_str[bucket->ahname_len] = '\0';
- bucket->ahvalue = Nnull_string;
-
- bucket->ahnext = symbol->var_array[hash1];
- bucket->ahcode = code;
-
- /*
- * Set the numeric value for the index if it's available. Useful
- * for numeric sorting by index. Do this only if the numeric
- * value is available, instead of all the time, since doing it
- * all the time is a big performance hit for something that may
- * never be used.
- */
- if ((subs->flags & NUMCUR) != 0) {
- bucket->ahname_num = subs->numbr;
- bucket->flags |= NUMIND;
- }
-
- /* hook it into the symbol table */
- symbol->var_array[hash1] = bucket;
- return &(bucket->ahvalue);
-}
-
-
/* adjust_fcall_stack: remove subarray(s) of symbol[] from
* function call stack.
*/
@@ -602,7 +478,7 @@ adjust_fcall_stack(NODE *symbol, int nsubs)
func = frame_ptr->func_node;
if (func == NULL) /* in main */
return;
- pcount = func->lnode->param_cnt;
+ pcount = func->param_cnt;
sp = frame_ptr->stack;
for (; pcount > 0; pcount--) {
@@ -627,12 +503,10 @@ adjust_fcall_stack(NODE *symbol, int nsubs)
* function f(c, d) { delete c; ..}
* BEGIN { a[0][0] = 1; f(a[0], a[0]); ...}
*/
- char *save;
-local_array:
- save = r->vname;
- memset(r, '\0', sizeof(NODE));
- r->vname = save;
- r->type = Node_var_array;
+
+ init_array(r);
+ r->parent_array = NULL;
+ r->flags = 0;
continue;
}
@@ -648,8 +522,10 @@ local_array:
* BEGIN { a[0][0][0][0] = 1; f(a[0], a[0][0][0]); .. }
*
*/
-
- goto local_array;
+ init_array(r);
+ r->parent_array = NULL;
+ r->flags = 0;
+ break;
}
}
}
@@ -660,18 +536,17 @@ local_array:
/*
* `symbol' is array
- * `nsubs' is number of subscripts
+ * `nsubs' is no of subscripts
*/
void
do_delete(NODE *symbol, int nsubs)
{
- unsigned long hash1 = 0;
- NODE *subs, *bucket, *last, *r;
+ NODE *val, *subs;
int i;
assert(symbol->type == Node_var_array);
- subs = bucket = last = r = NULL; /* silence the compiler */
+ subs = val = NULL; /* silence the compiler */
/*
* The force_string() call is needed to make sure that
@@ -683,16 +558,17 @@ do_delete(NODE *symbol, int nsubs)
* Without it, the code does not fail.
*/
-#define free_subs(n) \
-do { \
+#define free_subs(n) do { \
NODE *s = PEEK(n - 1); \
if (s->type == Node_val) { \
- (void) force_string(s); /* may have side effects ? */ \
+ (void) force_string(s); /* may have side effects. */ \
DEREF(s); \
} \
} while (--n > 0)
- if (nsubs == 0) { /* delete array */
+ if (nsubs == 0) {
+ /* delete array */
+
adjust_fcall_stack(symbol, 0); /* fix function call stack; See above. */
assoc_clear(symbol);
return;
@@ -706,66 +582,46 @@ do { \
free_subs(i);
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(subs));
}
- (void) force_string(subs);
-
- last = NULL; /* shut up gcc -Wall */
- hash1 = 0; /* ditto */
- bucket = NULL; /* array may be empty */
- if (symbol->var_array != NULL) {
- hash1 = hash(subs->stptr, subs->stlen,
- (unsigned long) symbol->array_size, NULL);
- bucket = assoc_find(symbol, subs, hash1, &last);
- }
-
- if (bucket == NULL) {
- if (do_lint)
+ val = in_array(symbol, subs);
+ if (val == NULL) {
+ if (do_lint) {
+ subs = force_string(subs);
lintwarn(_("delete: index `%s' not in array `%s'"),
subs->stptr, array_vname(symbol));
+ }
/* avoid memory leak, free all subs */
free_subs(i);
return;
}
if (i > 1) {
- if (bucket->ahvalue->type != Node_var_array) {
+ if (val->type != Node_var_array) {
/* e.g.: a[1] = 1; delete a[1][1] */
+
free_subs(i);
+ subs = force_string(subs);
fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"),
array_vname(symbol),
- (int) bucket->ahname_len,
- bucket->ahname_str);
+ (int) subs->stlen,
+ subs->stptr);
}
- symbol = bucket->ahvalue;
+ symbol = val;
+ DEREF(subs);
}
- DEREF(subs);
}
- r = bucket->ahvalue;
- if (r->type == Node_var_array) {
- adjust_fcall_stack(r, nsubs); /* fix function call stack; See above. */
- assoc_clear(r);
+ if (val->type == Node_var_array) {
+ adjust_fcall_stack(val, nsubs); /* fix function call stack; See above. */
+ assoc_clear(val);
/* cleared a sub-array, free Node_var_array */
- efree(r->vname);
- freenode(r);
+ efree(val->vname);
+ freenode(val);
} else
- unref(r);
+ unref(val);
- if (last != NULL)
- last->ahnext = bucket->ahnext;
- else
- symbol->var_array[hash1] = bucket->ahnext;
-
- unref(bucket); /* unref() will free the ahname_str */
- symbol->table_size--;
- if (symbol->table_size <= 0) {
- symbol->table_size = symbol->array_size = 0;
- symbol->flags &= ~ARRAYMAXED;
- if (symbol->var_array != NULL) {
- efree(symbol->var_array);
- symbol->var_array = NULL;
- }
- }
+ (void) assoc_remove(symbol, subs);
+ DEREF(subs);
#undef free_subs
}
@@ -782,272 +638,164 @@ do { \
void
do_delete_loop(NODE *symbol, NODE **lhs)
{
- long i;
-
- assert(symbol->type == Node_var_array);
+ NODE **list;
+ NODE fl;
- if (symbol->var_array == NULL)
+ if (array_empty(symbol))
return;
- /* get first index value */
- for (i = 0; i < symbol->array_size; i++) {
- if (symbol->var_array[i] != NULL) {
- unref(*lhs);
- *lhs = make_string(symbol->var_array[i]->ahname_str,
- symbol->var_array[i]->ahname_len);
- break;
- }
- }
+ fl.flags = AINDEX|ADELETE; /* need a single index */
+ list = symbol->alist(symbol, & fl);
+ assert(list != NULL);
+
+ unref(*lhs);
+ *lhs = list[0];
+ efree(list);
/* blast the array in one shot */
- adjust_fcall_stack(symbol, 0);
+ adjust_fcall_stack(symbol, 0);
assoc_clear(symbol);
}
-/* grow_table --- grow a hash table */
+
+/* value_info --- print scalar node info */
+
static void
-grow_table(NODE *symbol)
+value_info(NODE *n)
{
- NODE **old, **new, *chain, *next;
- int i, j;
- unsigned long hash1;
- unsigned long oldsize, newsize, k;
- /*
- * This is an array of primes. We grow the table by an order of
- * magnitude each time (not just doubling) so that growing is a
- * rare operation. We expect, on average, that it won't happen
- * more than twice. When things are very large (> 8K), we just
- * double more or less, instead of just jumping from 8K to 64K.
- */
- static const long sizes[] = {
- 13, 127, 1021, 8191, 16381, 32749, 65497, 131101, 262147,
- 524309, 1048583, 2097169, 4194319, 8388617, 16777259, 33554467,
- 67108879, 134217757, 268435459, 536870923, 1073741827
- };
-
- /* find next biggest hash size */
- newsize = oldsize = symbol->array_size;
- for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
- if (oldsize < sizes[i]) {
- newsize = sizes[i];
- break;
- }
- }
- if (newsize == oldsize) { /* table already at max (!) */
- symbol->flags |= ARRAYMAXED;
+#define PREC_NUM -1
+#define PREC_STR -1
+
+ if (n == Nnull_string || n == Null_field) {
+ fprintf(output_fp, "<(null)>");
return;
}
- /* allocate new table */
- emalloc(new, NODE **, newsize * sizeof(NODE *), "grow_table");
- memset(new, '\0', newsize * sizeof(NODE *));
-
- /* brand new hash table, set things up and return */
- if (symbol->var_array == NULL) {
- symbol->table_size = 0;
- goto done;
- }
+ if ((n->flags & (STRING|STRCUR)) != 0) {
+ fprintf(output_fp, "<");
+ fprintf(output_fp, "\"%.*s\"", PREC_STR, n->stptr);
+ if ((n->flags & (NUMBER|NUMCUR)) != 0)
+ fprintf(output_fp, ":%.*g", PREC_NUM, n->numbr);
+ fprintf(output_fp, ">");
+ } else
+ fprintf(output_fp, "<%.*g>", PREC_NUM, n->numbr);
- /* old hash table there, move stuff to new, free old */
- old = symbol->var_array;
- for (k = 0; k < oldsize; k++) {
- if (old[k] == NULL)
- continue;
+ fprintf(output_fp, ":%s", flags2str(n->flags));
- for (chain = old[k]; chain != NULL; chain = next) {
- next = chain->ahnext;
- hash1 = chain->ahcode % newsize;
+ if ((n->flags & FIELD) == 0)
+ fprintf(output_fp, ":%ld", n->valref);
+ else
+ fprintf(output_fp, ":");
- /* remove from old list, add to new */
- chain->ahnext = new[hash1];
- new[hash1] = chain;
- }
+ if ((n->flags & (STRING|STRCUR)) == STRCUR) {
+ fprintf(output_fp, "][");
+ fprintf(output_fp, "stfmt=%d, ", n->stfmt);
+ fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
+ : fmt_list[n->stfmt]->stptr);
}
- efree(old);
-done:
- /*
- * note that symbol->table_size does not change if an old array,
- * and is explicitly set to 0 if a new one.
- */
- symbol->var_array = new;
- symbol->array_size = newsize;
+#undef PREC_NUM
+#undef PREC_STR
}
-/* pr_node --- print simple node info */
-static void
-pr_node(NODE *n)
+#ifdef ARRAYDEBUG
+
+NODE *
+do_aoption(int nargs)
{
- if ((n->flags & NUMBER) != 0)
- printf("%s %g p: %p", flags2str(n->flags), n->numbr, n);
- else
- printf("%s %.*s p: %p", flags2str(n->flags),
- (int) n->stlen, n->stptr, n);
+ int ret = -1;
+ NODE *opt, *val;
+ int i;
+ array_ptr *afunc;
+
+ val = POP_SCALAR();
+ opt = POP_SCALAR();
+ for (i = 0; i < num_atypes; i++) {
+ afunc = atypes[i];
+ if (afunc[NUM_AFUNCS] && (*afunc[NUM_AFUNCS])(opt, val) != NULL) {
+ ret = 0;
+ break;
+ }
+ }
+ DEREF(opt);
+ DEREF(val);
+ return make_number((AWKNUM) ret);
}
+#endif
-static void
+void
indent(int indent_level)
{
- int k;
- for (k = 0; k < indent_level; k++)
- putchar('\t');
+ int i;
+ for (i = 0; i < indent_level; i++)
+ fprintf(output_fp, "%s", indent_char);
}
-/* assoc_dump --- dump the contents of an array */
+/* assoc_info --- print index, value info */
-NODE *
-assoc_dump(NODE *symbol, int indent_level)
+void
+assoc_info(NODE *subs, NODE *val, NODE *ndump, const char *aname)
{
- long i;
- NODE *bucket;
+ int indent_level = ndump->alevel;
+ indent_level++;
indent(indent_level);
- if (symbol->var_array == NULL) {
- printf(_("%s: empty (null)\n"), symbol->vname);
- return make_number((AWKNUM) 0);
- }
-
- if (symbol->table_size == 0) {
- printf(_("%s: empty (zero)\n"), symbol->vname);
- return make_number((AWKNUM) 0);
- }
+ fprintf(output_fp, "I: [%s:", aname);
+ if ((subs->flags & INTIND) != 0)
+ fprintf(output_fp, "<%ld>", (long) subs->numbr);
+ else
+ value_info(subs);
+ fprintf(output_fp, "]\n");
- printf(_("%s: table_size = %d, array_size = %d\n"), symbol->vname,
- (int) symbol->table_size, (int) symbol->array_size);
-
- for (i = 0; i < symbol->array_size; i++) {
- for (bucket = symbol->var_array[i]; bucket != NULL;
- bucket = bucket->ahnext) {
- indent(indent_level);
- printf("%s: I: [len %d <%.*s> p: %p] V: [",
- symbol->vname,
- (int) bucket->ahname_len,
- (int) bucket->ahname_len,
- bucket->ahname_str,
- bucket->ahname_str);
- if (bucket->ahvalue->type == Node_var_array) {
- printf("\n");
- assoc_dump(bucket->ahvalue, indent_level + 1);
- indent(indent_level);
- } else
- pr_node(bucket->ahvalue);
- printf("]\n");
- }
+ indent(indent_level);
+ if (val->type == Node_val) {
+ fprintf(output_fp, "V: [scalar: ");
+ value_info(val);
+ } else {
+ fprintf(output_fp, "V: [");
+ ndump->alevel++;
+ ndump->adepth--;
+ assoc_dump(val, ndump);
+ ndump->adepth++;
+ ndump->alevel--;
+ indent(indent_level);
}
-
- return make_number((AWKNUM) 0);
+ fprintf(output_fp, "]\n");
}
+
/* do_adump --- dump an array: interface to assoc_dump */
NODE *
do_adump(int nargs)
{
- NODE *r, *a;
+ NODE *symbol, *tmp;
+ static NODE ndump;
+ long depth = 0;
- a = POP();
- if (a->type == Node_param_list) {
- printf(_("%s: is parameter\n"), a->vname);
- a = GET_PARAM(a->param_cnt);
- }
- if (a->type == Node_array_ref) {
- printf(_("%s: array_ref to %s\n"), a->vname,
- a->orig_array->vname);
- a = a->orig_array;
- }
- if (a->type != Node_var_array)
- fatal(_("adump: argument not an array"));
- r = assoc_dump(a, 0);
- return r;
-}
-
-/*
- * The following functions implement the builtin
- * asort function. Initial work by Alan J. Broder,
- * ajb@woti.com.
- */
-
-/* dup_table --- recursively duplicate input array "symbol" */
+ /* depth < 0, no index and value info.
+ * = 0, main array index and value info; does not descend into sub-arrays.
+ * > 0, descends into 'depth' sub-arrays, and prints index and value info.
+ */
-static NODE *
-dup_table(NODE *symbol, NODE *newsymb)
-{
- NODE **old, **new, *chain, *bucket;
- long i;
- unsigned long cursize;
-
- /* find the current hash size */
- cursize = symbol->array_size;
-
- new = NULL;
-
- /* input is a brand new hash table, so there's nothing to copy */
- if (symbol->var_array == NULL)
- newsymb->table_size = 0;
- else {
- /* old hash table there, dupnode stuff into a new table */
-
- /* allocate new table */
- emalloc(new, NODE **, cursize * sizeof(NODE *), "dup_table");
- memset(new, '\0', cursize * sizeof(NODE *));
-
- /* do the copying/dupnode'ing */
- old = symbol->var_array;
- for (i = 0; i < cursize; i++) {
- if (old[i] != NULL) {
- for (chain = old[i]; chain != NULL;
- chain = chain->ahnext) {
- /* get a node for the linked list */
- getnode(bucket);
- bucket->type = Node_ahash;
- bucket->flags |= MALLOC;
- bucket->ahname_ref = 1;
- bucket->ahcode = chain->ahcode;
- if ((chain->flags & NUMIND) != 0) {
- bucket->ahname_num = chain->ahname_num;
- bucket->flags |= NUMIND;
- }
-
- /*
- * copy the corresponding name and
- * value from the original input list
- */
- emalloc(bucket->ahname_str, char *, chain->ahname_len + 2, "dup_table");
- bucket->ahname_len = chain->ahname_len;
-
- memcpy(bucket->ahname_str, chain->ahname_str, chain->ahname_len);
- bucket->ahname_str[bucket->ahname_len] = '\0';
-
- if (chain->ahvalue->type == Node_var_array) {
- NODE *r;
- getnode(r);
- r->type = Node_var_array;
- r->vname = estrdup(chain->ahname_str, chain->ahname_len);
- r->parent_array = newsymb;
- bucket->ahvalue = dup_table(chain->ahvalue, r);
- } else
- bucket->ahvalue = dupnode(chain->ahvalue);
-
- /*
- * put the node on the corresponding
- * linked list in the new table
- */
- bucket->ahnext = new[i];
- new[i] = bucket;
- }
- }
- }
- newsymb->table_size = symbol->table_size;
+ if (nargs == 2) {
+ tmp = POP_SCALAR();
+ depth = (long) force_number(tmp);
+ DEREF(tmp);
}
-
- newsymb->var_array = new;
- newsymb->array_size = cursize;
- newsymb->flags = symbol->flags; /* ARRAYMAXED */
- return newsymb;
+ symbol = POP_PARAM();
+ if (symbol->type != Node_var_array)
+ fatal(_("adump: first argument not an array"));
+
+ ndump.type = Node_dump_array;
+ ndump.adepth = depth;
+ ndump.alevel = 0;
+ assoc_dump(symbol, & ndump);
+ return make_number((AWKNUM) 0);
}
@@ -1059,15 +807,13 @@ asort_actual(int nargs, SORT_CTXT ctxt)
NODE *array, *dest = NULL, *result;
NODE *r, *subs, *s;
NODE **list, **ptr;
-#define TSIZE 100 /* an arbitrary amount */
- static char buf[TSIZE+2];
unsigned long num_elems, i;
const char *sort_str;
if (nargs == 3) /* 3rd optional arg */
s = POP_STRING();
else
- s = Nnull_string; /* "" => default sorting */
+ s = dupnode(Nnull_string); /* "" => default sorting */
s = force_string(s);
sort_str = s->stptr;
@@ -1078,7 +824,6 @@ asort_actual(int nargs, SORT_CTXT ctxt)
sort_str = "@ind_str_asc";
}
-
if (nargs >= 2) { /* 2nd optional arg */
dest = POP_PARAM();
if (dest->type != Node_var_array) {
@@ -1107,15 +852,16 @@ asort_actual(int nargs, SORT_CTXT ctxt)
fatal(ctxt == ASORT ?
_("asort: cannot use a subarray of second arg for first arg") :
_("asorti: cannot use a subarray of second arg for first arg"));
- }
+ }
}
- num_elems = array->table_size;
- if (num_elems == 0 || array->var_array == NULL) { /* source array is empty */
+ if (array_empty(array)) {
+ /* source array is empty */
if (dest != NULL && dest != array)
assoc_clear(dest);
return make_number((AWKNUM) 0);
}
+ num_elems = array->table_size;
/* sorting happens inside assoc_list */
list = assoc_list(array, sort_str, ctxt);
@@ -1132,70 +878,52 @@ asort_actual(int nargs, SORT_CTXT ctxt)
result = dest;
} else {
/* use 'result' as a temporary destination array */
- getnode(result);
- memset(result, '\0', sizeof(NODE));
- result->type = Node_var_array;
+ result = make_array();
result->vname = array->vname;
result->parent_array = array->parent_array;
}
- subs = make_str_node(buf, TSIZE, ALREADY_MALLOCED); /* fake it */
- subs->flags &= ~MALLOC; /* safety */
- for (i = 1, ptr = list; i <= num_elems; i++) {
- sprintf(buf, "%lu", i);
- subs->stlen = strlen(buf);
- /* make number valid in case this array gets sorted later */
- subs->numbr = i;
- subs->flags |= NUMCUR;
- r = *ptr++;
- if (ctxt == ASORTI) {
- /*
- * We want the indices of the source array as values
- * of the 'result' array.
- */
- *assoc_lookup(result, subs, FALSE) =
- make_string(r->ahname_str, r->ahname_len);
- } else {
- NODE *val;
-
- /* We want the values of the source array. */
-
- val = r->ahvalue;
- if (result != dest) {
- /* optimization for dest = NULL or dest = array */
-
- if (val->type == Node_var_array) {
- /* update subarray index in parent array */
- efree(val->vname);
- val->vname = estrdup(subs->stptr, subs->stlen);
- }
- *assoc_lookup(result, subs, FALSE) = val;
- r->ahvalue = Nnull_string;
- } else {
- if (val->type == Node_val)
- *assoc_lookup(result, subs, FALSE) = dupnode(val);
- else {
- NODE *arr;
-
- /*
- * There isn't any reference counting for
- * subarrays, so recursively copy subarrays
- * using dup_table().
- */
- getnode(arr);
- arr->type = Node_var_array;
- arr->var_array = NULL;
- arr->vname = estrdup(subs->stptr, subs->stlen);
- arr->parent_array = array; /* actual parent, not the temporary one. */
- *assoc_lookup(result, subs, FALSE) = dup_table(val, arr);
- }
+ subs = make_number((AWKNUM) 0.0);
+
+ if (ctxt == ASORTI) {
+ /* We want the indices of the source array. */
+
+ for (i = 1, ptr = list; i <= num_elems; i++, ptr += 2) {
+ subs->numbr = (AWKNUM) i;
+ r = *ptr;
+ *assoc_lookup(result, subs) = r;
+ }
+ } else {
+ /* We want the values of the source array. */
+
+ for (i = 1, ptr = list; i <= num_elems; i++) {
+ subs->numbr = (AWKNUM) i;
+
+ /* free index node */
+ r = *ptr++;
+ unref(r);
+
+ /* value node */
+ r = *ptr++;
+
+ /* FIXME: asort(a) optimization */
+
+ if (r->type == Node_val)
+ *assoc_lookup(result, subs) = dupnode(r);
+ else {
+ NODE *arr;
+ arr = make_array();
+ subs = force_string(subs);
+ arr->vname = subs->stptr;
+ subs->stptr = NULL;
+ subs->flags &= ~STRCUR;
+ arr->parent_array = array; /* actual parent, not the temporary one. */
+ *assoc_lookup(result, subs) = assoc_copy(r, arr);
}
}
+ }
- unref(r);
- }
-
- freenode(subs); /* stptr(buf) not malloc-ed */
+ unref(subs);
efree(list);
if (result != dest) {
@@ -1209,7 +937,6 @@ asort_actual(int nargs, SORT_CTXT ctxt)
return make_number((AWKNUM) num_elems);
}
-#undef TSIZE
/* do_asort --- sort array by value */
@@ -1227,6 +954,7 @@ do_asorti(int nargs)
return asort_actual(nargs, ASORTI);
}
+
/*
* cmp_string --- compare two strings; logic similar to cmp_nodes() in eval.c
* except the extra case-sensitive comparison when the case-insensitive
@@ -1241,18 +969,10 @@ cmp_string(const NODE *n1, const NODE *n2)
int ret;
size_t lmin;
- assert(n1->type == n2->type);
- if (n1->type == Node_ahash) {
- s1 = n1->ahname_str;
- len1 = n1->ahname_len;
- s2 = n2->ahname_str;
- len2 = n2->ahname_len;
- } else {
- s1 = n1->stptr;
- len1 = n1->stlen;
- s2 = n2->stptr;
- len2 = n2->stlen;
- }
+ s1 = n1->stptr;
+ len1 = n1->stlen;
+ s2 = n2->stptr;
+ len2 = n2->stlen;
if (len1 == 0)
return len2 == 0 ? 0 : -1;
@@ -1303,7 +1023,7 @@ sort_up_index_string(const void *p1, const void *p2)
}
-/* sort_down_index_string --- descending index strings */
+/* sort_down_index_str --- qsort comparison function; descending index strings. */
static int
sort_down_index_string(const void *p1, const void *p2)
@@ -1326,24 +1046,23 @@ sort_down_index_string(const void *p1, const void *p2)
static int
sort_up_index_number(const void *p1, const void *p2)
{
- const NODE *n1, *n2;
+ const NODE *t1, *t2;
int ret;
- n1 = *((const NODE *const *) p1);
- n2 = *((const NODE *const *) p2);
+ t1 = *((const NODE *const *) p1);
+ t2 = *((const NODE *const *) p2);
- if (n1->ahname_num < n2->ahname_num)
+ if (t1->numbr < t2->numbr)
ret = -1;
else
- ret = (n1->ahname_num > n2->ahname_num);
+ ret = (t1->numbr > t2->numbr);
/* break a tie with the index string itself */
if (ret == 0)
- return cmp_string(n1, n2);
+ return cmp_string(t1, t2);
return ret;
}
-
/* sort_down_index_number --- qsort comparison function; descending index numbers */
static int
@@ -1359,29 +1078,23 @@ static int
sort_up_value_string(const void *p1, const void *p2)
{
const NODE *t1, *t2;
- NODE *n1, *n2;
-
- /* we're passed a pair of index (array subscript) nodes */
- t1 = *(const NODE *const *) p1;
- t2 = *(const NODE *const *) p2;
- /* and we want to compare the element values they refer to */
- n1 = t1->ahvalue;
- n2 = t2->ahvalue;
+ t1 = *((const NODE *const *) p1 + 1);
+ t2 = *((const NODE *const *) p2 + 1);
- if (n1->type == Node_var_array) {
- /* return 0 if n2 is a sub-array too, else return 1 */
- return (n2->type != Node_var_array);
+ if (t1->type == Node_var_array) {
+ /* return 0 if t2 is a sub-array too, else return 1 */
+ return (t2->type != Node_var_array);
}
- if (n2->type == Node_var_array)
- return -1; /* n1 (scalar) < n2 (sub-array) */
+ if (t2->type == Node_var_array)
+ return -1; /* t1 (scalar) < t2 (sub-array) */
- /* n1 and n2 both have string values; See sort_force_value_string(). */
- return cmp_string(n1, n2);
+ /* t1 and t2 both have string values */
+ return cmp_string(t1, t2);
}
-/* sort_down_value_string --- descending value string */
+/* sort_down_value_string --- qsort comparison function; descending value string */
static int
sort_down_value_string(const void *p1, const void *p2)
@@ -1389,50 +1102,46 @@ sort_down_value_string(const void *p1, const void *p2)
return -sort_up_value_string(p1, p2);
}
+
/* sort_up_value_number --- qsort comparison function; ascending value number */
static int
sort_up_value_number(const void *p1, const void *p2)
{
- const NODE *t1, *t2;
- NODE *n1, *n2;
+ NODE *t1, *t2;
int ret;
- /* we're passed a pair of index (array subscript) nodes */
- t1 = *(const NODE *const *) p1;
- t2 = *(const NODE *const *) p2;
-
- /* and we want to compare the element values they refer to */
- n1 = t1->ahvalue;
- n2 = t2->ahvalue;
+ t1 = *((NODE *const *) p1 + 1);
+ t2 = *((NODE *const *) p2 + 1);
- if (n1->type == Node_var_array) {
- /* return 0 if n2 is a sub-array too, else return 1 */
- return (n2->type != Node_var_array);
+ if (t1->type == Node_var_array) {
+ /* return 0 if t2 is a sub-array too, else return 1 */
+ return (t2->type != Node_var_array);
}
- if (n2->type == Node_var_array)
- return -1; /* n1 (scalar) < n2 (sub-array) */
+ if (t2->type == Node_var_array)
+ return -1; /* t1 (scalar) < t2 (sub-array) */
- /* n1 and n2 both Node_val, and force_number'ed */
- if (n1->numbr < n2->numbr)
+ /* t1 and t2 both Node_val, and force_number'ed */
+ if (t1->numbr < t2->numbr)
ret = -1;
else
- ret = (n1->numbr > n2->numbr);
+ ret = (t1->numbr > t2->numbr);
if (ret == 0) {
/*
* Use string value to guarantee same sort order on all
* versions of qsort().
*/
- n1 = force_string(n1);
- n2 = force_string(n2);
- ret = cmp_string(n1, n2);
+ t1 = force_string(t1);
+ t2 = force_string(t2);
+ ret = cmp_string(t1, t2);
}
return ret;
}
-/* sort_down_value_number --- descending value number */
+
+/* sort_down_value_number --- qsort comparison function; descending value number */
static int
sort_down_value_number(const void *p1, const void *p2)
@@ -1440,21 +1149,17 @@ sort_down_value_number(const void *p1, const void *p2)
return -sort_up_value_number(p1, p2);
}
+
/* sort_up_value_type --- qsort comparison function; ascending value type */
static int
sort_up_value_type(const void *p1, const void *p2)
{
- const NODE *t1, *t2;
NODE *n1, *n2;
- /* we're passed a pair of index (array subscript) nodes */
- t1 = *(const NODE *const *) p1;
- t2 = *(const NODE *const *) p2;
-
- /* and we want to compare the element values they refer to */
- n1 = t1->ahvalue;
- n2 = t2->ahvalue;
+ /* we want to compare the element values */
+ n1 = *((NODE *const *) p1 + 1);
+ n2 = *((NODE *const *) p2 + 1);
/* 1. Arrays vs. scalar, scalar is less than array */
if (n1->type == Node_var_array) {
@@ -1472,6 +1177,12 @@ sort_up_value_type(const void *p1, const void *p2)
if ((n2->flags & MAYBE_NUM) != 0)
(void) force_number(n2);
+ /* 2.5. Resolve INTIND, so that is STRING, and not NUMBER */
+ if ((n1->flags & INTIND) != 0)
+ (void) force_string(n1);
+ if ((n2->flags & INTIND) != 0)
+ (void) force_string(n2);
+
if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) {
if (n1->numbr < n2->numbr)
return -1;
@@ -1492,7 +1203,7 @@ sort_up_value_type(const void *p1, const void *p2)
return cmp_string(n1, n2);
}
-/* sort_down_value_type --- descending value type */
+/* sort_down_value_type --- qsort comparison function; descending value type */
static int
sort_down_value_type(const void *p1, const void *p2)
@@ -1505,26 +1216,25 @@ sort_down_value_type(const void *p1, const void *p2)
static int
sort_user_func(const void *p1, const void *p2)
{
- const NODE *t1, *t2;
NODE *idx1, *idx2, *val1, *val2;
AWKNUM ret;
INSTRUCTION *code;
- t1 = *((const NODE *const *) p1);
- t2 = *((const NODE *const *) p2);
-
- idx1 = make_string(t1->ahname_str, t1->ahname_len);
- idx2 = make_string(t2->ahname_str, t2->ahname_len);
- val1 = t1->ahvalue;
- val2 = t2->ahvalue;
+ idx1 = *((NODE *const *) p1);
+ idx2 = *((NODE *const *) p2);
+ val1 = *((NODE *const *) p1 + 1);
+ val2 = *((NODE *const *) p2 + 1);
code = TOP()->code_ptr; /* comparison function call instructions */
/* setup 4 arguments to comp_func() */
+ UPREF(idx1);
PUSH(idx1);
if (val1->type == Node_val)
UPREF(val1);
PUSH(val1);
+
+ UPREF(idx2);
PUSH(idx2);
if (val2->type == Node_val)
UPREF(val2);
@@ -1539,113 +1249,74 @@ sort_user_func(const void *p1, const void *p2)
return (ret < 0.0) ? -1 : (ret > 0.0);
}
-/* sort_force_index_number -- pre-process list items for sorting indices as numbers */
-
-static void
-sort_force_index_number(NODE **list, size_t num_elems)
-{
- size_t i;
- NODE *r;
- static NODE temp_node;
-
- for (i = 0; i < num_elems; i++) {
- r = list[i];
-
- if ((r->flags & NUMIND) != 0) /* once in a lifetime is plenty */
- continue;
- temp_node.type = Node_val;
- temp_node.stptr = r->ahname_str;
- temp_node.stlen = r->ahname_len;
- temp_node.flags = 0; /* only interested in the return value of r_force_number */
- r->ahname_num = r_force_number(& temp_node);
- r->flags |= NUMIND;
- }
-}
-
-/* sort_force_value_number -- pre-process list items for sorting values as numbers */
-
-static void
-sort_force_value_number(NODE **list, size_t num_elems)
-{
- size_t i;
- NODE *r, *val;
-
- for (i = 0; i < num_elems; i++) {
- r = list[i];
- val = r->ahvalue;
- if (val->type == Node_val)
- (void) force_number(val);
- }
-}
-
-/* sort_force_value_string -- pre-process list items for sorting values as strings */
-
-static void
-sort_force_value_string(NODE **list, size_t num_elems)
-{
- size_t i;
- NODE *r, *val;
-
- for (i = 0; i < num_elems; i++) {
- r = list[i];
- val = r->ahvalue;
- if (val->type == Node_val)
- r->ahvalue = force_string(val);
- }
-}
/* assoc_list -- construct, and optionally sort, a list of array elements */
NODE **
-assoc_list(NODE *array, const char *sort_str, SORT_CTXT sort_ctxt)
+assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt)
{
- typedef void (*qsort_prefunc)(NODE **, size_t);
typedef int (*qsort_compfunc)(const void *, const void *);
static const struct qsort_funcs {
const char *name;
qsort_compfunc comp_func;
- qsort_prefunc pre_func; /* pre-processing of list items */
+ enum assoc_list_flags flags;
} sort_funcs[] = {
- { "@ind_str_asc", sort_up_index_string, 0 },
- { "@ind_num_asc", sort_up_index_number, sort_force_index_number },
- { "@val_str_asc", sort_up_value_string, sort_force_value_string },
- { "@val_num_asc", sort_up_value_number, sort_force_value_number },
- { "@ind_str_desc", sort_down_index_string, 0 },
- { "@ind_num_desc", sort_down_index_number, sort_force_index_number },
- { "@val_str_desc", sort_down_value_string, sort_force_value_string },
- { "@val_num_desc", sort_down_value_number, sort_force_value_number },
- { "@val_type_asc", sort_up_value_type, 0 },
- { "@val_type_desc", sort_down_value_type, 0 },
- { "@unsorted", 0, 0 },
- };
+{ "@ind_str_asc", sort_up_index_string, AINDEX|AISTR|AASC },
+{ "@ind_num_asc", sort_up_index_number, AINDEX|AINUM|AASC },
+{ "@val_str_asc", sort_up_value_string, AVALUE|AVSTR|AASC },
+{ "@val_num_asc", sort_up_value_number, AVALUE|AVNUM|AASC },
+{ "@ind_str_desc", sort_down_index_string, AINDEX|AISTR|ADESC },
+{ "@ind_num_desc", sort_down_index_number, AINDEX|AINUM|ADESC },
+{ "@val_str_desc", sort_down_value_string, AVALUE|AVSTR|ADESC },
+{ "@val_num_desc", sort_down_value_number, AVALUE|AVNUM|ADESC },
+{ "@val_type_asc", sort_up_value_type, AVALUE|AASC },
+{ "@val_type_desc", sort_down_value_type, AVALUE|ADESC },
+{ "@unsorted", 0, AINDEX },
+};
+
+ /* N.B.: AASC and ADESC are hints to the specific array types.
+ * See cint_list() in cint_array.c.
+ */
+
NODE **list;
- NODE *r;
- size_t num_elems, i, j;
+ NODE fl;
+ unsigned long num_elems, j;
+ int elem_size, qi;
qsort_compfunc cmp_func = 0;
- qsort_prefunc pre_func = 0;
INSTRUCTION *code = NULL;
- int qi;
extern int currule;
+ int save_rule = 0;
- num_elems = array->table_size;
+ num_elems = symbol->table_size;
assert(num_elems > 0);
+ elem_size = 1;
+ fl.flags = 0;
+
for (qi = 0, j = sizeof(sort_funcs)/sizeof(sort_funcs[0]); qi < j; qi++) {
if (strcmp(sort_funcs[qi].name, sort_str) == 0)
break;
}
- if (qi >= 0 && qi < j) {
+ if (qi < j) {
cmp_func = sort_funcs[qi].comp_func;
- pre_func = sort_funcs[qi].pre_func;
+ fl.flags = sort_funcs[qi].flags;
+
+ if (symbol->array_funcs != cint_array_func)
+ fl.flags &= ~(AASC|ADESC);
- } else { /* unrecognized */
+ if (sort_ctxt != SORTED_IN || (fl.flags & AVALUE) != 0) {
+ /* need index and value pair in the list */
+
+ fl.flags |= (AINDEX|AVALUE);
+ elem_size = 2;
+ }
+
+ } else { /* unrecognized */
NODE *f;
const char *sp;
- assert(sort_str != NULL);
-
for (sp = sort_str; *sp != '\0'
&& ! isspace((unsigned char) *sp); sp++)
continue;
@@ -1659,7 +1330,10 @@ assoc_list(NODE *array, const char *sort_str, SORT_CTXT sort_ctxt)
fatal(_("sort comparison function `%s' is not defined"), sort_str);
cmp_func = sort_user_func;
- /* pre_func is still NULL */
+
+ /* need index and value pair in the list */
+ fl.flags |= (AVALUE|AINDEX);
+ elem_size = 2;
/* make function call instructions */
code = bcalloc(Op_func_call, 2, 0);
@@ -1673,103 +1347,37 @@ assoc_list(NODE *array, const char *sort_str, SORT_CTXT sort_ctxt)
* to undefined (0).
*/
- (code + 1)->inrule = currule; /* save current rule */
+ save_rule = currule; /* save current rule */
currule = 0;
PUSH_CODE(code);
}
- /* allocate space for array; the extra space is used in for(i in a) opcode (eval.c) */
- emalloc(list, NODE **, (num_elems + 1) * sizeof(NODE *), "assoc_list");
-
- /* populate it */
- for (i = j = 0; i < array->array_size; i++)
- for (r = array->var_array[i]; r != NULL; r = r->ahnext)
- list[j++] = dupnode(r);
- list[num_elems] = NULL;
+ list = symbol->alist(symbol, & fl);
- if (! cmp_func) /* unsorted */
- return list;
+ if (! cmp_func || (fl.flags & (AASC|ADESC)) != 0)
+ return list; /* unsorted or list already sorted */
- /* special pre-processing of list items */
- if (pre_func)
- pre_func(list, num_elems);
-
- qsort(list, num_elems, sizeof(NODE *), cmp_func); /* shazzam! */
+ qsort(list, num_elems, elem_size * sizeof(NODE *), cmp_func); /* shazzam! */
if (cmp_func == sort_user_func) {
code = POP_CODE();
- currule = (code + 1)->inrule; /* restore current rule */
+ currule = save_rule; /* restore current rule */
bcfree(code->nexti); /* Op_stop */
bcfree(code); /* Op_func_call */
}
- return list;
-}
-
-
-/*
-From bonzini@gnu.org Mon Oct 28 16:05:26 2002
-Date: Mon, 28 Oct 2002 13:33:03 +0100
-From: Paolo Bonzini <bonzini@gnu.org>
-To: arnold@skeeve.com
-Subject: Hash function
-Message-ID: <20021028123303.GA6832@biancaneve>
-
-Here is the hash function I'm using in GNU Smalltalk. The scrambling is
-needed if you use powers of two as the table sizes. If you use primes it
-is not needed.
-
-To use double-hashing with power-of-two size, you should use the
-_gst_hash_string(str, len) as the primary hash and
-scramble(_gst_hash_string (str, len)) | 1 as the secondary hash.
-
-Paolo
-
-*/
-/*
- * ADR: Slightly modified to work w/in the context of gawk.
- */
-
-static unsigned long
-gst_hash_string(const char *str, size_t len, unsigned long hsize, size_t *code)
-{
- unsigned long hashVal = 1497032417; /* arbitrary value */
- unsigned long ret;
-
- while (len--) {
- hashVal += *str++;
- hashVal += (hashVal << 10);
- hashVal ^= (hashVal >> 6);
- }
-
- ret = scramble(hashVal);
-
- if (code != NULL)
- *code = ret;
-
- if (ret >= hsize)
- ret %= hsize;
-
- return ret;
-}
+ if (sort_ctxt == SORTED_IN
+ && (fl.flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE)
+ ) {
+ /* relocate all index nodes to the first half of the list. */
+ for (j = 1; j < num_elems; j++)
+ list[j] = list[2 * j];
-static unsigned long
-scramble(unsigned long x)
-{
- if (sizeof(long) == 4) {
- int y = ~x;
+ /* give back extra memory */
- x += (y << 10) | (y >> 22);
- x += (x << 6) | (x >> 26);
- x -= (x << 16) | (x >> 16);
- } else {
- x ^= (~x) >> 31;
- x += (x << 21) | (x >> 11);
- x += (x << 5) | (x >> 27);
- x += (x << 27) | (x >> 5);
- x += (x << 31);
+ erealloc(list, NODE **, num_elems * sizeof(NODE *), "assoc_list");
}
- return x;
+ return list;
}
diff --git a/awk.h b/awk.h
index a267d2ee..a430111f 100644
--- a/awk.h
+++ b/awk.h
@@ -256,10 +256,9 @@ extern double gawk_strtod();
#define FALSE 0
#endif
-#define LINT_INVALID 1 /* only warn about invalid */
-#define LINT_ALL 2 /* warn about all things */
+#define INT32_BIT 32
-enum defrule {BEGIN = 1, Rule, END, BEGINFILE, ENDFILE,
+enum defrule { BEGIN = 1, Rule, END, BEGINFILE, ENDFILE,
MAXRULE /* sentinel, not legal */ };
extern const char *const ruletab[];
@@ -278,10 +277,13 @@ typedef enum nodevals {
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_hashnode, /* an identifier in the symbol table */
- Node_ahash, /* an array element */
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,
@@ -291,9 +293,44 @@ typedef enum nodevals {
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;
+
+/* 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 **(*array_ptr)(struct exp_node *, struct exp_node *);
+
/*
* NOTE - this struct is a rather kludgey -- it is packed to minimize
* space usage, at the expense of cleanliness. Alter at own risk.
@@ -305,13 +342,15 @@ typedef struct exp_node {
struct exp_node *lptr;
struct exp_instruction *li;
long ll;
+ array_ptr *lp;
} l;
union {
struct exp_node *rptr;
Regexp *preg;
struct exp_node **av;
+ BUCKET **bv;
void (*uptr)(void);
- struct exp_instruction *ri;
+ struct exp_instruction *iptr;
} r;
union {
struct exp_node *extra;
@@ -320,16 +359,19 @@ typedef struct exp_node {
char **param_list;
} x;
char *name;
+ size_t reserved;
struct exp_node *rn;
+ unsigned long cnt;
unsigned long reflags;
# define CASE 1
# define CONSTANT 2
# define FS_DFLT 4
} nodep;
+
struct {
AWKNUM fltnum; /* this is here for optimal packing of
- * the structure on many machines
- */
+ * the structure on many machines
+ */
char *sp;
size_t slen;
long sref;
@@ -339,97 +381,122 @@ typedef struct exp_node {
size_t wslen;
#endif
} val;
- struct {
- AWKNUM num;
- struct exp_node *next;
- char *name;
- size_t length;
- struct exp_node *value;
- long ref;
- size_t code;
- } hash;
-#define hnext sub.hash.next
-#define hname sub.hash.name
-#define hlength sub.hash.length
-#define hvalue sub.hash.value
-
-#define ahnext sub.hash.next
-#define ahname_str sub.hash.name
-#define ahname_len sub.hash.length
-#define ahname_num sub.hash.num
-#define ahvalue sub.hash.value
-#define ahname_ref sub.hash.ref
-#define ahcode sub.hash.code
} sub;
NODETYPE type;
- unsigned short flags;
-# define MALLOC 1 /* can be free'd */
-# define PERM 2 /* can't be free'd */
-# define STRING 4 /* assigned as string */
-# define STRCUR 8 /* string value is current */
-# define NUMCUR 16 /* numeric value is current */
-# define NUMBER 32 /* assigned as number */
-# define MAYBE_NUM 64 /* user input: if NUMERIC then
- * a NUMBER */
-# define ARRAYMAXED 128 /* array is at max size */
-# define FUNC 256 /* this parameter is really a
- * function name; see awkgram.y */
-# define FIELD 512 /* this is a field */
-# define INTLSTR 1024 /* use localized version */
-# define NUMIND 2048 /* numeric val of index is current */
-# define WSTRCUR 4096 /* wide str value is current */
+ unsigned int flags;
+
+/* any type */
+# define MALLOC 0x0001 /* can be free'd */
+
+/* type = Node_val */
+# 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 MAYBE_NUM 0x0020 /* user input: if NUMERIC then
+ * a NUMBER */
+# define FIELD 0x0040 /* this is a field */
+# define INTLSTR 0x0080 /* use localized version */
+# define NUMINT 0x0100 /* numeric value is an integer */
+# define INTIND 0x0200 /* integral value is array index;
+ * lazy conversion to string.
+ */
+# define WSTRCUR 0x0400 /* wide str value is current */
+
+/* type = Node_var_array */
+# define ARRAYMAXED 0x0800 /* array is at max size */
+# define HALFHAT 0x1000 /* half-capacity Hashed Array Tree;
+ * See cint_array.c */
+# define XARRAY 0x2000 /* FIXME: Nuke */
} NODE;
-
#define vname sub.nodep.name
#define lnode sub.nodep.l.lptr
#define nextp sub.nodep.l.lptr
#define rnode sub.nodep.r.rptr
-#define param_cnt sub.nodep.l.ll
-#define param vname
+/* Node_hashnode, Node_param_list */
+#define hnext sub.nodep.r.rptr
+#define hname vname
+#define hlength sub.nodep.reserved
+#define hcode sub.nodep.cnt
+#define hvalue sub.nodep.x.extra
+
+/* Node_param_list, Node_func */
+#define param_cnt sub.nodep.l.ll
+/* Node_param_list */
+#define param vname
-#define parmlist sub.nodep.x.param_list
-#define code_ptr sub.nodep.r.ri
+/* 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
+#define re_cnt flags
+/* Node_val */
#define stptr sub.val.sp
#define stlen sub.val.slen
#define valref sub.val.sref
-#define stfmt sub.val.idx
-
+#define stfmt sub.val.idx
#define wstptr sub.val.wsp
#define wstlen sub.val.wslen
-
#define numbr sub.val.fltnum
+/* 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
+#define num_tail_calls sub.nodep.cnt
/* Node_var: */
-#define var_value lnode
+#define var_value lnode
#define var_update sub.nodep.r.uptr
#define var_assign sub.nodep.x.aptr
/* Node_var_array: */
-#define var_array sub.nodep.r.av
-#define array_size sub.nodep.l.ll
-#define table_size sub.nodep.x.xl
-#define parent_array sub.nodep.rn
+#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
+
+/* array_funcs[0] is the array initialization function and
+ * array_funcs[1] is the index type checking function
+ */
+#define alookup array_funcs[2]
+#define aexists array_funcs[3]
+#define aclear array_funcs[4]
+#define aremove array_funcs[5]
+#define alist array_funcs[6]
+#define acopy array_funcs[7]
+#define adump array_funcs[8]
+#define NUM_AFUNCS 9 /* # of entries in array_funcs */
/* 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
+
/* --------------------------------lint warning types----------------------------*/
typedef enum lintvals {
LINT_illegal,
@@ -527,6 +594,7 @@ typedef enum opcodeval {
Op_builtin,
Op_sub_builtin, /* sub, gsub and gensub */
+ Op_ext_builtin,
Op_in_array, /* boolean test of membership in array */
/* function call instruction */
@@ -559,7 +627,6 @@ typedef enum opcodeval {
Op_after_beginfile,
Op_after_endfile,
- Op_ext_func,
Op_func,
Op_exec_count,
@@ -660,6 +727,7 @@ typedef struct exp_instruction {
/* Op_token */
#define lextok d.name
+#define param_count x.xl
/* Op_rule */
#define in_rule x.xl
@@ -668,11 +736,11 @@ typedef struct exp_instruction {
/* 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 stmt_start case_exp
+#define stmt_end case_stmt
+#define match_exp x.xl
-#define target_stmt x.xi
+#define target_stmt x.xi
/* Op_K_switch */
#define switch_end x.xi
@@ -697,7 +765,7 @@ typedef struct exp_instruction {
#define func_body x.xn
/* Op_func_call */
-#define inrule d.dl
+#define tail_call d.dl
/* Op_subscript */
#define sub_count d.dl
@@ -732,9 +800,9 @@ typedef struct exp_instruction {
#define assign_ctxt d.dl
/* Op_concat */
-#define concat_flag d.dl
-#define CSUBSEP 1
-#define CSVAR 2
+#define concat_flag d.dl
+#define CSUBSEP 1
+#define CSVAR 2
/* Op_breakpoint */
#define break_pt x.bpt
@@ -764,6 +832,10 @@ typedef struct exp_instruction {
#define condpair_left d.di
#define condpair_right x.xi
+/* Op_store_var */
+#define initval x.xn
+
+
typedef struct iobuf {
const char *name; /* filename */
int fd; /* file descriptor */
@@ -856,7 +928,7 @@ typedef struct context {
SRCFILE srcfiles;
int sourceline;
char *source;
- void (*install_func)(char *);
+ void (*install_func)(NODE *);
struct context *prev;
} AWK_CONTEXT;
@@ -866,6 +938,20 @@ struct flagtab {
const char *name;
};
+
+typedef struct block_item {
+ size_t size;
+ struct block_item *freep;
+} BLOCK;
+
+enum block_id {
+ BLOCK_INVALID = 0, /* not legal */
+ BLOCK_NODE,
+ BLOCK_BUCKET,
+ BLOCK_MAX /* count */
+};
+
+
#ifndef LONG_MAX
#define LONG_MAX ((long)(~(1L << (sizeof (long) * 8 - 1))))
#endif
@@ -906,21 +992,52 @@ extern int sourceline;
extern char *source;
#if __GNUC__ < 2
-extern NODE *_t; /* used as temporary in tree_eval */
+extern NODE *_t; /* used as temporary in macros */
#endif
-extern NODE *_r; /* used as temporary in stack macros */
+extern NODE *_r; /* used as temporary in macros */
-extern NODE *nextfree;
+extern BLOCK nextfree[];
extern int field0_valid;
-extern int do_traditional;
-extern int do_posix;
-extern int do_intervals;
-extern int do_intl;
-extern int do_non_decimal_data;
-extern int do_profiling;
-extern int do_dump_vars;
-extern int do_tidy_mem;
-extern int do_sandbox;
+
+extern int do_flags;
+
+/* only warn about invalid */
+#define DO_LINT_INVALID 0x0001
+/* warn about all things */
+#define DO_LINT_ALL 0x0002
+/* warn about stuff not in V7 awk */
+#define DO_LINT_OLD 0x0004
+/* no gnu extensions, add traditional weirdnesses */
+#define DO_TRADITIONAL 0x0008
+/* turn off gnu and unix extensions */
+#define DO_POSIX 0x0010
+/* dump locale-izable strings to stdout */
+#define DO_INTL 0x0020
+/* allow octal/hex C style DATA. Use with caution! */
+#define DO_NON_DEC_DATA 0x0040
+/* allow {...,...} in regexps, see resetup() */
+#define DO_INTERVALS 0x0080
+/* profile and pretty print the program */
+#define DO_PROFILING 0x0100
+/* dump all global variables at end */
+#define DO_DUMP_VARS 0x0200
+/* release vars when done */
+#define DO_TIDY_MEM 0x0400
+/* sandbox mode - disable 'system' function & redirections */
+#define DO_SANDBOX 0x0800
+
+
+#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_profiling (do_flags & DO_PROFILING)
+#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)
+
+
extern int do_optimize;
extern int use_lc_numeric;
extern int exit_val;
@@ -929,8 +1046,8 @@ extern int exit_val;
#define do_lint 0
#define do_lint_old 0
#else
-extern int do_lint;
-extern int do_lint_old;
+#define do_lint (do_flags & (DO_LINT_INVALID|DO_LINT_ALL))
+#define do_lint_old (do_flags & DO_LINT_OLD)
#endif
#if MBS_SUPPORT
extern int gawk_mb_cur_max;
@@ -967,7 +1084,7 @@ extern enum exe_mode which_gawk; /* (defined in eval.c) */
typedef union stack_item {
NODE *rptr; /* variable etc. */
- NODE **lptr; /* address of a variable etc. */
+ NODE **lptr; /* address of a variable etc. */
} STACK_ITEM;
extern STACK_ITEM *stack_ptr;
@@ -975,84 +1092,75 @@ extern NODE *frame_ptr;
extern STACK_ITEM *stack_bottom;
extern STACK_ITEM *stack_top;
-#define decr_sp() (stack_ptr--)
+#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))
-
+#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]
+#define GET_PARAM(n) frame_ptr->stack[n]
/*
- * UPREF and DEREF --- simplified versions of dupnode and unref
- * UPREF does not handle FIELD node. Most appropriate use is
- * for elements on the runtime stack. When in doubt, use dupnode.
- */
+ * 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++)
-#define DEREF(r) ( _r = (r), (!(_r->flags & PERM) && (--_r->valref == 0)) ? unref(_r) : (void)0 )
+#define DEREF(r) ( _r = (r), (--_r->valref == 0) ? r_unref(_r) : (void)0 )
#if __GNUC__ >= 2
-#define UPREF(r) ({ NODE *_t = (r); !(_t->flags & PERM) && _t->valref++;})
#define POP_ARRAY() ({ NODE *_t = POP(); \
- _t->type == Node_var_array ? \
- _t : get_array(_t, TRUE); })
+ _t->type == Node_var_array ? _t : get_array(_t, TRUE); })
#define POP_PARAM() ({ NODE *_t = POP(); \
- _t->type == Node_var_array ? \
- _t : get_array(_t, FALSE); })
+ _t->type == Node_var_array ? _t : get_array(_t, FALSE); })
-#define POP_NUMBER(x) ({ NODE *_t = POP_SCALAR(); \
- x = force_number(_t); DEREF(_t); })
-#define TOP_NUMBER(x) ({ NODE *_t = TOP_SCALAR(); \
- x = force_number(_t); DEREF(_t); })
+#define POP_NUMBER(x) ({ NODE *_t = POP_SCALAR(); x = force_number(_t); DEREF(_t); })
+#define TOP_NUMBER(x) ({ NODE *_t = TOP_SCALAR(); x = force_number(_t); DEREF(_t); })
-#define POP_SCALAR() ({ NODE *_t = POP(); _t->type != Node_var_array ? _t \
- : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t);})
-#define TOP_SCALAR() ({ NODE *_t = TOP(); _t->type != Node_var_array ? _t \
- : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t);})
+#define POP_SCALAR() ({ NODE *_t = POP(); _t->type != Node_var_array ? _t \
+ : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t);})
+#define TOP_SCALAR() ({ NODE *_t = TOP(); _t->type != Node_var_array ? _t \
+ : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t);})
-#else /* not __GNUC__ */
+#define POP_STRING() force_string(POP_SCALAR())
+#define TOP_STRING() force_string(TOP_SCALAR())
-#define UPREF(r) (_t = (r), !(_t->flags & PERM) && _t->valref++)
+#else /* not __GNUC__ */
#define POP_ARRAY() (_t = POP(), \
- _t->type == Node_var_array ? \
- _t : get_array(_t, TRUE))
+ _t->type == Node_var_array ? _t : get_array(_t, TRUE))
#define POP_PARAM() (_t = POP(), \
- _t->type == Node_var_array ? \
- _t : get_array(_t, FALSE))
+ _t->type == Node_var_array ? _t : get_array(_t, FALSE))
-#define POP_NUMBER(x) (_t = POP_SCALAR(), \
- x = force_number(_t), DEREF(_t))
-#define TOP_NUMBER(x) (_t = TOP_SCALAR(), \
- x = force_number(_t), DEREF(_t))
+#define POP_NUMBER(x) (_t = POP_SCALAR(), x = force_number(_t), DEREF(_t))
+#define TOP_NUMBER(x) (_t = TOP_SCALAR(), x = force_number(_t), DEREF(_t))
#define POP_SCALAR() (_t = POP(), _t->type != Node_var_array ? _t \
- : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t))
+ : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t))
#define TOP_SCALAR() (_t = TOP(), _t->type != Node_var_array ? _t \
- : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t))
-
-#endif /* __GNUC__ */
+ : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t))
+#define POP_STRING() (_r = POP_SCALAR(), m_force_string(_r))
+#define TOP_STRING() (_r = TOP_SCALAR(), m_force_string(_r))
-#define POP_STRING() force_string(POP_SCALAR())
-#define TOP_STRING() force_string(TOP_SCALAR())
+#endif /* __GNUC__ */
/* ------------------------- Pseudo-functions ------------------------- */
-
#define is_identchar(c) (isalnum(c) || (c) == '_')
#define var_uninitialized(n) ((n)->var_value == Nnull_string)
@@ -1060,21 +1168,20 @@ extern STACK_ITEM *stack_top;
#define get_lhs(n, r) (n)->type == Node_var && ! var_uninitialized(n) ? \
&((n)->var_value) : r_get_lhs((n), (r))
-#ifdef MPROF
-#define getnode(n) emalloc((n), NODE *, sizeof(NODE), "getnode"), \
- (n)->flags = 0
-#define freenode(n) efree(n)
-#else /* not MPROF */
-#define getnode(n) (void) (nextfree ? \
- (n = nextfree, nextfree = nextfree->nextp) \
- : (n = more_nodes()))
-#define freenode(n) ((n)->flags = 0, (n)->nextp = nextfree, nextfree = (n))
-#endif /* not MPROF */
+#define getblock(p, id, ty) (void) ((p = (ty) nextfree[id].freep) ? \
+ (ty) (nextfree[id].freep = ((BLOCK *) p)->freep) \
+ : (p = (ty) more_blocks(id)))
+#define freeblock(p, id) (void) (((BLOCK *) p)->freep = nextfree[id].freep, \
+ nextfree[id].freep = (BLOCK *) p)
-#define make_number(x) mk_number((x), (unsigned int)(MALLOC|NUMCUR|NUMBER))
+#define getnode(n) getblock(n, BLOCK_NODE, NODE *)
+#define freenode(n) freeblock(n, BLOCK_NODE)
-#define make_string(s, l) r_make_str_node((s), (size_t) (l), 0)
-#define make_str_node(s, l, f) r_make_str_node((s), (size_t) (l), (f))
+#define getbucket(b) getblock(b, BLOCK_BUCKET, BUCKET *)
+#define freebucket(b) freeblock(b, BLOCK_BUCKET)
+
+#define make_string(s, l) r_make_str_node((s), (l), 0)
+#define make_str_node(s, l, f) r_make_str_node((s), (l), (f))
#define SCAN 1
#define ALREADY_MALLOCED 2
@@ -1094,19 +1201,34 @@ extern STACK_ITEM *stack_top;
#ifdef GAWKDEBUG
#define force_number r_force_number
-#define force_string r_force_string
+#define dupnode r_dupnode
+#define unref r_unref
+#define m_force_string r_force_string
+extern NODE *r_force_string(NODE *s);
#else /* not GAWKDEBUG */
+
+#define unref(r) ( _r = (r), (_r == NULL || --_r->valref > 0) ? \
+ (void)0 : r_unref(_r) )
+
+#define m_force_string(_ts) (((_ts->flags & STRCUR) && \
+ (_ts->stfmt == -1 || _ts->stfmt == CONVFMTidx)) ? \
+ _ts : format_val(CONVFMT, CONVFMTidx, _ts))
+
#if __GNUC__ >= 2
-#define force_number(n) __extension__ ({NODE *_tn = (n);\
- (_tn->flags & NUMCUR) ? _tn->numbr : r_force_number(_tn);})
+#define dupnode(n) __extension__ ({ NODE *_tn = (n); \
+ (_tn->flags & MALLOC) ? (_tn->valref++, _tn) : r_dupnode(_tn); })
+
+#define force_number(n) __extension__ ({ NODE *_tn = (n);\
+ (_tn->flags & NUMCUR) ? _tn->numbr : r_force_number(_tn); })
+
+#define force_string(s) __extension__ ({ NODE *_ts = (s); m_force_string(_ts); })
-#define force_string(s) __extension__ ({NODE *_ts = (s);\
- ((_ts->flags & STRCUR) && \
- (_ts->stfmt == -1 || _ts->stfmt == CONVFMTidx)) ?\
- _ts : format_val(CONVFMT, CONVFMTidx, _ts);})
#else /* not __GNUC__ */
+#define dupnode(n) (_t = (n), \
+ (_t->flags & MALLOC) ? (_t->valref++, _t) : r_dupnode(_t))
+
#define force_number r_force_number
-#define force_string r_force_string
+#define force_string(s) (_t = (s), m_force_string(_t))
#endif /* __GNUC__ */
#endif /* GAWKDEBUG */
@@ -1127,57 +1249,67 @@ if (val++) \
if (--val) \
memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf))
-/* ------------- Function prototypes or defs (as appropriate) ------------- */
-typedef int (*Func_print)(FILE *, const char *, ...);
+#define array_empty(a) ((a)->table_size == 0)
+#define assoc_lookup(a, s) (a)->alookup(a, s)
+
+#if __GNUC__ >= 2
+#define in_array(a, s) ({ NODE **_l; array_empty(a) ? NULL \
+ : (_l = (a)->aexists(a, s), _l ? *_l : NULL); })
+#else /* not __GNUC__ */
+#define in_array(a, s) r_in_array(a, s)
+#endif /* __GNUC__ */
+
+/* ------------- Function prototypes or defs (as appropriate) ------------- */
/* array.c */
typedef enum sort_context { SORTED_IN = 1, ASORT, ASORTI } SORT_CTXT;
-extern NODE **assoc_list(NODE *array, const char *sort_str, SORT_CTXT sort_ctxt);
+enum assoc_list_flags {
+AINDEX = 0x01, /* list of indices */
+AVALUE = 0x02, /* list of values */
+AINUM = 0x04, /* numeric index */
+AISTR = 0x08, /* string index */
+AVNUM = 0x10, /* numeric scalar value */
+AVSTR = 0x20, /* string scalar value */
+AASC = 0x40, /* ascending order */
+ADESC = 0x80, /* descending order */
+ADELETE = 0x100, /* need a single index; for use in do_delete_loop */
+};
+
+extern NODE *make_array(void);
+extern void init_array(NODE *symbol);
extern NODE *get_array(NODE *symbol, int canfatal);
-extern char *array_vname(const NODE *symbol);
+extern const char *make_aname(const NODE *symbol);
+extern const char *array_vname(const NODE *symbol);
extern void array_init(void);
+extern int register_array_func(array_ptr *afunc);
extern void set_SUBSEP(void);
extern NODE *concat_exp(int nargs, int do_subsep);
-extern void ahash_unref(NODE *tmp);
extern void assoc_clear(NODE *symbol);
-extern NODE *in_array(NODE *symbol, NODE *subs);
-extern NODE **assoc_lookup(NODE *symbol, NODE *subs, int reference);
+extern NODE *r_in_array(NODE *symbol, NODE *subs);
+extern int assoc_remove(NODE *symbol, NODE *subs);
+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_CTXT 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 *assoc_dump(NODE *symbol, int indent_level);
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);
/* awkgram.c */
-extern NODE *mk_symbol(NODETYPE type, NODE *value);
-extern NODE *install_symbol(char *name, NODE *value);
-extern NODE *remove_symbol(char *name);
-extern NODE *lookup(const char *name);
-extern NODE *variable(char *name, NODETYPE type);
+extern NODE *variable(int location, char *name, NODETYPE type);
extern int parse_program(INSTRUCTION **pcode);
extern void dump_funcs(void);
extern void dump_vars(const char *fname);
-extern void release_all_vars(void);
extern const char *getfname(NODE *(*)(int));
-extern NODE *stopme(int nargs);
extern void shadow_funcs(void);
extern int check_special(const char *name);
-extern int foreach_func(int (*)(INSTRUCTION *, void *), int, void *);
-extern INSTRUCTION *bcalloc(OPCODE op, int size, int srcline);
-extern void bcfree(INSTRUCTION *);
extern SRCFILE *add_srcfile(int stype, char *src, SRCFILE *curr, int *already_included, int *errcode);
extern void register_deferred_variable(const char *name, NODE *(*load_func)(void));
extern int files_are_same(char *path, SRCFILE *src);
extern void valinfo(NODE *n, Func_print print_func, FILE *fp);
-extern void print_vars(Func_print print_func, FILE *fp);
-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, int );
-extern void append_symbol(char *name);
-
/* builtin.c */
extern double double_to_int(double d);
extern NODE *do_exp(int nargs);
@@ -1227,7 +1359,7 @@ extern int strncasecmpmbs(const unsigned char *,
extern void PUSH_CODE(INSTRUCTION *cp);
extern INSTRUCTION *POP_CODE(void);
extern int interpret(INSTRUCTION *);
-extern int cmp_nodes(NODE *, NODE *);
+extern int cmp_nodes(NODE *p1, NODE *p2);
extern void set_IGNORECASE(void);
extern void set_OFS(void);
extern void set_ORS(void);
@@ -1259,7 +1391,6 @@ extern void dump_fcall_stack(FILE *fp);
NODE *do_ext(int nargs);
#ifdef DYNAMIC
void make_builtin(const char *, NODE *(*)(int), int);
-size_t get_curfunc_arg_count(void);
NODE *get_argument(int);
NODE *get_actual_argument(int, int, int);
#define get_scalar_argument(i, opt) get_actual_argument((i), (opt), FALSE)
@@ -1323,6 +1454,7 @@ extern int arg_assign(char *arg, int initing);
extern int is_std_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);
/* msg.c */
extern void gawk_exit(int status);
extern void err(const char *s, const char *emsg, va_list argp) ATTRIBUTE_PRINTF(2, 0);
@@ -1350,12 +1482,11 @@ extern void pp_string_fp(Func_print print_func, FILE *fp, const char *str,
/* node.c */
extern AWKNUM r_force_number(NODE *n);
extern NODE *format_val(const char *format, int index, NODE *s);
-extern NODE *r_force_string(NODE *s);
-extern NODE *dupnode(NODE *n);
-extern NODE *mk_number(AWKNUM x, unsigned int flags);
-extern NODE *r_make_str_node(const char *s, unsigned long len, int scan);
-extern NODE *more_nodes(void);
-extern void unref(NODE *tmp);
+extern NODE *r_dupnode(NODE *n);
+extern NODE *make_number(AWKNUM x);
+extern NODE *r_make_str_node(const char *s, size_t len, int flags);
+extern void *more_blocks(int id);
+extern void r_unref(NODE *tmp);
extern int parse_escape(const char **string_ptr);
#if MBS_SUPPORT
extern NODE *str2wstr(NODE *n, size_t **ptr);
@@ -1386,6 +1517,29 @@ extern int reisstring(const char *text, size_t len, Regexp *re, const char *buf)
extern int remaybelong(const char *text, size_t len);
extern int isnondecimal(const char *str, int use_locale);
+/* symbol.c */
+extern NODE *install_symbol(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, int );
+extern NODE **variable_list();
+extern NODE **function_list(int sort);
+extern void print_vars(NODE **table, Func_print print_func, FILE *fp);
+
/* floatcomp.c */
#ifdef VMS /* VMS linker weirdness? */
#define Ceil gawk_ceil
diff --git a/awkgram.c b/awkgram.c
index 7a06667e..32a4b66c 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -86,19 +86,15 @@ static char *get_src_buf(void);
static int yylex(void);
int yyparse(void);
static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
-static int func_install(INSTRUCTION *fp, INSTRUCTION *def);
-static void pop_params(NODE *params);
-static NODE *make_param(char *pname);
+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 append_param(char *pname);
-static int dup_parms(INSTRUCTION *fp, NODE *func);
static void param_sanity(INSTRUCTION *arglist);
static int parms_shadow(INSTRUCTION *pc, int *shadow);
static int isnoeffect(OPCODE type);
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 int isarray(NODE *n);
static int include_source(INSTRUCTION *file);
static void next_sourcefile(void);
static char *tokexpand(void);
@@ -107,6 +103,7 @@ static char *tokexpand(void);
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);
@@ -125,16 +122,13 @@ static void add_lint(INSTRUCTION *list, LINTTYPE linttype);
enum defref { FUNC_DEFINE, FUNC_USE };
static void func_use(const char *name, enum defref how);
static void check_funcs(void);
-static void free_bcpool(INSTRUCTION *pl);
static ssize_t read_one_line(int fd, void *buffer, size_t count);
static int one_line_close(int fd);
-static void (*install_func)(char *) = NULL;
-
static int want_source = FALSE;
static int want_regexp; /* lexical scanning kludge */
-static int can_return; /* parsing kludge */
+static char *in_function; /* parsing kludge */
static int rule = 0;
const char *const ruletab[] = {
@@ -169,22 +163,11 @@ static int continue_allowed; /* kludge for continue */
#define END_SRC -2000
#define YYDEBUG_LEXER_TEXT (lexeme)
-static int param_counter;
-static NODE *func_params; /* list of parameters for the current function */
static char *tokstart = NULL;
static char *tok = NULL;
static char *tokend;
static int errcount = 0;
-static NODE *symbol_list;
-extern void destroy_symbol(char *name);
-
-static long func_count; /* total number of functions */
-
-#define HASHSIZE 1021 /* this constant only used here */
-NODE *variables[HASHSIZE];
-static int var_count; /* total number of global variables */
-
extern char *source;
extern int sourceline;
extern SRCFILE *srcfiles;
@@ -206,22 +189,12 @@ 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);
-/*
- * This string cannot occur as a real awk identifier.
- * Use it as a special token to make function parsing
- * uniform, but if it's seen, don't install the function.
- * e.g.
- * function split(x) { return x }
- * function x(a) { return a }
- * should only produce one error message, and not core dump.
- */
-static char builtin_func[] = "@builtin";
#define YYSTYPE INSTRUCTION *
/* Line 268 of yacc.c */
-#line 225 "awkgram.c"
+#line 198 "awkgram.c"
/* Enabling traces. */
#ifndef YYDEBUG
@@ -367,7 +340,7 @@ typedef int YYSTYPE;
/* Line 343 of yacc.c */
-#line 371 "awkgram.c"
+#line 344 "awkgram.c"
#ifdef short
# undef short
@@ -583,16 +556,16 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 1157
+#define YYLAST 1150
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 74
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 65
+#define YYNNTS 64
/* YYNRULES -- Number of rules. */
-#define YYNRULES 185
+#define YYNRULES 184
/* YYNRULES -- Number of states. */
-#define YYNSTATES 330
+#define YYNSTATES 329
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
@@ -644,110 +617,110 @@ static const yytype_uint16 yyprhs[] =
{
0, 0, 3, 4, 7, 10, 13, 16, 19, 22,
25, 30, 32, 35, 37, 38, 40, 45, 47, 49,
- 51, 53, 59, 61, 63, 65, 68, 70, 72, 73,
- 81, 82, 86, 88, 90, 91, 94, 97, 99, 102,
- 105, 109, 111, 121, 128, 137, 146, 159, 171, 173,
- 176, 179, 182, 185, 189, 190, 195, 198, 199, 204,
- 205, 210, 215, 217, 218, 220, 221, 224, 227, 233,
- 238, 240, 243, 246, 248, 250, 252, 254, 256, 260,
- 261, 262, 266, 273, 283, 285, 288, 289, 291, 292,
- 295, 296, 298, 300, 304, 306, 309, 313, 314, 316,
- 317, 319, 321, 325, 327, 330, 334, 338, 342, 346,
- 350, 354, 358, 362, 368, 370, 372, 374, 377, 379,
- 381, 383, 385, 387, 389, 392, 394, 398, 402, 406,
- 410, 414, 418, 422, 425, 428, 434, 439, 443, 447,
- 451, 455, 459, 463, 465, 468, 472, 477, 482, 484,
- 486, 488, 491, 494, 496, 498, 501, 504, 506, 509,
- 514, 515, 517, 518, 521, 523, 526, 528, 532, 534,
- 537, 540, 542, 545, 547, 551, 553, 555, 556, 559,
- 562, 564, 565, 567, 569, 571
+ 51, 53, 59, 61, 63, 65, 68, 70, 72, 79,
+ 80, 84, 86, 88, 89, 92, 95, 97, 100, 103,
+ 107, 109, 119, 126, 135, 144, 157, 169, 171, 174,
+ 177, 180, 183, 187, 188, 193, 196, 197, 202, 203,
+ 208, 213, 215, 216, 218, 219, 222, 225, 231, 236,
+ 238, 241, 244, 246, 248, 250, 252, 254, 258, 259,
+ 260, 264, 271, 281, 283, 286, 287, 289, 290, 293,
+ 294, 296, 298, 302, 304, 307, 311, 312, 314, 315,
+ 317, 319, 323, 325, 328, 332, 336, 340, 344, 348,
+ 352, 356, 360, 366, 368, 370, 372, 375, 377, 379,
+ 381, 383, 385, 387, 390, 392, 396, 400, 404, 408,
+ 412, 416, 420, 423, 426, 432, 437, 441, 445, 449,
+ 453, 457, 461, 463, 466, 470, 475, 480, 482, 484,
+ 486, 489, 492, 494, 496, 499, 502, 504, 507, 512,
+ 513, 515, 516, 519, 521, 524, 526, 530, 532, 535,
+ 538, 540, 543, 545, 549, 551, 553, 554, 557, 560,
+ 562, 563, 565, 567, 569
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int16 yyrhs[] =
{
- 75, 0, -1, -1, 75, 76, -1, 75, 104, -1,
+ 75, 0, -1, -1, 75, 76, -1, 75, 103, -1,
75, 47, -1, 75, 1, -1, 78, 79, -1, 78,
- 88, -1, 82, 79, -1, 68, 48, 77, 88, -1,
- 6, -1, 6, 1, -1, 1, -1, -1, 112, -1,
- 112, 54, 105, 112, -1, 17, -1, 18, -1, 36,
- -1, 37, -1, 132, 87, 133, 135, 105, -1, 4,
+ 87, -1, 82, 79, -1, 68, 48, 77, 87, -1,
+ 6, -1, 6, 1, -1, 1, -1, -1, 111, -1,
+ 111, 54, 104, 111, -1, 17, -1, 18, -1, 36,
+ -1, 37, -1, 131, 86, 132, 134, 104, -1, 4,
-1, 3, -1, 81, -1, 68, 49, -1, 45, -1,
- 46, -1, -1, 35, 83, 80, 66, 107, 134, 105,
- -1, -1, 86, 85, 5, -1, 60, -1, 51, -1,
- -1, 87, 89, -1, 87, 1, -1, 104, -1, 136,
- 105, -1, 136, 105, -1, 132, 87, 133, -1, 103,
- -1, 23, 66, 112, 134, 105, 132, 96, 105, 133,
- -1, 26, 66, 112, 134, 105, 89, -1, 27, 105,
- 89, 26, 66, 112, 134, 105, -1, 28, 66, 4,
- 40, 129, 134, 105, 89, -1, 28, 66, 95, 136,
- 105, 112, 136, 105, 95, 134, 105, 89, -1, 28,
- 66, 95, 136, 105, 136, 105, 95, 134, 105, 89,
- -1, 90, -1, 29, 88, -1, 30, 88, -1, 33,
- 88, -1, 39, 88, -1, 34, 109, 88, -1, -1,
- 21, 91, 109, 88, -1, 92, 88, -1, -1, 99,
- 93, 100, 101, -1, -1, 22, 4, 94, 123, -1,
- 22, 66, 4, 67, -1, 112, -1, -1, 92, -1,
- -1, 96, 97, -1, 96, 1, -1, 24, 98, 137,
- 105, 87, -1, 25, 137, 105, 87, -1, 7, -1,
- 58, 7, -1, 57, 7, -1, 8, -1, 84, -1,
- 31, -1, 32, -1, 110, -1, 66, 111, 134, -1,
- -1, -1, 10, 102, 116, -1, 19, 66, 112, 134,
- 105, 89, -1, 19, 66, 112, 134, 105, 89, 20,
- 105, 89, -1, 50, -1, 104, 50, -1, -1, 104,
- -1, -1, 55, 117, -1, -1, 108, -1, 4, -1,
- 108, 138, 4, -1, 1, -1, 108, 1, -1, 108,
- 138, 1, -1, -1, 112, -1, -1, 111, -1, 112,
- -1, 111, 138, 112, -1, 1, -1, 111, 1, -1,
- 111, 1, 112, -1, 111, 138, 1, -1, 130, 113,
- 112, -1, 112, 41, 112, -1, 112, 42, 112, -1,
- 112, 14, 112, -1, 112, 40, 129, -1, 112, 115,
- 112, -1, 112, 52, 112, 53, 112, -1, 116, -1,
- 13, -1, 12, -1, 51, 13, -1, 9, -1, 55,
- -1, 114, -1, 56, -1, 117, -1, 118, -1, 116,
- 117, -1, 119, -1, 117, 64, 117, -1, 117, 59,
- 117, -1, 117, 60, 117, -1, 117, 61, 117, -1,
- 117, 57, 117, -1, 117, 58, 117, -1, 38, 122,
- 106, -1, 130, 43, -1, 130, 44, -1, 66, 111,
- 134, 40, 129, -1, 116, 11, 38, 122, -1, 118,
- 64, 117, -1, 118, 59, 117, -1, 118, 60, 117,
- -1, 118, 61, 117, -1, 118, 57, 117, -1, 118,
- 58, 117, -1, 84, -1, 62, 117, -1, 66, 112,
- 134, -1, 45, 66, 110, 134, -1, 46, 66, 110,
- 134, -1, 46, -1, 120, -1, 130, -1, 43, 130,
- -1, 44, 130, -1, 7, -1, 8, -1, 58, 117,
- -1, 57, 117, -1, 121, -1, 68, 121, -1, 3,
- 66, 110, 134, -1, -1, 130, -1, -1, 124, 16,
- -1, 125, -1, 124, 125, -1, 126, -1, 69, 111,
- 70, -1, 126, -1, 127, 126, -1, 127, 16, -1,
- 4, -1, 4, 128, -1, 129, -1, 65, 119, 131,
- -1, 43, -1, 44, -1, -1, 71, 105, -1, 72,
- 105, -1, 67, -1, -1, 136, -1, 73, -1, 53,
- -1, 54, 105, -1
+ 46, -1, 35, 80, 66, 106, 133, 104, -1, -1,
+ 85, 84, 5, -1, 60, -1, 51, -1, -1, 86,
+ 88, -1, 86, 1, -1, 103, -1, 135, 104, -1,
+ 135, 104, -1, 131, 86, 132, -1, 102, -1, 23,
+ 66, 111, 133, 104, 131, 95, 104, 132, -1, 26,
+ 66, 111, 133, 104, 88, -1, 27, 104, 88, 26,
+ 66, 111, 133, 104, -1, 28, 66, 4, 40, 128,
+ 133, 104, 88, -1, 28, 66, 94, 135, 104, 111,
+ 135, 104, 94, 133, 104, 88, -1, 28, 66, 94,
+ 135, 104, 135, 104, 94, 133, 104, 88, -1, 89,
+ -1, 29, 87, -1, 30, 87, -1, 33, 87, -1,
+ 39, 87, -1, 34, 108, 87, -1, -1, 21, 90,
+ 108, 87, -1, 91, 87, -1, -1, 98, 92, 99,
+ 100, -1, -1, 22, 4, 93, 122, -1, 22, 66,
+ 4, 67, -1, 111, -1, -1, 91, -1, -1, 95,
+ 96, -1, 95, 1, -1, 24, 97, 136, 104, 86,
+ -1, 25, 136, 104, 86, -1, 7, -1, 58, 7,
+ -1, 57, 7, -1, 8, -1, 83, -1, 31, -1,
+ 32, -1, 109, -1, 66, 110, 133, -1, -1, -1,
+ 10, 101, 115, -1, 19, 66, 111, 133, 104, 88,
+ -1, 19, 66, 111, 133, 104, 88, 20, 104, 88,
+ -1, 50, -1, 103, 50, -1, -1, 103, -1, -1,
+ 55, 116, -1, -1, 107, -1, 4, -1, 107, 137,
+ 4, -1, 1, -1, 107, 1, -1, 107, 137, 1,
+ -1, -1, 111, -1, -1, 110, -1, 111, -1, 110,
+ 137, 111, -1, 1, -1, 110, 1, -1, 110, 1,
+ 111, -1, 110, 137, 1, -1, 129, 112, 111, -1,
+ 111, 41, 111, -1, 111, 42, 111, -1, 111, 14,
+ 111, -1, 111, 40, 128, -1, 111, 114, 111, -1,
+ 111, 52, 111, 53, 111, -1, 115, -1, 13, -1,
+ 12, -1, 51, 13, -1, 9, -1, 55, -1, 113,
+ -1, 56, -1, 116, -1, 117, -1, 115, 116, -1,
+ 118, -1, 116, 64, 116, -1, 116, 59, 116, -1,
+ 116, 60, 116, -1, 116, 61, 116, -1, 116, 57,
+ 116, -1, 116, 58, 116, -1, 38, 121, 105, -1,
+ 129, 43, -1, 129, 44, -1, 66, 110, 133, 40,
+ 128, -1, 115, 11, 38, 121, -1, 117, 64, 116,
+ -1, 117, 59, 116, -1, 117, 60, 116, -1, 117,
+ 61, 116, -1, 117, 57, 116, -1, 117, 58, 116,
+ -1, 83, -1, 62, 116, -1, 66, 111, 133, -1,
+ 45, 66, 109, 133, -1, 46, 66, 109, 133, -1,
+ 46, -1, 119, -1, 129, -1, 43, 129, -1, 44,
+ 129, -1, 7, -1, 8, -1, 58, 116, -1, 57,
+ 116, -1, 120, -1, 68, 120, -1, 3, 66, 109,
+ 133, -1, -1, 129, -1, -1, 123, 16, -1, 124,
+ -1, 123, 124, -1, 125, -1, 69, 110, 70, -1,
+ 125, -1, 126, 125, -1, 126, 16, -1, 4, -1,
+ 4, 127, -1, 128, -1, 65, 118, 130, -1, 43,
+ -1, 44, -1, -1, 71, 104, -1, 72, 104, -1,
+ 67, -1, -1, 135, -1, 73, -1, 53, -1, 54,
+ 104, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 218, 218, 220, 225, 226, 230, 242, 246, 257,
- 265, 273, 281, 283, 289, 290, 292, 318, 329, 340,
- 346, 355, 365, 367, 369, 380, 385, 386, 391, 390,
- 420, 419, 452, 454, 459, 460, 473, 478, 479, 483,
- 485, 487, 494, 584, 626, 668, 781, 788, 795, 805,
- 814, 823, 832, 847, 863, 862, 874, 886, 886, 982,
- 982, 1007, 1030, 1036, 1037, 1043, 1044, 1051, 1056, 1068,
- 1082, 1084, 1090, 1095, 1097, 1105, 1107, 1116, 1117, 1125,
- 1130, 1130, 1141, 1145, 1153, 1154, 1157, 1159, 1164, 1165,
- 1172, 1174, 1178, 1184, 1191, 1193, 1195, 1202, 1203, 1209,
- 1210, 1215, 1217, 1222, 1224, 1226, 1228, 1234, 1241, 1243,
- 1245, 1261, 1271, 1278, 1280, 1285, 1287, 1289, 1297, 1299,
- 1304, 1306, 1311, 1313, 1315, 1368, 1370, 1372, 1374, 1376,
- 1378, 1380, 1382, 1405, 1410, 1415, 1440, 1446, 1448, 1450,
- 1452, 1454, 1456, 1461, 1465, 1496, 1498, 1504, 1510, 1523,
- 1524, 1525, 1530, 1535, 1539, 1543, 1555, 1568, 1573, 1609,
- 1627, 1628, 1634, 1635, 1640, 1642, 1649, 1666, 1683, 1685,
- 1692, 1697, 1705, 1719, 1731, 1740, 1744, 1748, 1752, 1756,
- 1760, 1763, 1765, 1769, 1773, 1777
+ 0, 191, 191, 193, 198, 199, 203, 215, 219, 230,
+ 236, 244, 252, 254, 260, 261, 263, 289, 300, 311,
+ 317, 326, 336, 338, 340, 346, 351, 352, 356, 375,
+ 374, 408, 410, 415, 416, 429, 434, 435, 439, 441,
+ 443, 450, 540, 582, 624, 737, 744, 751, 761, 770,
+ 779, 788, 803, 819, 818, 842, 854, 854, 948, 948,
+ 973, 996, 1002, 1003, 1009, 1010, 1017, 1022, 1034, 1048,
+ 1050, 1056, 1061, 1063, 1071, 1073, 1082, 1083, 1091, 1096,
+ 1096, 1107, 1111, 1119, 1120, 1123, 1125, 1130, 1131, 1140,
+ 1141, 1146, 1151, 1157, 1159, 1161, 1168, 1169, 1175, 1176,
+ 1181, 1183, 1188, 1190, 1192, 1194, 1200, 1207, 1209, 1211,
+ 1227, 1237, 1244, 1246, 1251, 1253, 1255, 1263, 1265, 1270,
+ 1272, 1277, 1279, 1281, 1331, 1333, 1335, 1337, 1339, 1341,
+ 1343, 1345, 1368, 1373, 1378, 1403, 1409, 1411, 1413, 1415,
+ 1417, 1419, 1424, 1428, 1459, 1461, 1467, 1473, 1486, 1487,
+ 1488, 1493, 1498, 1502, 1506, 1519, 1532, 1537, 1573, 1591,
+ 1592, 1598, 1599, 1604, 1606, 1613, 1630, 1647, 1649, 1656,
+ 1661, 1669, 1679, 1691, 1700, 1704, 1708, 1712, 1716, 1720,
+ 1723, 1725, 1729, 1733, 1737
};
#endif
@@ -769,10 +742,10 @@ static const char *const yytname[] =
"'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "UNARY", "'^'", "'$'", "'('",
"')'", "'@'", "'['", "']'", "'{'", "'}'", "';'", "$accept", "program",
"rule", "source", "pattern", "action", "func_name", "lex_builtin",
- "function_prologue", "$@1", "regexp", "$@2", "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",
+ "function_prologue", "regexp", "$@1", "a_slash", "statements",
+ "statement_term", "statement", "non_compound_stmt", "$@2", "simple_stmt",
+ "$@3", "$@4", "opt_simple_stmt", "case_statements", "case_statement",
+ "case_value", "print", "print_expression_list", "output_redir", "$@5",
"if_statement", "nls", "opt_nls", "input_redir", "opt_param_list",
"param_list", "opt_exp", "opt_expression_list", "expression_list", "exp",
"assign_operator", "relop_or_less", "a_relop", "common_exp", "simp_exp",
@@ -805,23 +778,23 @@ static const yytype_uint8 yyr1[] =
{
0, 74, 75, 75, 75, 75, 75, 76, 76, 76,
76, 77, 77, 77, 78, 78, 78, 78, 78, 78,
- 78, 79, 80, 80, 80, 80, 81, 81, 83, 82,
- 85, 84, 86, 86, 87, 87, 87, 88, 88, 89,
- 89, 89, 89, 89, 89, 89, 89, 89, 89, 90,
- 90, 90, 90, 90, 91, 90, 90, 93, 92, 94,
- 92, 92, 92, 95, 95, 96, 96, 96, 97, 97,
- 98, 98, 98, 98, 98, 99, 99, 100, 100, 101,
- 102, 101, 103, 103, 104, 104, 105, 105, 106, 106,
- 107, 107, 108, 108, 108, 108, 108, 109, 109, 110,
- 110, 111, 111, 111, 111, 111, 111, 112, 112, 112,
- 112, 112, 112, 112, 112, 113, 113, 113, 114, 114,
- 115, 115, 116, 116, 116, 117, 117, 117, 117, 117,
- 117, 117, 117, 117, 117, 117, 118, 118, 118, 118,
- 118, 118, 118, 119, 119, 119, 119, 119, 119, 119,
- 119, 119, 119, 119, 119, 119, 119, 120, 120, 121,
- 122, 122, 123, 123, 124, 124, 125, 126, 127, 127,
- 128, 129, 129, 130, 130, 131, 131, 131, 132, 133,
- 134, 135, 135, 136, 137, 138
+ 78, 79, 80, 80, 80, 80, 81, 81, 82, 84,
+ 83, 85, 85, 86, 86, 86, 87, 87, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 89, 89,
+ 89, 89, 89, 90, 89, 89, 92, 91, 93, 91,
+ 91, 91, 94, 94, 95, 95, 95, 96, 96, 97,
+ 97, 97, 97, 97, 98, 98, 99, 99, 100, 101,
+ 100, 102, 102, 103, 103, 104, 104, 105, 105, 106,
+ 106, 107, 107, 107, 107, 107, 108, 108, 109, 109,
+ 110, 110, 110, 110, 110, 110, 111, 111, 111, 111,
+ 111, 111, 111, 111, 112, 112, 112, 113, 113, 114,
+ 114, 115, 115, 115, 116, 116, 116, 116, 116, 116,
+ 116, 116, 116, 116, 116, 117, 117, 117, 117, 117,
+ 117, 117, 118, 118, 118, 118, 118, 118, 118, 118,
+ 118, 118, 118, 118, 118, 118, 119, 119, 120, 121,
+ 121, 122, 122, 123, 123, 124, 125, 126, 126, 127,
+ 128, 128, 129, 129, 130, 130, 130, 131, 132, 133,
+ 134, 134, 135, 136, 137
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
@@ -829,23 +802,23 @@ static const yytype_uint8 yyr2[] =
{
0, 2, 0, 2, 2, 2, 2, 2, 2, 2,
4, 1, 2, 1, 0, 1, 4, 1, 1, 1,
- 1, 5, 1, 1, 1, 2, 1, 1, 0, 7,
- 0, 3, 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, 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, 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
+ 1, 5, 1, 1, 1, 2, 1, 1, 6, 0,
+ 3, 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, 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, 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
};
/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -853,353 +826,353 @@ static const yytype_uint8 yyr2[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 2, 0, 1, 6, 0, 171, 153, 154, 17, 18,
- 28, 19, 20, 160, 0, 0, 0, 148, 5, 84,
- 33, 0, 0, 32, 0, 0, 0, 0, 3, 0,
- 0, 143, 30, 4, 15, 114, 122, 123, 125, 149,
- 157, 173, 150, 0, 0, 168, 0, 172, 0, 88,
- 161, 151, 152, 0, 0, 0, 156, 150, 155, 144,
- 0, 177, 150, 103, 0, 101, 0, 158, 86, 183,
- 7, 8, 37, 34, 86, 9, 0, 85, 118, 0,
- 0, 0, 0, 0, 86, 119, 121, 120, 0, 0,
- 124, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 116, 115, 133, 134, 0, 0, 0,
- 0, 101, 0, 170, 169, 23, 22, 26, 27, 0,
- 0, 24, 0, 132, 0, 0, 0, 175, 176, 174,
- 104, 86, 180, 0, 0, 145, 13, 0, 0, 87,
- 178, 0, 38, 31, 110, 111, 108, 109, 0, 0,
- 112, 160, 130, 131, 127, 128, 129, 126, 141, 142,
- 138, 139, 140, 137, 117, 107, 159, 167, 25, 0,
- 89, 146, 147, 105, 185, 0, 106, 102, 12, 10,
- 36, 0, 54, 0, 0, 0, 86, 0, 0, 0,
- 75, 76, 0, 97, 0, 86, 35, 48, 0, 57,
- 41, 62, 34, 181, 86, 0, 16, 136, 94, 92,
- 0, 0, 135, 0, 97, 59, 0, 0, 0, 0,
- 63, 49, 50, 51, 0, 98, 52, 179, 56, 0,
- 0, 86, 182, 39, 113, 86, 95, 0, 0, 0,
- 162, 0, 0, 0, 0, 171, 64, 0, 53, 0,
- 79, 77, 40, 21, 29, 96, 93, 86, 55, 60,
- 0, 164, 166, 61, 86, 86, 0, 0, 86, 0,
- 80, 58, 0, 163, 165, 0, 0, 0, 0, 0,
- 78, 0, 82, 65, 43, 0, 86, 0, 86, 81,
- 86, 0, 86, 0, 86, 63, 0, 67, 0, 0,
- 66, 0, 44, 45, 63, 0, 83, 70, 73, 0,
- 0, 74, 0, 184, 86, 42, 0, 86, 72, 71,
- 86, 34, 86, 0, 34, 0, 0, 47, 0, 46
+ 2, 0, 1, 6, 0, 170, 152, 153, 17, 18,
+ 0, 19, 20, 159, 0, 0, 0, 147, 5, 83,
+ 32, 0, 0, 31, 0, 0, 0, 0, 3, 0,
+ 0, 142, 29, 4, 15, 113, 121, 122, 124, 148,
+ 156, 172, 149, 0, 0, 167, 0, 171, 23, 22,
+ 26, 27, 0, 0, 24, 87, 160, 150, 151, 0,
+ 0, 0, 155, 149, 154, 143, 0, 176, 149, 102,
+ 0, 100, 0, 157, 85, 182, 7, 8, 36, 33,
+ 85, 9, 0, 84, 117, 0, 0, 0, 0, 0,
+ 85, 118, 120, 119, 0, 0, 123, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 115,
+ 114, 132, 133, 0, 0, 0, 0, 100, 0, 169,
+ 168, 25, 0, 0, 131, 0, 0, 0, 174, 175,
+ 173, 103, 85, 179, 0, 0, 144, 13, 0, 0,
+ 86, 177, 0, 37, 30, 109, 110, 107, 108, 0,
+ 0, 111, 159, 129, 130, 126, 127, 128, 125, 140,
+ 141, 137, 138, 139, 136, 116, 106, 158, 166, 93,
+ 91, 0, 0, 88, 145, 146, 104, 184, 0, 105,
+ 101, 12, 10, 35, 0, 53, 0, 0, 0, 85,
+ 0, 0, 0, 74, 75, 0, 96, 0, 85, 34,
+ 47, 0, 56, 40, 61, 33, 180, 85, 0, 16,
+ 135, 85, 94, 0, 134, 0, 96, 58, 0, 0,
+ 0, 0, 62, 48, 49, 50, 0, 97, 51, 178,
+ 55, 0, 0, 85, 181, 38, 112, 28, 95, 92,
+ 0, 0, 161, 0, 0, 0, 0, 170, 63, 0,
+ 52, 0, 78, 76, 39, 21, 85, 54, 59, 0,
+ 163, 165, 60, 85, 85, 0, 0, 85, 0, 79,
+ 57, 0, 162, 164, 0, 0, 0, 0, 0, 77,
+ 0, 81, 64, 42, 0, 85, 0, 85, 80, 85,
+ 0, 85, 0, 85, 62, 0, 66, 0, 0, 65,
+ 0, 43, 44, 62, 0, 82, 69, 72, 0, 0,
+ 73, 0, 183, 85, 41, 0, 85, 71, 70, 85,
+ 33, 85, 0, 33, 0, 0, 46, 0, 45
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 28, 138, 29, 70, 120, 121, 30, 48,
- 31, 76, 32, 141, 71, 196, 197, 214, 198, 229,
- 240, 247, 291, 300, 312, 199, 250, 271, 281, 200,
- 139, 140, 123, 210, 211, 224, 109, 110, 201, 108,
- 87, 88, 35, 36, 37, 38, 39, 40, 49, 259,
- 260, 261, 45, 46, 47, 41, 42, 129, 202, 203,
- 135, 231, 204, 314, 134
+ -1, 1, 28, 139, 29, 76, 53, 54, 30, 31,
+ 82, 32, 142, 77, 199, 200, 216, 201, 231, 242,
+ 249, 290, 299, 311, 202, 252, 270, 280, 203, 140,
+ 141, 124, 171, 172, 226, 115, 116, 204, 114, 93,
+ 94, 35, 36, 37, 38, 39, 40, 55, 258, 259,
+ 260, 45, 46, 47, 41, 42, 130, 205, 206, 136,
+ 233, 207, 313, 135
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -269
+#define YYPACT_NINF -264
static const yytype_int16 yypact[] =
{
- -269, 335, -269, -269, -31, -24, -269, -269, -269, -269,
- -269, -269, -269, 12, 12, 12, -19, -12, -269, -269,
- -269, 978, 978, -269, 978, 1023, 804, 21, -269, 115,
- -21, -269, -269, 8, 1062, 952, -20, 330, -269, -269,
- -269, -269, 246, 736, 804, -269, 2, -269, 205, 15,
- -269, -269, -269, 736, 736, 70, 52, 80, 52, 52,
- 978, 147, -269, -269, 50, 308, 174, -269, 64, -269,
- -269, -269, 8, -269, 64, -269, 129, -269, -269, 978,
- 143, 978, 978, 978, 64, -269, -269, -269, 978, 112,
- -20, 978, 978, 978, 978, 978, 978, 978, 978, 978,
- 978, 978, 978, -269, -269, -269, -269, 141, 978, 90,
- 152, 1101, 48, -269, -269, -269, -269, -269, -269, 111,
- 105, -269, 978, -269, 90, 90, 308, -269, -269, -269,
- 978, 64, -269, 134, 830, -269, -269, 13, -16, 8,
- -269, 552, -269, -269, 53, -269, 142, 300, 1081, 978,
- 103, 12, 185, 185, 52, 52, 52, 52, 185, 185,
- 52, 52, 52, 52, -269, 1101, -269, -269, -269, 63,
- -20, -269, -269, 1101, -269, 143, -269, 1101, -269, -269,
- -269, 121, -269, 6, 130, 137, 64, 139, -16, -16,
- -269, -269, -16, 978, -16, 64, -269, -269, -16, -269,
- -269, 1101, -269, 127, 64, 978, 1101, -269, -269, -269,
- 90, 118, -269, 978, 978, -269, 180, 978, 978, 665,
- 875, -269, -269, -269, -16, 1101, -269, -269, -269, 598,
- 552, 64, -269, -269, 1101, 64, -269, 28, 308, -16,
- -24, 140, 308, 308, 189, -14, -269, 127, -269, 804,
- 201, -269, -269, -269, -269, -269, -269, 64, -269, -269,
- 14, -269, -269, -269, 64, 64, 158, 143, 64, 50,
- -269, -269, 665, -269, -269, -21, 665, 978, 90, 710,
- 134, 978, 198, -269, -269, 308, 64, 1056, 64, 952,
- 64, 60, 64, 665, 64, 907, 665, -269, 119, 177,
- -269, 155, -269, -269, 907, 90, -269, -269, -269, 224,
- 228, -269, 177, -269, 64, -269, 90, 64, -269, -269,
- 64, -269, 64, 665, -269, 406, 665, -269, 479, -269
+ -264, 367, -264, -264, -31, -42, -264, -264, -264, -264,
+ 165, -264, -264, 46, 46, 46, -29, -27, -264, -264,
+ -264, 1010, 1010, -264, 1010, 1055, 836, 27, -264, -35,
+ -7, -264, -264, 17, 1088, 984, 288, 362, -264, -264,
+ -264, -264, 146, 768, 836, -264, 1, -264, -264, -264,
+ -264, -264, 60, -18, -264, 11, -264, -264, -264, 768,
+ 768, 74, 52, 9, 52, 52, 1010, 13, -264, -264,
+ 53, 341, 28, -264, 79, -264, -264, -264, 17, -264,
+ 79, -264, 119, -264, -264, 1010, 148, 1010, 1010, 1010,
+ 79, -264, -264, -264, 1010, 122, 288, 1010, 1010, 1010,
+ 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, -264,
+ -264, -264, -264, 151, 1010, 94, 81, 1094, 40, -264,
+ -264, -264, 45, 1010, -264, 94, 94, 341, -264, -264,
+ -264, 1010, 79, -264, 125, 862, -264, -264, 82, -22,
+ 17, -264, 584, -264, -264, 62, -264, 212, 267, 301,
+ 1010, 118, 46, 127, 127, 52, 52, 52, 52, 127,
+ 127, 52, 52, 52, 52, -264, 1094, -264, -264, -264,
+ -264, 94, 61, 288, -264, -264, 1094, -264, 148, -264,
+ 1094, -264, -264, -264, 105, -264, 10, 109, 112, 79,
+ 113, -22, -22, -264, -264, -22, 1010, -22, 79, -264,
+ -264, -22, -264, -264, 1094, -264, 107, 79, 1010, 1094,
+ -264, 79, -264, 43, -264, 1010, 1010, -264, 180, 1010,
+ 1010, 697, 907, -264, -264, -264, -22, 1094, -264, -264,
+ -264, 630, 584, 79, -264, -264, 1094, -264, -264, -264,
+ 341, -22, -42, 126, 341, 341, 166, -14, -264, 107,
+ -264, 836, 190, -264, -264, -264, 79, -264, -264, 16,
+ -264, -264, -264, 79, 79, 136, 148, 79, 53, -264,
+ -264, 697, -264, -264, -7, 697, 1010, 94, 742, 125,
+ 1010, 186, -264, -264, 341, 79, 278, 79, 984, 79,
+ 132, 79, 697, 79, 939, 697, -264, 240, 155, -264,
+ 137, -264, -264, 939, 94, -264, -264, -264, 205, 206,
+ -264, 155, -264, 79, -264, 94, 79, -264, -264, 79,
+ -264, 79, 697, -264, 438, 697, -264, 511, -264
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -269, -269, -269, -269, -269, 208, -269, -269, -269, -269,
- -58, -269, -269, -193, 72, -171, -269, -269, -189, -269,
- -269, -268, -269, -269, -269, -269, -269, -269, -269, -269,
- 45, 37, -269, -269, -269, 38, -48, -23, -1, -269,
- -269, -269, -26, 44, -269, 217, -269, 1, 102, -269,
- -269, -3, -39, -269, -269, -72, -2, -269, -28, -213,
- -49, -269, -25, -47, 66
+ -264, -264, -264, -264, -264, 187, -264, -264, -264, -74,
+ -264, -264, -197, 98, -203, -264, -264, -213, -264, -264,
+ -263, -264, -264, -264, -264, -264, -264, -264, -264, 44,
+ 73, -264, -264, -264, 18, -54, -23, -1, -264, -264,
+ -264, -55, 39, -264, 202, -264, 124, 77, -264, -264,
+ -19, -39, -264, -264, -70, -2, -264, -28, -222, -46,
+ -264, -25, -79, 70
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
number is the opposite. If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -101
+#define YYTABLE_NINF -100
static const yytype_int16 yytable[] =
{
- 34, 73, 73, 64, 74, 124, 125, 114, 145, 230,
- 215, 50, 51, 52, 178, 133, 5, 252, 113, 57,
- 57, 112, 57, 62, 4, 65, 267, 305, 67, 255,
- 273, 246, 256, 57, 19, 43, 316, 91, 92, 93,
- 94, 95, 111, 111, 96, 44, 33, 53, 244, 130,
- 68, 130, 111, 111, 54, 44, 67, 69, 77, 126,
- 166, 297, 78, -11, 208, 56, 58, 209, 59, 66,
- 122, 44, 216, 4, 72, 171, 172, 25, 144, 90,
- 146, 147, 148, 44, 298, 299, -11, 150, 315, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 282, 131, 212, 131, 284, 246, 165, 85, 86,
- 19, 142, -101, 74, 19, 246, 96, 132, 167, 236,
- 57, 149, 303, 105, 106, 306, 307, 308, 325, 173,
- -90, 328, -86, 177, 143, 152, 153, 154, 155, 156,
- 157, 158, 159, 160, 161, 162, 163, 5, 206, 50,
- 151, 78, 327, 130, 164, 329, 79, 132, -101, -101,
- 168, 235, -100, 74, 74, 19, 170, 74, 174, 74,
- 20, 169, 131, 74, 175, 136, 309, 310, 232, 23,
- 137, 251, 80, 72, 241, -91, 68, 213, 69, 257,
- 127, 128, 225, 264, 265, 278, 217, 85, 86, 74,
- 69, 262, -100, 218, 234, 220, 131, 263, 115, 116,
- 179, 270, 238, 225, 74, 266, 242, 243, 290, -100,
- 280, 262, 268, 219, 277, -100, 269, 195, 111, 286,
- 313, 318, 227, 72, 72, 319, 292, 72, 75, 72,
- 311, 233, 61, 72, 93, 94, 95, 283, 65, 96,
- 117, 118, 239, 207, 288, 289, 317, 274, 103, 104,
- 221, 222, 294, 0, 223, 320, 226, 322, 253, 72,
- 228, 0, 254, 119, 0, 0, 285, 237, 287, 57,
- 0, 0, 0, 0, 72, 0, 0, 57, 0, 105,
- 106, 0, 0, 0, 272, 0, 248, 107, 0, 0,
- 0, 275, 276, 0, 0, 279, 0, 0, 0, 78,
- 0, 258, 0, 0, 79, 0, 0, 78, 0, 0,
- 0, 0, 79, 293, 0, 295, 0, 296, 301, 302,
- 0, 304, 0, 90, 0, 2, 3, 0, 4, 5,
- 80, 81, 6, 7, 0, 0, 0, 0, 80, 81,
- 82, 321, 8, 9, 323, 85, 86, 324, 0, 326,
- 83, 0, 0, 85, 86, 0, 0, 0, 0, 0,
- 10, 11, 12, 13, 0, 132, 0, 0, 14, 15,
- 16, 17, 18, 0, 0, 19, 20, 97, 98, 99,
- 100, 101, 21, 22, 102, 23, 0, 24, 0, 0,
- 25, 26, 0, 27, 0, 0, -14, 180, -14, 4,
- 5, 0, 0, 6, 7, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 181, 0, 182, 183, 184,
- -69, -69, 185, 186, 187, 188, 189, 190, 191, 192,
- 193, 0, 0, 0, 13, 194, 0, 0, 0, 14,
- 15, 16, 17, 0, 0, 0, -69, 20, 0, 0,
- 0, 0, 0, 21, 22, 0, 23, 0, 24, 0,
- 0, 25, 26, 0, 55, 0, 0, 68, -69, 69,
- 180, 0, 4, 5, 0, 0, 6, 7, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 181, 0,
- 182, 183, 184, -68, -68, 185, 186, 187, 188, 189,
- 190, 191, 192, 193, 0, 0, 0, 13, 194, 0,
- 0, 0, 14, 15, 16, 17, 0, 0, 0, -68,
- 20, 0, 0, 0, 0, 0, 21, 22, 0, 23,
- 0, 24, 0, 0, 25, 26, 0, 55, 0, 0,
- 68, -68, 69, 180, 0, 4, 5, 0, 0, 6,
- 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 181, 0, 182, 183, 184, 0, 0, 185, 186,
- 187, 188, 189, 190, 191, 192, 193, 0, 0, 0,
- 13, 194, 0, 0, 0, 14, 15, 16, 17, 63,
- 0, 4, 5, 20, 0, 6, 7, 0, -99, 21,
- 22, 0, 23, 0, 24, 0, 0, 25, 26, 0,
- 55, 0, 0, 68, 195, 69, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 13, 0, 0, 0,
- 0, 14, 15, 16, 17, 0, 0, 0, -99, 20,
+ 34, 79, 79, 70, 80, 125, 126, 120, 232, 248,
+ 254, 56, 57, 58, 217, 19, 146, 119, 246, 63,
+ 63, 118, 63, 68, 134, 71, 266, 44, 19, 137,
+ 4, 304, 272, 63, 138, 43, 74, 59, 75, 60,
+ 315, 131, 117, 117, 238, 33, 169, 239, 122, 170,
+ 5, 75, 111, 112, 131, 44, 128, 129, 117, 117,
+ 62, 64, 212, 65, 74, 127, 123, 83, 281, 167,
+ 44, 84, 283, 78, 96, 72, 218, 4, 314, 174,
+ 175, 248, 131, 181, 145, 44, 147, 148, 149, 302,
+ 248, -99, 305, 151, 132, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 132, 214, 121,
+ 168, 25, -89, 166, 80, 132, 102, 91, 92, 326,
+ 133, 63, 328, 324, 144, 211, 327, -100, -90, 19,
+ 176, -99, -11, 296, 180, 132, 153, 154, 155, 156,
+ 157, 158, 159, 160, 161, 162, 163, 164, -99, 209,
+ 56, 73, 5, 143, -99, -11, 297, 298, 109, 110,
+ 152, 133, 173, 150, 165, 178, 80, 80, 48, 49,
+ 80, 215, 80, -100, -100, 219, 80, 253, 220, 222,
+ 75, 234, 19, 78, 243, 73, 99, 100, 101, 111,
+ 112, 102, 265, 262, 256, 227, 277, 113, 263, 264,
+ 269, 80, 276, 261, -85, 177, 289, 236, 312, 198,
+ 50, 51, 317, 318, 240, 227, 80, 81, 244, 245,
+ 261, 84, 279, 310, 267, 288, 85, 67, 268, 210,
+ 117, 285, 319, 52, 241, 78, 78, 182, 291, 78,
+ 273, 78, 213, 0, 0, 78, 282, 306, 307, 0,
+ 71, 0, 86, 287, 0, 0, 0, 0, 316, 0,
+ 0, 293, 221, 0, 0, 0, 0, 91, 92, 321,
+ 78, 229, 0, 0, 0, 284, 84, 286, 63, 0,
+ 235, 85, 0, 0, 237, 78, 63, 84, 0, 223,
+ 224, 20, 85, 225, 0, 228, 0, 308, 309, 230,
+ 23, 0, 0, 0, 0, 0, 255, 86, 87, 0,
+ 84, 0, 0, 0, 0, 85, 0, 0, 86, 87,
+ 88, 0, 91, 92, 250, 0, 0, 96, 0, 271,
+ 89, 0, 0, 91, 92, 0, 274, 275, 0, 257,
+ 278, 86, 87, 88, 0, 97, 98, 99, 100, 101,
+ 84, 75, 102, 89, 208, 85, 91, 92, 292, 0,
+ 294, 0, 295, 300, 301, 0, 303, 2, 3, 0,
+ 4, 5, 0, 0, 6, 7, 0, 0, 0, 0,
+ 0, 86, 87, 88, 8, 9, 320, 0, 0, 322,
+ 0, 0, 323, 89, 325, 0, 91, 92, 0, 0,
+ 0, 0, 10, 11, 12, 13, 0, 0, 133, 0,
+ 14, 15, 16, 17, 18, 0, 0, 19, 20, 103,
+ 104, 105, 106, 107, 21, 22, 108, 23, 0, 24,
+ 0, 0, 25, 26, 0, 27, 0, 0, -14, 183,
+ -14, 4, 5, 0, 0, 6, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 184, 0, 185,
+ 186, 187, -68, -68, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 0, 0, 0, 13, 197, 0, 0,
+ 0, 14, 15, 16, 17, 0, 0, 0, -68, 20,
0, 0, 0, 0, 0, 21, 22, 0, 23, 0,
- 24, 0, 0, 25, 249, -99, 55, 0, 4, 5,
- 0, -99, 6, 7, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 181, 0, 182, 183, 184, 0,
- 0, 185, 186, 187, 188, 189, 190, 191, 192, 193,
- 0, 0, 0, 13, 194, 0, 0, 0, 14, 15,
- 16, 17, 0, 4, 5, 0, 20, 6, 7, 0,
- 0, 0, 21, 22, 0, 23, 0, 24, 0, 0,
- 25, 26, 0, 55, 0, 0, 68, 63, 69, 4,
- 5, 0, 0, 6, 7, 0, 0, 0, 13, 0,
- 0, 0, 0, 14, 15, 16, 17, 0, 0, 0,
- 0, 20, 0, 0, 0, 0, 0, 21, 22, 0,
- 23, 0, 24, 0, 13, 25, 26, 0, 55, 14,
- 15, 16, 17, 69, 0, 0, 0, 20, 0, 0,
- 0, 0, 0, 21, 22, 0, 23, 0, 24, 0,
- 0, 25, 26, -99, 55, 63, 0, 4, 5, 0,
+ 24, 0, 0, 25, 26, 0, 61, 0, 0, 74,
+ -68, 75, 183, 0, 4, 5, 0, 0, 6, 7,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 184, 0, 185, 186, 187, -67, -67, 188, 189, 190,
+ 191, 192, 193, 194, 195, 196, 0, 0, 0, 13,
+ 197, 0, 0, 0, 14, 15, 16, 17, 0, 0,
+ 0, -67, 20, 0, 0, 0, 0, 0, 21, 22,
+ 0, 23, 0, 24, 0, 0, 25, 26, 0, 61,
+ 0, 0, 74, -67, 75, 183, 0, 4, 5, 0,
0, 6, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 184, 0, 185, 186, 187, 0, 0,
+ 188, 189, 190, 191, 192, 193, 194, 195, 196, 0,
+ 0, 0, 13, 197, 0, 0, 0, 14, 15, 16,
+ 17, 69, 0, 4, 5, 20, 0, 6, 7, 0,
+ -98, 21, 22, 0, 23, 0, 24, 0, 0, 25,
+ 26, 0, 61, 0, 0, 74, 198, 75, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 0, 0, 14, 15, 16, 17, 0, 0, 0,
+ -98, 20, 0, 0, 0, 0, 0, 21, 22, 0,
+ 23, 0, 24, 0, 0, 25, 251, -98, 61, 0,
+ 4, 5, 0, -98, 6, 7, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 184, 0, 185, 186,
+ 187, 0, 0, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 0, 0, 0, 13, 197, 0, 0, 0,
+ 14, 15, 16, 17, 0, 4, 5, 0, 20, 6,
+ 7, 0, 0, 0, 21, 22, 0, 23, 0, 24,
+ 0, 0, 25, 26, 0, 61, 0, 0, 74, 69,
+ 75, 4, 5, 0, 0, 6, 7, 0, 0, 0,
+ 13, 0, 0, 0, 0, 14, 15, 16, 17, 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, 75, 0, 0, 0, 20,
+ 0, 0, 0, 0, 0, 21, 22, 0, 23, 0,
+ 24, 0, 0, 25, 26, -98, 61, 69, 0, 4,
+ 5, 0, 0, 6, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 176, 0, 4, 5, 0, 0, 6, 7, 0,
+ 0, 0, 0, 179, 0, 4, 5, 0, 0, 6,
+ 7, 0, 0, 0, 13, 0, 0, 0, 0, 14,
+ 15, 16, 17, 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,
+ 4, 247, 0, 20, 6, 7, 0, 0, 0, 21,
+ 22, 0, 23, 0, 24, 0, 0, 25, 26, 186,
+ 61, 0, 0, 0, 0, 0, 0, 0, 193, 194,
+ 0, 0, 4, 5, 0, 13, 6, 7, 0, 0,
+ 14, 15, 16, 17, 0, 0, 0, 0, 20, 0,
+ 0, 186, 0, 0, 21, 22, 0, 23, 0, 24,
+ 193, 194, 25, 26, 0, 61, 0, 13, 0, 0,
+ 0, 0, 14, 15, 16, 17, 0, 4, 5, 0,
+ 20, 6, 7, 0, 0, 95, 21, 22, 0, 23,
+ 0, 24, 0, 0, 25, 26, 0, 61, 0, 0,
+ 0, 0, 0, 4, 5, 0, 0, 6, 7, 0,
0, 0, 13, 0, 0, 0, 0, 14, 15, 16,
17, 0, 0, 0, 0, 20, 0, 0, 0, 0,
0, 21, 22, 0, 23, 0, 24, 0, 13, 25,
- 26, 0, 55, 14, 15, 16, 17, 0, 4, 245,
+ 26, 0, 61, 14, 15, 16, 17, 0, 4, 5,
0, 20, 6, 7, 0, 0, 0, 21, 22, 0,
- 23, 0, 24, 0, 0, 25, 26, 183, 55, 0,
- 0, 0, 0, 0, 0, 0, 190, 191, 0, 0,
- 4, 5, 0, 13, 6, 7, 0, 0, 14, 15,
- 16, 17, 0, 0, 0, 0, 20, 0, 0, 183,
- 0, 0, 21, 22, 0, 23, 0, 24, 190, 191,
- 25, 26, 0, 55, 0, 13, 0, 0, 0, 0,
- 14, 15, 16, 17, 0, 4, 5, 0, 20, 6,
- 7, 0, 0, 89, 21, 22, 0, 23, 0, 24,
- 0, 0, 25, 26, 0, 55, 0, 0, 0, 0,
- 0, 4, 5, 0, 0, 6, 7, 0, 0, 0,
- 13, 0, 0, 0, 0, 14, 15, 16, 17, 0,
- 0, 0, 0, 20, 0, 0, 0, 0, 0, 21,
- 22, 0, 23, 0, 24, 0, 13, 25, 26, 0,
- 55, 14, 15, 16, 17, 0, 4, 5, 0, 20,
- 6, 7, 0, 0, 0, 21, 22, 0, 23, 0,
- 24, 0, 0, 25, 26, 0, 55, 0, 0, 0,
+ 23, 0, 24, 0, 0, 25, 26, 0, 61, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 78, 14, 15, 16, 17,
- 79, 78, 0, 0, 20, 0, 79, 0, 0, 0,
- 21, 22, 0, 23, 0, 24, 0, 0, 25, 60,
- 78, 55, 0, 0, 0, 79, 80, 81, 82, 0,
- 0, 0, 80, 81, 82, 0, 0, 0, 83, 0,
- 78, 85, 86, 0, 83, 79, 84, 85, 86, 0,
- 0, 80, 81, 82, 0, 0, 0, 0, 0, 69,
- 0, 0, 0, 83, 205, 0, 85, 86, 0, 0,
- 0, 80, 81, 82, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 83, 0, 0, 85, 86
+ 0, 0, 0, 0, 0, 0, 0, 84, 14, 15,
+ 16, 17, 85, 84, 0, 0, 20, 0, 85, 0,
+ 0, 0, 21, 22, 0, 23, 0, 24, 0, 0,
+ 25, 66, 0, 61, 0, 0, 0, 0, 86, 87,
+ 88, 0, 0, 0, 86, 87, 88, 0, 0, 0,
+ 89, 0, 90, 91, 92, 0, 89, 0, 0, 91,
+ 92
};
#define yypact_value_is_default(yystate) \
- ((yystate) == (-269))
+ ((yystate) == (-264))
#define yytable_value_is_error(yytable_value) \
- ((yytable_value) == (-101))
+ ((yytable_value) == (-100))
static const yytype_int16 yycheck[] =
{
- 1, 29, 30, 26, 29, 53, 54, 46, 80, 202,
- 4, 13, 14, 15, 1, 64, 4, 230, 16, 21,
- 22, 44, 24, 25, 3, 26, 40, 295, 27, 1,
- 16, 220, 4, 35, 50, 66, 304, 57, 58, 59,
- 60, 61, 43, 44, 64, 69, 1, 66, 219, 1,
- 71, 1, 53, 54, 66, 69, 55, 73, 50, 60,
- 109, 1, 9, 50, 1, 21, 22, 4, 24, 48,
- 55, 69, 66, 3, 29, 124, 125, 65, 79, 35,
- 81, 82, 83, 69, 24, 25, 73, 88, 301, 91,
- 92, 93, 94, 95, 96, 97, 98, 99, 100, 101,
- 102, 272, 54, 175, 54, 276, 295, 108, 55, 56,
- 50, 74, 9, 138, 50, 304, 64, 67, 70, 1,
- 122, 84, 293, 43, 44, 296, 7, 8, 321, 130,
- 67, 324, 72, 134, 5, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 4, 149, 151,
- 38, 9, 323, 1, 13, 326, 14, 67, 55, 56,
- 49, 210, 10, 188, 189, 50, 122, 192, 131, 194,
- 51, 66, 54, 198, 40, 1, 57, 58, 203, 60,
- 6, 229, 40, 138, 4, 67, 71, 66, 73, 238,
- 43, 44, 193, 242, 243, 267, 66, 55, 56, 224,
- 73, 240, 50, 66, 205, 66, 54, 67, 3, 4,
- 138, 10, 213, 214, 239, 26, 217, 218, 20, 67,
- 269, 260, 247, 186, 66, 73, 249, 72, 229, 278,
- 53, 7, 195, 188, 189, 7, 285, 192, 30, 194,
- 298, 204, 25, 198, 59, 60, 61, 275, 249, 64,
- 45, 46, 214, 151, 279, 281, 305, 260, 12, 13,
- 188, 189, 287, -1, 192, 312, 194, 316, 231, 224,
- 198, -1, 235, 68, -1, -1, 277, 211, 279, 281,
- -1, -1, -1, -1, 239, -1, -1, 289, -1, 43,
- 44, -1, -1, -1, 257, -1, 224, 51, -1, -1,
- -1, 264, 265, -1, -1, 268, -1, -1, -1, 9,
- -1, 239, -1, -1, 14, -1, -1, 9, -1, -1,
- -1, -1, 14, 286, -1, 288, -1, 290, 291, 292,
- -1, 294, -1, 289, -1, 0, 1, -1, 3, 4,
- 40, 41, 7, 8, -1, -1, -1, -1, 40, 41,
- 42, 314, 17, 18, 317, 55, 56, 320, -1, 322,
- 52, -1, -1, 55, 56, -1, -1, -1, -1, -1,
- 35, 36, 37, 38, -1, 67, -1, -1, 43, 44,
- 45, 46, 47, -1, -1, 50, 51, 57, 58, 59,
- 60, 61, 57, 58, 64, 60, -1, 62, -1, -1,
- 65, 66, -1, 68, -1, -1, 71, 1, 73, 3,
- 4, -1, -1, 7, 8, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 19, -1, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, -1, -1, -1, 38, 39, -1, -1, -1, 43,
- 44, 45, 46, -1, -1, -1, 50, 51, -1, -1,
- -1, -1, -1, 57, 58, -1, 60, -1, 62, -1,
- -1, 65, 66, -1, 68, -1, -1, 71, 72, 73,
- 1, -1, 3, 4, -1, -1, 7, 8, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 19, -1,
- 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, -1, -1, -1, 38, 39, -1,
- -1, -1, 43, 44, 45, 46, -1, -1, -1, 50,
- 51, -1, -1, -1, -1, -1, 57, 58, -1, 60,
- -1, 62, -1, -1, 65, 66, -1, 68, -1, -1,
- 71, 72, 73, 1, -1, 3, 4, -1, -1, 7,
- 8, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 19, -1, 21, 22, 23, -1, -1, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, -1, -1, -1,
- 38, 39, -1, -1, -1, 43, 44, 45, 46, 1,
- -1, 3, 4, 51, -1, 7, 8, -1, 10, 57,
- 58, -1, 60, -1, 62, -1, -1, 65, 66, -1,
- 68, -1, -1, 71, 72, 73, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 38, -1, -1, -1,
+ 1, 29, 30, 26, 29, 59, 60, 46, 205, 222,
+ 232, 13, 14, 15, 4, 50, 86, 16, 221, 21,
+ 22, 44, 24, 25, 70, 26, 40, 69, 50, 1,
+ 3, 294, 16, 35, 6, 66, 71, 66, 73, 66,
+ 303, 1, 43, 44, 1, 1, 1, 4, 66, 4,
+ 4, 73, 43, 44, 1, 69, 43, 44, 59, 60,
+ 21, 22, 1, 24, 71, 66, 55, 50, 271, 115,
+ 69, 9, 275, 29, 35, 48, 66, 3, 300, 125,
+ 126, 294, 1, 1, 85, 69, 87, 88, 89, 292,
+ 303, 10, 295, 94, 54, 97, 98, 99, 100, 101,
+ 102, 103, 104, 105, 106, 107, 108, 54, 178, 49,
+ 70, 65, 67, 114, 139, 54, 64, 55, 56, 322,
+ 67, 123, 325, 320, 5, 171, 323, 9, 67, 50,
+ 131, 50, 50, 1, 135, 54, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108, 67, 150,
+ 152, 27, 4, 80, 73, 73, 24, 25, 12, 13,
+ 38, 67, 123, 90, 13, 40, 191, 192, 3, 4,
+ 195, 66, 197, 55, 56, 66, 201, 231, 66, 66,
+ 73, 206, 50, 139, 4, 61, 59, 60, 61, 43,
+ 44, 64, 26, 67, 240, 196, 266, 51, 244, 245,
+ 10, 226, 66, 242, 72, 132, 20, 208, 53, 72,
+ 45, 46, 7, 7, 215, 216, 241, 30, 219, 220,
+ 259, 9, 268, 297, 249, 280, 14, 25, 251, 152,
+ 231, 277, 311, 68, 216, 191, 192, 139, 284, 195,
+ 259, 197, 172, -1, -1, 201, 274, 7, 8, -1,
+ 251, -1, 40, 278, -1, -1, -1, -1, 304, -1,
+ -1, 286, 189, -1, -1, -1, -1, 55, 56, 315,
+ 226, 198, -1, -1, -1, 276, 9, 278, 280, -1,
+ 207, 14, -1, -1, 211, 241, 288, 9, -1, 191,
+ 192, 51, 14, 195, -1, 197, -1, 57, 58, 201,
+ 60, -1, -1, -1, -1, -1, 233, 40, 41, -1,
+ 9, -1, -1, -1, -1, 14, -1, -1, 40, 41,
+ 42, -1, 55, 56, 226, -1, -1, 288, -1, 256,
+ 52, -1, -1, 55, 56, -1, 263, 264, -1, 241,
+ 267, 40, 41, 42, -1, 57, 58, 59, 60, 61,
+ 9, 73, 64, 52, 53, 14, 55, 56, 285, -1,
+ 287, -1, 289, 290, 291, -1, 293, 0, 1, -1,
+ 3, 4, -1, -1, 7, 8, -1, -1, -1, -1,
+ -1, 40, 41, 42, 17, 18, 313, -1, -1, 316,
+ -1, -1, 319, 52, 321, -1, 55, 56, -1, -1,
+ -1, -1, 35, 36, 37, 38, -1, -1, 67, -1,
+ 43, 44, 45, 46, 47, -1, -1, 50, 51, 57,
+ 58, 59, 60, 61, 57, 58, 64, 60, -1, 62,
+ -1, -1, 65, 66, -1, 68, -1, -1, 71, 1,
+ 73, 3, 4, -1, -1, 7, 8, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 19, -1, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, -1, -1, -1, 38, 39, -1, -1,
-1, 43, 44, 45, 46, -1, -1, -1, 50, 51,
-1, -1, -1, -1, -1, 57, 58, -1, 60, -1,
- 62, -1, -1, 65, 66, 67, 68, -1, 3, 4,
- -1, 73, 7, 8, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 19, -1, 21, 22, 23, -1,
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- -1, -1, -1, 38, 39, -1, -1, -1, 43, 44,
- 45, 46, -1, 3, 4, -1, 51, 7, 8, -1,
- -1, -1, 57, 58, -1, 60, -1, 62, -1, -1,
- 65, 66, -1, 68, -1, -1, 71, 1, 73, 3,
- 4, -1, -1, 7, 8, -1, -1, -1, 38, -1,
- -1, -1, -1, 43, 44, 45, 46, -1, -1, -1,
- -1, 51, -1, -1, -1, -1, -1, 57, 58, -1,
- 60, -1, 62, -1, 38, 65, 66, -1, 68, 43,
- 44, 45, 46, 73, -1, -1, -1, 51, -1, -1,
- -1, -1, -1, 57, 58, -1, 60, -1, 62, -1,
- -1, 65, 66, 67, 68, 1, -1, 3, 4, -1,
+ 62, -1, -1, 65, 66, -1, 68, -1, -1, 71,
+ 72, 73, 1, -1, 3, 4, -1, -1, 7, 8,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 19, -1, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, -1, -1, -1, 38,
+ 39, -1, -1, -1, 43, 44, 45, 46, -1, -1,
+ -1, 50, 51, -1, -1, -1, -1, -1, 57, 58,
+ -1, 60, -1, 62, -1, -1, 65, 66, -1, 68,
+ -1, -1, 71, 72, 73, 1, -1, 3, 4, -1,
-1, 7, 8, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 19, -1, 21, 22, 23, -1, -1,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, -1,
+ -1, -1, 38, 39, -1, -1, -1, 43, 44, 45,
+ 46, 1, -1, 3, 4, 51, -1, 7, 8, -1,
+ 10, 57, 58, -1, 60, -1, 62, -1, -1, 65,
+ 66, -1, 68, -1, -1, 71, 72, 73, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 38, -1,
+ -1, -1, -1, 43, 44, 45, 46, -1, -1, -1,
+ 50, 51, -1, -1, -1, -1, -1, 57, 58, -1,
+ 60, -1, 62, -1, -1, 65, 66, 67, 68, -1,
+ 3, 4, -1, 73, 7, 8, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 19, -1, 21, 22,
+ 23, -1, -1, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, -1, -1, -1, 38, 39, -1, -1, -1,
+ 43, 44, 45, 46, -1, 3, 4, -1, 51, 7,
+ 8, -1, -1, -1, 57, 58, -1, 60, -1, 62,
+ -1, -1, 65, 66, -1, 68, -1, -1, 71, 1,
+ 73, 3, 4, -1, -1, 7, 8, -1, -1, -1,
+ 38, -1, -1, -1, -1, 43, 44, 45, 46, -1,
+ -1, -1, -1, 51, -1, -1, -1, -1, -1, 57,
+ 58, -1, 60, -1, 62, -1, 38, 65, 66, -1,
+ 68, 43, 44, 45, 46, 73, -1, -1, -1, 51,
+ -1, -1, -1, -1, -1, 57, 58, -1, 60, -1,
+ 62, -1, -1, 65, 66, 67, 68, 1, -1, 3,
+ 4, -1, -1, 7, 8, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 1, -1, 3, 4, -1, -1, 7, 8, -1,
+ -1, -1, -1, 1, -1, 3, 4, -1, -1, 7,
+ 8, -1, -1, -1, 38, -1, -1, -1, -1, 43,
+ 44, 45, 46, -1, -1, -1, -1, 51, -1, -1,
+ -1, -1, -1, 57, 58, -1, 60, -1, 62, -1,
+ 38, 65, 66, -1, 68, 43, 44, 45, 46, -1,
+ 3, 4, -1, 51, 7, 8, -1, -1, -1, 57,
+ 58, -1, 60, -1, 62, -1, -1, 65, 66, 22,
+ 68, -1, -1, -1, -1, -1, -1, -1, 31, 32,
+ -1, -1, 3, 4, -1, 38, 7, 8, -1, -1,
+ 43, 44, 45, 46, -1, -1, -1, -1, 51, -1,
+ -1, 22, -1, -1, 57, 58, -1, 60, -1, 62,
+ 31, 32, 65, 66, -1, 68, -1, 38, -1, -1,
+ -1, -1, 43, 44, 45, 46, -1, 3, 4, -1,
+ 51, 7, 8, -1, -1, 11, 57, 58, -1, 60,
+ -1, 62, -1, -1, 65, 66, -1, 68, -1, -1,
+ -1, -1, -1, 3, 4, -1, -1, 7, 8, -1,
-1, -1, 38, -1, -1, -1, -1, 43, 44, 45,
46, -1, -1, -1, -1, 51, -1, -1, -1, -1,
-1, 57, 58, -1, 60, -1, 62, -1, 38, 65,
66, -1, 68, 43, 44, 45, 46, -1, 3, 4,
-1, 51, 7, 8, -1, -1, -1, 57, 58, -1,
- 60, -1, 62, -1, -1, 65, 66, 22, 68, -1,
- -1, -1, -1, -1, -1, -1, 31, 32, -1, -1,
- 3, 4, -1, 38, 7, 8, -1, -1, 43, 44,
- 45, 46, -1, -1, -1, -1, 51, -1, -1, 22,
- -1, -1, 57, 58, -1, 60, -1, 62, 31, 32,
- 65, 66, -1, 68, -1, 38, -1, -1, -1, -1,
- 43, 44, 45, 46, -1, 3, 4, -1, 51, 7,
- 8, -1, -1, 11, 57, 58, -1, 60, -1, 62,
- -1, -1, 65, 66, -1, 68, -1, -1, -1, -1,
- -1, 3, 4, -1, -1, 7, 8, -1, -1, -1,
- 38, -1, -1, -1, -1, 43, 44, 45, 46, -1,
- -1, -1, -1, 51, -1, -1, -1, -1, -1, 57,
- 58, -1, 60, -1, 62, -1, 38, 65, 66, -1,
- 68, 43, 44, 45, 46, -1, 3, 4, -1, 51,
- 7, 8, -1, -1, -1, 57, 58, -1, 60, -1,
- 62, -1, -1, 65, 66, -1, 68, -1, -1, -1,
+ 60, -1, 62, -1, -1, 65, 66, -1, 68, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 9, 43, 44, 45, 46,
- 14, 9, -1, -1, 51, -1, 14, -1, -1, -1,
- 57, 58, -1, 60, -1, 62, -1, -1, 65, 66,
- 9, 68, -1, -1, -1, 14, 40, 41, 42, -1,
- -1, -1, 40, 41, 42, -1, -1, -1, 52, -1,
- 9, 55, 56, -1, 52, 14, 54, 55, 56, -1,
- -1, 40, 41, 42, -1, -1, -1, -1, -1, 73,
- -1, -1, -1, 52, 53, -1, 55, 56, -1, -1,
- -1, 40, 41, 42, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 52, -1, -1, 55, 56
+ -1, -1, -1, -1, -1, -1, -1, 9, 43, 44,
+ 45, 46, 14, 9, -1, -1, 51, -1, 14, -1,
+ -1, -1, 57, 58, -1, 60, -1, 62, -1, -1,
+ 65, 66, -1, 68, -1, -1, -1, -1, 40, 41,
+ 42, -1, -1, -1, 40, 41, 42, -1, -1, -1,
+ 52, -1, 54, 55, 56, -1, 52, -1, -1, 55,
+ 56
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -1209,36 +1182,36 @@ static const yytype_uint8 yystos[] =
0, 75, 0, 1, 3, 4, 7, 8, 17, 18,
35, 36, 37, 38, 43, 44, 45, 46, 47, 50,
51, 57, 58, 60, 62, 65, 66, 68, 76, 78,
- 82, 84, 86, 104, 112, 116, 117, 118, 119, 120,
- 121, 129, 130, 66, 69, 126, 127, 128, 83, 122,
- 130, 130, 130, 66, 66, 68, 117, 130, 117, 117,
- 66, 119, 130, 1, 111, 112, 48, 121, 71, 73,
- 79, 88, 104, 132, 136, 79, 85, 50, 9, 14,
- 40, 41, 42, 52, 54, 55, 56, 114, 115, 11,
- 117, 57, 58, 59, 60, 61, 64, 57, 58, 59,
- 60, 61, 64, 12, 13, 43, 44, 51, 113, 110,
- 111, 112, 111, 16, 126, 3, 4, 45, 46, 68,
- 80, 81, 55, 106, 110, 110, 112, 43, 44, 131,
- 1, 54, 67, 134, 138, 134, 1, 6, 77, 104,
- 105, 87, 105, 5, 112, 129, 112, 112, 112, 105,
- 112, 38, 117, 117, 117, 117, 117, 117, 117, 117,
- 117, 117, 117, 117, 13, 112, 134, 70, 49, 66,
- 117, 134, 134, 112, 105, 40, 1, 112, 1, 88,
- 1, 19, 21, 22, 23, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, 39, 72, 89, 90, 92, 99,
- 103, 112, 132, 133, 136, 53, 112, 122, 1, 4,
- 107, 108, 129, 66, 91, 4, 66, 66, 66, 105,
- 66, 88, 88, 88, 109, 112, 88, 105, 88, 93,
- 87, 135, 136, 105, 112, 134, 1, 138, 112, 109,
- 94, 4, 112, 112, 89, 4, 92, 95, 88, 66,
- 100, 110, 133, 105, 105, 1, 4, 134, 88, 123,
- 124, 125, 126, 67, 134, 134, 26, 40, 136, 111,
- 10, 101, 105, 16, 125, 105, 105, 66, 129, 105,
- 134, 102, 89, 132, 89, 112, 134, 112, 136, 116,
- 20, 96, 134, 105, 136, 105, 105, 1, 24, 25,
- 97, 105, 105, 89, 105, 95, 89, 7, 8, 57,
- 58, 84, 98, 53, 137, 133, 95, 134, 7, 7,
- 137, 105, 134, 105, 105, 87, 105, 89, 87, 89
+ 82, 83, 85, 103, 111, 115, 116, 117, 118, 119,
+ 120, 128, 129, 66, 69, 125, 126, 127, 3, 4,
+ 45, 46, 68, 80, 81, 121, 129, 129, 129, 66,
+ 66, 68, 116, 129, 116, 116, 66, 118, 129, 1,
+ 110, 111, 48, 120, 71, 73, 79, 87, 103, 131,
+ 135, 79, 84, 50, 9, 14, 40, 41, 42, 52,
+ 54, 55, 56, 113, 114, 11, 116, 57, 58, 59,
+ 60, 61, 64, 57, 58, 59, 60, 61, 64, 12,
+ 13, 43, 44, 51, 112, 109, 110, 111, 110, 16,
+ 125, 49, 66, 55, 105, 109, 109, 111, 43, 44,
+ 130, 1, 54, 67, 133, 137, 133, 1, 6, 77,
+ 103, 104, 86, 104, 5, 111, 128, 111, 111, 111,
+ 104, 111, 38, 116, 116, 116, 116, 116, 116, 116,
+ 116, 116, 116, 116, 116, 13, 111, 133, 70, 1,
+ 4, 106, 107, 116, 133, 133, 111, 104, 40, 1,
+ 111, 1, 87, 1, 19, 21, 22, 23, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 39, 72, 88,
+ 89, 91, 98, 102, 111, 131, 132, 135, 53, 111,
+ 121, 133, 1, 137, 128, 66, 90, 4, 66, 66,
+ 66, 104, 66, 87, 87, 87, 108, 111, 87, 104,
+ 87, 92, 86, 134, 135, 104, 111, 104, 1, 4,
+ 111, 108, 93, 4, 111, 111, 88, 4, 91, 94,
+ 87, 66, 99, 109, 132, 104, 133, 87, 122, 123,
+ 124, 125, 67, 133, 133, 26, 40, 135, 110, 10,
+ 100, 104, 16, 124, 104, 104, 66, 128, 104, 133,
+ 101, 88, 131, 88, 111, 133, 111, 135, 115, 20,
+ 95, 133, 104, 135, 104, 104, 1, 24, 25, 96,
+ 104, 104, 88, 104, 94, 88, 7, 8, 57, 58,
+ 83, 97, 53, 136, 132, 94, 133, 7, 7, 136,
+ 104, 133, 104, 104, 86, 104, 88, 86, 88
};
#define yyerrok (yyerrstatus = 0)
@@ -2066,7 +2039,7 @@ yyreduce:
case 3:
/* Line 1806 of yacc.c */
-#line 221 "awkgram.y"
+#line 194 "awkgram.y"
{
rule = 0;
yyerrok;
@@ -2076,7 +2049,7 @@ yyreduce:
case 5:
/* Line 1806 of yacc.c */
-#line 227 "awkgram.y"
+#line 200 "awkgram.y"
{
next_sourcefile();
}
@@ -2085,7 +2058,7 @@ yyreduce:
case 6:
/* Line 1806 of yacc.c */
-#line 231 "awkgram.y"
+#line 204 "awkgram.y"
{
rule = 0;
/*
@@ -2099,7 +2072,7 @@ yyreduce:
case 7:
/* Line 1806 of yacc.c */
-#line 243 "awkgram.y"
+#line 216 "awkgram.y"
{
(void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -2108,7 +2081,7 @@ yyreduce:
case 8:
/* Line 1806 of yacc.c */
-#line 247 "awkgram.y"
+#line 220 "awkgram.y"
{
if (rule != Rule) {
msg(_("%s blocks must have an action part"), ruletab[rule]);
@@ -2124,12 +2097,10 @@ yyreduce:
case 9:
/* Line 1806 of yacc.c */
-#line 258 "awkgram.y"
+#line 231 "awkgram.y"
{
- can_return = FALSE;
- if ((yyvsp[(1) - (2)]) && func_install((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])) < 0)
- YYABORT;
- func_params = NULL;
+ in_function = NULL;
+ (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
yyerrok;
}
break;
@@ -2137,7 +2108,7 @@ yyreduce:
case 10:
/* Line 1806 of yacc.c */
-#line 266 "awkgram.y"
+#line 237 "awkgram.y"
{
want_source = FALSE;
yyerrok;
@@ -2147,7 +2118,7 @@ yyreduce:
case 11:
/* Line 1806 of yacc.c */
-#line 274 "awkgram.y"
+#line 245 "awkgram.y"
{
if (include_source((yyvsp[(1) - (1)])) < 0)
YYABORT;
@@ -2160,35 +2131,35 @@ yyreduce:
case 12:
/* Line 1806 of yacc.c */
-#line 282 "awkgram.y"
+#line 253 "awkgram.y"
{ (yyval) = NULL; }
break;
case 13:
/* Line 1806 of yacc.c */
-#line 284 "awkgram.y"
+#line 255 "awkgram.y"
{ (yyval) = NULL; }
break;
case 14:
/* Line 1806 of yacc.c */
-#line 289 "awkgram.y"
+#line 260 "awkgram.y"
{ (yyval) = NULL; rule = Rule; }
break;
case 15:
/* Line 1806 of yacc.c */
-#line 291 "awkgram.y"
+#line 262 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
break;
case 16:
/* Line 1806 of yacc.c */
-#line 293 "awkgram.y"
+#line 264 "awkgram.y"
{
INSTRUCTION *tp;
@@ -2219,7 +2190,7 @@ yyreduce:
case 17:
/* Line 1806 of yacc.c */
-#line 319 "awkgram.y"
+#line 290 "awkgram.y"
{
static int begin_seen = 0;
if (do_lint_old && ++begin_seen == 2)
@@ -2235,7 +2206,7 @@ yyreduce:
case 18:
/* Line 1806 of yacc.c */
-#line 330 "awkgram.y"
+#line 301 "awkgram.y"
{
static int end_seen = 0;
if (do_lint_old && ++end_seen == 2)
@@ -2251,7 +2222,7 @@ yyreduce:
case 19:
/* Line 1806 of yacc.c */
-#line 341 "awkgram.y"
+#line 312 "awkgram.y"
{
(yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
(yyvsp[(1) - (1)])->source_file = source;
@@ -2262,7 +2233,7 @@ yyreduce:
case 20:
/* Line 1806 of yacc.c */
-#line 347 "awkgram.y"
+#line 318 "awkgram.y"
{
(yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
(yyvsp[(1) - (1)])->source_file = source;
@@ -2273,7 +2244,7 @@ yyreduce:
case 21:
/* Line 1806 of yacc.c */
-#line 356 "awkgram.y"
+#line 327 "awkgram.y"
{
if ((yyvsp[(2) - (5)]) == NULL)
(yyval) = list_create(instruction(Op_no_op));
@@ -2285,89 +2256,69 @@ yyreduce:
case 22:
/* Line 1806 of yacc.c */
-#line 366 "awkgram.y"
+#line 337 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 23:
/* Line 1806 of yacc.c */
-#line 368 "awkgram.y"
+#line 339 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 24:
/* Line 1806 of yacc.c */
-#line 370 "awkgram.y"
+#line 341 "awkgram.y"
{
yyerror(_("`%s' is a built-in function, it cannot be redefined"),
- tokstart);
- (yyvsp[(1) - (1)])->opcode = Op_symbol; /* Op_symbol instead of Op_token so that
- * free_bc_internal does not try to free it
- */
- (yyvsp[(1) - (1)])->lextok = builtin_func;
- (yyval) = (yyvsp[(1) - (1)]);
- /* yyerrok; */
+ tokstart);
+ YYABORT;
}
break;
case 25:
/* Line 1806 of yacc.c */
-#line 381 "awkgram.y"
+#line 347 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (2)]); }
break;
case 28:
/* Line 1806 of yacc.c */
-#line 391 "awkgram.y"
+#line 357 "awkgram.y"
{
- param_counter = 0;
- func_params = NULL;
+ (yyvsp[(1) - (6)])->source_file = source;
+ if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - (6)]), (yyvsp[(4) - (6)])) < 0)
+ YYABORT;
+ in_function = (yyvsp[(2) - (6)])->lextok;
+ (yyvsp[(2) - (6)])->lextok = NULL;
+ bcfree((yyvsp[(2) - (6)]));
+ /* $4 already free'd in install_function */
+ (yyval) = (yyvsp[(1) - (6)]);
}
break;
case 29:
/* Line 1806 of yacc.c */
-#line 396 "awkgram.y"
- {
- NODE *t;
-
- (yyvsp[(1) - (7)])->source_file = source;
- t = make_param((yyvsp[(3) - (7)])->lextok);
- (yyvsp[(3) - (7)])->lextok = NULL;
- bcfree((yyvsp[(3) - (7)]));
- t->flags |= FUNC;
- t->rnode = func_params;
- func_params = t;
- (yyval) = (yyvsp[(1) - (7)]);
- can_return = TRUE;
- /* check for duplicate parameter names */
- if (dup_parms((yyvsp[(1) - (7)]), t))
- errcount++;
- }
- break;
-
- case 30:
-
-/* Line 1806 of yacc.c */
-#line 420 "awkgram.y"
+#line 375 "awkgram.y"
{ ++want_regexp; }
break;
- case 31:
+ case 30:
/* Line 1806 of yacc.c */
-#line 422 "awkgram.y"
+#line 377 "awkgram.y"
{
NODE *n, *exp;
char *re;
size_t len;
re = (yyvsp[(3) - (3)])->lextok;
+ (yyvsp[(3) - (3)])->lextok = NULL;
len = strlen(re);
if (do_lint) {
if (len == 0)
@@ -2391,24 +2342,24 @@ yyreduce:
}
break;
- case 32:
+ case 31:
/* Line 1806 of yacc.c */
-#line 453 "awkgram.y"
+#line 409 "awkgram.y"
{ bcfree((yyvsp[(1) - (1)])); }
break;
- case 34:
+ case 33:
/* Line 1806 of yacc.c */
-#line 459 "awkgram.y"
+#line 415 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 35:
+ case 34:
/* Line 1806 of yacc.c */
-#line 461 "awkgram.y"
+#line 417 "awkgram.y"
{
if ((yyvsp[(2) - (2)]) == NULL)
(yyval) = (yyvsp[(1) - (2)]);
@@ -2423,31 +2374,31 @@ yyreduce:
}
break;
- case 36:
+ case 35:
/* Line 1806 of yacc.c */
-#line 474 "awkgram.y"
+#line 430 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 39:
+ case 38:
/* Line 1806 of yacc.c */
-#line 484 "awkgram.y"
+#line 440 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 40:
+ case 39:
/* Line 1806 of yacc.c */
-#line 486 "awkgram.y"
+#line 442 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
- case 41:
+ case 40:
/* Line 1806 of yacc.c */
-#line 488 "awkgram.y"
+#line 444 "awkgram.y"
{
if (do_profiling)
(yyval) = list_prepend((yyvsp[(1) - (1)]), instruction(Op_exec_count));
@@ -2456,10 +2407,10 @@ yyreduce:
}
break;
- case 42:
+ case 41:
/* Line 1806 of yacc.c */
-#line 495 "awkgram.y"
+#line 451 "awkgram.y"
{
INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
INSTRUCTION *ip, *nextc, *tbreak;
@@ -2551,10 +2502,10 @@ yyreduce:
}
break;
- case 43:
+ case 42:
/* Line 1806 of yacc.c */
-#line 585 "awkgram.y"
+#line 541 "awkgram.y"
{
/*
* -----------------
@@ -2598,10 +2549,10 @@ yyreduce:
}
break;
- case 44:
+ case 43:
/* Line 1806 of yacc.c */
-#line 627 "awkgram.y"
+#line 583 "awkgram.y"
{
/*
* -----------------
@@ -2645,10 +2596,10 @@ yyreduce:
}
break;
- case 45:
+ case 44:
/* Line 1806 of yacc.c */
-#line 669 "awkgram.y"
+#line 625 "awkgram.y"
{
INSTRUCTION *ip;
char *var_name = (yyvsp[(3) - (8)])->lextok;
@@ -2715,7 +2666,7 @@ regular_loop:
tbreak = instruction(Op_arrayfor_final);
(yyvsp[(4) - (8)])->opcode = Op_arrayfor_incr;
- (yyvsp[(4) - (8)])->array_var = variable(var_name, Node_var);
+ (yyvsp[(4) - (8)])->array_var = variable((yyvsp[(3) - (8)])->source_line, var_name, Node_var);
(yyvsp[(4) - (8)])->target_jmp = tbreak;
tcont = (yyvsp[(4) - (8)]);
(yyvsp[(3) - (8)])->opcode = Op_arrayfor_init;
@@ -2763,10 +2714,10 @@ regular_loop:
}
break;
- case 46:
+ case 45:
/* Line 1806 of yacc.c */
-#line 782 "awkgram.y"
+#line 738 "awkgram.y"
{
(yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), (yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
@@ -2775,10 +2726,10 @@ regular_loop:
}
break;
- case 47:
+ case 46:
/* Line 1806 of yacc.c */
-#line 789 "awkgram.y"
+#line 745 "awkgram.y"
{
(yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), (INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
@@ -2787,10 +2738,10 @@ regular_loop:
}
break;
- case 48:
+ case 47:
/* Line 1806 of yacc.c */
-#line 796 "awkgram.y"
+#line 752 "awkgram.y"
{
if (do_profiling)
(yyval) = list_prepend((yyvsp[(1) - (1)]), instruction(Op_exec_count));
@@ -2799,10 +2750,10 @@ regular_loop:
}
break;
- case 49:
+ case 48:
/* Line 1806 of yacc.c */
-#line 806 "awkgram.y"
+#line 762 "awkgram.y"
{
if (! break_allowed)
error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2813,10 +2764,10 @@ regular_loop:
}
break;
- case 50:
+ case 49:
/* Line 1806 of yacc.c */
-#line 815 "awkgram.y"
+#line 771 "awkgram.y"
{
if (! continue_allowed)
error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2827,10 +2778,10 @@ regular_loop:
}
break;
- case 51:
+ case 50:
/* Line 1806 of yacc.c */
-#line 824 "awkgram.y"
+#line 780 "awkgram.y"
{
/* if inside function (rule = 0), resolve context at run-time */
if (rule && rule != Rule)
@@ -2841,10 +2792,10 @@ regular_loop:
}
break;
- case 52:
+ case 51:
/* Line 1806 of yacc.c */
-#line 833 "awkgram.y"
+#line 789 "awkgram.y"
{
if (do_traditional)
error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2861,10 +2812,10 @@ regular_loop:
}
break;
- case 53:
+ case 52:
/* Line 1806 of yacc.c */
-#line 848 "awkgram.y"
+#line 804 "awkgram.y"
{
/* Initialize the two possible jump targets, the actual target
* is resolved at run-time.
@@ -2875,47 +2826,59 @@ regular_loop:
if ((yyvsp[(2) - (3)]) == NULL) {
(yyval) = list_create((yyvsp[(1) - (3)]));
(void) list_prepend((yyval), instruction(Op_push_i));
- (yyval)->nexti->memory = Nnull_string;
+ (yyval)->nexti->memory = dupnode(Nnull_string);
} else
(yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
}
break;
- case 54:
+ case 53:
/* Line 1806 of yacc.c */
-#line 863 "awkgram.y"
+#line 819 "awkgram.y"
{
- if (! can_return)
+ if (! in_function)
yyerror(_("`return' used outside function context"));
}
break;
- case 55:
+ case 54:
/* Line 1806 of yacc.c */
-#line 866 "awkgram.y"
+#line 822 "awkgram.y"
{
if ((yyvsp[(3) - (4)]) == NULL) {
(yyval) = list_create((yyvsp[(1) - (4)]));
(void) list_prepend((yyval), instruction(Op_push_i));
- (yyval)->nexti->memory = Nnull_string;
- } else
+ (yyval)->nexti->memory = dupnode(Nnull_string);
+ } else {
+ if (do_optimize > 1
+ && (yyvsp[(3) - (4)])->lasti->opcode == Op_func_call
+ && STREQ((yyvsp[(3) - (4)])->lasti->func_name, in_function)
+ ) {
+ /* Do tail recursion optimization. Tail
+ * call without a return value is recognized
+ * in mk_function().
+ */
+ ((yyvsp[(3) - (4)])->lasti + 1)->tail_call = TRUE;
+ }
+
(yyval) = list_append((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
+ }
}
break;
- case 57:
+ case 56:
/* Line 1806 of yacc.c */
-#line 886 "awkgram.y"
+#line 854 "awkgram.y"
{ in_print = TRUE; in_parens = 0; }
break;
- case 58:
+ case 57:
/* Line 1806 of yacc.c */
-#line 887 "awkgram.y"
+#line 855 "awkgram.y"
{
/*
* Optimization: plain `print' has no expression list, so $3 is null.
@@ -2924,13 +2887,13 @@ regular_loop:
*/
if ((yyvsp[(1) - (4)])->opcode == Op_K_print &&
- ((yyvsp[(3) - (4)]) == NULL
- || ((yyvsp[(3) - (4)])->lasti->opcode == Op_field_spec
- && (yyvsp[(3) - (4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti
- && (yyvsp[(3) - (4)])->nexti->nexti->opcode == Op_push_i
- && (yyvsp[(3) - (4)])->nexti->nexti->memory->type == Node_val
- && (yyvsp[(3) - (4)])->nexti->nexti->memory->numbr == 0.0)
- )
+ ((yyvsp[(3) - (4)]) == NULL
+ || ((yyvsp[(3) - (4)])->lasti->opcode == Op_field_spec
+ && (yyvsp[(3) - (4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti
+ && (yyvsp[(3) - (4)])->nexti->nexti->opcode == Op_push_i
+ && (yyvsp[(3) - (4)])->nexti->nexti->memory->type == Node_val
+ && (yyvsp[(3) - (4)])->nexti->nexti->memory->numbr == 0.0)
+ )
) {
static short warned = FALSE;
/* -----------------
@@ -2944,8 +2907,6 @@ regular_loop:
if ((yyvsp[(3) - (4)]) != NULL) {
bcfree((yyvsp[(3) - (4)])->lasti); /* Op_field_spec */
- (yyvsp[(3) - (4)])->nexti->nexti->memory->flags &= ~PERM;
- (yyvsp[(3) - (4)])->nexti->nexti->memory->flags |= MALLOC;
unref((yyvsp[(3) - (4)])->nexti->nexti->memory); /* Node_val */
bcfree((yyvsp[(3) - (4)])->nexti->nexti); /* Op_push_i */
bcfree((yyvsp[(3) - (4)])->nexti); /* Op_list */
@@ -3012,22 +2973,22 @@ regular_loop:
}
break;
- case 59:
+ case 58:
/* Line 1806 of yacc.c */
-#line 982 "awkgram.y"
+#line 948 "awkgram.y"
{ sub_counter = 0; }
break;
- case 60:
+ case 59:
/* Line 1806 of yacc.c */
-#line 983 "awkgram.y"
+#line 949 "awkgram.y"
{
char *arr = (yyvsp[(2) - (4)])->lextok;
(yyvsp[(2) - (4)])->opcode = Op_push_array;
- (yyvsp[(2) - (4)])->memory = variable(arr, Node_var_new);
+ (yyvsp[(2) - (4)])->memory = variable((yyvsp[(2) - (4)])->source_line, arr, Node_var_new);
if ((yyvsp[(4) - (4)]) == NULL) {
static short warned = FALSE;
@@ -3049,10 +3010,10 @@ regular_loop:
}
break;
- case 61:
+ case 60:
/* Line 1806 of yacc.c */
-#line 1012 "awkgram.y"
+#line 978 "awkgram.y"
{
static short warned = FALSE;
char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3066,45 +3027,45 @@ regular_loop:
error_ln((yyvsp[(1) - (4)])->source_line,
_("`delete array' is a gawk extension"));
}
- (yyvsp[(3) - (4)])->memory = variable(arr, Node_var_new);
+ (yyvsp[(3) - (4)])->memory = variable((yyvsp[(3) - (4)])->source_line, arr, Node_var_new);
(yyvsp[(3) - (4)])->opcode = Op_push_array;
(yyvsp[(1) - (4)])->expr_count = 0;
(yyval) = list_append(list_create((yyvsp[(3) - (4)])), (yyvsp[(1) - (4)]));
}
break;
- case 62:
+ case 61:
/* Line 1806 of yacc.c */
-#line 1031 "awkgram.y"
+#line 997 "awkgram.y"
{ (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
break;
- case 63:
+ case 62:
/* Line 1806 of yacc.c */
-#line 1036 "awkgram.y"
+#line 1002 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 64:
+ case 63:
/* Line 1806 of yacc.c */
-#line 1038 "awkgram.y"
+#line 1004 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 65:
+ case 64:
/* Line 1806 of yacc.c */
-#line 1043 "awkgram.y"
+#line 1009 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 66:
+ case 65:
/* Line 1806 of yacc.c */
-#line 1045 "awkgram.y"
+#line 1011 "awkgram.y"
{
if ((yyvsp[(1) - (2)]) == NULL)
(yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3113,17 +3074,17 @@ regular_loop:
}
break;
- case 67:
+ case 66:
/* Line 1806 of yacc.c */
-#line 1052 "awkgram.y"
+#line 1018 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 68:
+ case 67:
/* Line 1806 of yacc.c */
-#line 1057 "awkgram.y"
+#line 1023 "awkgram.y"
{
INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
if ((yyvsp[(5) - (5)]) == NULL)
@@ -3137,10 +3098,10 @@ regular_loop:
}
break;
- case 69:
+ case 68:
/* Line 1806 of yacc.c */
-#line 1069 "awkgram.y"
+#line 1035 "awkgram.y"
{
INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
if ((yyvsp[(4) - (4)]) == NULL)
@@ -3153,17 +3114,17 @@ regular_loop:
}
break;
- case 70:
+ case 69:
/* Line 1806 of yacc.c */
-#line 1083 "awkgram.y"
+#line 1049 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 71:
+ case 70:
/* Line 1806 of yacc.c */
-#line 1085 "awkgram.y"
+#line 1051 "awkgram.y"
{
(yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - (2)])->memory));
bcfree((yyvsp[(1) - (2)]));
@@ -3171,60 +3132,60 @@ regular_loop:
}
break;
- case 72:
+ case 71:
/* Line 1806 of yacc.c */
-#line 1091 "awkgram.y"
+#line 1057 "awkgram.y"
{
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
}
break;
- case 73:
+ case 72:
/* Line 1806 of yacc.c */
-#line 1096 "awkgram.y"
+#line 1062 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 74:
+ case 73:
/* Line 1806 of yacc.c */
-#line 1098 "awkgram.y"
+#line 1064 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_push_re;
(yyval) = (yyvsp[(1) - (1)]);
}
break;
- case 75:
+ case 74:
/* Line 1806 of yacc.c */
-#line 1106 "awkgram.y"
+#line 1072 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 76:
+ case 75:
/* Line 1806 of yacc.c */
-#line 1108 "awkgram.y"
+#line 1074 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 78:
+ case 77:
/* Line 1806 of yacc.c */
-#line 1118 "awkgram.y"
+#line 1084 "awkgram.y"
{
(yyval) = (yyvsp[(2) - (3)]);
}
break;
- case 79:
+ case 78:
/* Line 1806 of yacc.c */
-#line 1125 "awkgram.y"
+#line 1091 "awkgram.y"
{
in_print = FALSE;
in_parens = 0;
@@ -3232,17 +3193,17 @@ regular_loop:
}
break;
- case 80:
+ case 79:
/* Line 1806 of yacc.c */
-#line 1130 "awkgram.y"
+#line 1096 "awkgram.y"
{ in_print = FALSE; in_parens = 0; }
break;
- case 81:
+ case 80:
/* Line 1806 of yacc.c */
-#line 1131 "awkgram.y"
+#line 1097 "awkgram.y"
{
if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
&& (yyvsp[(3) - (3)])->lasti->opcode == Op_K_getline_redir
@@ -3252,162 +3213,174 @@ regular_loop:
}
break;
- case 82:
+ case 81:
/* Line 1806 of yacc.c */
-#line 1142 "awkgram.y"
+#line 1108 "awkgram.y"
{
(yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), (yyvsp[(6) - (6)]), NULL, NULL);
}
break;
- case 83:
+ case 82:
/* Line 1806 of yacc.c */
-#line 1147 "awkgram.y"
+#line 1113 "awkgram.y"
{
(yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), (yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
}
break;
- case 88:
+ case 87:
/* Line 1806 of yacc.c */
-#line 1164 "awkgram.y"
+#line 1130 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 89:
+ case 88:
/* Line 1806 of yacc.c */
-#line 1166 "awkgram.y"
+#line 1132 "awkgram.y"
{
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
}
break;
- case 92:
+ case 89:
+
+/* Line 1806 of yacc.c */
+#line 1140 "awkgram.y"
+ { (yyval) = NULL; }
+ break;
+
+ case 90:
+
+/* Line 1806 of yacc.c */
+#line 1142 "awkgram.y"
+ { (yyval) = (yyvsp[(1) - (1)]) ; }
+ break;
+
+ case 91:
/* Line 1806 of yacc.c */
-#line 1179 "awkgram.y"
+#line 1147 "awkgram.y"
{
- append_param((yyvsp[(1) - (1)])->lextok);
- (yyvsp[(1) - (1)])->lextok = NULL;
- bcfree((yyvsp[(1) - (1)]));
+ (yyvsp[(1) - (1)])->param_count = 0;
+ (yyval) = list_create((yyvsp[(1) - (1)]));
}
break;
- case 93:
+ case 92:
/* Line 1806 of yacc.c */
-#line 1185 "awkgram.y"
+#line 1152 "awkgram.y"
{
- append_param((yyvsp[(3) - (3)])->lextok);
- (yyvsp[(3) - (3)])->lextok = NULL;
- bcfree((yyvsp[(3) - (3)]));
+ (yyvsp[(3) - (3)])->param_count = (yyvsp[(1) - (3)])->lasti->param_count + 1;
+ (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
yyerrok;
}
break;
- case 94:
+ case 93:
/* Line 1806 of yacc.c */
-#line 1192 "awkgram.y"
- { /* func_params = NULL; */ }
+#line 1158 "awkgram.y"
+ { (yyval) = NULL; }
break;
- case 95:
+ case 94:
/* Line 1806 of yacc.c */
-#line 1194 "awkgram.y"
- { /* func_params = NULL; */ }
+#line 1160 "awkgram.y"
+ { (yyval) = (yyvsp[(1) - (2)]); }
break;
- case 96:
+ case 95:
/* Line 1806 of yacc.c */
-#line 1196 "awkgram.y"
- { /* func_params = NULL; */ }
+#line 1162 "awkgram.y"
+ { (yyval) = (yyvsp[(1) - (3)]); }
break;
- case 97:
+ case 96:
/* Line 1806 of yacc.c */
-#line 1202 "awkgram.y"
+#line 1168 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 98:
+ case 97:
/* Line 1806 of yacc.c */
-#line 1204 "awkgram.y"
+#line 1170 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 99:
+ case 98:
/* Line 1806 of yacc.c */
-#line 1209 "awkgram.y"
+#line 1175 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 100:
+ case 99:
/* Line 1806 of yacc.c */
-#line 1211 "awkgram.y"
+#line 1177 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 101:
+ case 100:
/* Line 1806 of yacc.c */
-#line 1216 "awkgram.y"
+#line 1182 "awkgram.y"
{ (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
break;
- case 102:
+ case 101:
/* Line 1806 of yacc.c */
-#line 1218 "awkgram.y"
+#line 1184 "awkgram.y"
{
(yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
yyerrok;
}
break;
- case 103:
+ case 102:
/* Line 1806 of yacc.c */
-#line 1223 "awkgram.y"
+#line 1189 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 104:
+ case 103:
/* Line 1806 of yacc.c */
-#line 1225 "awkgram.y"
+#line 1191 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 105:
+ case 104:
/* Line 1806 of yacc.c */
-#line 1227 "awkgram.y"
+#line 1193 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 106:
+ case 105:
/* Line 1806 of yacc.c */
-#line 1229 "awkgram.y"
+#line 1195 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 107:
+ case 106:
/* Line 1806 of yacc.c */
-#line 1235 "awkgram.y"
+#line 1201 "awkgram.y"
{
if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec)
lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3416,24 +3389,24 @@ regular_loop:
}
break;
- case 108:
+ case 107:
/* Line 1806 of yacc.c */
-#line 1242 "awkgram.y"
+#line 1208 "awkgram.y"
{ (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
- case 109:
+ case 108:
/* Line 1806 of yacc.c */
-#line 1244 "awkgram.y"
+#line 1210 "awkgram.y"
{ (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
- case 110:
+ case 109:
/* Line 1806 of yacc.c */
-#line 1246 "awkgram.y"
+#line 1212 "awkgram.y"
{
if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3451,13 +3424,13 @@ regular_loop:
}
break;
- case 111:
+ case 110:
/* Line 1806 of yacc.c */
-#line 1262 "awkgram.y"
+#line 1228 "awkgram.y"
{
if (do_lint_old)
- warning_ln((yyvsp[(2) - (3)])->source_line,
+ warning_ln((yyvsp[(2) - (3)])->source_line,
_("old awk does not support the keyword `in' except after `for'"));
(yyvsp[(3) - (3)])->nexti->opcode = Op_push_array;
(yyvsp[(2) - (3)])->opcode = Op_in_array;
@@ -3466,10 +3439,10 @@ regular_loop:
}
break;
- case 112:
+ case 111:
/* Line 1806 of yacc.c */
-#line 1272 "awkgram.y"
+#line 1238 "awkgram.y"
{
if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec)
lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3478,90 +3451,90 @@ regular_loop:
}
break;
- case 113:
+ case 112:
/* Line 1806 of yacc.c */
-#line 1279 "awkgram.y"
+#line 1245 "awkgram.y"
{ (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), (yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
break;
- case 114:
+ case 113:
/* Line 1806 of yacc.c */
-#line 1281 "awkgram.y"
+#line 1247 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 115:
+ case 114:
/* Line 1806 of yacc.c */
-#line 1286 "awkgram.y"
+#line 1252 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 116:
+ case 115:
/* Line 1806 of yacc.c */
-#line 1288 "awkgram.y"
+#line 1254 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 117:
+ case 116:
/* Line 1806 of yacc.c */
-#line 1290 "awkgram.y"
+#line 1256 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
(yyval) = (yyvsp[(2) - (2)]);
}
break;
+ case 117:
+
+/* Line 1806 of yacc.c */
+#line 1264 "awkgram.y"
+ { (yyval) = (yyvsp[(1) - (1)]); }
+ break;
+
case 118:
/* Line 1806 of yacc.c */
-#line 1298 "awkgram.y"
+#line 1266 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 119:
/* Line 1806 of yacc.c */
-#line 1300 "awkgram.y"
+#line 1271 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 120:
/* Line 1806 of yacc.c */
-#line 1305 "awkgram.y"
+#line 1273 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 121:
/* Line 1806 of yacc.c */
-#line 1307 "awkgram.y"
+#line 1278 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 122:
/* Line 1806 of yacc.c */
-#line 1312 "awkgram.y"
+#line 1280 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 123:
/* Line 1806 of yacc.c */
-#line 1314 "awkgram.y"
- { (yyval) = (yyvsp[(1) - (1)]); }
- break;
-
- case 124:
-
-/* Line 1806 of yacc.c */
-#line 1316 "awkgram.y"
+#line 1282 "awkgram.y"
{
int count = 2;
int is_simple_var = FALSE;
@@ -3573,32 +3546,29 @@ regular_loop:
(yyvsp[(1) - (2)])->lasti->opcode = Op_no_op;
} else {
is_simple_var = ((yyvsp[(1) - (2)])->nexti->opcode == Op_push
- && (yyvsp[(1) - (2)])->lasti == (yyvsp[(1) - (2)])->nexti); /* first exp. is a simple
- * variable?; kludge for use
- * in Op_assign_concat.
- */
+ && (yyvsp[(1) - (2)])->lasti == (yyvsp[(1) - (2)])->nexti); /* first exp. is a simple
+ * variable?; kludge for use
+ * in Op_assign_concat.
+ */
}
if (do_optimize > 1
- && (yyvsp[(1) - (2)])->nexti == (yyvsp[(1) - (2)])->lasti && (yyvsp[(1) - (2)])->nexti->opcode == Op_push_i
- && (yyvsp[(2) - (2)])->nexti == (yyvsp[(2) - (2)])->lasti && (yyvsp[(2) - (2)])->nexti->opcode == Op_push_i
+ && (yyvsp[(1) - (2)])->nexti == (yyvsp[(1) - (2)])->lasti && (yyvsp[(1) - (2)])->nexti->opcode == Op_push_i
+ && (yyvsp[(2) - (2)])->nexti == (yyvsp[(2) - (2)])->lasti && (yyvsp[(2) - (2)])->nexti->opcode == Op_push_i
) {
NODE *n1 = (yyvsp[(1) - (2)])->nexti->memory;
NODE *n2 = (yyvsp[(2) - (2)])->nexti->memory;
size_t nlen;
- (void) force_string(n1);
- (void) force_string(n2);
+ n1 = force_string(n1);
+ n2 = force_string(n2);
nlen = n1->stlen + n2->stlen;
erealloc(n1->stptr, char *, nlen + 2, "constant fold");
memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
n1->stlen = nlen;
n1->stptr[nlen] = '\0';
- n1->flags &= ~(NUMCUR|NUMBER);
+ n1->flags &= ~(NUMCUR|NUMBER|NUMINT);
n1->flags |= (STRING|STRCUR);
-
- n2->flags &= ~PERM;
- n2->flags |= MALLOC;
unref(n2);
bcfree((yyvsp[(2) - (2)])->nexti);
bcfree((yyvsp[(2) - (2)]));
@@ -3613,52 +3583,52 @@ regular_loop:
}
break;
+ case 125:
+
+/* Line 1806 of yacc.c */
+#line 1334 "awkgram.y"
+ { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
+ break;
+
case 126:
/* Line 1806 of yacc.c */
-#line 1371 "awkgram.y"
+#line 1336 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 127:
/* Line 1806 of yacc.c */
-#line 1373 "awkgram.y"
+#line 1338 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 128:
/* Line 1806 of yacc.c */
-#line 1375 "awkgram.y"
+#line 1340 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 129:
/* Line 1806 of yacc.c */
-#line 1377 "awkgram.y"
+#line 1342 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 130:
/* Line 1806 of yacc.c */
-#line 1379 "awkgram.y"
+#line 1344 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 131:
/* Line 1806 of yacc.c */
-#line 1381 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
- break;
-
- case 132:
-
-/* Line 1806 of yacc.c */
-#line 1383 "awkgram.y"
+#line 1346 "awkgram.y"
{
/*
* In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3683,30 +3653,30 @@ regular_loop:
}
break;
- case 133:
+ case 132:
/* Line 1806 of yacc.c */
-#line 1406 "awkgram.y"
+#line 1369 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_postincrement;
(yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - (2)]));
}
break;
- case 134:
+ case 133:
/* Line 1806 of yacc.c */
-#line 1411 "awkgram.y"
+#line 1374 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_postdecrement;
(yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - (2)]));
}
break;
- case 135:
+ case 134:
/* Line 1806 of yacc.c */
-#line 1416 "awkgram.y"
+#line 1379 "awkgram.y"
{
if (do_lint_old) {
warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3728,81 +3698,81 @@ regular_loop:
}
break;
- case 136:
+ case 135:
/* Line 1806 of yacc.c */
-#line 1441 "awkgram.y"
+#line 1404 "awkgram.y"
{
(yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), (yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
bcfree((yyvsp[(2) - (4)]));
}
break;
+ case 136:
+
+/* Line 1806 of yacc.c */
+#line 1410 "awkgram.y"
+ { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
+ break;
+
case 137:
/* Line 1806 of yacc.c */
-#line 1447 "awkgram.y"
+#line 1412 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 138:
/* Line 1806 of yacc.c */
-#line 1449 "awkgram.y"
+#line 1414 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 139:
/* Line 1806 of yacc.c */
-#line 1451 "awkgram.y"
+#line 1416 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 140:
/* Line 1806 of yacc.c */
-#line 1453 "awkgram.y"
+#line 1418 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 141:
/* Line 1806 of yacc.c */
-#line 1455 "awkgram.y"
+#line 1420 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
break;
case 142:
/* Line 1806 of yacc.c */
-#line 1457 "awkgram.y"
- { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); }
- break;
-
- case 143:
-
-/* Line 1806 of yacc.c */
-#line 1462 "awkgram.y"
+#line 1425 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
break;
- case 144:
+ case 143:
/* Line 1806 of yacc.c */
-#line 1466 "awkgram.y"
+#line 1429 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
(yyvsp[(2) - (2)])->opcode = Op_nomatch;
(yyvsp[(1) - (2)])->opcode = Op_push_i;
- (yyvsp[(1) - (2)])->memory = mk_number(0.0, (PERM|NUMCUR|NUMBER));
+ (yyvsp[(1) - (2)])->memory = make_number(0.0);
(yyval) = list_append(list_append(list_create((yyvsp[(1) - (2)])),
- instruction(Op_field_spec)), (yyvsp[(2) - (2)]));
+ instruction(Op_field_spec)), (yyvsp[(2) - (2)]));
} else {
if (do_optimize > 1 && (yyvsp[(2) - (2)])->nexti == (yyvsp[(2) - (2)])->lasti
- && (yyvsp[(2) - (2)])->nexti->opcode == Op_push_i
+ && (yyvsp[(2) - (2)])->nexti->opcode == Op_push_i
) {
NODE *n = (yyvsp[(2) - (2)])->nexti->memory;
if ((n->flags & (STRCUR|STRING)) != 0) {
@@ -3825,17 +3795,17 @@ regular_loop:
}
break;
- case 145:
+ case 144:
/* Line 1806 of yacc.c */
-#line 1497 "awkgram.y"
+#line 1460 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
- case 146:
+ case 145:
/* Line 1806 of yacc.c */
-#line 1499 "awkgram.y"
+#line 1462 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3843,10 +3813,10 @@ regular_loop:
}
break;
- case 147:
+ case 146:
/* Line 1806 of yacc.c */
-#line 1505 "awkgram.y"
+#line 1468 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3854,10 +3824,10 @@ regular_loop:
}
break;
- case 148:
+ case 147:
/* Line 1806 of yacc.c */
-#line 1511 "awkgram.y"
+#line 1474 "awkgram.y"
{
static short warned1 = FALSE;
@@ -3872,51 +3842,52 @@ regular_loop:
}
break;
- case 151:
+ case 150:
/* Line 1806 of yacc.c */
-#line 1526 "awkgram.y"
+#line 1489 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_preincrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)]));
}
break;
- case 152:
+ case 151:
/* Line 1806 of yacc.c */
-#line 1531 "awkgram.y"
+#line 1494 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_predecrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)]));
}
break;
- case 153:
+ case 152:
/* Line 1806 of yacc.c */
-#line 1536 "awkgram.y"
+#line 1499 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
break;
- case 154:
+ case 153:
/* Line 1806 of yacc.c */
-#line 1540 "awkgram.y"
+#line 1503 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
break;
- case 155:
+ case 154:
/* Line 1806 of yacc.c */
-#line 1544 "awkgram.y"
+#line 1507 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
- && ((yyvsp[(2) - (2)])->lasti->memory->flags & (STRCUR|STRING)) == 0) {
+ && ((yyvsp[(2) - (2)])->lasti->memory->flags & (STRCUR|STRING)) == 0
+ ) {
(yyvsp[(2) - (2)])->lasti->memory->numbr = -(force_number((yyvsp[(2) - (2)])->lasti->memory));
(yyval) = (yyvsp[(2) - (2)]);
bcfree((yyvsp[(1) - (2)]));
@@ -3927,35 +3898,35 @@ regular_loop:
}
break;
- case 156:
+ case 155:
/* Line 1806 of yacc.c */
-#line 1556 "awkgram.y"
+#line 1520 "awkgram.y"
{
/*
* was: $$ = $2
* POSIX semantics: force a conversion to numeric type
*/
(yyvsp[(1) - (2)])->opcode = Op_plus_i;
- (yyvsp[(1) - (2)])->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ (yyvsp[(1) - (2)])->memory = make_number(0.0);
(yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
}
break;
- case 157:
+ case 156:
/* Line 1806 of yacc.c */
-#line 1569 "awkgram.y"
+#line 1533 "awkgram.y"
{
func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
(yyval) = (yyvsp[(1) - (1)]);
}
break;
- case 158:
+ case 157:
/* Line 1806 of yacc.c */
-#line 1574 "awkgram.y"
+#line 1538 "awkgram.y"
{
/* indirect function call */
INSTRUCTION *f, *t;
@@ -3976,7 +3947,7 @@ regular_loop:
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(name, Node_var_new);
+ indirect_var = variable(f->source_line, name, Node_var_new);
t = instruction(Op_push);
t->memory = indirect_var;
@@ -3990,10 +3961,10 @@ regular_loop:
}
break;
- case 159:
+ case 158:
/* Line 1806 of yacc.c */
-#line 1610 "awkgram.y"
+#line 1574 "awkgram.y"
{
param_sanity((yyvsp[(3) - (4)]));
(yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -4009,54 +3980,54 @@ regular_loop:
}
break;
- case 160:
+ case 159:
/* Line 1806 of yacc.c */
-#line 1627 "awkgram.y"
+#line 1591 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 161:
+ case 160:
/* Line 1806 of yacc.c */
-#line 1629 "awkgram.y"
+#line 1593 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 162:
+ case 161:
/* Line 1806 of yacc.c */
-#line 1634 "awkgram.y"
+#line 1598 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 163:
+ case 162:
/* Line 1806 of yacc.c */
-#line 1636 "awkgram.y"
+#line 1600 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
- case 164:
+ case 163:
/* Line 1806 of yacc.c */
-#line 1641 "awkgram.y"
+#line 1605 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 165:
+ case 164:
/* Line 1806 of yacc.c */
-#line 1643 "awkgram.y"
+#line 1607 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
break;
- case 166:
+ case 165:
/* Line 1806 of yacc.c */
-#line 1650 "awkgram.y"
+#line 1614 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated expressions */
@@ -4072,10 +4043,10 @@ regular_loop:
}
break;
- case 167:
+ case 166:
/* Line 1806 of yacc.c */
-#line 1667 "awkgram.y"
+#line 1631 "awkgram.y"
{
INSTRUCTION *t = (yyvsp[(2) - (3)]);
if ((yyvsp[(2) - (3)]) == NULL) {
@@ -4083,7 +4054,7 @@ regular_loop:
_("invalid subscript expression"));
/* install Null string as subscript. */
t = list_create(instruction(Op_push_i));
- t->nexti->memory = Nnull_string;
+ t->nexti->memory = dupnode(Nnull_string);
(yyvsp[(3) - (3)])->sub_count = 1;
} else
(yyvsp[(3) - (3)])->sub_count = count_expressions(&t, FALSE);
@@ -4091,67 +4062,63 @@ regular_loop:
}
break;
- case 168:
+ case 167:
/* Line 1806 of yacc.c */
-#line 1684 "awkgram.y"
+#line 1648 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
- case 169:
+ case 168:
/* Line 1806 of yacc.c */
-#line 1686 "awkgram.y"
+#line 1650 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
break;
- case 170:
+ case 169:
/* Line 1806 of yacc.c */
-#line 1693 "awkgram.y"
+#line 1657 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
- case 171:
+ case 170:
/* Line 1806 of yacc.c */
-#line 1698 "awkgram.y"
+#line 1662 "awkgram.y"
{
char *var_name = (yyvsp[(1) - (1)])->lextok;
(yyvsp[(1) - (1)])->opcode = Op_push;
- (yyvsp[(1) - (1)])->memory = variable(var_name, Node_var_new);
+ (yyvsp[(1) - (1)])->memory = variable((yyvsp[(1) - (1)])->source_line, var_name, Node_var_new);
(yyval) = list_create((yyvsp[(1) - (1)]));
}
break;
- case 172:
+ case 171:
/* Line 1806 of yacc.c */
-#line 1706 "awkgram.y"
+#line 1670 "awkgram.y"
{
- NODE *n;
-
char *arr = (yyvsp[(1) - (2)])->lextok;
- if ((n = lookup(arr)) != NULL && ! isarray(n))
- yyerror(_("use of non-array as array"));
- (yyvsp[(1) - (2)])->memory = variable(arr, Node_var_new);
+ (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - (2)])->source_line, arr, Node_var_new);
(yyvsp[(1) - (2)])->opcode = Op_push_array;
(yyval) = list_prepend((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
}
break;
- case 173:
+ case 172:
/* Line 1806 of yacc.c */
-#line 1720 "awkgram.y"
+#line 1680 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
if (ip->opcode == Op_push
- && ip->memory->type == Node_var
- && ip->memory->var_update
+ && ip->memory->type == Node_var
+ && ip->memory->var_update
) {
(yyval) = list_prepend((yyvsp[(1) - (1)]), instruction(Op_var_update));
(yyval)->nexti->update_var = ip->memory->var_update;
@@ -4160,81 +4127,81 @@ regular_loop:
}
break;
- case 174:
+ case 173:
/* Line 1806 of yacc.c */
-#line 1732 "awkgram.y"
+#line 1692 "awkgram.y"
{
(yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
if ((yyvsp[(3) - (3)]) != NULL)
- mk_assignment((yyvsp[(2) - (3)]), NULL, (yyvsp[(3) - (3)]));
+ mk_assignment((yyvsp[(2) - (3)]), NULL, (yyvsp[(3) - (3)]));
}
break;
- case 175:
+ case 174:
/* Line 1806 of yacc.c */
-#line 1741 "awkgram.y"
+#line 1701 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postincrement;
}
break;
- case 176:
+ case 175:
/* Line 1806 of yacc.c */
-#line 1745 "awkgram.y"
+#line 1705 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postdecrement;
}
break;
- case 177:
+ case 176:
/* Line 1806 of yacc.c */
-#line 1748 "awkgram.y"
+#line 1708 "awkgram.y"
{ (yyval) = NULL; }
break;
- case 179:
+ case 178:
/* Line 1806 of yacc.c */
-#line 1756 "awkgram.y"
+#line 1716 "awkgram.y"
{ yyerrok; }
break;
- case 180:
+ case 179:
/* Line 1806 of yacc.c */
-#line 1760 "awkgram.y"
+#line 1720 "awkgram.y"
{ yyerrok; }
break;
- case 183:
+ case 182:
/* Line 1806 of yacc.c */
-#line 1769 "awkgram.y"
+#line 1729 "awkgram.y"
{ yyerrok; }
break;
- case 184:
+ case 183:
/* Line 1806 of yacc.c */
-#line 1773 "awkgram.y"
+#line 1733 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
break;
- case 185:
+ case 184:
/* Line 1806 of yacc.c */
-#line 1777 "awkgram.y"
+#line 1737 "awkgram.y"
{ yyerrok; }
break;
/* Line 1806 of yacc.c */
-#line 4250 "awkgram.c"
+#line 4217 "awkgram.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -4465,7 +4432,7 @@ yyreturn:
/* Line 2067 of yacc.c */
-#line 1779 "awkgram.y"
+#line 1739 "awkgram.y"
struct token {
@@ -4513,9 +4480,12 @@ static const struct token tokentab[] = {
{"END", Op_rule, LEX_END, 0, 0},
{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0},
#ifdef ARRAYDEBUG
-{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_adump},
+{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump},
#endif
{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and},
+#ifdef ARRAYDEBUG
+{"aoption", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_aoption},
+#endif
{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort},
{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti},
{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2},
@@ -4568,9 +4538,6 @@ static const struct token tokentab[] = {
{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf},
{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt},
{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand},
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme},
-#endif
{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime},
{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum},
{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0},
@@ -5094,6 +5061,7 @@ next_sourcefile()
*
* assert(lexeof == TRUE);
*/
+
lexeof = FALSE;
eof_warned = FALSE;
sourcefile->srclines = sourceline; /* total no of lines in current file */
@@ -5484,6 +5452,7 @@ yylex(void)
char *tokkey;
int inhex = FALSE;
int intlstr = FALSE;
+ AWKNUM d;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -5922,9 +5891,7 @@ retry:
yylval->opcode = Op_push_i;
yylval->memory = make_str_node(tokstart,
- tok - tokstart, esc_seen ? SCAN : 0);
- yylval->memory->flags &= ~MALLOC;
- yylval->memory->flags |= PERM;
+ tok - tokstart, esc_seen ? SCAN : 0);
if (intlstr) {
yylval->memory->flags |= INTLSTR;
intlstr = FALSE;
@@ -6066,10 +6033,12 @@ retry:
lintwarn("numeric constant `%.*s' treated as hexadecimal",
(int) strlen(tokstart)-1, tokstart);
}
- yylval->memory = mk_number(nondec2awknum(tokstart, strlen(tokstart)),
- PERM|NUMCUR|NUMBER);
+ d = nondec2awknum(tokstart, strlen(tokstart));
} else
- yylval->memory = mk_number(atof(tokstart), PERM|NUMCUR|NUMBER);
+ d = atof(tokstart);
+ yylval->memory = make_number(d);
+ if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+ yylval->memory->flags |= NUMINT;
return lasttok = YNUMBER;
case '&':
@@ -6246,23 +6215,6 @@ out:
#undef NEWLINE_EOF
}
-/* mk_symbol --- allocates a symbol for the symbol table. */
-
-NODE *
-mk_symbol(NODETYPE type, NODE *value)
-{
- NODE *r;
-
- getnode(r);
- r->type = type;
- r->flags = MALLOC;
- r->lnode = value;
- r->rnode = NULL;
- r->parent_array = NULL;
- r->var_assign = (Func_ptr) 0;
- return r;
-}
-
/* snode --- instructions for builtin functions. Checks for arg. count
and supplies defaults where possible. */
@@ -6314,7 +6266,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
INSTRUCTION *expr;
expr = list_create(instruction(Op_push_i));
- expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ expr->nexti->memory = make_number(0.0);
(void) mk_expression_list(subn,
list_append(expr, instruction(Op_field_spec)));
}
@@ -6358,7 +6310,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
r->sub_flags |= GENSUB;
if (nexp == 3) {
ip = instruction(Op_push_i);
- ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ ip->memory = make_number(0.0);
(void) mk_expression_list(subn,
list_append(list_create(ip), instruction(Op_field_spec)));
}
@@ -6381,7 +6333,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
list = list_create(r);
(void) list_prepend(list, instruction(Op_field_spec));
(void) list_prepend(list, instruction(Op_push_i));
- list->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ list->nexti->memory = make_number(0.0);
return list;
} else {
arg = subn->nexti;
@@ -6509,7 +6461,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
if (ip->opcode == Op_push)
ip->opcode = Op_push_array;
}
-#endif
+#endif
if (subn != NULL) {
r->expr_count = count_expressions(&subn, FALSE);
@@ -6520,75 +6472,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
return list_create(r);
}
-/* append_param --- append PNAME to the list of parameters
- * for the current function.
- */
-
-static void
-append_param(char *pname)
-{
- static NODE *savetail = NULL;
- NODE *p;
-
- p = make_param(pname);
- if (func_params == NULL) {
- func_params = p;
- savetail = p;
- } else if (savetail != NULL) {
- savetail->rnode = p;
- savetail = p;
- }
-}
-
-/* dup_parms --- return TRUE if there are duplicate parameters */
-
-static int
-dup_parms(INSTRUCTION *fp, NODE *func)
-{
- NODE *np;
- const char *fname, **names;
- int count, i, j, dups;
- NODE *params;
-
- if (func == NULL) /* error earlier */
- return TRUE;
-
- fname = func->param;
- count = func->param_cnt;
- params = func->rnode;
-
- if (count == 0) /* no args, no problem */
- return FALSE;
-
- if (params == NULL) /* error earlier */
- return TRUE;
-
- emalloc(names, const char **, count * sizeof(char *), "dup_parms");
-
- i = 0;
- for (np = params; np != NULL; np = np->rnode) {
- if (np->param == NULL) { /* error earlier, give up, go home */
- efree(names);
- return TRUE;
- }
- names[i++] = np->param;
- }
-
- dups = 0;
- for (i = 1; i < count; i++) {
- for (j = 0; j < i; j++) {
- if (strcmp(names[i], names[j]) == 0) {
- dups++;
- error_ln(fp->source_line,
- _("function `%s': parameter #%d, `%s', duplicates parameter #%d"),
- fname, i + 1, names[j], j+1);
- }
- }
- }
-
- efree(names);
- return (dups > 0 ? TRUE : FALSE);
-}
/* parms_shadow --- check if parameters shadow globals */
@@ -6597,18 +6480,19 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
{
int pcount, i;
int ret = FALSE;
- NODE *func;
+ NODE *func, *fp;
char *fname;
func = pc->func_body;
- fname = func->lnode->param;
-
+ 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->lnode->param_cnt;
+ pcount = func->param_cnt;
if (pcount == 0) /* no args, no problem */
return 0;
@@ -6620,10 +6504,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
* about all shadowed parameters.
*/
for (i = 0; i < pcount; i++) {
- if (lookup(func->parmlist[i]) != NULL) {
+ if (lookup(fp[i].param) != NULL) {
warning(
_("function `%s': parameter `%s' shadows global variable"),
- fname, func->parmlist[i]);
+ fname, fp[i].param);
ret = TRUE;
}
}
@@ -6633,79 +6517,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
}
-/*
- * install_symbol:
- * Install a name in the symbol table, even if it is already there.
- * Caller must check against redefinition if that is desired.
- */
-
-
-NODE *
-install_symbol(char *name, NODE *value)
-{
- NODE *hp;
- size_t len;
- int bucket;
-
- if (install_func)
- (*install_func)(name);
-
- var_count++;
- len = strlen(name);
- bucket = hash(name, len, (unsigned long) HASHSIZE, NULL);
- getnode(hp);
- hp->type = Node_hashnode;
- hp->hnext = variables[bucket];
- variables[bucket] = hp;
- hp->hlength = len;
- hp->hvalue = value;
- hp->hname = name;
- hp->hvalue->vname = name;
- return hp->hvalue;
-}
-
-/* lookup --- find the most recent hash node for name installed by install_symbol */
-
-NODE *
-lookup(const char *name)
-{
- NODE *bucket;
- size_t len;
-
- len = strlen(name);
- for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE, NULL)];
- bucket != NULL; bucket = bucket->hnext)
- if (bucket->hlength == len && STREQN(bucket->hname, name, len))
- return bucket->hvalue;
- return NULL;
-}
-
-/* sym_comp --- compare two symbol (variable or function) names */
-
-static int
-sym_comp(const void *v1, const void *v2)
-{
- const NODE *const *npp1, *const *npp2;
- const NODE *n1, *n2;
- int minlen;
-
- npp1 = (const NODE *const *) v1;
- npp2 = (const NODE *const *) v2;
- n1 = *npp1;
- n2 = *npp2;
-
- if (n1->hlength > n2->hlength)
- minlen = n1->hlength;
- else
- minlen = n2->hlength;
-
- return strncmp(n1->hname, n2->hname, minlen);
-}
-
/* valinfo --- dump var info */
void
-valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp)
+valinfo(NODE *n, Func_print print_func, FILE *fp)
{
if (n == Nnull_string)
print_func(fp, "uninitialized scalar\n");
@@ -6723,52 +6538,6 @@ valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp)
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
-/* get_varlist --- list of global variables */
-
-NODE **
-get_varlist()
-{
- int i, j;
- NODE **table;
- NODE *p;
-
- emalloc(table, NODE **, (var_count + 1) * sizeof(NODE *), "get_varlist");
- update_global_values();
- for (i = j = 0; i < HASHSIZE; i++)
- for (p = variables[i]; p != NULL; p = p->hnext)
- table[j++] = p;
- assert(j == var_count);
-
- /* Shazzam! */
- qsort(table, j, sizeof(NODE *), sym_comp);
-
- table[j] = NULL;
- return table;
-}
-
-/* print_vars --- print names and values of global variables */
-
-void
-print_vars(int (*print_func)(FILE *, const char *, ...), FILE *fp)
-{
- int i;
- NODE **table;
- NODE *p;
-
- table = get_varlist();
- for (i = 0; (p = table[i]) != NULL; i++) {
- if (p->hvalue->type == Node_func)
- continue;
- print_func(fp, "%.*s: ", (int) p->hlength, p->hname);
- if (p->hvalue->type == Node_var_array)
- print_func(fp, "array, %ld elements\n", p->hvalue->table_size);
- else if (p->hvalue->type == Node_var_new)
- print_func(fp, "untyped variable\n");
- else if (p->hvalue->type == Node_var)
- valinfo(p->hvalue->var_value, print_func, fp);
- }
- efree(table);
-}
/* dump_vars --- dump the symbol table */
@@ -6776,6 +6545,7 @@ void
dump_vars(const char *fname)
{
FILE *fp;
+ NODE **vars;
if (fname == NULL)
fp = stderr;
@@ -6785,48 +6555,25 @@ dump_vars(const char *fname)
fp = stderr;
}
- print_vars(fprintf, fp);
+ vars = variable_list();
+ print_vars(vars, fprintf, fp);
+ efree(vars);
if (fp != stderr && fclose(fp) != 0)
warning(_("%s: close failed (%s)"), fname, strerror(errno));
}
-/* release_all_vars --- free all variable memory */
-
-void
-release_all_vars()
-{
- int i;
- NODE *p, *next;
-
- for (i = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = next) {
- next = p->hnext;
-
- if (p->hvalue->type == Node_func)
- continue;
- else if (p->hvalue->type == Node_var_array)
- assoc_clear(p->hvalue);
- else if (p->hvalue->type != Node_var_new)
- unref(p->hvalue->var_value);
-
- efree(p->hname);
- freenode(p->hvalue);
- freenode(p);
- }
- }
-}
-
/* dump_funcs --- print all functions */
void
dump_funcs()
{
- if (func_count <= 0)
- return;
-
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) pp_func, TRUE, (void *) 0);
+ 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
@@ -6834,175 +6581,165 @@ shadow_funcs()
{
static int calls = 0;
int shadow = FALSE;
-
- if (func_count <= 0)
- return;
+ NODE **funcs;
if (calls++ != 0)
fatal(_("shadow_funcs() called twice!"));
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) parms_shadow, TRUE, &shadow);
+ 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 != warning)
lintwarn(_("there were shadowed variables."));
}
-/*
- * func_install:
- * check if name is already installed; if so, it had better have Null value,
- * in which case def is added as the value. Otherwise, install name with def
- * as value.
- *
- * Extra work, build up and save a list of the parameter names in a table
- * and hang it off params->parmlist. This is used to set the `vname' field
- * of each function parameter during a function call. See eval.c.
+
+/* mk_function --- finalize function definition node; remove parameters
+ * out of the symbol table.
*/
-static int
-func_install(INSTRUCTION *func, INSTRUCTION *def)
+static INSTRUCTION *
+mk_function(INSTRUCTION *fi, INSTRUCTION *def)
{
- NODE *params;
- NODE *r, *n, *thisfunc, *hp;
- char **pnames = NULL;
- char *fname;
- int pcount = 0;
- int i;
+ NODE *thisfunc;
- params = func_params;
+ thisfunc = fi->func_body;
+ assert(thisfunc != NULL);
- /* check for function foo(foo) { ... }. bleah. */
- for (n = params->rnode; n != NULL; n = n->rnode) {
- if (strcmp(n->param, params->param) == 0) {
- error_ln(func->source_line,
- _("function `%s': can't use function name as parameter name"), params->param);
- return -1;
- } else if (is_std_var(n->param)) {
- error_ln(func->source_line,
- _("function `%s': can't use special variable `%s' as a function parameter"),
- params->param, n->param);
- return -1;
- }
- }
+ if (do_optimize > 1 && def->lasti->opcode == Op_pop) {
+ /* tail call which does not return any value. */
- thisfunc = NULL; /* turn off warnings */
+ INSTRUCTION *t;
- fname = params->param;
- /* symbol table management */
- hp = remove_symbol(params->param); /* remove function name out of symbol table */
- if (hp != NULL)
- freenode(hp);
- r = lookup(fname);
- if (r != NULL) {
- error_ln(func->source_line,
- _("function name `%s' previously defined"), fname);
- return -1;
- } else if (fname == builtin_func) /* not a valid function name */
- goto remove_params;
+ for (t = def->nexti; t->nexti != def->lasti; t = t->nexti)
+ ;
+ if (t->opcode == Op_func_call
+ && STREQ(t->func_name, thisfunc->vname)
+ )
+ (t + 1)->tail_call = TRUE;
+ }
/* add an implicit return at end;
* also used by 'return' command in debugger
*/
-
+
(void) list_append(def, instruction(Op_push_i));
- def->lasti->memory = Nnull_string;
+ def->lasti->memory = dupnode(Nnull_string);
(void) list_append(def, instruction(Op_K_return));
if (do_profiling)
(void) list_prepend(def, instruction(Op_exec_count));
- /* func->opcode is Op_func */
- (func + 1)->firsti = def->nexti;
- (func + 1)->lasti = def->lasti;
- (func + 2)->first_line = func->source_line;
- (func + 2)->last_line = lastline;
-
- func->nexti = def->nexti;
+ /* 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, func + 1); /* debugging */
-
- /* install the function */
- thisfunc = mk_symbol(Node_func, params);
- (void) install_symbol(fname, thisfunc);
- thisfunc->code_ptr = func;
- func->func_body = thisfunc;
-
- for (n = params->rnode; n != NULL; n = n->rnode)
- pcount++;
-
- if (pcount != 0) {
- emalloc(pnames, char **, (pcount + 1) * sizeof(char *), "func_install");
- for (i = 0, n = params->rnode; i < pcount; i++, n = n->rnode)
- pnames[i] = n->param;
- pnames[pcount] = NULL;
- }
- thisfunc->parmlist = pnames;
+ (void) list_append(rule_list, fi + 1); /* debugging */
/* update lint table info */
- func_use(fname, FUNC_DEFINE);
-
- func_count++; /* used in profiler / pretty printer */
+ func_use(thisfunc->vname, FUNC_DEFINE);
-remove_params:
/* remove params from symbol table */
- pop_params(params->rnode);
- return 0;
+ remove_params(thisfunc);
+ return fi;
}
-/* remove_symbol --- remove a variable from the symbol table */
+/*
+ * install_function:
+ * install function name in the symbol table.
+ * Extra work, build up and install a list of the parameter names.
+ */
-NODE *
-remove_symbol(char *name)
+static int
+install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
{
- NODE *bucket, **save;
- size_t len;
+ NODE *r, *f;
+ int pcount = 0;
- len = strlen(name);
- save = &(variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]);
- for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
- if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
- var_count--;
- *save = bucket->hnext;
- return bucket;
- }
- save = &(bucket->hnext);
+ r = lookup(fname);
+ if (r != NULL) {
+ error_ln(fi->source_line, _("function name `%s' previously defined"), fname);
+ return -1;
}
- return NULL;
+
+ if (plist != NULL)
+ pcount = plist->lasti->param_count + 1;
+ f = install_symbol(fname, Node_func);
+ 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;
}
-/* pop_params --- remove list of function parameters from symbol table */
-/*
- * pop parameters out of the symbol table. do this in reverse order to
- * avoid reading freed memory if there were duplicated parameters.
+/* check_params --- build a list of function parameter names after
+ * making sure that the names are valid and there are no duplicates.
*/
-static void
-pop_params(NODE *params)
+
+static char **
+check_params(char *fname, int pcount, INSTRUCTION *list)
{
- NODE *hp;
- if (params == NULL)
- return;
- pop_params(params->rnode);
- hp = remove_symbol(params->param);
- if (hp != NULL)
- freenode(hp);
-}
+ INSTRUCTION *p, *np;
+ int i, j;
+ char *name;
+ char **pnames;
-/* make_param --- make NAME into a function parameter */
+ assert(pcount > 0);
-static NODE *
-make_param(char *name)
-{
- NODE *r;
+ emalloc(pnames, char **, pcount * sizeof(char *), "check_params");
- getnode(r);
- r->type = Node_param_list;
- r->rnode = NULL;
- r->param_cnt = param_counter++;
- return (install_symbol(name, r));
+ 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);
+ }
+
+ /* 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;
@@ -7110,69 +6847,6 @@ param_sanity(INSTRUCTION *arglist)
}
}
-/* foreach_func --- execute given function for each awk function in symbol table. */
-
-int
-foreach_func(int (*pfunc)(INSTRUCTION *, void *), int sort, void *data)
-{
- int i, j;
- NODE *p;
- int ret = 0;
-
- if (sort) {
- NODE **tab;
-
- /*
- * Walk through symbol table counting functions.
- * Could be more than func_count if there are
- * extension functions.
- */
- for (i = j = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = p->hnext) {
- if (p->hvalue->type == Node_func) {
- j++;
- }
- }
- }
-
- if (j == 0)
- return 0;
-
- emalloc(tab, NODE **, j * sizeof(NODE *), "foreach_func");
-
- /* now walk again, copying info */
- for (i = j = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = p->hnext) {
- if (p->hvalue->type == Node_func) {
- tab[j] = p;
- j++;
- }
- }
- }
-
- /* Shazzam! */
- qsort(tab, j, sizeof(NODE *), sym_comp);
-
- for (i = 0; i < j; i++) {
- if ((ret = pfunc(tab[i]->hvalue->code_ptr, data)) != 0)
- break;
- }
-
- efree(tab);
- return ret;
- }
-
- /* unsorted */
- for (i = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = p->hnext) {
- if (p->hvalue->type == Node_func
- && (ret = pfunc(p->hvalue->code_ptr, data)) != 0)
- return ret;
- }
- }
- return 0;
-}
-
/* deferred variables --- those that are only defined if needed. */
/*
@@ -7207,17 +6881,14 @@ register_deferred_variable(const char *name, NODE *(*load_func)(void))
/* variable --- make sure NAME is in the symbol table */
NODE *
-variable(char *name, NODETYPE type)
+variable(int location, char *name, NODETYPE type)
{
NODE *r;
if ((r = lookup(name)) != NULL) {
- if (r->type == Node_func) {
- error(_("function `%s' called with space between name and `(',\nor used as a variable or an array"),
+ 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);
- errcount++;
- r->type = Node_var_new; /* continue parsing instead of exiting */
- }
} else {
/* not found */
struct deferred_variable *dv;
@@ -7227,11 +6898,7 @@ variable(char *name, NODETYPE type)
/*
* This is the only case in which we may not free the string.
*/
- if (type == Node_var)
- r = mk_symbol(type, Nnull_string);
- else
- r = mk_symbol(type, (NODE *) NULL);
- return install_symbol(name, r);
+ return install_symbol(name, type);
}
if (STREQ(name, dv->name)) {
r = (*dv->load_func)();
@@ -7338,9 +7005,6 @@ make_assignable(INSTRUCTION *ip)
{
switch (ip->opcode) {
case Op_push:
- if (ip->memory->type == Node_param_list
- && (ip->memory->flags & FUNC) != 0)
- return NULL;
ip->opcode = Op_push_lhs;
return ip;
case Op_field_spec:
@@ -7355,14 +7019,6 @@ make_assignable(INSTRUCTION *ip)
return NULL;
}
-/* stopme --- for debugging */
-
-NODE *
-stopme(int nargs ATTRIBUTE_UNUSED)
-{
- return (NODE *) 0;
-}
-
/* dumpintlstr --- write out an initial .po file entry for the string */
static void
@@ -7412,27 +7068,6 @@ dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2)
fflush(stdout);
}
-/* isarray --- can this type be subscripted? */
-
-static int
-isarray(NODE *n)
-{
- switch (n->type) {
- case Node_var_new:
- case Node_var_array:
- return TRUE;
- case Node_param_list:
- return (n->flags & FUNC) == 0;
- case Node_array_ref:
- cant_happen();
- break;
- default:
- break; /* keeps gcc -Wall happy */
- }
-
- return FALSE;
-}
-
/* mk_binary --- instructions for binary operators */
static INSTRUCTION *
@@ -7493,11 +7128,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
}
op->opcode = Op_push_i;
- op->memory = mk_number(res, (PERM|NUMCUR|NUMBER));
- n1->flags &= ~PERM;
- n1->flags |= MALLOC;
- n2->flags &= ~PERM;
- n2->flags |= MALLOC;
+ op->memory = make_number(res);
unref(n1);
unref(n2);
bcfree(ip1);
@@ -7828,9 +7459,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op)
static INSTRUCTION *
optimize_assignment(INSTRUCTION *exp)
{
- INSTRUCTION *i1;
- INSTRUCTION *i2;
- INSTRUCTION *i3;
+ INSTRUCTION *i1, *i2, *i3;
/*
* Optimize assignment statements array[subs] = x; var = x; $n = x;
@@ -7866,7 +7495,7 @@ optimize_assignment(INSTRUCTION *exp)
if ( ! do_optimize
|| ( 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) {
@@ -7951,13 +7580,26 @@ optimize_assignment(INSTRUCTION *exp)
case Op_push_lhs:
if (i2->nexti == i1
- && i1->opcode == Op_assign
+ && 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;
@@ -8259,320 +7901,6 @@ fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_targ
}
}
-
-/* append_symbol --- append symbol to the list of symbols
- * installed in the symbol table.
- */
-
-void
-append_symbol(char *name)
-{
- NODE *hp;
-
- /* N.B.: func_install removes func name and reinstalls it;
- * and we get two entries for it here!. destroy_symbol()
- * will find and destroy the Node_func which is what we want.
- */
-
- getnode(hp);
- hp->hname = name; /* shallow copy */
- hp->hnext = symbol_list->hnext;
- symbol_list->hnext = hp;
-}
-
-/* release_symbol --- free symbol list and optionally remove symbol from symbol table */
-
-void
-release_symbols(NODE *symlist, int keep_globals)
-{
- NODE *hp, *n;
-
- for (hp = symlist->hnext; hp != NULL; hp = n) {
- if (! keep_globals) {
- /* destroys globals, function, and params
- * if still in symbol table and not removed by func_install
- * due to syntax error.
- */
- destroy_symbol(hp->hname);
- }
- n = hp->hnext;
- freenode(hp);
- }
- symlist->hnext = NULL;
-}
-
-/* destroy_symbol --- remove a symbol from symbol table
-* and free all associated memory.
-*/
-
-void
-destroy_symbol(char *name)
-{
- NODE *symbol, *hp;
-
- symbol = lookup(name);
- if (symbol == NULL)
- return;
-
- if (symbol->type == Node_func) {
- char **varnames;
- NODE *func, *n;
-
- func = symbol;
- varnames = func->parmlist;
- if (varnames != NULL)
- efree(varnames);
-
- /* function parameters of type Node_param_list */
- for (n = func->lnode->rnode; n != NULL; ) {
- NODE *np;
- np = n->rnode;
- efree(n->param);
- freenode(n);
- n = np;
- }
- freenode(func->lnode);
- func_count--;
-
- } else if (symbol->type == Node_var_array)
- assoc_clear(symbol);
- else if (symbol->type == Node_var)
- unref(symbol->var_value);
-
- /* remove from symbol table */
- hp = remove_symbol(name);
- efree(hp->hname);
- freenode(hp->hvalue);
- freenode(hp);
-}
-
-#define pool_size d.dl
-#define freei x.xi
-static INSTRUCTION *pool_list;
-static AWK_CONTEXT *curr_ctxt = NULL;
-
-/* new_context --- create a new execution context. */
-
-AWK_CONTEXT *
-new_context()
-{
- AWK_CONTEXT *ctxt;
-
- emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
- memset(ctxt, 0, sizeof(AWK_CONTEXT));
- ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles;
- ctxt->rule_list.opcode = Op_list;
- ctxt->rule_list.lasti = &ctxt->rule_list;
- return ctxt;
-}
-
-/* set_context --- change current execution context. */
-
-static void
-set_context(AWK_CONTEXT *ctxt)
-{
- pool_list = &ctxt->pools;
- symbol_list = &ctxt->symbols;
- srcfiles = &ctxt->srcfiles;
- rule_list = &ctxt->rule_list;
- install_func = ctxt->install_func;
- curr_ctxt = ctxt;
-}
-
-/*
- * push_context:
- *
- * Switch to the given context after saving the current one. The set
- * of active execution contexts forms a stack; the global or main context
- * is at the bottom of the stack.
- */
-
-void
-push_context(AWK_CONTEXT *ctxt)
-{
- ctxt->prev = curr_ctxt;
- /* save current source and sourceline */
- if (curr_ctxt != NULL) {
- curr_ctxt->sourceline = sourceline;
- curr_ctxt->source = source;
- }
- sourceline = 0;
- source = NULL;
- set_context(ctxt);
-}
-
-/* pop_context --- switch to previous execution context. */
-
-void
-pop_context()
-{
- AWK_CONTEXT *ctxt;
-
- assert(curr_ctxt != NULL);
- ctxt = curr_ctxt->prev;
- /* restore source and sourceline */
- sourceline = ctxt->sourceline;
- source = ctxt->source;
- set_context(ctxt);
-}
-
-/* in_main_context --- are we in the main context ? */
-
-int
-in_main_context()
-{
- assert(curr_ctxt != NULL);
- return (curr_ctxt->prev == NULL);
-}
-
-/* free_context --- free context structure and related data. */
-
-void
-free_context(AWK_CONTEXT *ctxt, int keep_globals)
-{
- SRCFILE *s, *sn;
-
- if (ctxt == NULL)
- return;
-
- assert(curr_ctxt != ctxt);
-
- /* free all code including function codes */
- free_bcpool(&ctxt->pools);
- /* free symbols */
- release_symbols(&ctxt->symbols, keep_globals);
- /* free srcfiles */
- for (s = &ctxt->srcfiles; s != &ctxt->srcfiles; s = sn) {
- sn = s->next;
- if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
- efree(s->fullpath);
- efree(s->src);
- efree(s);
- }
- efree(ctxt);
-}
-
-/* free_bc_internal --- free internal memory of an instruction. */
-
-static void
-free_bc_internal(INSTRUCTION *cp)
-{
- NODE *m;
-
- switch(cp->opcode) {
- case Op_func_call:
- if (cp->func_name != NULL
- && cp->func_name != builtin_func
- )
- efree(cp->func_name);
- break;
- case Op_push_re:
- case Op_match_rec:
- case Op_match:
- case Op_nomatch:
- m = cp->memory;
- if (m->re_reg != NULL)
- refree(m->re_reg);
- if (m->re_exp != NULL)
- unref(m->re_exp);
- if (m->re_text != NULL)
- unref(m->re_text);
- freenode(m);
- break;
- case Op_token: /* token lost during error recovery in yyparse */
- if (cp->lextok != NULL)
- efree(cp->lextok);
- break;
- case Op_illegal:
- cant_happen();
- default:
- break;
- }
-}
-
-
-/* INSTR_CHUNK must be > largest code size (3) */
-#define INSTR_CHUNK 127
-
-/* bcfree --- deallocate instruction */
-
-void
-bcfree(INSTRUCTION *cp)
-{
- cp->opcode = 0;
- cp->nexti = pool_list->freei;
- pool_list->freei = cp;
-}
-
-/* bcalloc --- allocate a new instruction */
-
-INSTRUCTION *
-bcalloc(OPCODE op, int size, int srcline)
-{
- INSTRUCTION *cp;
-
- if (size > 1) {
- /* wide instructions Op_rule, Op_func_call .. */
- emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), "bcalloc");
- cp->pool_size = size;
- cp->nexti = pool_list->nexti;
- pool_list->nexti = cp++;
- } else {
- INSTRUCTION *pool;
-
- pool = pool_list->freei;
- if (pool == NULL) {
- INSTRUCTION *last;
- emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * sizeof(INSTRUCTION), "bcalloc");
-
- cp->pool_size = INSTR_CHUNK;
- cp->nexti = pool_list->nexti;
- pool_list->nexti = cp;
- pool = ++cp;
- last = &pool[INSTR_CHUNK - 1];
- for (; cp <= last; cp++) {
- cp->opcode = 0;
- cp->nexti = cp + 1;
- }
- --cp;
- cp->nexti = NULL;
- }
- cp = pool;
- pool_list->freei = cp->nexti;
- }
-
- memset(cp, 0, size * sizeof(INSTRUCTION));
- cp->opcode = op;
- cp->source_line = srcline;
- return cp;
-}
-
-/* free_bcpool --- free list of instruction memory pools */
-
-static void
-free_bcpool(INSTRUCTION *pl)
-{
- INSTRUCTION *pool, *tmp;
-
- for (pool = pl->nexti; pool != NULL; pool = tmp) {
- INSTRUCTION *cp, *last;
- long psiz;
- psiz = pool->pool_size;
- if (psiz == INSTR_CHUNK)
- last = pool + psiz;
- else
- last = pool + 1;
- for (cp = pool + 1; cp <= last ; cp++) {
- if (cp->opcode != 0)
- free_bc_internal(cp);
- }
- tmp = pool->nexti;
- efree(pool);
- }
- memset(pl, 0, sizeof(INSTRUCTION));
-}
-
-
static inline INSTRUCTION *
list_create(INSTRUCTION *x)
{
diff --git a/awkgram.y b/awkgram.y
index 69f74cab..08eb9904 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -42,19 +42,15 @@ static char *get_src_buf(void);
static int yylex(void);
int yyparse(void);
static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
-static int func_install(INSTRUCTION *fp, INSTRUCTION *def);
-static void pop_params(NODE *params);
-static NODE *make_param(char *pname);
+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 append_param(char *pname);
-static int dup_parms(INSTRUCTION *fp, NODE *func);
static void param_sanity(INSTRUCTION *arglist);
static int parms_shadow(INSTRUCTION *pc, int *shadow);
static int isnoeffect(OPCODE type);
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 int isarray(NODE *n);
static int include_source(INSTRUCTION *file);
static void next_sourcefile(void);
static char *tokexpand(void);
@@ -63,6 +59,7 @@ static char *tokexpand(void);
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);
@@ -81,16 +78,13 @@ static void add_lint(INSTRUCTION *list, LINTTYPE linttype);
enum defref { FUNC_DEFINE, FUNC_USE };
static void func_use(const char *name, enum defref how);
static void check_funcs(void);
-static void free_bcpool(INSTRUCTION *pl);
static ssize_t read_one_line(int fd, void *buffer, size_t count);
static int one_line_close(int fd);
-static void (*install_func)(char *) = NULL;
-
static int want_source = FALSE;
static int want_regexp; /* lexical scanning kludge */
-static int can_return; /* parsing kludge */
+static char *in_function; /* parsing kludge */
static int rule = 0;
const char *const ruletab[] = {
@@ -125,22 +119,11 @@ static int continue_allowed; /* kludge for continue */
#define END_SRC -2000
#define YYDEBUG_LEXER_TEXT (lexeme)
-static int param_counter;
-static NODE *func_params; /* list of parameters for the current function */
static char *tokstart = NULL;
static char *tok = NULL;
static char *tokend;
static int errcount = 0;
-static NODE *symbol_list;
-extern void destroy_symbol(char *name);
-
-static long func_count; /* total number of functions */
-
-#define HASHSIZE 1021 /* this constant only used here */
-NODE *variables[HASHSIZE];
-static int var_count; /* total number of global variables */
-
extern char *source;
extern int sourceline;
extern SRCFILE *srcfiles;
@@ -162,16 +145,6 @@ 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);
-/*
- * This string cannot occur as a real awk identifier.
- * Use it as a special token to make function parsing
- * uniform, but if it's seen, don't install the function.
- * e.g.
- * function split(x) { return x }
- * function x(a) { return a }
- * should only produce one error message, and not core dump.
- */
-static char builtin_func[] = "@builtin";
#define YYSTYPE INSTRUCTION *
%}
@@ -256,10 +229,8 @@ rule
}
| function_prologue action
{
- can_return = FALSE;
- if ($1 && func_install($1, $2) < 0)
- YYABORT;
- func_params = NULL;
+ in_function = NULL;
+ (void) mk_function($1, $2);
yyerrok;
}
| '@' LEX_INCLUDE source statement_term
@@ -369,13 +340,8 @@ func_name
| lex_builtin
{
yyerror(_("`%s' is a built-in function, it cannot be redefined"),
- tokstart);
- $1->opcode = Op_symbol; /* Op_symbol instead of Op_token so that
- * free_bc_internal does not try to free it
- */
- $1->lextok = builtin_func;
- $$ = $1;
- /* yyerrok; */
+ tokstart);
+ YYABORT;
}
| '@' LEX_EVAL
{ $$ = $2; }
@@ -387,28 +353,17 @@ lex_builtin
;
function_prologue
- : LEX_FUNCTION
+ : LEX_FUNCTION func_name '(' opt_param_list r_paren opt_nls
{
- param_counter = 0;
- func_params = NULL;
+ $1->source_file = source;
+ if (install_function($2->lextok, $1, $4) < 0)
+ YYABORT;
+ in_function = $2->lextok;
+ $2->lextok = NULL;
+ bcfree($2);
+ /* $4 already free'd in install_function */
+ $$ = $1;
}
- func_name '(' opt_param_list r_paren opt_nls
- {
- NODE *t;
-
- $1->source_file = source;
- t = make_param($3->lextok);
- $3->lextok = NULL;
- bcfree($3);
- t->flags |= FUNC;
- t->rnode = func_params;
- func_params = t;
- $$ = $1;
- can_return = TRUE;
- /* check for duplicate parameter names */
- if (dup_parms($1, t))
- errcount++;
- }
;
regexp
@@ -425,6 +380,7 @@ regexp
size_t len;
re = $3->lextok;
+ $3->lextok = NULL;
len = strlen(re);
if (do_lint) {
if (len == 0)
@@ -732,7 +688,7 @@ regular_loop:
tbreak = instruction(Op_arrayfor_final);
$4->opcode = Op_arrayfor_incr;
- $4->array_var = variable(var_name, Node_var);
+ $4->array_var = variable($3->source_line, var_name, Node_var);
$4->target_jmp = tbreak;
tcont = $4;
$3->opcode = Op_arrayfor_init;
@@ -855,21 +811,33 @@ non_compound_stmt
if ($2 == NULL) {
$$ = list_create($1);
(void) list_prepend($$, instruction(Op_push_i));
- $$->nexti->memory = Nnull_string;
+ $$->nexti->memory = dupnode(Nnull_string);
} else
$$ = list_append($2, $1);
}
| LEX_RETURN
{
- if (! can_return)
+ if (! in_function)
yyerror(_("`return' used outside function context"));
} opt_exp statement_term {
if ($3 == NULL) {
$$ = list_create($1);
(void) list_prepend($$, instruction(Op_push_i));
- $$->nexti->memory = Nnull_string;
- } else
+ $$->nexti->memory = dupnode(Nnull_string);
+ } else {
+ if (do_optimize > 1
+ && $3->lasti->opcode == Op_func_call
+ && STREQ($3->lasti->func_name, in_function)
+ ) {
+ /* Do tail recursion optimization. Tail
+ * call without a return value is recognized
+ * in mk_function().
+ */
+ ($3->lasti + 1)->tail_call = TRUE;
+ }
+
$$ = list_append($3, $1);
+ }
}
| simple_stmt statement_term
;
@@ -892,13 +860,13 @@ simple_stmt
*/
if ($1->opcode == Op_K_print &&
- ($3 == NULL
- || ($3->lasti->opcode == Op_field_spec
- && $3->nexti->nexti->nexti == $3->lasti
- && $3->nexti->nexti->opcode == Op_push_i
- && $3->nexti->nexti->memory->type == Node_val
- && $3->nexti->nexti->memory->numbr == 0.0)
- )
+ ($3 == NULL
+ || ($3->lasti->opcode == Op_field_spec
+ && $3->nexti->nexti->nexti == $3->lasti
+ && $3->nexti->nexti->opcode == Op_push_i
+ && $3->nexti->nexti->memory->type == Node_val
+ && $3->nexti->nexti->memory->numbr == 0.0)
+ )
) {
static short warned = FALSE;
/* -----------------
@@ -912,8 +880,6 @@ simple_stmt
if ($3 != NULL) {
bcfree($3->lasti); /* Op_field_spec */
- $3->nexti->nexti->memory->flags &= ~PERM;
- $3->nexti->nexti->memory->flags |= MALLOC;
unref($3->nexti->nexti->memory); /* Node_val */
bcfree($3->nexti->nexti); /* Op_push_i */
bcfree($3->nexti); /* Op_list */
@@ -984,7 +950,7 @@ simple_stmt
char *arr = $2->lextok;
$2->opcode = Op_push_array;
- $2->memory = variable(arr, Node_var_new);
+ $2->memory = variable($2->source_line, arr, Node_var_new);
if ($4 == NULL) {
static short warned = FALSE;
@@ -1022,7 +988,7 @@ simple_stmt
error_ln($1->source_line,
_("`delete array' is a gawk extension"));
}
- $3->memory = variable(arr, Node_var_new);
+ $3->memory = variable($3->source_line, arr, Node_var_new);
$3->opcode = Op_push_array;
$1->expr_count = 0;
$$ = list_append(list_create($3), $1);
@@ -1171,29 +1137,29 @@ input_redir
opt_param_list
: /* empty */
+ { $$ = NULL; }
| param_list
+ { $$ = $1 ; }
;
param_list
: NAME
{
- append_param($1->lextok);
- $1->lextok = NULL;
- bcfree($1);
+ $1->param_count = 0;
+ $$ = list_create($1);
}
| param_list comma NAME
{
- append_param($3->lextok);
- $3->lextok = NULL;
- bcfree($3);
+ $3->param_count = $1->lasti->param_count + 1;
+ $$ = list_append($1, $3);
yyerrok;
}
| error
- { /* func_params = NULL; */ }
+ { $$ = NULL; }
| param_list error
- { /* func_params = NULL; */ }
+ { $$ = $1; }
| param_list comma error
- { /* func_params = NULL; */ }
+ { $$ = $1; }
;
/* optional expression, as in for loop */
@@ -1261,7 +1227,7 @@ exp
| exp LEX_IN simple_variable
{
if (do_lint_old)
- warning_ln($2->source_line,
+ warning_ln($2->source_line,
_("old awk does not support the keyword `in' except after `for'"));
$3->nexti->opcode = Op_push_array;
$2->opcode = Op_in_array;
@@ -1324,32 +1290,29 @@ common_exp
$1->lasti->opcode = Op_no_op;
} else {
is_simple_var = ($1->nexti->opcode == Op_push
- && $1->lasti == $1->nexti); /* first exp. is a simple
- * variable?; kludge for use
- * in Op_assign_concat.
- */
+ && $1->lasti == $1->nexti); /* first exp. is a simple
+ * variable?; kludge for use
+ * in Op_assign_concat.
+ */
}
if (do_optimize > 1
- && $1->nexti == $1->lasti && $1->nexti->opcode == Op_push_i
- && $2->nexti == $2->lasti && $2->nexti->opcode == Op_push_i
+ && $1->nexti == $1->lasti && $1->nexti->opcode == Op_push_i
+ && $2->nexti == $2->lasti && $2->nexti->opcode == Op_push_i
) {
NODE *n1 = $1->nexti->memory;
NODE *n2 = $2->nexti->memory;
size_t nlen;
- (void) force_string(n1);
- (void) force_string(n2);
+ n1 = force_string(n1);
+ n2 = force_string(n2);
nlen = n1->stlen + n2->stlen;
erealloc(n1->stptr, char *, nlen + 2, "constant fold");
memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
n1->stlen = nlen;
n1->stptr[nlen] = '\0';
- n1->flags &= ~(NUMCUR|NUMBER);
+ n1->flags &= ~(NUMCUR|NUMBER|NUMINT);
n1->flags |= (STRING|STRCUR);
-
- n2->flags &= ~PERM;
- n2->flags |= MALLOC;
unref(n2);
bcfree($2->nexti);
bcfree($2);
@@ -1467,12 +1430,12 @@ non_post_simp_exp
if ($2->opcode == Op_match_rec) {
$2->opcode = Op_nomatch;
$1->opcode = Op_push_i;
- $1->memory = mk_number(0.0, (PERM|NUMCUR|NUMBER));
+ $1->memory = make_number(0.0);
$$ = list_append(list_append(list_create($1),
- instruction(Op_field_spec)), $2);
+ instruction(Op_field_spec)), $2);
} else {
if (do_optimize > 1 && $2->nexti == $2->lasti
- && $2->nexti->opcode == Op_push_i
+ && $2->nexti->opcode == Op_push_i
) {
NODE *n = $2->nexti->memory;
if ((n->flags & (STRCUR|STRING)) != 0) {
@@ -1543,7 +1506,8 @@ non_post_simp_exp
| '-' simp_exp %prec UNARY
{
if ($2->lasti->opcode == Op_push_i
- && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0) {
+ && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0
+ ) {
$2->lasti->memory->numbr = -(force_number($2->lasti->memory));
$$ = $2;
bcfree($1);
@@ -1559,7 +1523,7 @@ non_post_simp_exp
* POSIX semantics: force a conversion to numeric type
*/
$1->opcode = Op_plus_i;
- $1->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ $1->memory = make_number(0.0);
$$ = list_append($2, $1);
}
;
@@ -1591,7 +1555,7 @@ 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(name, Node_var_new);
+ indirect_var = variable(f->source_line, name, Node_var_new);
t = instruction(Op_push);
t->memory = indirect_var;
@@ -1671,7 +1635,7 @@ bracketed_exp_list
_("invalid subscript expression"));
/* install Null string as subscript. */
t = list_create(instruction(Op_push_i));
- t->nexti->memory = Nnull_string;
+ t->nexti->memory = dupnode(Nnull_string);
$3->sub_count = 1;
} else
$3->sub_count = count_expressions(&t, FALSE);
@@ -1699,17 +1663,13 @@ simple_variable
char *var_name = $1->lextok;
$1->opcode = Op_push;
- $1->memory = variable(var_name, Node_var_new);
+ $1->memory = variable($1->source_line, var_name, Node_var_new);
$$ = list_create($1);
}
| NAME subscript_list
{
- NODE *n;
-
char *arr = $1->lextok;
- if ((n = lookup(arr)) != NULL && ! isarray(n))
- yyerror(_("use of non-array as array"));
- $1->memory = variable(arr, Node_var_new);
+ $1->memory = variable($1->source_line, arr, Node_var_new);
$1->opcode = Op_push_array;
$$ = list_prepend($2, $1);
}
@@ -1720,8 +1680,8 @@ variable
{
INSTRUCTION *ip = $1->nexti;
if (ip->opcode == Op_push
- && ip->memory->type == Node_var
- && ip->memory->var_update
+ && ip->memory->type == Node_var
+ && ip->memory->var_update
) {
$$ = list_prepend($1, instruction(Op_var_update));
$$->nexti->update_var = ip->memory->var_update;
@@ -1732,7 +1692,7 @@ variable
{
$$ = list_append($2, $1);
if ($3 != NULL)
- mk_assignment($2, NULL, $3);
+ mk_assignment($2, NULL, $3);
}
;
@@ -1823,9 +1783,12 @@ static const struct token tokentab[] = {
{"END", Op_rule, LEX_END, 0, 0},
{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0},
#ifdef ARRAYDEBUG
-{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_adump},
+{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump},
#endif
{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and},
+#ifdef ARRAYDEBUG
+{"aoption", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_aoption},
+#endif
{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort},
{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti},
{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2},
@@ -1878,9 +1841,6 @@ static const struct token tokentab[] = {
{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf},
{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt},
{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand},
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme},
-#endif
{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime},
{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum},
{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0},
@@ -2404,6 +2364,7 @@ next_sourcefile()
*
* assert(lexeof == TRUE);
*/
+
lexeof = FALSE;
eof_warned = FALSE;
sourcefile->srclines = sourceline; /* total no of lines in current file */
@@ -2794,6 +2755,7 @@ yylex(void)
char *tokkey;
int inhex = FALSE;
int intlstr = FALSE;
+ AWKNUM d;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -3232,9 +3194,7 @@ retry:
yylval->opcode = Op_push_i;
yylval->memory = make_str_node(tokstart,
- tok - tokstart, esc_seen ? SCAN : 0);
- yylval->memory->flags &= ~MALLOC;
- yylval->memory->flags |= PERM;
+ tok - tokstart, esc_seen ? SCAN : 0);
if (intlstr) {
yylval->memory->flags |= INTLSTR;
intlstr = FALSE;
@@ -3376,10 +3336,12 @@ retry:
lintwarn("numeric constant `%.*s' treated as hexadecimal",
(int) strlen(tokstart)-1, tokstart);
}
- yylval->memory = mk_number(nondec2awknum(tokstart, strlen(tokstart)),
- PERM|NUMCUR|NUMBER);
+ d = nondec2awknum(tokstart, strlen(tokstart));
} else
- yylval->memory = mk_number(atof(tokstart), PERM|NUMCUR|NUMBER);
+ d = atof(tokstart);
+ yylval->memory = make_number(d);
+ if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+ yylval->memory->flags |= NUMINT;
return lasttok = YNUMBER;
case '&':
@@ -3556,23 +3518,6 @@ out:
#undef NEWLINE_EOF
}
-/* mk_symbol --- allocates a symbol for the symbol table. */
-
-NODE *
-mk_symbol(NODETYPE type, NODE *value)
-{
- NODE *r;
-
- getnode(r);
- r->type = type;
- r->flags = MALLOC;
- r->lnode = value;
- r->rnode = NULL;
- r->parent_array = NULL;
- r->var_assign = (Func_ptr) 0;
- return r;
-}
-
/* snode --- instructions for builtin functions. Checks for arg. count
and supplies defaults where possible. */
@@ -3624,7 +3569,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
INSTRUCTION *expr;
expr = list_create(instruction(Op_push_i));
- expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ expr->nexti->memory = make_number(0.0);
(void) mk_expression_list(subn,
list_append(expr, instruction(Op_field_spec)));
}
@@ -3668,7 +3613,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
r->sub_flags |= GENSUB;
if (nexp == 3) {
ip = instruction(Op_push_i);
- ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ ip->memory = make_number(0.0);
(void) mk_expression_list(subn,
list_append(list_create(ip), instruction(Op_field_spec)));
}
@@ -3691,7 +3636,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
list = list_create(r);
(void) list_prepend(list, instruction(Op_field_spec));
(void) list_prepend(list, instruction(Op_push_i));
- list->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER));
+ list->nexti->memory = make_number(0.0);
return list;
} else {
arg = subn->nexti;
@@ -3819,7 +3764,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
if (ip->opcode == Op_push)
ip->opcode = Op_push_array;
}
-#endif
+#endif
if (subn != NULL) {
r->expr_count = count_expressions(&subn, FALSE);
@@ -3830,75 +3775,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
return list_create(r);
}
-/* append_param --- append PNAME to the list of parameters
- * for the current function.
- */
-
-static void
-append_param(char *pname)
-{
- static NODE *savetail = NULL;
- NODE *p;
-
- p = make_param(pname);
- if (func_params == NULL) {
- func_params = p;
- savetail = p;
- } else if (savetail != NULL) {
- savetail->rnode = p;
- savetail = p;
- }
-}
-
-/* dup_parms --- return TRUE if there are duplicate parameters */
-
-static int
-dup_parms(INSTRUCTION *fp, NODE *func)
-{
- NODE *np;
- const char *fname, **names;
- int count, i, j, dups;
- NODE *params;
-
- if (func == NULL) /* error earlier */
- return TRUE;
-
- fname = func->param;
- count = func->param_cnt;
- params = func->rnode;
-
- if (count == 0) /* no args, no problem */
- return FALSE;
-
- if (params == NULL) /* error earlier */
- return TRUE;
-
- emalloc(names, const char **, count * sizeof(char *), "dup_parms");
-
- i = 0;
- for (np = params; np != NULL; np = np->rnode) {
- if (np->param == NULL) { /* error earlier, give up, go home */
- efree(names);
- return TRUE;
- }
- names[i++] = np->param;
- }
-
- dups = 0;
- for (i = 1; i < count; i++) {
- for (j = 0; j < i; j++) {
- if (strcmp(names[i], names[j]) == 0) {
- dups++;
- error_ln(fp->source_line,
- _("function `%s': parameter #%d, `%s', duplicates parameter #%d"),
- fname, i + 1, names[j], j+1);
- }
- }
- }
-
- efree(names);
- return (dups > 0 ? TRUE : FALSE);
-}
/* parms_shadow --- check if parameters shadow globals */
@@ -3907,18 +3783,19 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
{
int pcount, i;
int ret = FALSE;
- NODE *func;
+ NODE *func, *fp;
char *fname;
func = pc->func_body;
- fname = func->lnode->param;
-
+ 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->lnode->param_cnt;
+ pcount = func->param_cnt;
if (pcount == 0) /* no args, no problem */
return 0;
@@ -3930,10 +3807,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
* about all shadowed parameters.
*/
for (i = 0; i < pcount; i++) {
- if (lookup(func->parmlist[i]) != NULL) {
+ if (lookup(fp[i].param) != NULL) {
warning(
_("function `%s': parameter `%s' shadows global variable"),
- fname, func->parmlist[i]);
+ fname, fp[i].param);
ret = TRUE;
}
}
@@ -3943,79 +3820,10 @@ parms_shadow(INSTRUCTION *pc, int *shadow)
}
-/*
- * install_symbol:
- * Install a name in the symbol table, even if it is already there.
- * Caller must check against redefinition if that is desired.
- */
-
-
-NODE *
-install_symbol(char *name, NODE *value)
-{
- NODE *hp;
- size_t len;
- int bucket;
-
- if (install_func)
- (*install_func)(name);
-
- var_count++;
- len = strlen(name);
- bucket = hash(name, len, (unsigned long) HASHSIZE, NULL);
- getnode(hp);
- hp->type = Node_hashnode;
- hp->hnext = variables[bucket];
- variables[bucket] = hp;
- hp->hlength = len;
- hp->hvalue = value;
- hp->hname = name;
- hp->hvalue->vname = name;
- return hp->hvalue;
-}
-
-/* lookup --- find the most recent hash node for name installed by install_symbol */
-
-NODE *
-lookup(const char *name)
-{
- NODE *bucket;
- size_t len;
-
- len = strlen(name);
- for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE, NULL)];
- bucket != NULL; bucket = bucket->hnext)
- if (bucket->hlength == len && STREQN(bucket->hname, name, len))
- return bucket->hvalue;
- return NULL;
-}
-
-/* sym_comp --- compare two symbol (variable or function) names */
-
-static int
-sym_comp(const void *v1, const void *v2)
-{
- const NODE *const *npp1, *const *npp2;
- const NODE *n1, *n2;
- int minlen;
-
- npp1 = (const NODE *const *) v1;
- npp2 = (const NODE *const *) v2;
- n1 = *npp1;
- n2 = *npp2;
-
- if (n1->hlength > n2->hlength)
- minlen = n1->hlength;
- else
- minlen = n2->hlength;
-
- return strncmp(n1->hname, n2->hname, minlen);
-}
-
/* valinfo --- dump var info */
void
-valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp)
+valinfo(NODE *n, Func_print print_func, FILE *fp)
{
if (n == Nnull_string)
print_func(fp, "uninitialized scalar\n");
@@ -4033,52 +3841,6 @@ valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp)
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
-/* get_varlist --- list of global variables */
-
-NODE **
-get_varlist()
-{
- int i, j;
- NODE **table;
- NODE *p;
-
- emalloc(table, NODE **, (var_count + 1) * sizeof(NODE *), "get_varlist");
- update_global_values();
- for (i = j = 0; i < HASHSIZE; i++)
- for (p = variables[i]; p != NULL; p = p->hnext)
- table[j++] = p;
- assert(j == var_count);
-
- /* Shazzam! */
- qsort(table, j, sizeof(NODE *), sym_comp);
-
- table[j] = NULL;
- return table;
-}
-
-/* print_vars --- print names and values of global variables */
-
-void
-print_vars(int (*print_func)(FILE *, const char *, ...), FILE *fp)
-{
- int i;
- NODE **table;
- NODE *p;
-
- table = get_varlist();
- for (i = 0; (p = table[i]) != NULL; i++) {
- if (p->hvalue->type == Node_func)
- continue;
- print_func(fp, "%.*s: ", (int) p->hlength, p->hname);
- if (p->hvalue->type == Node_var_array)
- print_func(fp, "array, %ld elements\n", p->hvalue->table_size);
- else if (p->hvalue->type == Node_var_new)
- print_func(fp, "untyped variable\n");
- else if (p->hvalue->type == Node_var)
- valinfo(p->hvalue->var_value, print_func, fp);
- }
- efree(table);
-}
/* dump_vars --- dump the symbol table */
@@ -4086,6 +3848,7 @@ void
dump_vars(const char *fname)
{
FILE *fp;
+ NODE **vars;
if (fname == NULL)
fp = stderr;
@@ -4095,48 +3858,25 @@ dump_vars(const char *fname)
fp = stderr;
}
- print_vars(fprintf, fp);
+ vars = variable_list();
+ print_vars(vars, fprintf, fp);
+ efree(vars);
if (fp != stderr && fclose(fp) != 0)
warning(_("%s: close failed (%s)"), fname, strerror(errno));
}
-/* release_all_vars --- free all variable memory */
-
-void
-release_all_vars()
-{
- int i;
- NODE *p, *next;
-
- for (i = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = next) {
- next = p->hnext;
-
- if (p->hvalue->type == Node_func)
- continue;
- else if (p->hvalue->type == Node_var_array)
- assoc_clear(p->hvalue);
- else if (p->hvalue->type != Node_var_new)
- unref(p->hvalue->var_value);
-
- efree(p->hname);
- freenode(p->hvalue);
- freenode(p);
- }
- }
-}
-
/* dump_funcs --- print all functions */
void
dump_funcs()
{
- if (func_count <= 0)
- return;
-
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) pp_func, TRUE, (void *) 0);
+ 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
@@ -4144,175 +3884,165 @@ shadow_funcs()
{
static int calls = 0;
int shadow = FALSE;
-
- if (func_count <= 0)
- return;
+ NODE **funcs;
if (calls++ != 0)
fatal(_("shadow_funcs() called twice!"));
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) parms_shadow, TRUE, &shadow);
+ 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 != warning)
lintwarn(_("there were shadowed variables."));
}
-/*
- * func_install:
- * check if name is already installed; if so, it had better have Null value,
- * in which case def is added as the value. Otherwise, install name with def
- * as value.
- *
- * Extra work, build up and save a list of the parameter names in a table
- * and hang it off params->parmlist. This is used to set the `vname' field
- * of each function parameter during a function call. See eval.c.
+
+/* mk_function --- finalize function definition node; remove parameters
+ * out of the symbol table.
*/
-static int
-func_install(INSTRUCTION *func, INSTRUCTION *def)
+static INSTRUCTION *
+mk_function(INSTRUCTION *fi, INSTRUCTION *def)
{
- NODE *params;
- NODE *r, *n, *thisfunc, *hp;
- char **pnames = NULL;
- char *fname;
- int pcount = 0;
- int i;
+ NODE *thisfunc;
- params = func_params;
+ thisfunc = fi->func_body;
+ assert(thisfunc != NULL);
- /* check for function foo(foo) { ... }. bleah. */
- for (n = params->rnode; n != NULL; n = n->rnode) {
- if (strcmp(n->param, params->param) == 0) {
- error_ln(func->source_line,
- _("function `%s': can't use function name as parameter name"), params->param);
- return -1;
- } else if (is_std_var(n->param)) {
- error_ln(func->source_line,
- _("function `%s': can't use special variable `%s' as a function parameter"),
- params->param, n->param);
- return -1;
- }
- }
+ if (do_optimize > 1 && def->lasti->opcode == Op_pop) {
+ /* tail call which does not return any value. */
- thisfunc = NULL; /* turn off warnings */
+ INSTRUCTION *t;
- fname = params->param;
- /* symbol table management */
- hp = remove_symbol(params->param); /* remove function name out of symbol table */
- if (hp != NULL)
- freenode(hp);
- r = lookup(fname);
- if (r != NULL) {
- error_ln(func->source_line,
- _("function name `%s' previously defined"), fname);
- return -1;
- } else if (fname == builtin_func) /* not a valid function name */
- goto remove_params;
+ for (t = def->nexti; t->nexti != def->lasti; t = t->nexti)
+ ;
+ if (t->opcode == Op_func_call
+ && STREQ(t->func_name, thisfunc->vname)
+ )
+ (t + 1)->tail_call = TRUE;
+ }
/* add an implicit return at end;
* also used by 'return' command in debugger
*/
-
+
(void) list_append(def, instruction(Op_push_i));
- def->lasti->memory = Nnull_string;
+ def->lasti->memory = dupnode(Nnull_string);
(void) list_append(def, instruction(Op_K_return));
if (do_profiling)
(void) list_prepend(def, instruction(Op_exec_count));
- /* func->opcode is Op_func */
- (func + 1)->firsti = def->nexti;
- (func + 1)->lasti = def->lasti;
- (func + 2)->first_line = func->source_line;
- (func + 2)->last_line = lastline;
-
- func->nexti = def->nexti;
+ /* 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, func + 1); /* debugging */
-
- /* install the function */
- thisfunc = mk_symbol(Node_func, params);
- (void) install_symbol(fname, thisfunc);
- thisfunc->code_ptr = func;
- func->func_body = thisfunc;
-
- for (n = params->rnode; n != NULL; n = n->rnode)
- pcount++;
-
- if (pcount != 0) {
- emalloc(pnames, char **, (pcount + 1) * sizeof(char *), "func_install");
- for (i = 0, n = params->rnode; i < pcount; i++, n = n->rnode)
- pnames[i] = n->param;
- pnames[pcount] = NULL;
- }
- thisfunc->parmlist = pnames;
+ (void) list_append(rule_list, fi + 1); /* debugging */
/* update lint table info */
- func_use(fname, FUNC_DEFINE);
+ func_use(thisfunc->vname, FUNC_DEFINE);
- func_count++; /* used in profiler / pretty printer */
-
-remove_params:
/* remove params from symbol table */
- pop_params(params->rnode);
- return 0;
+ remove_params(thisfunc);
+ return fi;
}
-/* remove_symbol --- remove a variable from the symbol table */
+/*
+ * install_function:
+ * install function name in the symbol table.
+ * Extra work, build up and install a list of the parameter names.
+ */
-NODE *
-remove_symbol(char *name)
+static int
+install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
{
- NODE *bucket, **save;
- size_t len;
+ NODE *r, *f;
+ int pcount = 0;
- len = strlen(name);
- save = &(variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]);
- for (bucket = *save; bucket != NULL; bucket = bucket->hnext) {
- if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
- var_count--;
- *save = bucket->hnext;
- return bucket;
- }
- save = &(bucket->hnext);
+ r = lookup(fname);
+ if (r != NULL) {
+ error_ln(fi->source_line, _("function name `%s' previously defined"), fname);
+ return -1;
}
- return NULL;
+
+ if (plist != NULL)
+ pcount = plist->lasti->param_count + 1;
+ f = install_symbol(fname, Node_func);
+ 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;
}
-/* pop_params --- remove list of function parameters from symbol table */
-/*
- * pop parameters out of the symbol table. do this in reverse order to
- * avoid reading freed memory if there were duplicated parameters.
+/* check_params --- build a list of function parameter names after
+ * making sure that the names are valid and there are no duplicates.
*/
-static void
-pop_params(NODE *params)
+
+static char **
+check_params(char *fname, int pcount, INSTRUCTION *list)
{
- NODE *hp;
- if (params == NULL)
- return;
- pop_params(params->rnode);
- hp = remove_symbol(params->param);
- if (hp != NULL)
- freenode(hp);
-}
+ INSTRUCTION *p, *np;
+ int i, j;
+ char *name;
+ char **pnames;
-/* make_param --- make NAME into a function parameter */
+ assert(pcount > 0);
-static NODE *
-make_param(char *name)
-{
- NODE *r;
+ 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);
+ }
+
+ /* 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);
- getnode(r);
- r->type = Node_param_list;
- r->rnode = NULL;
- r->param_cnt = param_counter++;
- return (install_symbol(name, r));
+ return pnames;
}
+
+#ifdef HASHSIZE
+undef HASHSIZE
+#endif
+#define HASHSIZE 1021
+
static struct fdesc {
char *name;
short used;
@@ -4420,69 +4150,6 @@ param_sanity(INSTRUCTION *arglist)
}
}
-/* foreach_func --- execute given function for each awk function in symbol table. */
-
-int
-foreach_func(int (*pfunc)(INSTRUCTION *, void *), int sort, void *data)
-{
- int i, j;
- NODE *p;
- int ret = 0;
-
- if (sort) {
- NODE **tab;
-
- /*
- * Walk through symbol table counting functions.
- * Could be more than func_count if there are
- * extension functions.
- */
- for (i = j = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = p->hnext) {
- if (p->hvalue->type == Node_func) {
- j++;
- }
- }
- }
-
- if (j == 0)
- return 0;
-
- emalloc(tab, NODE **, j * sizeof(NODE *), "foreach_func");
-
- /* now walk again, copying info */
- for (i = j = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = p->hnext) {
- if (p->hvalue->type == Node_func) {
- tab[j] = p;
- j++;
- }
- }
- }
-
- /* Shazzam! */
- qsort(tab, j, sizeof(NODE *), sym_comp);
-
- for (i = 0; i < j; i++) {
- if ((ret = pfunc(tab[i]->hvalue->code_ptr, data)) != 0)
- break;
- }
-
- efree(tab);
- return ret;
- }
-
- /* unsorted */
- for (i = 0; i < HASHSIZE; i++) {
- for (p = variables[i]; p != NULL; p = p->hnext) {
- if (p->hvalue->type == Node_func
- && (ret = pfunc(p->hvalue->code_ptr, data)) != 0)
- return ret;
- }
- }
- return 0;
-}
-
/* deferred variables --- those that are only defined if needed. */
/*
@@ -4517,17 +4184,14 @@ register_deferred_variable(const char *name, NODE *(*load_func)(void))
/* variable --- make sure NAME is in the symbol table */
NODE *
-variable(char *name, NODETYPE type)
+variable(int location, char *name, NODETYPE type)
{
NODE *r;
if ((r = lookup(name)) != NULL) {
- if (r->type == Node_func) {
- error(_("function `%s' called with space between name and `(',\nor used as a variable or an array"),
+ 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);
- errcount++;
- r->type = Node_var_new; /* continue parsing instead of exiting */
- }
} else {
/* not found */
struct deferred_variable *dv;
@@ -4537,11 +4201,7 @@ variable(char *name, NODETYPE type)
/*
* This is the only case in which we may not free the string.
*/
- if (type == Node_var)
- r = mk_symbol(type, Nnull_string);
- else
- r = mk_symbol(type, (NODE *) NULL);
- return install_symbol(name, r);
+ return install_symbol(name, type);
}
if (STREQ(name, dv->name)) {
r = (*dv->load_func)();
@@ -4648,9 +4308,6 @@ make_assignable(INSTRUCTION *ip)
{
switch (ip->opcode) {
case Op_push:
- if (ip->memory->type == Node_param_list
- && (ip->memory->flags & FUNC) != 0)
- return NULL;
ip->opcode = Op_push_lhs;
return ip;
case Op_field_spec:
@@ -4665,14 +4322,6 @@ make_assignable(INSTRUCTION *ip)
return NULL;
}
-/* stopme --- for debugging */
-
-NODE *
-stopme(int nargs ATTRIBUTE_UNUSED)
-{
- return (NODE *) 0;
-}
-
/* dumpintlstr --- write out an initial .po file entry for the string */
static void
@@ -4722,27 +4371,6 @@ dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2)
fflush(stdout);
}
-/* isarray --- can this type be subscripted? */
-
-static int
-isarray(NODE *n)
-{
- switch (n->type) {
- case Node_var_new:
- case Node_var_array:
- return TRUE;
- case Node_param_list:
- return (n->flags & FUNC) == 0;
- case Node_array_ref:
- cant_happen();
- break;
- default:
- break; /* keeps gcc -Wall happy */
- }
-
- return FALSE;
-}
-
/* mk_binary --- instructions for binary operators */
static INSTRUCTION *
@@ -4803,11 +4431,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
}
op->opcode = Op_push_i;
- op->memory = mk_number(res, (PERM|NUMCUR|NUMBER));
- n1->flags &= ~PERM;
- n1->flags |= MALLOC;
- n2->flags &= ~PERM;
- n2->flags |= MALLOC;
+ op->memory = make_number(res);
unref(n1);
unref(n2);
bcfree(ip1);
@@ -5138,9 +4762,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op)
static INSTRUCTION *
optimize_assignment(INSTRUCTION *exp)
{
- INSTRUCTION *i1;
- INSTRUCTION *i2;
- INSTRUCTION *i3;
+ INSTRUCTION *i1, *i2, *i3;
/*
* Optimize assignment statements array[subs] = x; var = x; $n = x;
@@ -5176,7 +4798,7 @@ optimize_assignment(INSTRUCTION *exp)
if ( ! do_optimize
|| ( 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) {
@@ -5261,13 +4883,26 @@ optimize_assignment(INSTRUCTION *exp)
case Op_push_lhs:
if (i2->nexti == i1
- && i1->opcode == Op_assign
+ && 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;
@@ -5569,320 +5204,6 @@ fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_targ
}
}
-
-/* append_symbol --- append symbol to the list of symbols
- * installed in the symbol table.
- */
-
-void
-append_symbol(char *name)
-{
- NODE *hp;
-
- /* N.B.: func_install removes func name and reinstalls it;
- * and we get two entries for it here!. destroy_symbol()
- * will find and destroy the Node_func which is what we want.
- */
-
- getnode(hp);
- hp->hname = name; /* shallow copy */
- hp->hnext = symbol_list->hnext;
- symbol_list->hnext = hp;
-}
-
-/* release_symbol --- free symbol list and optionally remove symbol from symbol table */
-
-void
-release_symbols(NODE *symlist, int keep_globals)
-{
- NODE *hp, *n;
-
- for (hp = symlist->hnext; hp != NULL; hp = n) {
- if (! keep_globals) {
- /* destroys globals, function, and params
- * if still in symbol table and not removed by func_install
- * due to parse error.
- */
- destroy_symbol(hp->hname);
- }
- n = hp->hnext;
- freenode(hp);
- }
- symlist->hnext = NULL;
-}
-
-/* destroy_symbol --- remove a symbol from symbol table
-* and free all associated memory.
-*/
-
-void
-destroy_symbol(char *name)
-{
- NODE *symbol, *hp;
-
- symbol = lookup(name);
- if (symbol == NULL)
- return;
-
- if (symbol->type == Node_func) {
- char **varnames;
- NODE *func, *n;
-
- func = symbol;
- varnames = func->parmlist;
- if (varnames != NULL)
- efree(varnames);
-
- /* function parameters of type Node_param_list */
- for (n = func->lnode->rnode; n != NULL; ) {
- NODE *np;
- np = n->rnode;
- efree(n->param);
- freenode(n);
- n = np;
- }
- freenode(func->lnode);
- func_count--;
-
- } else if (symbol->type == Node_var_array)
- assoc_clear(symbol);
- else if (symbol->type == Node_var)
- unref(symbol->var_value);
-
- /* remove from symbol table */
- hp = remove_symbol(name);
- efree(hp->hname);
- freenode(hp->hvalue);
- freenode(hp);
-}
-
-#define pool_size d.dl
-#define freei x.xi
-static INSTRUCTION *pool_list;
-static AWK_CONTEXT *curr_ctxt = NULL;
-
-/* new_context --- create a new execution context. */
-
-AWK_CONTEXT *
-new_context()
-{
- AWK_CONTEXT *ctxt;
-
- emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
- memset(ctxt, 0, sizeof(AWK_CONTEXT));
- ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles;
- ctxt->rule_list.opcode = Op_list;
- ctxt->rule_list.lasti = &ctxt->rule_list;
- return ctxt;
-}
-
-/* set_context --- change current execution context. */
-
-static void
-set_context(AWK_CONTEXT *ctxt)
-{
- pool_list = &ctxt->pools;
- symbol_list = &ctxt->symbols;
- srcfiles = &ctxt->srcfiles;
- rule_list = &ctxt->rule_list;
- install_func = ctxt->install_func;
- curr_ctxt = ctxt;
-}
-
-/*
- * push_context:
- *
- * Switch to the given context after saving the current one. The set
- * of active execution contexts forms a stack; the global or main context
- * is at the bottom of the stack.
- */
-
-void
-push_context(AWK_CONTEXT *ctxt)
-{
- ctxt->prev = curr_ctxt;
- /* save current source and sourceline */
- if (curr_ctxt != NULL) {
- curr_ctxt->sourceline = sourceline;
- curr_ctxt->source = source;
- }
- sourceline = 0;
- source = NULL;
- set_context(ctxt);
-}
-
-/* pop_context --- switch to previous execution context. */
-
-void
-pop_context()
-{
- AWK_CONTEXT *ctxt;
-
- assert(curr_ctxt != NULL);
- ctxt = curr_ctxt->prev;
- /* restore source and sourceline */
- sourceline = ctxt->sourceline;
- source = ctxt->source;
- set_context(ctxt);
-}
-
-/* in_main_context --- are we in the main context ? */
-
-int
-in_main_context()
-{
- assert(curr_ctxt != NULL);
- return (curr_ctxt->prev == NULL);
-}
-
-/* free_context --- free context structure and related data. */
-
-void
-free_context(AWK_CONTEXT *ctxt, int keep_globals)
-{
- SRCFILE *s, *sn;
-
- if (ctxt == NULL)
- return;
-
- assert(curr_ctxt != ctxt);
-
- /* free all code including function codes */
- free_bcpool(&ctxt->pools);
- /* free symbols */
- release_symbols(&ctxt->symbols, keep_globals);
- /* free srcfiles */
- for (s = &ctxt->srcfiles; s != &ctxt->srcfiles; s = sn) {
- sn = s->next;
- if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
- efree(s->fullpath);
- efree(s->src);
- efree(s);
- }
- efree(ctxt);
-}
-
-/* free_bc_internal --- free internal memory of an instruction. */
-
-static void
-free_bc_internal(INSTRUCTION *cp)
-{
- NODE *m;
-
- switch(cp->opcode) {
- case Op_func_call:
- if (cp->func_name != NULL
- && cp->func_name != builtin_func
- )
- efree(cp->func_name);
- break;
- case Op_push_re:
- case Op_match_rec:
- case Op_match:
- case Op_nomatch:
- m = cp->memory;
- if (m->re_reg != NULL)
- refree(m->re_reg);
- if (m->re_exp != NULL)
- unref(m->re_exp);
- if (m->re_text != NULL)
- unref(m->re_text);
- freenode(m);
- break;
- case Op_token: /* token lost during error recovery in yyparse */
- if (cp->lextok != NULL)
- efree(cp->lextok);
- break;
- case Op_illegal:
- cant_happen();
- default:
- break;
- }
-}
-
-
-/* INSTR_CHUNK must be > largest code size (3) */
-#define INSTR_CHUNK 127
-
-/* bcfree --- deallocate instruction */
-
-void
-bcfree(INSTRUCTION *cp)
-{
- cp->opcode = 0;
- cp->nexti = pool_list->freei;
- pool_list->freei = cp;
-}
-
-/* bcalloc --- allocate a new instruction */
-
-INSTRUCTION *
-bcalloc(OPCODE op, int size, int srcline)
-{
- INSTRUCTION *cp;
-
- if (size > 1) {
- /* wide instructions Op_rule, Op_func_call .. */
- emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), "bcalloc");
- cp->pool_size = size;
- cp->nexti = pool_list->nexti;
- pool_list->nexti = cp++;
- } else {
- INSTRUCTION *pool;
-
- pool = pool_list->freei;
- if (pool == NULL) {
- INSTRUCTION *last;
- emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * sizeof(INSTRUCTION), "bcalloc");
-
- cp->pool_size = INSTR_CHUNK;
- cp->nexti = pool_list->nexti;
- pool_list->nexti = cp;
- pool = ++cp;
- last = &pool[INSTR_CHUNK - 1];
- for (; cp <= last; cp++) {
- cp->opcode = 0;
- cp->nexti = cp + 1;
- }
- --cp;
- cp->nexti = NULL;
- }
- cp = pool;
- pool_list->freei = cp->nexti;
- }
-
- memset(cp, 0, size * sizeof(INSTRUCTION));
- cp->opcode = op;
- cp->source_line = srcline;
- return cp;
-}
-
-/* free_bcpool --- free list of instruction memory pools */
-
-static void
-free_bcpool(INSTRUCTION *pl)
-{
- INSTRUCTION *pool, *tmp;
-
- for (pool = pl->nexti; pool != NULL; pool = tmp) {
- INSTRUCTION *cp, *last;
- long psiz;
- psiz = pool->pool_size;
- if (psiz == INSTR_CHUNK)
- last = pool + psiz;
- else
- last = pool + 1;
- for (cp = pool + 1; cp <= last ; cp++) {
- if (cp->opcode != 0)
- free_bc_internal(cp);
- }
- tmp = pool->nexti;
- efree(pool);
- }
- memset(pl, 0, sizeof(INSTRUCTION));
-}
-
-
static inline INSTRUCTION *
list_create(INSTRUCTION *x)
{
diff --git a/awklib/.gitignore b/awklib/.gitignore
new file mode 100644
index 00000000..b46084d4
--- /dev/null
+++ b/awklib/.gitignore
@@ -0,0 +1,8 @@
+# Ignore files that are created by a build.
+# For example objects and archives.
+grcat
+group.awk
+igawk
+passwd.awk
+pwcat
+
diff --git a/builtin.c b/builtin.c
index 4b4b9722..5bc1c023 100644
--- a/builtin.c
+++ b/builtin.c
@@ -80,8 +80,10 @@ extern FILE *output_fp;
#define POP_TWO_SCALARS(s1, s2) \
s2 = POP_SCALAR(); \
s1 = POP(); \
-if ((s1)->type == Node_var_array) \
- DEREF(s2), fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)), 0
+do { if (s1->type == Node_var_array) { \
+DEREF(s2); \
+fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \
+}} while (FALSE)
/*
@@ -334,8 +336,10 @@ do_index(int nargs)
if ((s2->flags & (STRING|STRCUR)) == 0)
lintwarn(_("index: received non-string second argument"));
}
- force_string(s1);
- force_string(s2);
+
+ s1 = force_string(s1);
+ s2 = force_string(s2);
+
p1 = s1->stptr;
p2 = s2->stptr;
l1 = s1->stlen;
@@ -502,7 +506,7 @@ do_length(int nargs)
if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
lintwarn(_("length: received non-string argument"));
- (void) force_string(tmp);
+ tmp = force_string(tmp);
#if MBS_SUPPORT
if (gawk_mb_cur_max > 1) {
@@ -1385,7 +1389,7 @@ printf_common(int nargs)
}
}
- force_string(args_array[0]);
+ args_array[0] = force_string(args_array[0]);
r = format_tree(args_array[0]->stptr, args_array[0]->stlen, args_array, nargs);
for (i = 0; i < nargs; i++)
DEREF(args_array[i]);
@@ -1498,12 +1502,12 @@ do_substr(int nargs)
if (nargs == 3) {
if (! (d_length >= 1)) {
- if (do_lint == LINT_ALL)
+ if (do_lint == DO_LINT_ALL)
lintwarn(_("substr: length %g is not >= 1"), d_length);
- else if (do_lint == LINT_INVALID && ! (d_length >= 0))
+ else if (do_lint == DO_LINT_INVALID && ! (d_length >= 0))
lintwarn(_("substr: length %g is not >= 0"), d_length);
DEREF(t1);
- return Nnull_string;
+ return dupnode(Nnull_string);
}
if (do_lint) {
if (double_to_int(d_length) != d_length)
@@ -1554,10 +1558,10 @@ do_substr(int nargs)
if (t1->stlen == 0) {
/* substr("", 1, 0) produces a warning only if LINT_ALL */
- if (do_lint && (do_lint == LINT_ALL || ((indx | length) != 0)))
+ if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 0)))
lintwarn(_("substr: source string is zero length"));
DEREF(t1);
- return Nnull_string;
+ return dupnode(Nnull_string);
}
/* get total len of input string, for following checks */
@@ -1574,7 +1578,7 @@ do_substr(int nargs)
lintwarn(_("substr: start index %g is past end of string"),
d_index);
DEREF(t1);
- return Nnull_string;
+ return dupnode(Nnull_string);
}
if (length > src_len - indx) {
if (do_lint)
@@ -1672,7 +1676,7 @@ do_strftime(int nargs)
do_gmt = (t3->stlen > 0);
DEREF(t3);
}
-
+
if (nargs >= 2) {
t2 = POP_SCALAR();
if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0)
@@ -1687,6 +1691,7 @@ do_strftime(int nargs)
tmp = POP_SCALAR();
if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
lintwarn(_("strftime: received non-string first argument"));
+
t1 = force_string(tmp);
format = t1->stptr;
formatlen = t1->stlen;
@@ -1769,13 +1774,13 @@ do_mktime(int nargs)
& hour, & minute, & second,
& dst);
- if (do_lint /* Ready? Set! Go: */
- && ( (second < 0 || second > 60)
- || (minute < 0 || minute > 60)
- || (hour < 0 || hour > 23)
- || (day < 1 || day > 31)
- || (month < 1 || month > 12) ))
- lintwarn(_("mktime: at least one of the values is out of the default range"));
+ if (do_lint /* Ready? Set! Go: */
+ && ( (second < 0 || second > 60)
+ || (minute < 0 || minute > 60)
+ || (hour < 0 || hour > 23)
+ || (day < 1 || day > 31)
+ || (month < 1 || month > 12) ))
+ lintwarn(_("mktime: at least one of the values is out of the default range"));
t1->stptr[t1->stlen] = save;
DEREF(t1);
@@ -1836,11 +1841,9 @@ do_system(int nargs)
return make_number((AWKNUM) ret);
}
-extern NODE **fmt_list; /* declared in eval.c */
-
/* do_print --- print items, separated by OFS, terminated with ORS */
-void
+void
do_print(int nargs, int redirtype)
{
struct redirect *rp = NULL;
@@ -1848,7 +1851,7 @@ do_print(int nargs, int redirtype)
FILE *fp = NULL;
int i;
NODE *redir_exp = NULL;
- NODE *tmp;
+ NODE *tmp = NULL;
assert(nargs <= max_args);
@@ -1869,12 +1872,10 @@ do_print(int nargs, int redirtype)
DEREF(args_array[i]);
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp));
}
- if (do_lint && tmp->type == Node_var_new)
- lintwarn(_("reference to uninitialized variable `%s'"),
- tmp->vname);
+
if ((tmp->flags & (NUMBER|STRING)) == NUMBER) {
if (OFMTidx == CONVFMTidx)
- (void) force_string(tmp);
+ args_array[i] = force_string(tmp);
else
args_array[i] = format_val(OFMT, OFMTidx, tmp);
}
@@ -2266,7 +2267,7 @@ do_match(int nargs)
it->flags |= MAYBE_NUM; /* user input */
sub = make_number((AWKNUM) (ii));
- lhs = assoc_lookup(dest, sub, FALSE);
+ lhs = assoc_lookup(dest, sub);
unref(*lhs);
*lhs = it;
unref(sub);
@@ -2289,7 +2290,7 @@ do_match(int nargs)
it = make_number((AWKNUM) subpat_start + 1);
sub = make_string(buf, slen);
- lhs = assoc_lookup(dest, sub, FALSE);
+ lhs = assoc_lookup(dest, sub);
unref(*lhs);
*lhs = it;
unref(sub);
@@ -2302,7 +2303,7 @@ do_match(int nargs)
it = make_number((AWKNUM) subpat_len);
sub = make_string(buf, slen);
- lhs = assoc_lookup(dest, sub, FALSE);
+ lhs = assoc_lookup(dest, sub);
unref(*lhs);
*lhs = it;
unref(sub);
diff --git a/cint_array.c b/cint_array.c
new file mode 100644
index 00000000..3d812cbb
--- /dev/null
+++ b/cint_array.c
@@ -0,0 +1,1232 @@
+/*
+ * cint_array.c - routines for arrays of (mostly) consecutive positive integer indices.
+ */
+
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-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
+ */
+
+#include "awk.h"
+
+extern FILE *output_fp;
+extern void indent(int indent_level);
+extern NODE **is_integer(NODE *symbol, NODE *subs);
+
+/*
+ * NHAT --- maximum size of a leaf array (2^NHAT).
+ * THRESHOLD --- Maximum capacity waste; THRESHOLD >= 2^(NHAT + 1).
+ */
+
+static int NHAT = 10;
+static long THRESHOLD;
+
+/* What is the optimium NHAT ? timing results suggest that 10 is a good choice,
+ * although differences aren't that significant for > 10.
+ */
+
+
+static NODE **cint_array_init(NODE *symbol, NODE *subs);
+static NODE **is_uinteger(NODE *symbol, NODE *subs);
+static NODE **cint_lookup(NODE *symbol, NODE *subs);
+static NODE **cint_exists(NODE *symbol, NODE *subs);
+static NODE **cint_clear(NODE *symbol, NODE *subs);
+static NODE **cint_remove(NODE *symbol, NODE *subs);
+static NODE **cint_list(NODE *symbol, NODE *t);
+static NODE **cint_copy(NODE *symbol, NODE *newsymb);
+static NODE **cint_dump(NODE *symbol, NODE *ndump);
+#ifdef ARRAYDEBUG
+static NODE **cint_option(NODE *opt, NODE *val);
+static void cint_print(NODE *symbol);
+#endif
+
+array_ptr cint_array_func[] = {
+ cint_array_init,
+ is_uinteger,
+ cint_lookup,
+ cint_exists,
+ cint_clear,
+ cint_remove,
+ cint_list,
+ cint_copy,
+ cint_dump,
+#ifdef ARRAYDEBUG
+ cint_option,
+#endif
+};
+
+static inline int cint_hash(long k);
+static inline NODE **cint_find(NODE *symbol, long k, int h1);
+
+static inline NODE *make_node(NODETYPE type);
+
+static NODE **tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base);
+static NODE **tree_exists(NODE *tree, long k);
+static void tree_clear(NODE *tree);
+static int tree_remove(NODE *symbol, NODE *tree, long k);
+static void tree_copy(NODE *newsymb, NODE *tree, NODE *newtree);
+static long tree_list(NODE *tree, NODE **list, unsigned int flags);
+static inline NODE **tree_find(NODE *tree, long k, int i);
+static void tree_info(NODE *tree, NODE *ndump, const char *aname);
+static size_t tree_kilobytes(NODE *tree);
+#ifdef ARRAYDEBUG
+static void tree_print(NODE *tree, size_t bi, int indent_level);
+#endif
+
+static inline NODE **leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base);
+static inline NODE **leaf_exists(NODE *array, long k);
+static void leaf_clear(NODE *array);
+static int leaf_remove(NODE *symbol, NODE *array, long k);
+static void leaf_copy(NODE *newsymb, NODE *array, NODE *newarray);
+static long leaf_list(NODE *array, NODE **list, unsigned int flags);
+static void leaf_info(NODE *array, NODE *ndump, const char *aname);
+#ifdef ARRAYDEBUG
+static void leaf_print(NODE *array, size_t bi, int indent_level);
+#endif
+
+/* powers of 2 table upto 2^30 */
+static const long power_two_table[] = {
+ 1, 2, 4, 8, 16, 32, 64,
+ 128, 256, 512, 1024, 2048, 4096,
+ 8192, 16384, 32768, 65536, 131072, 262144,
+ 524288, 1048576, 2097152, 4194304, 8388608, 16777216,
+ 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824
+};
+
+
+#define ISUINT(a, s) ((((s)->flags & NUMINT) != 0 || is_integer(a, s) != NULL) \
+ && (s)->numbr >= 0)
+
+/*
+ * To store 2^n integers, allocate top-level array of size n, elements
+ * of which are 1-Dimensional (leaf-array) of geometrically increasing
+ * size (power of 2).
+ *
+ * [0] --> [ 0 ]
+ * [1] --> [ 1 ]
+ * |2| --> [ 2 | 3 ]
+ * |3| --> [ 4 | 5 | 6 | 7 ]
+ * |.|
+ * |k| --> [ 2^(k - 1)| ... | 2^k - 1 ]
+ * ...
+ *
+ * For a given integer n (> 0), the leaf-array is at 1 + floor(log2(n)).
+ *
+ * The idea for the geometrically increasing array sizes is from:
+ * Fast Functional Lists, Hash-Lists, Deques and Variable Length Arrays.
+ * Bagwell, Phil (2002).
+ * http://infoscience.epfl.ch/record/64410/files/techlists.pdf
+ *
+ * Disadvantage:
+ * Worst case memory waste > 99% and will happen when each of the
+ * leaf arrays contains only a single element. Even with consecutive
+ * integers, memory waste can be as high as 50%.
+ *
+ * Solution: Hashed Array Trees (HATs).
+ *
+ */
+
+/* cint_array_init --- check relevant environment variables */
+
+static NODE **
+cint_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
+{
+ long newval;
+
+ if ((newval = getenv_long("NHAT")) > 1 && newval < INT32_BIT)
+ NHAT = newval;
+ THRESHOLD = power_two_table[NHAT + 1];
+ return (NODE **) ! NULL;
+}
+
+
+/* is_uinteger --- test if the subscript is an integer >= 0 */
+
+NODE **
+is_uinteger(NODE *symbol, NODE *subs)
+{
+ if (is_integer(symbol, subs) != NULL && subs->numbr >= 0)
+ return (NODE **) ! NULL;
+ return NULL;
+}
+
+
+/* cint_lookup --- Find the subscript in the array; Install it if it isn't there. */
+
+static NODE **
+cint_lookup(NODE *symbol, NODE *subs)
+{
+ NODE **lhs;
+ long k;
+ int h1 = -1, m, li;
+ NODE *tn, *xn;
+ long cint_size, capacity;
+
+ k = -1;
+ if (ISUINT(symbol, subs)) {
+ k = subs->numbr; /* k >= 0 */
+ h1 = cint_hash(k); /* h1 >= NHAT */
+ if ((lhs = cint_find(symbol, k, h1)) != NULL)
+ return lhs;
+ }
+ xn = symbol->xarray;
+ if (xn != NULL && (lhs = xn->aexists(xn, subs)) != NULL)
+ return lhs;
+
+ /* It's not there, install it */
+
+ if (k < 0)
+ goto xinstall;
+
+ m = h1 - 1; /* m >= (NHAT- 1) */
+
+ /* Estimate capacity upper bound.
+ * capacity upper bound = current capacity + leaf array size.
+ */
+ li = m > NHAT ? m : NHAT;
+ while (li >= NHAT) {
+ /* leaf-array of a HAT */
+ li = (li + 1) / 2;
+ }
+ capacity = symbol->array_capacity + power_two_table[li];
+
+ cint_size = (xn == NULL) ? symbol->table_size
+ : (symbol->table_size - xn->table_size);
+ assert(cint_size >= 0);
+ if ((capacity - cint_size) > THRESHOLD)
+ goto xinstall;
+
+ if (symbol->nodes == NULL) {
+ symbol->array_capacity = 0;
+ assert(symbol->table_size == 0);
+
+ /* nodes[0] .. nodes[NHAT- 1] not used */
+ emalloc(symbol->nodes, NODE **, INT32_BIT * sizeof(NODE *), "cint_lookup");
+ memset(symbol->nodes, '\0', INT32_BIT * sizeof(NODE *));
+ }
+
+ symbol->table_size++; /* one more element in array */
+
+ tn = symbol->nodes[h1];
+ if (tn == NULL) {
+ tn = make_node(Node_array_tree);
+ symbol->nodes[h1] = tn;
+ }
+
+ if (m < NHAT)
+ return tree_lookup(symbol, tn, k, NHAT, 0);
+ return tree_lookup(symbol, tn, k, m, power_two_table[m]);
+
+xinstall:
+
+ symbol->table_size++;
+ if (xn == NULL) {
+ extern array_ptr int_array_func[];
+ extern array_ptr str_array_func[];
+
+ xn = symbol->xarray = make_array();
+ xn->vname = symbol->vname; /* shallow copy */
+
+ /* Avoid using assoc_lookup(xn, subs) which may lead
+ * to infinite recursion.
+ */
+
+ if (is_integer(xn, subs))
+ xn->array_funcs = int_array_func;
+ else
+ xn->array_funcs = str_array_func;
+ xn->flags |= XARRAY;
+ }
+ return xn->alookup(xn, subs);
+}
+
+
+/* cint_exists --- test whether an index is in the array or not. */
+
+static NODE **
+cint_exists(NODE *symbol, NODE *subs)
+{
+ NODE *xn;
+
+ if (ISUINT(symbol, subs)) {
+ long k = subs->numbr;
+ NODE **lhs;
+ if ((lhs = cint_find(symbol, k, cint_hash(k))) != NULL)
+ return lhs;
+ }
+ if ((xn = symbol->xarray) == NULL)
+ return NULL;
+ return xn->aexists(xn, subs);
+}
+
+
+/* cint_clear --- flush all the values in symbol[] */
+
+static NODE **
+cint_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
+{
+ size_t i;
+ NODE *tn;
+
+ assert(symbol->nodes != NULL);
+
+ if (symbol->xarray != NULL) {
+ NODE *xn = symbol->xarray;
+ assoc_clear(xn);
+ freenode(xn);
+ symbol->xarray = NULL;
+ }
+
+ for (i = NHAT; i < INT32_BIT; i++) {
+ tn = symbol->nodes[i];
+ if (tn != NULL) {
+ tree_clear(tn);
+ freenode(tn);
+ }
+ }
+
+ efree(symbol->nodes);
+ init_array(symbol); /* re-initialize symbol */
+ return NULL;
+}
+
+
+/* cint_remove --- remove an index from the array */
+
+static NODE **
+cint_remove(NODE *symbol, NODE *subs)
+{
+ long k;
+ int h1;
+ NODE *tn, *xn = symbol->xarray;
+
+ assert(symbol->nodes != NULL);
+ if (! ISUINT(symbol, subs))
+ goto xremove;
+
+ k = subs->numbr;
+ h1 = cint_hash(k);
+ tn = symbol->nodes[h1];
+ if (tn == NULL || ! tree_remove(symbol, tn, k))
+ goto xremove;
+
+ if (tn->table_size == 0) {
+ freenode(tn);
+ symbol->nodes[h1] = NULL;
+ }
+
+ symbol->table_size--;
+
+ if (xn == NULL && symbol->table_size == 0) {
+ efree(symbol->nodes);
+ init_array(symbol); /* re-initialize array 'symbol' */
+ } else if(xn != NULL && symbol->table_size == xn->table_size) {
+ /* promote xn to symbol */
+ xn->flags &= ~XARRAY;
+ xn->parent_array = symbol->parent_array;
+ efree(symbol->nodes);
+ *symbol = *xn;
+ freenode(xn);
+ }
+
+ return (NODE **) ! NULL;
+
+xremove:
+ xn = symbol->xarray;
+ if (xn == NULL || xn->aremove(xn, subs) == NULL)
+ return NULL;
+ if (xn->table_size == 0) {
+ freenode(xn);
+ symbol->xarray = NULL;
+ }
+ symbol->table_size--;
+ assert(symbol->table_size > 0);
+
+ return (NODE **) ! NULL;
+}
+
+
+/* cint_copy --- duplicate input array "symbol" */
+
+static NODE **
+cint_copy(NODE *symbol, NODE *newsymb)
+{
+ NODE **old, **new;
+ size_t i;
+
+ assert(symbol->nodes != NULL);
+
+ /* allocate new table */
+ emalloc(new, NODE **, INT32_BIT * sizeof(NODE *), "cint_copy");
+ memset(new, '\0', INT32_BIT * sizeof(NODE *));
+
+ old = symbol->nodes;
+ for (i = NHAT; i < INT32_BIT; i++) {
+ if (old[i] == NULL)
+ continue;
+ new[i] = make_node(Node_array_tree);
+ tree_copy(newsymb, old[i], new[i]);
+ }
+
+ if (symbol->xarray != NULL) {
+ NODE *xn, *n;
+ xn = symbol->xarray;
+ n = make_array();
+ n->vname = newsymb->vname;
+ (void) xn->acopy(xn, n);
+ newsymb->xarray = n;
+ } else
+ newsymb->xarray = NULL;
+
+ newsymb->nodes = new;
+ newsymb->table_size = symbol->table_size;
+ newsymb->array_capacity = symbol->array_capacity;
+ newsymb->flags = symbol->flags;
+
+ return NULL;
+}
+
+
+/* cint_list --- return a list of items */
+
+static NODE**
+cint_list(NODE *symbol, NODE *t)
+{
+ NODE **list = NULL;
+ NODE *tn, *xn;
+ unsigned long k = 0, num_elems, list_size;
+ size_t j, ja, jd;
+ int elem_size = 1;
+
+ num_elems = symbol->table_size;
+ if (num_elems == 0)
+ return NULL;
+
+ if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+ num_elems = 1;
+
+ if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+ elem_size = 2;
+ list_size = num_elems * elem_size;
+
+ if (symbol->xarray != NULL) {
+ xn = symbol->xarray;
+ list = xn->alist(xn, t);
+ assert(list != NULL);
+ t->flags &= ~(AASC|ADESC);
+ if (num_elems == 1 || num_elems == xn->table_size)
+ return list;
+ erealloc(list, NODE **, list_size * sizeof(NODE *), "cint_list");
+ k = elem_size * xn->table_size;
+ } else
+ emalloc(list, NODE **, list_size * sizeof(NODE *), "cint_list");
+
+
+ if ((t->flags & AINUM) == 0) /* not sorting by "index num" */
+ t->flags &= ~(AASC|ADESC);
+
+ /* populate it with index in ascending or descending order */
+
+ for (ja = NHAT, jd = INT32_BIT - 1; ja < INT32_BIT && jd >= NHAT; ) {
+ j = (t->flags & ADESC) ? jd-- : ja++;
+ tn = symbol->nodes[j];
+ if (tn == NULL)
+ continue;
+ k += tree_list(tn, list + k, t->flags);
+ if (k >= list_size)
+ return list;
+ }
+ return list;
+}
+
+
+/* cint_dump --- dump array info */
+
+static NODE **
+cint_dump(NODE *symbol, NODE *ndump)
+{
+ NODE *tn, *xn = NULL;
+ int indent_level;
+ size_t i;
+ long cint_size = 0, xsize = 0;
+ AWKNUM kb = 0;
+ extern AWKNUM int_kilobytes(NODE *symbol);
+ extern AWKNUM str_kilobytes(NODE *symbol);
+ extern array_ptr int_array_func[];
+
+ indent_level = ndump->alevel;
+
+ if (symbol->xarray != NULL) {
+ xn = symbol->xarray;
+ xsize = xn->table_size;
+ }
+ cint_size = symbol->table_size - xsize;
+
+ if ((symbol->flags & XARRAY) == 0)
+ fprintf(output_fp, "%s `%s'\n",
+ (symbol->parent_array == NULL) ? "array" : "sub-array",
+ array_vname(symbol));
+ indent_level++;
+ indent(indent_level);
+ fprintf(output_fp, "array_func: cint_array_func\n");
+ if (symbol->flags != 0) {
+ indent(indent_level);
+ fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
+ }
+ indent(indent_level);
+ fprintf(output_fp, "NHAT: %d\n", NHAT);
+ indent(indent_level);
+ fprintf(output_fp, "THRESHOLD: %ld\n", THRESHOLD);
+ indent(indent_level);
+ fprintf(output_fp, "table_size: %ld (total), %ld (cint), %ld (int + str)\n",
+ symbol->table_size, cint_size, xsize);
+ indent(indent_level);
+ fprintf(output_fp, "array_capacity: %lu\n", (unsigned long) symbol->array_capacity);
+ indent(indent_level);
+ fprintf(output_fp, "Load Factor: %.2g\n", (AWKNUM) cint_size / symbol->array_capacity);
+
+ for (i = NHAT; i < INT32_BIT; i++) {
+ tn = symbol->nodes[i];
+ if (tn == NULL)
+ continue;
+ /* Node_array_tree + HAT */
+ kb += (sizeof(NODE) + tree_kilobytes(tn)) / 1024.0;
+ }
+ kb += (INT32_BIT * sizeof(NODE *)) / 1024.0; /* symbol->nodes */
+ kb += (symbol->array_capacity * sizeof(NODE *)) / 1024.0; /* value nodes in Node_array_leaf(s) */
+ if (xn != NULL) {
+ if (xn->array_funcs == int_array_func)
+ kb += int_kilobytes(xn);
+ else
+ kb += str_kilobytes(xn);
+ }
+
+ indent(indent_level);
+ fprintf(output_fp, "memory: %.2g kB (total)\n", kb);
+
+ /* dump elements */
+
+ if (ndump->adepth >= 0) {
+ const char *aname;
+
+ fprintf(output_fp, "\n");
+ aname = make_aname(symbol);
+ for (i = NHAT; i < INT32_BIT; i++) {
+ tn = symbol->nodes[i];
+ if (tn != NULL)
+ tree_info(tn, ndump, aname);
+ }
+ }
+
+ if (xn != NULL) {
+ fprintf(output_fp, "\n");
+ xn->adump(xn, ndump);
+ }
+
+#ifdef ARRAYDEBUG
+ if (ndump->adepth < -999)
+ cint_print(symbol);
+#endif
+
+ return NULL;
+}
+
+
+/* cint_hash --- locate the HAT for a given number 'k' */
+
+static inline int
+cint_hash(long k)
+{
+ uint32_t num, r, shift;
+
+ assert(k >= 0);
+ if (k == 0)
+ return NHAT;
+ num = k;
+
+ /* Find the Floor(log base 2 of 32-bit integer) */
+
+ /* Warren Jr., Henry S. (2002). Hacker's Delight.
+ * Addison Wesley. pp. pp. 215. ISBN 978-0201914658.
+ *
+ * r = 0;
+ * if (num >= 1<<16) { num >>= 16; r += 16; }
+ * if (num >= 1<< 8) { num >>= 8; r += 8; }
+ * if (num >= 1<< 4) { num >>= 4; r += 4; }
+ * if (num >= 1<< 2) { num >>= 2; r += 2; }
+ * if (num >= 1<< 1) { r += 1; }
+ */
+
+
+ /* Slightly different code copied from:
+ *
+ * http://www-graphics.stanford.edu/~seander/bithacks.html
+ * Bit Twiddling Hacks
+ * By Sean Eron Anderson
+ * seander@cs.stanford.edu
+ * Individually, the code snippets here are in the public domain
+ * (unless otherwise noted) — feel free to use them however you please.
+ * The aggregate collection and descriptions are © 1997-2005
+ * Sean Eron Anderson. The code and descriptions are distributed in the
+ * hope that they will be useful, but WITHOUT ANY WARRANTY and without
+ * even the implied warranty of merchantability or fitness for a particular
+ * purpose.
+ *
+ */
+
+ r = (num > 0xFFFF) << 4; num >>= r;
+ shift = (num > 0xFF) << 3; num >>= shift; r |= shift;
+ shift = (num > 0x0F) << 2; num >>= shift; r |= shift;
+ shift = (num > 0x03) << 1; num >>= shift; r |= shift;
+ r |= (num >> 1);
+
+ /* We use a single HAT for 0 <= num < 2^NHAT */
+ if (r < NHAT)
+ return NHAT;
+
+ return (1 + r);
+}
+
+
+/* cint_find --- locate the integer subscript */
+
+static inline NODE **
+cint_find(NODE *symbol, long k, int h1)
+{
+ NODE *tn;
+
+ if (symbol->nodes == NULL || (tn = symbol->nodes[h1]) == NULL)
+ return NULL;
+ return tree_exists(tn, k);
+}
+
+
+#ifdef ARRAYDEBUG
+
+static NODE **
+cint_option(NODE *opt, NODE *val)
+{
+ NODE *tmp;
+ NODE **ret = (NODE **) ! NULL;
+
+ tmp = force_string(opt);
+ (void) force_number(val);
+ if (STREQ(tmp->stptr, "NHAT"))
+ NHAT = (int) val->numbr;
+ else
+ ret = NULL;
+ return ret;
+}
+
+
+/* cint_print --- print structural info */
+
+static void
+cint_print(NODE *symbol)
+{
+ NODE *tn;
+ size_t i;
+
+ fprintf(output_fp, "I[%4lu:%-4lu]\n", (unsigned long) INT32_BIT,
+ (unsigned long) symbol->table_size);
+ for (i = NHAT; i < INT32_BIT; i++) {
+ tn = symbol->nodes[i];
+ if (tn == NULL)
+ continue;
+ tree_print(tn, i, 1);
+ }
+}
+
+#endif
+
+
+/*------------------------ Hashed Array Trees -----------------------------*/
+
+/*
+ * HATs: Hashed Array Trees
+ * Fast variable-length arrays
+ * Edward Sitarski
+ * http://www.drdobbs.com/architecture-and-design/184409965
+ *
+ * HAT has a top-level array containing a power of two
+ * number of leaf arrays. All leaf arrays are the same size as the
+ * top-level array. A full HAT can hold n^2 elements,
+ * where n (some power of 2) is the size of each leaf array.
+ * [i/n][i & (n - 1)] locates the `i th' element in a HAT.
+ *
+ */
+
+/*
+ * A half HAT is defined here as a HAT with a top-level array of size n^2/2
+ * and holds the first n^2/2 elements.
+ *
+ * 1. 2^8 elements can be stored in a full HAT of size 2^4.
+ * 2. 2^9 elements can be stored in a half HAT of size 2^5.
+ * 3. When the number of elements is some power of 2, it
+ * can be stored in a full or a half HAT.
+ * 4. When the number of elements is some power of 2, it
+ * can be stored in a HAT (full or half) with HATs as leaf elements
+ * (full or half), and so on (e.g. 2^8 elements in a HAT of size 2^4 (top-level
+ * array dimension) with each leaf array being a HAT of size 2^2).
+ *
+ * IMPLEMENTATION DETAILS:
+ * 1. A HAT of 2^12 elements needs 2^6 house-keeping NODEs
+ * of Node_array_leaf.
+ *
+ * 2. A HAT of HATS of 2^12 elements needs
+ * 2^6 * (1 Node_array_tree + 2^3 Node_array_leaf)
+ * ~ 2^9 house-keeping NODEs.
+ *
+ * 3. When a leaf array (or leaf HAT) becomes empty, the memory
+ * is deallocated, and when there is no leaf array (or leaf HAT) left,
+ * the HAT is deleted.
+ *
+ * 4. A HAT stores the base (first) element, and locates the leaf array/HAT
+ * for the `i th' element using integer division
+ * (i - base)/n where n is the size of the top-level array.
+ *
+ */
+
+/* make_node --- initialize a NODE */
+
+static inline NODE *
+make_node(NODETYPE type)
+{
+ NODE *n;
+ getnode(n);
+ memset(n, '\0', sizeof(NODE));
+ n->type = type;
+ return n;
+}
+
+
+/* tree_lookup --- Find an integer subscript in a HAT; Install it if it isn't there */
+
+static NODE **
+tree_lookup(NODE *symbol, NODE *tree, long k, int m, long base)
+{
+ NODE **lhs;
+ NODE *tn;
+ int i, n;
+ size_t size;
+ long num = k;
+
+ /*
+ * HAT size (size of Top & Leaf array) = 2^n
+ * where n = Floor ((m + 1)/2). For an odd value of m,
+ * only the first half of the HAT is needed.
+ */
+
+ n = (m + 1) / 2;
+
+ if (tree->table_size == 0) {
+ size_t actual_size;
+ NODE **table;
+
+ assert(tree->nodes == NULL);
+
+ /* initialize top-level array */
+ size = actual_size = power_two_table[n];
+ tree->array_base = base;
+ tree->array_size = size;
+ tree->table_size = 0; /* # of elements in the array */
+ if (n > m/2) {
+ /* only first half of the array used */
+ actual_size /= 2;
+ tree->flags |= HALFHAT;
+ }
+ emalloc(table, NODE **, actual_size * sizeof(NODE *), "tree_lookup");
+ memset(table, '\0', actual_size * sizeof(NODE *));
+ tree->nodes = table;
+ } else
+ size = tree->array_size;
+
+ num -= tree->array_base;
+ i = num / size; /* top-level array index */
+ assert(i >= 0);
+
+ if ((lhs = tree_find(tree, k, i)) != NULL)
+ return lhs;
+
+ /* It's not there, install it */
+
+ tree->table_size++;
+ base += (size * i);
+ tn = tree->nodes[i];
+ if (n > NHAT) {
+ if (tn == NULL)
+ tn = tree->nodes[i] = make_node(Node_array_tree);
+ return tree_lookup(symbol, tn, k, n, base);
+ } else {
+ if (tn == NULL)
+ tn = tree->nodes[i] = make_node(Node_array_leaf);
+ return leaf_lookup(symbol, tn, k, size, base);
+ }
+}
+
+
+/* tree_exists --- test whether integer subscript `k' exists or not */
+
+static NODE **
+tree_exists(NODE *tree, long k)
+{
+ int i;
+ NODE *tn;
+
+ i = (k - tree->array_base) / tree->array_size;
+ assert(i >= 0);
+ tn = tree->nodes[i];
+ if (tn == NULL)
+ return NULL;
+ if (tn->type == Node_array_tree)
+ return tree_exists(tn, k);
+ return leaf_exists(tn, k);
+}
+
+/* tree_clear --- flush all the values */
+
+static void
+tree_clear(NODE *tree)
+{
+ NODE *tn;
+ size_t j, hsize;
+
+ hsize = tree->array_size;
+ if ((tree->flags & HALFHAT) != 0)
+ hsize /= 2;
+
+ for (j = 0; j < hsize; j++) {
+ tn = tree->nodes[j];
+ if (tn == NULL)
+ continue;
+ if (tn->type == Node_array_tree)
+ tree_clear(tn);
+ else
+ leaf_clear(tn);
+ freenode(tn);
+ }
+
+ efree(tree->nodes);
+ memset(tree, '\0', sizeof(NODE));
+ tree->type = Node_array_tree;
+}
+
+
+/* tree_remove --- If the integer subscript is in the HAT, remove it */
+
+static int
+tree_remove(NODE *symbol, NODE *tree, long k)
+{
+ int i;
+ NODE *tn;
+
+ i = (k - tree->array_base) / tree->array_size;
+ assert(i >= 0);
+ tn = tree->nodes[i];
+ if (tn == NULL)
+ return FALSE;
+
+ if (tn->type == Node_array_tree
+ && ! tree_remove(symbol, tn, k))
+ return FALSE;
+ else if (tn->type == Node_array_leaf
+ && ! leaf_remove(symbol, tn, k))
+ return FALSE;
+
+ if (tn->table_size == 0) {
+ freenode(tn);
+ tree->nodes[i] = NULL;
+ }
+
+ /* one less item in array */
+ if (--tree->table_size == 0) {
+ efree(tree->nodes);
+ memset(tree, '\0', sizeof(NODE));
+ tree->type = Node_array_tree;
+ }
+ return TRUE;
+}
+
+
+/* tree_find --- locate an interger subscript in the HAT */
+
+static inline NODE **
+tree_find(NODE *tree, long k, int i)
+{
+ NODE *tn;
+
+ assert(tree->nodes != NULL);
+ tn = tree->nodes[i];
+ if (tn != NULL) {
+ if (tn->type == Node_array_tree)
+ return tree_exists(tn, k);
+ return leaf_exists(tn, k);
+ }
+ return NULL;
+}
+
+
+/* tree_list --- return a list of items in the HAT */
+
+static long
+tree_list(NODE *tree, NODE **list, unsigned int flags)
+{
+ NODE *tn;
+ size_t j, cj, hsize;
+ long k = 0;
+
+ assert(list != NULL);
+
+ hsize = tree->array_size;
+ if ((tree->flags & HALFHAT) != 0)
+ hsize /= 2;
+
+ for (j = 0; j < hsize; j++) {
+ cj = (flags & ADESC) ? (hsize - 1 - j) : j;
+ tn = tree->nodes[cj];
+ if (tn == NULL)
+ continue;
+ if (tn->type == Node_array_tree)
+ k += tree_list(tn, list + k, flags);
+ else
+ k += leaf_list(tn, list + k, flags);
+ if ((flags & ADELETE) != 0 && k >= 1)
+ return k;
+ }
+ return k;
+}
+
+
+/* tree_copy --- duplicate a HAT */
+
+static void
+tree_copy(NODE *newsymb, NODE *tree, NODE *newtree)
+{
+ NODE **old, **new;
+ size_t j, hsize;
+
+ hsize = tree->array_size;
+ if ((tree->flags & HALFHAT) != 0)
+ hsize /= 2;
+
+ emalloc(new, NODE **, hsize * sizeof(NODE *), "tree_copy");
+ memset(new, '\0', hsize * sizeof(NODE *));
+ newtree->nodes = new;
+ newtree->array_base = tree->array_base;
+ newtree->array_size = tree->array_size;
+ newtree->table_size = tree->table_size;
+ newtree->flags = tree->flags;
+
+ old = tree->nodes;
+ for (j = 0; j < hsize; j++) {
+ if (old[j] == NULL)
+ continue;
+ if (old[j]->type == Node_array_tree) {
+ new[j] = make_node(Node_array_tree);
+ tree_copy(newsymb, old[j], new[j]);
+ } else {
+ new[j] = make_node(Node_array_leaf);
+ leaf_copy(newsymb, old[j], new[j]);
+ }
+ }
+}
+
+
+/* tree_info --- print index, value info */
+
+static void
+tree_info(NODE *tree, NODE *ndump, const char *aname)
+{
+ NODE *tn;
+ size_t j, hsize;
+
+ hsize = tree->array_size;
+ if ((tree->flags & HALFHAT) != 0)
+ hsize /= 2;
+
+ for (j = 0; j < hsize; j++) {
+ tn = tree->nodes[j];
+ if (tn == NULL)
+ continue;
+ if (tn->type == Node_array_tree)
+ tree_info(tn, ndump, aname);
+ else
+ leaf_info(tn, ndump, aname);
+ }
+}
+
+
+/* tree_kilobytes --- calculate memory consumption of a HAT */
+
+static size_t
+tree_kilobytes(NODE *tree)
+{
+ NODE *tn;
+ size_t j, hsize;
+ size_t sz = 0;
+
+ hsize = tree->array_size;
+ if ((tree->flags & HALFHAT) != 0)
+ hsize /= 2;
+ for (j = 0; j < hsize; j++) {
+ tn = tree->nodes[j];
+ if (tn == NULL)
+ continue;
+ sz += sizeof(NODE); /* Node_array_tree or Node_array_leaf */
+ if (tn->type == Node_array_tree)
+ sz += tree_kilobytes(tn);
+ }
+ sz += hsize * sizeof(NODE *); /* tree->nodes */
+ return sz;
+}
+
+#ifdef ARRAYDEBUG
+
+/* tree_print --- print the HAT structures */
+
+static void
+tree_print(NODE *tree, size_t bi, int indent_level)
+{
+ NODE *tn;
+ size_t j, hsize;
+
+ indent(indent_level);
+
+ hsize = tree->array_size;
+ if ((tree->flags & HALFHAT) != 0)
+ hsize /= 2;
+ fprintf(output_fp, "%4lu:%s[%4lu:%-4lu]\n", bi,
+ (tree->flags & HALFHAT) ? "HH" : "H",
+ (unsigned long) hsize, (unsigned long) tree->table_size);
+
+ for (j = 0; j < hsize; j++) {
+ tn = tree->nodes[j];
+ if (tn == NULL)
+ continue;
+ if (tn->type == Node_array_tree)
+ tree_print(tn, j, indent_level + 1);
+ else
+ leaf_print(tn, j, indent_level + 1);
+ }
+}
+#endif
+
+/*--------------------- leaf (linear 1-D) array --------------------*/
+
+/* leaf_lookup --- find an integer subscript in the array; Install it if
+ it isn't there.
+*/
+
+static inline NODE **
+leaf_lookup(NODE *symbol, NODE *array, long k, long size, long base)
+{
+ NODE **lhs;
+
+ if (array->nodes == NULL) {
+ array->table_size = 0; /* sanity */
+ array->array_size = size;
+ array->array_base = base;
+ emalloc(array->nodes, NODE **, size * sizeof(NODE *), "leaf_lookup");
+ memset(array->nodes, '\0', size * sizeof(NODE *));
+ symbol->array_capacity += size;
+ }
+
+ lhs = array->nodes + (k - base); /* leaf element */
+ if (*lhs == NULL) {
+ array->table_size++; /* one more element in leaf array */
+ *lhs = dupnode(Nnull_string);
+ }
+ return lhs;
+}
+
+
+/* leaf_exists --- check if the array contains an integer subscript */
+
+static inline NODE **
+leaf_exists(NODE *array, long k)
+{
+ NODE **lhs;
+ lhs = array->nodes + (k - array->array_base);
+ return (*lhs != NULL) ? lhs : NULL;
+}
+
+
+/* leaf_clear --- flush all values in the array */
+
+static void
+leaf_clear(NODE *array)
+{
+ long i, size = array->array_size;
+ NODE *r;
+
+ for (i = 0; i < size; i++) {
+ r = array->nodes[i];
+ if (r == NULL)
+ continue;
+ if (r->type == Node_var_array) {
+ assoc_clear(r); /* recursively clear all sub-arrays */
+ efree(r->vname);
+ freenode(r);
+ } else
+ unref(r);
+ }
+ efree(array->nodes);
+ array->nodes = NULL;
+ array->array_size = array->table_size = 0;
+}
+
+
+/* leaf_remove --- remove an integer subscript from the array */
+
+static int
+leaf_remove(NODE *symbol, NODE *array, long k)
+{
+ NODE **lhs;
+
+ lhs = array->nodes + (k - array->array_base);
+ if (*lhs == NULL)
+ return FALSE;
+ *lhs = NULL;
+ if (--array->table_size == 0) {
+ efree(array->nodes);
+ array->nodes = NULL;
+ symbol->array_capacity -= array->array_size;
+ array->array_size = 0; /* sanity */
+ }
+ return TRUE;
+}
+
+
+/* leaf_copy --- duplicate a leaf array */
+
+static void
+leaf_copy(NODE *newsymb, NODE *array, NODE *newarray)
+{
+ NODE **old, **new;
+ long size, i;
+
+ size = array->array_size;
+ emalloc(new, NODE **, size * sizeof(NODE *), "leaf_copy");
+ memset(new, '\0', size * sizeof(NODE *));
+ newarray->nodes = new;
+ newarray->array_size = size;
+ newarray->array_base = array->array_base;
+ newarray->flags = array->flags;
+ newarray->table_size = array->table_size;
+
+ old = array->nodes;
+ for (i = 0; i < size; i++) {
+ if (old[i] == NULL)
+ continue;
+ if (old[i]->type == Node_val)
+ new[i] = dupnode(old[i]);
+ else {
+ NODE *r;
+ r = make_array();
+ r->vname = estrdup(old[i]->vname, strlen(old[i]->vname));
+ r->parent_array = newsymb;
+ new[i] = assoc_copy(old[i], r);
+ }
+ }
+}
+
+
+/* leaf_list --- return a list of items */
+
+static long
+leaf_list(NODE *array, NODE **list, unsigned int flags)
+{
+ NODE *r, *subs;
+ long num, i, ci, k = 0;
+ long size = array->array_size;
+ static char buf[100];
+
+ for (i = 0; i < size; i++) {
+ ci = (flags & ADESC) ? (size - 1 - i) : i;
+ r = array->nodes[ci];
+ if (r == NULL)
+ continue;
+
+ /* index */
+ num = array->array_base + ci;
+ if (flags & AISTR) {
+ sprintf(buf, "%ld", num);
+ subs = make_string(buf, strlen(buf));
+ subs->numbr = num;
+ subs->flags |= (NUMCUR|NUMINT);
+ } else {
+ subs = make_number((AWKNUM) num);
+ subs->flags |= (INTIND|NUMINT);
+ }
+ list[k++] = subs;
+
+ /* value */
+ if (flags & AVALUE) {
+ if (r->type == Node_val) {
+ if ((flags & AVNUM) != 0)
+ (void) force_number(r);
+ else if ((flags & AVSTR) != 0)
+ r = force_string(r);
+ }
+ list[k++] = r;
+ }
+ if ((flags & ADELETE) != 0 && k >= 1)
+ return k;
+ }
+
+ return k;
+}
+
+
+/* leaf_info --- print index, value info */
+
+static void
+leaf_info(NODE *array, NODE *ndump, const char *aname)
+{
+ NODE *subs, *val;
+ size_t i, size;
+
+ size = array->array_size;
+
+ subs = make_number((AWKNUM) 0.0);
+ subs->flags |= (INTIND|NUMINT);
+ for (i = 0; i < size; i++) {
+ val = array->nodes[i];
+ if (val == NULL)
+ continue;
+ subs->numbr = array->array_base + i;
+ assoc_info(subs, val, ndump, aname);
+ }
+ unref(subs);
+}
+
+#ifdef ARRAYDEBUG
+
+/* leaf_print --- print the leaf-array structure */
+
+
+static void
+leaf_print(NODE *array, size_t bi, int indent_level)
+{
+ indent(indent_level);
+ fprintf(output_fp, "%4lu:L[%4lu:%-4lu]\n", bi,
+ (unsigned long) array->array_size,
+ (unsigned long) array->table_size);
+}
+#endif
diff --git a/cmd.h b/cmd.h
index a0c17881..8f8026ae 100644
--- a/cmd.h
+++ b/cmd.h
@@ -28,8 +28,7 @@
#include <readline/history.h>
extern char **command_completion(const char *text, int start, int end);
extern void initialize_pager(FILE *fp); /* debug.c */
-extern NODE **get_varlist(void);
-extern char **get_parmlist(void);
+extern NODE *get_function(void);
#else
#define initialize_pager(x) /* nothing */
#define add_history(x) /* nothing */
diff --git a/command.c b/command.c
index 2b3b3494..8b41b6c4 100644
--- a/command.c
+++ b/command.c
@@ -1,9 +1,10 @@
-/* A Bison parser, made by GNU Bison 2.4.3. */
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton implementation for Bison's Yacc-like parsers in C
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,7 +46,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.4.3"
+#define YYBISON_VERSION "2.4.1"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -103,7 +104,7 @@ static int num_dim;
static int in_eval = FALSE;
static const char start_EVAL[] = "function @eval(){";
static const char end_EVAL[] = "}";
-static CMDARG *append_statement(CMDARG *alist, char *stmt);
+static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
static char *next_word(char *p, int len, char **endp);
static NODE *concat_args(CMDARG *a, int count);
@@ -144,7 +145,7 @@ static int find_argument(CMDARG *arg);
/* Line 189 of yacc.c */
-#line 148 "command.c"
+#line 149 "command.c"
/* Enabling traces. */
#ifndef YYDEBUG
@@ -282,7 +283,7 @@ typedef int YYSTYPE;
/* Line 264 of yacc.c */
-#line 286 "command.c"
+#line 287 "command.c"
#ifdef short
# undef short
@@ -332,7 +333,7 @@ typedef short int yytype_int16;
#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
+# if YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
# define YY_(msgid) dgettext ("bison-runtime", msgid)
@@ -893,18 +894,9 @@ static const yytype_uint8 yystos[] =
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. However,
- YYFAIL appears to be in use. Nevertheless, it is formally deprecated
- in Bison 2.4.2's NEWS entry, where a plan to phase it out is
- discussed. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#define YYFAIL goto yyerrlab
-#if defined YYFAIL
- /* This is here to suppress warnings from the GCC cpp's
- -Wunused-macros. Normally we don't worry about that warning, but
- some users do, and we want to make it easy for users to remove
- YYFAIL uses, which will produce warnings from Bison 2.5. */
-#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -961,7 +953,7 @@ while (YYID (0))
we won't break user code: when these are the locations we know. */
#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# if YYLTYPE_IS_TRIVIAL
# define YY_LOCATION_PRINT(File, Loc) \
fprintf (File, "%d.%d-%d.%d", \
(Loc).first_line, (Loc).first_column, \
@@ -1691,7 +1683,7 @@ yyreduce:
{
case 3:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 109 "command.y"
{
cmd_idx = -1;
@@ -1711,7 +1703,7 @@ yyreduce:
case 5:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 128 "command.y"
{
if (errcount == 0 && cmd_idx >= 0) {
@@ -1766,7 +1758,7 @@ yyreduce:
case 6:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 178 "command.y"
{
yyerrok;
@@ -1775,14 +1767,14 @@ yyreduce:
case 22:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 212 "command.y"
{ want_nodeval = TRUE; }
break;
case 23:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 217 "command.y"
{
if (errcount == 0) {
@@ -1802,7 +1794,7 @@ yyreduce:
case 24:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 235 "command.y"
{
(yyval) = append_statement(arg_list, (char *) start_EVAL);
@@ -1815,14 +1807,14 @@ yyreduce:
case 25:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 242 "command.y"
{ (yyval) = append_statement((yyvsp[(1) - (2)]), lexptr_begin); }
break;
case 26:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 243 "command.y"
{
(yyval) = (yyvsp[(3) - (4)]);
@@ -1831,7 +1823,7 @@ yyreduce:
case 27:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 250 "command.y"
{
arg_list = append_statement((yyvsp[(2) - (3)]), (char *) end_EVAL);
@@ -1852,7 +1844,7 @@ yyreduce:
case 28:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 266 "command.y"
{
NODE *n;
@@ -1868,7 +1860,7 @@ yyreduce:
case 34:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 285 "command.y"
{
if (cmdtab[cmd_idx].class == D_FRAME
@@ -1879,7 +1871,7 @@ yyreduce:
case 35:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 291 "command.y"
{
int idx = find_argument((yyvsp[(2) - (2)]));
@@ -1896,49 +1888,49 @@ yyreduce:
case 38:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 304 "command.y"
{ want_nodeval = TRUE; }
break;
case 40:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 305 "command.y"
{ want_nodeval = TRUE; }
break;
case 46:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 310 "command.y"
{ want_nodeval = TRUE; }
break;
case 49:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 312 "command.y"
{ want_nodeval = TRUE; }
break;
case 51:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 313 "command.y"
{ want_nodeval = TRUE; }
break;
case 53:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 314 "command.y"
{ want_nodeval = TRUE; }
break;
case 57:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 318 "command.y"
{
if (in_cmd_src((yyvsp[(2) - (2)])->a_string))
@@ -1948,7 +1940,7 @@ yyreduce:
case 58:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 323 "command.y"
{
if (! input_from_tty)
@@ -1958,7 +1950,7 @@ yyreduce:
case 59:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 328 "command.y"
{
int type = 0;
@@ -1989,7 +1981,7 @@ yyreduce:
case 60:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 354 "command.y"
{
if (! in_commands)
@@ -2004,7 +1996,7 @@ yyreduce:
case 61:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 364 "command.y"
{
if (! in_commands)
@@ -2014,7 +2006,7 @@ yyreduce:
case 62:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 369 "command.y"
{
int idx = find_argument((yyvsp[(2) - (2)]));
@@ -2031,14 +2023,14 @@ yyreduce:
case 63:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 380 "command.y"
{ want_nodeval = TRUE; }
break;
case 64:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 381 "command.y"
{
int type;
@@ -2051,7 +2043,7 @@ yyreduce:
case 65:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 389 "command.y"
{
if (in_commands) {
@@ -2067,7 +2059,7 @@ yyreduce:
case 66:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 403 "command.y"
{
if ((yyvsp[(1) - (1)]) != NULL) {
@@ -2082,42 +2074,42 @@ yyreduce:
case 68:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 417 "command.y"
{ (yyval) = NULL; }
break;
case 69:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 422 "command.y"
{ (yyval) = NULL; }
break;
case 74:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 431 "command.y"
{ (yyval) = NULL; }
break;
case 75:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 436 "command.y"
{ (yyval) = NULL; }
break;
case 77:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 439 "command.y"
{ (yyval) = NULL; }
break;
case 78:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 444 "command.y"
{
NODE *n;
@@ -2129,14 +2121,14 @@ yyreduce:
case 79:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 454 "command.y"
{ (yyval) = NULL; }
break;
case 80:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 456 "command.y"
{
if (find_option((yyvsp[(1) - (1)])->a_string) < 0)
@@ -2146,7 +2138,7 @@ yyreduce:
case 81:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 461 "command.y"
{
if (find_option((yyvsp[(1) - (3)])->a_string) < 0)
@@ -2156,7 +2148,7 @@ yyreduce:
case 82:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 469 "command.y"
{
NODE *n;
@@ -2174,56 +2166,56 @@ yyreduce:
case 83:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 485 "command.y"
{ (yyval) = NULL; }
break;
case 88:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 494 "command.y"
{ (yyval) = NULL; }
break;
case 89:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 495 "command.y"
{ want_nodeval = TRUE; }
break;
case 92:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 497 "command.y"
{ want_nodeval = TRUE; }
break;
case 95:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 503 "command.y"
{ (yyval) = NULL; }
break;
case 97:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 509 "command.y"
{ (yyval) = NULL; }
break;
case 99:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 515 "command.y"
{ (yyval) = NULL; }
break;
case 104:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 527 "command.y"
{
int idx = find_argument((yyvsp[(1) - (2)]));
@@ -2240,7 +2232,7 @@ yyreduce:
case 106:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 543 "command.y"
{
(yyvsp[(2) - (2)])->type = D_array; /* dump all items */
@@ -2250,7 +2242,7 @@ yyreduce:
case 107:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 548 "command.y"
{
(yyvsp[(2) - (3)])->type = D_array;
@@ -2260,21 +2252,21 @@ yyreduce:
case 117:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 574 "command.y"
{ (yyval) = NULL; }
break;
case 118:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 576 "command.y"
{ (yyval) = NULL; }
break;
case 119:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 578 "command.y"
{
CMDARG *a;
@@ -2286,7 +2278,7 @@ yyreduce:
case 126:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 594 "command.y"
{
if ((yyvsp[(1) - (3)])->a_int > (yyvsp[(3) - (3)])->a_int)
@@ -2300,28 +2292,28 @@ yyreduce:
case 127:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 606 "command.y"
{ (yyval) = NULL; }
break;
case 134:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 620 "command.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 135:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 622 "command.y"
{ (yyval) = (yyvsp[(1) - (3)]); }
break;
case 137:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 628 "command.y"
{
CMDARG *a;
@@ -2341,21 +2333,21 @@ yyreduce:
case 139:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 647 "command.y"
{ (yyval) = (yyvsp[(1) - (1)]); num_dim = 1; }
break;
case 140:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 649 "command.y"
{ (yyval) = (yyvsp[(1) - (2)]); num_dim++; }
break;
case 142:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 655 "command.y"
{
NODE *n = (yyvsp[(2) - (2)])->a_node;
@@ -2369,7 +2361,7 @@ yyreduce:
case 143:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 664 "command.y"
{
/* a_string is array name, a_count is dimension count */
@@ -2381,14 +2373,14 @@ yyreduce:
case 144:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 674 "command.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 145:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 676 "command.y"
{
NODE *n = (yyvsp[(2) - (2)])->a_node;
@@ -2400,7 +2392,7 @@ yyreduce:
case 146:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 683 "command.y"
{
NODE *n = (yyvsp[(2) - (2)])->a_node;
@@ -2414,35 +2406,35 @@ yyreduce:
case 147:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 695 "command.y"
{ (yyval) = NULL; }
break;
case 148:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 697 "command.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 149:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 702 "command.y"
{ (yyval) = NULL; }
break;
case 150:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 704 "command.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 151:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 709 "command.y"
{
if ((yyvsp[(1) - (1)])->a_int == 0)
@@ -2453,7 +2445,7 @@ yyreduce:
case 152:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 715 "command.y"
{
if ((yyvsp[(2) - (2)])->a_int == 0)
@@ -2464,21 +2456,21 @@ yyreduce:
case 153:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 724 "command.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 154:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 726 "command.y"
{ (yyval) = (yyvsp[(2) - (2)]); }
break;
case 155:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 728 "command.y"
{
(yyvsp[(2) - (2)])->a_int = - (yyvsp[(2) - (2)])->a_int;
@@ -2488,7 +2480,7 @@ yyreduce:
case 156:
-/* Line 1464 of yacc.c */
+/* Line 1455 of yacc.c */
#line 736 "command.y"
{
if (lexptr_begin != NULL) {
@@ -2502,8 +2494,8 @@ yyreduce:
-/* Line 1464 of yacc.c */
-#line 2519 "command.c"
+/* Line 1455 of yacc.c */
+#line 2511 "command.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -2714,7 +2706,7 @@ yyreturn:
-/* Line 1684 of yacc.c */
+/* Line 1675 of yacc.c */
#line 746 "command.y"
@@ -2722,7 +2714,7 @@ yyreturn:
/* append_statement --- append 'stmt' to the list of eval awk statements */
static CMDARG *
-append_statement(CMDARG *alist, char *stmt)
+append_statement(CMDARG *stmt_list, char *stmt)
{
CMDARG *a, *arg;
char *s;
@@ -2732,7 +2724,7 @@ append_statement(CMDARG *alist, char *stmt)
if (stmt == start_EVAL) {
len = sizeof(start_EVAL);
- for (a = alist; a != NULL; a = a->next)
+ for (a = stmt_list; a != NULL; a = a->next)
len += strlen(a->a_string) + 1; /* 1 for ',' */
len += EVALSIZE;
@@ -2744,7 +2736,7 @@ append_statement(CMDARG *alist, char *stmt)
slen = sizeof("function @eval(") - 1;
memcpy(s, start_EVAL, slen);
- for (a = alist; a != NULL; a = a->next) {
+ for (a = stmt_list; a != NULL; a = a->next) {
len = strlen(a->a_string);
memcpy(s + slen, a->a_string, len);
slen += len;
@@ -2758,14 +2750,14 @@ append_statement(CMDARG *alist, char *stmt)
}
len = strlen(stmt) + 1; /* 1 for newline */
- s = alist->a_string;
+ s = stmt_list->a_string;
slen = strlen(s);
- ssize = alist->a_count;
+ ssize = stmt_list->a_count;
if (len > ssize - slen) {
ssize = slen + len + EVALSIZE;
erealloc(s, char *, (ssize + 2) * sizeof(char), "append_statement");
- alist->a_string = s;
- alist->a_count = ssize;
+ stmt_list->a_string = s;
+ stmt_list->a_count = ssize;
}
memcpy(s + slen, stmt, len);
slen += len;
@@ -2775,8 +2767,8 @@ append_statement(CMDARG *alist, char *stmt)
}
if (stmt == end_EVAL)
- erealloc(alist->a_string, char *, slen + 2, "append_statement");
- return alist;
+ erealloc(stmt_list->a_string, char *, slen + 2, "append_statement");
+ return stmt_list;
#undef EVALSIZE
}
@@ -3165,7 +3157,7 @@ err:
if (! want_nodeval) {
yylval = mk_cmdarg(D_string);
- yylval->a_string = estrdup(str, p - str);
+ yylval->a_string = str;
append_cmdarg(yylval);
return D_STRING;
} else { /* awk string */
@@ -3356,8 +3348,10 @@ find_command(const char *token, size_t toklen)
&& strncmp(name, token, toklen) == 0
)
return i;
- if (*name > *token)
+
+ if (*name > *token || i == (k - 1))
try_exact = FALSE;
+
if (abrv_match < 0) {
abrv = cmdtab[i].abbrvn;
if (abrv[0] == token[0]) {
@@ -3497,6 +3491,7 @@ command_completion(const char *text, int start, int end)
return NULL;
}
}
+
if (this_cmd == D_print || this_cmd == D_printf)
return rl_completion_matches(text, variable_generator);
return NULL;
@@ -3557,7 +3552,7 @@ argument_generator(const char *text, int state)
{
static size_t textlen;
static int idx;
- char *name;
+ const char *name;
if (! state) { /* first time */
textlen = strlen(text);
@@ -3565,12 +3560,12 @@ argument_generator(const char *text, int state)
}
if (this_cmd == D_help) {
- while ((name = (char *) cmdtab[idx++].name) != NULL) {
+ while ((name = cmdtab[idx++].name) != NULL) {
if (strncmp(name, text, textlen) == 0)
return estrdup(name, strlen(name));
}
} else {
- while ((name = (char *) argtab[idx].name) != NULL) {
+ while ((name = argtab[idx].name) != NULL) {
if (this_cmd != argtab[idx++].cmd)
continue;
if (strncmp(name, text, textlen) == 0)
@@ -3587,45 +3582,39 @@ variable_generator(const char *text, int state)
{
static size_t textlen;
static int idx = 0;
- static char **pnames = NULL;
- static NODE **var_table = NULL;
- char *name;
- NODE *hp;
+ static NODE *func = NULL;
+ static NODE **vars = NULL;
+ const char *name;
+ NODE *r;
if (! state) { /* first time */
textlen = strlen(text);
- if (var_table != NULL)
- efree(var_table);
- var_table = get_varlist();
+ if (vars != NULL)
+ efree(vars);
+ vars = variable_list();
idx = 0;
- pnames = get_parmlist(); /* names of function params in
- * current context; the array
- * is NULL terminated in
- * awkgram.y (func_install).
- */
+ func = get_function(); /* function in current context */
}
/* function params */
- while (pnames != NULL) {
- name = pnames[idx];
- if (name == NULL) {
- pnames = NULL; /* don't try to match params again */
+ while (func != NULL) {
+ if (idx >= func->param_cnt) {
+ func = NULL; /* don't try to match params again */
idx = 0;
break;
}
- idx++;
+ name = func->fparms[idx++].param;
if (strncmp(name, text, textlen) == 0)
return estrdup(name, strlen(name));
}
/* globals */
- while ((hp = var_table[idx]) != NULL) {
- idx++;
- if (hp->hvalue->type == Node_func)
- continue;
- if (strncmp(hp->hname, text, textlen) == 0)
- return estrdup(hp->hname, hp->hlength);
+ while ((r = vars[idx++]) != NULL) {
+ name = r->vname;
+ if (strncmp(name, text, textlen) == 0)
+ return estrdup(name, strlen(name));
}
+
return NULL;
}
@@ -3651,4 +3640,3 @@ history_expand_line(char **line)
#endif
-
diff --git a/command.y b/command.y
index bcaa74f0..18ef0613 100644
--- a/command.y
+++ b/command.y
@@ -50,7 +50,7 @@ static int num_dim;
static int in_eval = FALSE;
static const char start_EVAL[] = "function @eval(){";
static const char end_EVAL[] = "}";
-static CMDARG *append_statement(CMDARG *alist, char *stmt);
+static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
static char *next_word(char *p, int len, char **endp);
static NODE *concat_args(CMDARG *a, int count);
@@ -749,7 +749,7 @@ nls
/* append_statement --- append 'stmt' to the list of eval awk statements */
static CMDARG *
-append_statement(CMDARG *alist, char *stmt)
+append_statement(CMDARG *stmt_list, char *stmt)
{
CMDARG *a, *arg;
char *s;
@@ -759,7 +759,7 @@ append_statement(CMDARG *alist, char *stmt)
if (stmt == start_EVAL) {
len = sizeof(start_EVAL);
- for (a = alist; a != NULL; a = a->next)
+ for (a = stmt_list; a != NULL; a = a->next)
len += strlen(a->a_string) + 1; /* 1 for ',' */
len += EVALSIZE;
@@ -771,7 +771,7 @@ append_statement(CMDARG *alist, char *stmt)
slen = sizeof("function @eval(") - 1;
memcpy(s, start_EVAL, slen);
- for (a = alist; a != NULL; a = a->next) {
+ for (a = stmt_list; a != NULL; a = a->next) {
len = strlen(a->a_string);
memcpy(s + slen, a->a_string, len);
slen += len;
@@ -785,14 +785,14 @@ append_statement(CMDARG *alist, char *stmt)
}
len = strlen(stmt) + 1; /* 1 for newline */
- s = alist->a_string;
+ s = stmt_list->a_string;
slen = strlen(s);
- ssize = alist->a_count;
+ ssize = stmt_list->a_count;
if (len > ssize - slen) {
ssize = slen + len + EVALSIZE;
erealloc(s, char *, (ssize + 2) * sizeof(char), "append_statement");
- alist->a_string = s;
- alist->a_count = ssize;
+ stmt_list->a_string = s;
+ stmt_list->a_count = ssize;
}
memcpy(s + slen, stmt, len);
slen += len;
@@ -802,8 +802,8 @@ append_statement(CMDARG *alist, char *stmt)
}
if (stmt == end_EVAL)
- erealloc(alist->a_string, char *, slen + 2, "append_statement");
- return alist;
+ erealloc(stmt_list->a_string, char *, slen + 2, "append_statement");
+ return stmt_list;
#undef EVALSIZE
}
@@ -1192,7 +1192,7 @@ err:
if (! want_nodeval) {
yylval = mk_cmdarg(D_string);
- yylval->a_string = estrdup(str, p - str);
+ yylval->a_string = str;
append_cmdarg(yylval);
return D_STRING;
} else { /* awk string */
@@ -1383,8 +1383,10 @@ find_command(const char *token, size_t toklen)
&& strncmp(name, token, toklen) == 0
)
return i;
- if (*name > *token)
+
+ if (*name > *token || i == (k - 1))
try_exact = FALSE;
+
if (abrv_match < 0) {
abrv = cmdtab[i].abbrvn;
if (abrv[0] == token[0]) {
@@ -1524,6 +1526,7 @@ command_completion(const char *text, int start, int end)
return NULL;
}
}
+
if (this_cmd == D_print || this_cmd == D_printf)
return rl_completion_matches(text, variable_generator);
return NULL;
@@ -1584,7 +1587,7 @@ argument_generator(const char *text, int state)
{
static size_t textlen;
static int idx;
- char *name;
+ const char *name;
if (! state) { /* first time */
textlen = strlen(text);
@@ -1592,12 +1595,12 @@ argument_generator(const char *text, int state)
}
if (this_cmd == D_help) {
- while ((name = (char *) cmdtab[idx++].name) != NULL) {
+ while ((name = cmdtab[idx++].name) != NULL) {
if (strncmp(name, text, textlen) == 0)
return estrdup(name, strlen(name));
}
} else {
- while ((name = (char *) argtab[idx].name) != NULL) {
+ while ((name = argtab[idx].name) != NULL) {
if (this_cmd != argtab[idx++].cmd)
continue;
if (strncmp(name, text, textlen) == 0)
@@ -1614,45 +1617,39 @@ variable_generator(const char *text, int state)
{
static size_t textlen;
static int idx = 0;
- static char **pnames = NULL;
- static NODE **var_table = NULL;
- char *name;
- NODE *hp;
+ static NODE *func = NULL;
+ static NODE **vars = NULL;
+ const char *name;
+ NODE *r;
if (! state) { /* first time */
textlen = strlen(text);
- if (var_table != NULL)
- efree(var_table);
- var_table = get_varlist();
+ if (vars != NULL)
+ efree(vars);
+ vars = variable_list();
idx = 0;
- pnames = get_parmlist(); /* names of function params in
- * current context; the array
- * is NULL terminated in
- * awkgram.y (func_install).
- */
+ func = get_function(); /* function in current context */
}
/* function params */
- while (pnames != NULL) {
- name = pnames[idx];
- if (name == NULL) {
- pnames = NULL; /* don't try to match params again */
+ while (func != NULL) {
+ if (idx >= func->param_cnt) {
+ func = NULL; /* don't try to match params again */
idx = 0;
break;
}
- idx++;
+ name = func->fparms[idx++].param;
if (strncmp(name, text, textlen) == 0)
return estrdup(name, strlen(name));
}
/* globals */
- while ((hp = var_table[idx]) != NULL) {
- idx++;
- if (hp->hvalue->type == Node_func)
- continue;
- if (strncmp(hp->hname, text, textlen) == 0)
- return estrdup(hp->hname, hp->hlength);
+ while ((r = vars[idx++]) != NULL) {
+ name = r->vname;
+ if (strncmp(name, text, textlen) == 0)
+ return estrdup(name, strlen(name));
}
+
return NULL;
}
@@ -1677,4 +1674,3 @@ history_expand_line(char **line)
}
#endif
-
diff --git a/configure b/configure
index 859c252b..9f916cf0 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for GNU Awk 4.0.0g.
+# Generated by GNU Autoconf 2.68 for GNU Awk 4.0.70.
#
# Report bugs to <bug-gawk@gnu.org>.
#
@@ -560,8 +560,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='GNU Awk'
PACKAGE_TARNAME='gawk'
-PACKAGE_VERSION='4.0.0g'
-PACKAGE_STRING='GNU Awk 4.0.0g'
+PACKAGE_VERSION='4.0.70'
+PACKAGE_STRING='GNU Awk 4.0.70'
PACKAGE_BUGREPORT='bug-gawk@gnu.org'
PACKAGE_URL='http://www.gnu.org/software/gawk/'
@@ -1290,7 +1290,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures GNU Awk 4.0.0g to adapt to many kinds of systems.
+\`configure' configures GNU Awk 4.0.70 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1360,7 +1360,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of GNU Awk 4.0.0g:";;
+ short | recursive ) echo "Configuration of GNU Awk 4.0.70:";;
esac
cat <<\_ACEOF
@@ -1472,7 +1472,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-GNU Awk configure 4.0.0g
+GNU Awk configure 4.0.70
generated by GNU Autoconf 2.68
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2176,7 +2176,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by GNU Awk $as_me 4.0.0g, which was
+It was created by GNU Awk $as_me 4.0.70, which was
generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -3011,7 +3011,7 @@ fi
# Define the identity of the package.
PACKAGE='gawk'
- VERSION='4.0.0g'
+ VERSION='4.0.70'
cat >>confdefs.h <<_ACEOF
@@ -5486,7 +5486,7 @@ $as_echo_n "checking for special development options... " >&6; }
if test -f $srcdir/.developing
then
# add other debug flags as appropriate, save GAWKDEBUG for emergencies
- CFLAGS="$CFLAGS -DARRAYDEBUG -DYYDEBUG"
+ CFLAGS="$CFLAGS -DARRAYDEBUG"
if grep dbug $srcdir/.developing
then
CFLAGS="$CFLAGS -DDBUG"
@@ -5496,7 +5496,7 @@ then
# enable debugging using macros also
if test "$GCC" = yes
then
- CFLAGS="$CFLAGS -Wall -fno-builtin -g3 -gdwarf-2"
+ CFLAGS="$CFLAGS -Wall"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
@@ -11221,7 +11221,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by GNU Awk $as_me 4.0.0g, which was
+This file was extended by GNU Awk $as_me 4.0.70, which was
generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -11289,7 +11289,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-GNU Awk config.status 4.0.0g
+GNU Awk config.status 4.0.70
configured by $0, generated by GNU Autoconf 2.68,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 545ad10b..3b0ba330 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@ dnl
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([GNU Awk], 4.0.0g, bug-gawk@gnu.org, gawk)
+AC_INIT([GNU Awk], 4.0.70, bug-gawk@gnu.org, gawk)
# This is a hack. Different versions of install on different systems
# are just too different. Chuck it and use install-sh.
@@ -80,7 +80,7 @@ AC_MSG_CHECKING([for special development options])
if test -f $srcdir/.developing
then
# add other debug flags as appropriate, save GAWKDEBUG for emergencies
- CFLAGS="$CFLAGS -DARRAYDEBUG -DYYDEBUG"
+ CFLAGS="$CFLAGS -DARRAYDEBUG"
if grep dbug $srcdir/.developing
then
CFLAGS="$CFLAGS -DDBUG"
@@ -90,7 +90,7 @@ then
# enable debugging using macros also
if test "$GCC" = yes
then
- CFLAGS="$CFLAGS -Wall -fno-builtin -g3 -gdwarf-2"
+ CFLAGS="$CFLAGS -Wall"
fi
AC_MSG_RESULT([yes])
else
diff --git a/debug.c b/debug.c
index ea652478..37418115 100644
--- a/debug.c
+++ b/debug.c
@@ -44,8 +44,6 @@ extern int r_interpret(INSTRUCTION *);
extern int zzparse(void);
#define read_command() (void) zzparse()
-extern int free_instruction(INSTRUCTION *, int *);
-extern void destroy_symbol(char *name);
extern const char *redir2str(int redirtype);
static char *linebuf = NULL; /* used to print a single line of source */
@@ -267,7 +265,7 @@ static void save_options(const char *file);
/* pager */
jmp_buf pager_quit_tag;
-int pager_quit_tag_valid;
+int pager_quit_tag_valid = FALSE;
static int screen_width = INT_MAX; /* no of columns */
static int screen_height = INT_MAX; /* no of rows */
static int pager_lines_printed = 0; /* no of lines printed so far */
@@ -307,8 +305,8 @@ static struct list_item *add_item(struct list_item *list, int type, NODE *symbol
static void delete_item(struct list_item *d);
static int breakpoint_triggered(BREAKPOINT *b);
static int watchpoint_triggered(struct list_item *w);
-
static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump);
+static int print_code(INSTRUCTION *pc, void *x);
static void next_command();
static char *g_readline(const char *prompt);
static int prompt_yes_no(const char *, char , int , FILE *);
@@ -335,9 +333,6 @@ struct command_source
static struct command_source *cmd_src = NULL;
-#define get_param_count(f) (f)->lnode->param_cnt
-#define get_params(f) (f)->parmlist
-
#define CHECK_PROG_RUNNING() \
do { \
@@ -719,6 +714,8 @@ list:
int
do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
{
+ NODE **table;
+
if (arg == NULL || arg->type != D_argument)
return FALSE;
@@ -804,7 +801,6 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
INSTRUCTION *pc;
int arg_count, pcount;
int i, from, to;
- char **pnames;
CHECK_PROG_RUNNING();
f = find_frame(cur_frame);
@@ -815,8 +811,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
return FALSE;
}
- pcount = get_param_count(func); /* # of defined params */
- pnames = get_params(func); /* param names */
+ pcount = func->param_cnt; /* # of defined params */
pc = (INSTRUCTION *) f->reti; /* Op_func_call instruction */
arg_count = (pc + 1)->expr_count; /* # of arguments supplied */
@@ -836,7 +831,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
r = f->stack[i];
if (r->type == Node_array_ref)
r = r->orig_array;
- fprintf(out_fp, "%s = ", pnames[i]);
+ fprintf(out_fp, "%s = ", func->fparms[i].param);
print_symbol(r, TRUE);
}
if (to < from)
@@ -848,25 +843,28 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
break;
case A_VARIABLES:
+ table = variable_list();
initialize_pager(out_fp);
if (setjmp(pager_quit_tag) == 0) {
gprintf(out_fp, _("All defined variables:\n\n"));
- print_vars(gprintf, out_fp);
+ print_vars(table, gprintf, out_fp);
}
+ efree(table);
break;
case A_FUNCTIONS:
+ table = function_list(TRUE);
initialize_pager(out_fp);
if (setjmp(pager_quit_tag) == 0) {
gprintf(out_fp, _("All defined functions:\n\n"));
pf_data.print_func = gprintf;
pf_data.fp = out_fp;
pf_data.defn = TRUE;
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_function,
- FALSE, /* sort */
- &pf_data /* data */
- );
+ (void) foreach_func(table,
+ (int (*)(INSTRUCTION *, void *)) print_function,
+ &pf_data);
}
+ efree(table);
break;
case A_DISPLAY:
@@ -977,6 +975,7 @@ find_param(const char *name, long num, char **pname)
{
NODE *r = NULL;
NODE *f;
+ char *fparam;
if (pname)
*pname = NULL;
@@ -986,20 +985,18 @@ find_param(const char *name, long num, char **pname)
f = find_frame(num);
if (f->func_node != NULL) { /* in function */
NODE *func;
- char **pnames;
int i, pcount;
func = f->func_node;
- pnames = get_params(func);
- pcount = get_param_count(func);
-
+ pcount = func->param_cnt;
for (i = 0; i < pcount; i++) {
- if (STREQ(name, pnames[i])) {
+ fparam = func->fparms[i].param;
+ if (STREQ(name, fparam)) {
r = f->stack[i];
if (r->type == Node_array_ref)
r = r->orig_array;
if (pname)
- *pname = pnames[i];
+ *pname = fparam;
break;
}
}
@@ -1059,7 +1056,7 @@ print_field(long field_num)
static int
print_array(volatile NODE *arr, char *arr_name)
{
- NODE *bucket;
+ NODE *subs;
NODE **list;
int i;
size_t num_elems = 0;
@@ -1067,7 +1064,7 @@ print_array(volatile NODE *arr, char *arr_name)
volatile int ret = 0;
volatile jmp_buf pager_quit_tag_stack;
- if (arr->var_array == NULL || arr->table_size == 0) {
+ if (array_empty(arr)) {
gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
return 0;
}
@@ -1080,12 +1077,12 @@ print_array(volatile NODE *arr, char *arr_name)
PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
if (setjmp(pager_quit_tag) == 0) {
for (i = 0; ret == 0 && i < num_elems; i++) {
- bucket = list[i];
- r = bucket->ahvalue;
+ subs = list[i];
+ r = *assoc_lookup((NODE *) arr, subs);
if (r->type == Node_var_array)
ret = print_array(r, r->vname);
else {
- gprintf(out_fp, "%s[\"%s\"] = ", arr_name, bucket->ahname_str);
+ gprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
valinfo((NODE *) r, gprintf, out_fp);
}
}
@@ -1215,7 +1212,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
switch (r->type) {
case Node_var_new:
r->type = Node_var;
- r->var_value = Nnull_string;
+ r->var_value = dupnode(Nnull_string);
/* fall through */
case Node_var:
lhs = &r->var_value;
@@ -1255,7 +1252,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
else {
arg = arg->next;
val = arg->a_node;
- lhs = assoc_lookup(r, subs, FALSE);
+ lhs = assoc_lookup(r, subs);
unref(*lhs);
*lhs = dupnode(val);
fprintf(out_fp, "%s[\"%s\"] = ", name, subs->stptr);
@@ -1264,12 +1261,10 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
} else {
if (value == NULL) {
NODE *array;
-
- getnode(array);
- array->type = Node_var_array;
- array->var_array = NULL;
+ array = make_array();
array->vname = estrdup(subs->stptr, subs->stlen);
- *assoc_lookup(r, subs, FALSE) = array;
+ array->parent_array = r;
+ *assoc_lookup(r, subs) = array;
r = array;
} else if (value->type != Node_var_array) {
d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
@@ -1306,7 +1301,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
break;
}
return FALSE;
-}
+}
/* find_item --- find an item in the watch/display list */
@@ -1378,14 +1373,18 @@ add_item(struct list_item *list, int type, NODE *symbol, char *pname)
d->fcall_count = fcall_count - cur_frame;
}
- if (type == D_field) { /* field number */
+ if (type == D_field) {
+ /* field number */
d->symbol = symbol;
d->flags |= FIELD_NUM;
- } else if (type == D_subscript) { /* subscript */
+ } else if (type == D_subscript) {
+ /* subscript */
d->symbol = symbol;
d->flags |= SUBSCRIPT;
- } else /* array or variable */
+ } else {
+ /* array or variable */
d->symbol = symbol;
+ }
/* add to list */
d->next = list->next;
@@ -1430,7 +1429,7 @@ do_add_item(struct list_item *list, CMDARG *arg)
for (i = 0; i < count; i++) {
arg = arg->next;
subs[i] = dupnode(arg->a_node);
- (void) force_string(subs[i]);
+ subs[i] = force_string(subs[i]);
}
item->subs = subs;
item->num_subs = count;
@@ -1598,7 +1597,6 @@ condition_triggered(struct condition *cndn)
}
-
static int
find_subscript(struct list_item *item, NODE **ptr)
{
@@ -1617,7 +1615,8 @@ find_subscript(struct list_item *item, NODE **ptr)
else if (i < count - 1)
return -1;
}
- *ptr = r;
+ if (r != NULL)
+ *ptr = r;
return 0;
}
@@ -1647,8 +1646,7 @@ cmp_val(struct list_item *w, NODE *old, NODE *new)
if (new->type == Node_val) /* 7 */
return TRUE;
/* new->type == Node_var_array */ /* 8 */
- if (new->var_array != NULL)
- size = new->table_size;
+ size = new->table_size;
if (w->cur_size == size)
return FALSE;
return TRUE;
@@ -1722,7 +1720,7 @@ watchpoint_triggered(struct list_item *w)
w->flags &= ~CUR_IS_ARRAY;
w->cur_value = dupnode(t2);
} else
- w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
+ w->cur_size = (t2->type == Node_var_array) ? t2->table_size : 0;
} else if (! t1) { /* 1, 2 */
w->old_value = 0;
/* new != NULL */
@@ -1730,7 +1728,7 @@ watchpoint_triggered(struct list_item *w)
w->cur_value = dupnode(t2);
else {
w->flags |= CUR_IS_ARRAY;
- w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
+ w->cur_size = (t2->type == Node_var_array) ? t2->table_size : 0;
}
} else /* if (t1->type == Node_val) */ { /* 4, 5, 6 */
w->old_value = w->cur_value;
@@ -1738,7 +1736,7 @@ watchpoint_triggered(struct list_item *w)
w->cur_value = 0;
else if (t2->type == Node_var_array) {
w->flags |= CUR_IS_ARRAY;
- w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
+ w->cur_size = t2->table_size;
} else
w->cur_value = dupnode(t2);
}
@@ -1764,7 +1762,7 @@ initialize_watch_item(struct list_item *w)
w->cur_value = (NODE *) 0;
else if (r->type == Node_var_array) { /* it's a sub-array */
w->flags |= CUR_IS_ARRAY;
- w->cur_size = (r->var_array != NULL) ? r->table_size : 0;
+ w->cur_size = r->table_size;
} else
w->cur_value = dupnode(r);
} else if (IS_FIELD(w)) {
@@ -1781,7 +1779,7 @@ initialize_watch_item(struct list_item *w)
w->cur_value = dupnode(r);
} else if (symbol->type == Node_var_array) {
w->flags |= CUR_IS_ARRAY;
- w->cur_size = (symbol->var_array != NULL) ? symbol->table_size : 0;
+ w->cur_size = symbol->table_size;
} /* else
can't happen */
}
@@ -1873,19 +1871,17 @@ print_function(INSTRUCTION *pc, void *x)
{
NODE *func;
int i, pcount;
- char **pnames;
struct pf_data *data = (struct pf_data *) x;
int defn = data->defn;
Func_print print_func = data->print_func;
FILE *fp = data->fp;
func = pc->func_body;
- pcount = get_param_count(func);
- pnames = get_params(func);
+ pcount = func->param_cnt;
- print_func(fp, "%s(", func->lnode->param);
+ print_func(fp, "%s(", func->vname);
for (i = 0; i < pcount; i++) {
- print_func(fp, "%s", pnames[i]);
+ print_func(fp, "%s", func->fparms[i].param);
if (i < pcount - 1)
print_func(fp, ", ");
}
@@ -2368,7 +2364,7 @@ func:
rp = func->code_ptr;
if ((b = set_breakpoint_at(rp, rp->source_line, FALSE)) == NULL)
fprintf(out_fp, _("Can't set breakpoint in function `%s'\n"),
- func->lnode->param);
+ func->vname);
else if (temporary)
b->flags |= BP_TEMP;
lineno = b->bpi->source_line;
@@ -2495,7 +2491,7 @@ func:
}
if (! bp_found)
fprintf(out_fp, _("No breakpoint(s) at entry to function `%s'\n"),
- func->lnode->param);
+ func->vname);
else
fprintf(out_fp, "\n");
/* fall through */
@@ -2690,19 +2686,17 @@ do_disable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
#ifdef HAVE_LIBREADLINE
-/* get_parmlist --- list of function params in current context */
+/* get_function --- function definition in current context */
-char **
-get_parmlist()
+NODE *
+get_function()
{
NODE *func;
if (! prog_running)
return NULL;
func = find_frame(cur_frame)->func_node;
- if (func == NULL) /* in main */
- return NULL;
- return func->parmlist;
+ return func;
}
/* initialize_readline --- initialize readline */
@@ -2933,9 +2927,9 @@ do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
fatal_tag_valid = FALSE;
prog_running = FALSE;
fprintf(out_fp, _("Program exited %s with exit value: %d\n"),
- (! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
- : "normally",
- exit_val);
+ (! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
+ : "normally",
+ exit_val);
need_restart = TRUE;
return FALSE;
}
@@ -3135,7 +3129,6 @@ do_next(CMDARG *arg, int cmd)
static int
check_nexti(INSTRUCTION **pi)
{
-
/* make sure not to step inside function calls */
if (fcall_count < stop.fcall_count) {
@@ -3224,7 +3217,7 @@ check_return(INSTRUCTION **pi)
int
do_return(CMDARG *arg, int cmd)
{
- NODE *func;
+ NODE *func, *n;
CHECK_PROG_RUNNING();
func = find_frame(cur_frame)->func_node;
@@ -3241,12 +3234,11 @@ do_return(CMDARG *arg, int cmd)
stop.check_func = check_return;
- if (arg != NULL && arg->type == D_node) { /* optional return value */
- NODE *n;
+ if (arg != NULL && arg->type == D_node) /* optional return value */
n = dupnode(arg->a_node);
- PUSH(n);
- } else
- PUSH(Nnull_string);
+ else
+ n = dupnode(Nnull_string);
+ PUSH(n);
return TRUE;
}
@@ -3315,7 +3307,7 @@ do_until(CMDARG *arg, int cmd)
s = source_find(arg->a_string);
arg = arg->next;
if (s == NULL || arg == NULL
- || (arg->type != D_int && arg->type != D_func))
+ || (arg->type != D_int && arg->type != D_func))
return FALSE;
src = s->src;
if (arg->type == D_func)
@@ -3345,7 +3337,7 @@ func:
}
}
fprintf(out_fp, _("Can't find specified location in function `%s'\n"),
- func->lnode->param);
+ func->vname);
/* fall through */
default:
return FALSE;
@@ -3614,7 +3606,6 @@ pre_execute(INSTRUCTION **pi)
return TRUE;
case Op_func:
- case Op_ext_func:
case Op_var_update:
return TRUE;
@@ -3649,7 +3640,7 @@ pre_execute(INSTRUCTION **pi)
/* print_memory --- print a scalar value */
static void
-print_memory(NODE *m, char **fparms, Func_print print_func, FILE *fp)
+print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
{
switch (m->type) {
case Node_val:
@@ -3676,8 +3667,8 @@ print_memory(NODE *m, char **fparms, Func_print print_func, FILE *fp)
break;
case Node_param_list:
- assert(fparms != NULL);
- print_func(fp, "%s", fparms[m->param_cnt]);
+ assert(func != NULL);
+ print_func(fp, "%s", func->fparms[m->param_cnt].param);
break;
case Node_var:
@@ -3696,9 +3687,8 @@ print_memory(NODE *m, char **fparms, Func_print print_func, FILE *fp)
static void
print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
{
- static char **fparms = NULL;
int pcount = 0;
- NODE *func = NULL;
+ static NODE *func = NULL;
static int noffset = 0;
if (noffset == 0) {
@@ -3709,25 +3699,17 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
if (pc->opcode == Op_func) {
func = pc->func_body;
- fparms = get_params(func);
- pcount = get_param_count(func);
+ pcount = func->param_cnt;
if (in_dump) {
int j;
- print_func(fp, "\n\t# Function: %s (", func->lnode->param);
+ print_func(fp, "\n\t# Function: %s (", func->vname);
for (j = 0; j < pcount; j++) {
- print_func(fp, "%s", fparms[j]);
+ print_func(fp, "%s", func->fparms[j].param);
if (j < pcount - 1)
print_func(fp, ", ");
}
print_func(fp, ")\n\n");
}
- } else if (pc->opcode == Op_ext_func) {
- func = pc->func_body;
- fparms = get_params(func);
- pcount = get_param_count(func);
- if (in_dump)
- print_func(fp, "\n\t# Extension function: %s (... %d params ...)\n\n",
- func->lnode->param, pcount);
} else if (pc->opcode == Op_rule) {
if (in_dump)
print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]);
@@ -3743,12 +3725,8 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
pc->source_line, pc, opcode2str(pc->opcode));
if (prog_running && ! in_dump) {
- /* find params in the current frame */
+ /* find Node_func if in function */
func = find_frame(0)->func_node;
- if (func != NULL)
- fparms = get_params(func);
- /* else
- fparms = NULL; */
}
@@ -3774,10 +3752,6 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
pc->target_assign, pc->do_reference ? "TRUE" : "FALSE");
break;
- case Op_ext_func:
- print_func(fp, "[param_cnt = %d]\n", pcount);
- break;
-
case Op_func:
print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount,
pc->source_file ? pc->source_file : "cmd. line");
@@ -3852,7 +3826,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
case Op_arrayfor_incr:
print_func(fp, "[array_var = %s] [target_jmp = %p]\n",
pc->array_var->type == Node_param_list ?
- fparms[pc->array_var->param_cnt] : pc->array_var->vname,
+ func->fparms[pc->array_var->param_cnt].param : pc->array_var->vname,
pc->target_jmp);
break;
@@ -3887,13 +3861,13 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
break;
case Op_builtin:
- {
- const char *fname = getfname(pc->builtin);
- if (fname == NULL)
- print_func(fp, "(extension func) [arg_count = %ld]\n", pc->expr_count);
- else
- print_func(fp, "%s [arg_count = %ld]\n", fname, pc->expr_count);
- }
+ print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin),
+ pc->expr_count);
+ break;
+
+ case Op_ext_builtin:
+ print_func(fp, "%s [arg_count = %ld]\n", (pc + 1)->func_name,
+ pc->expr_count);
break;
case Op_subscript:
@@ -3902,7 +3876,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
break;
case Op_store_sub:
- print_memory(pc->memory, fparms, print_func, fp);
+ print_memory(pc->memory, func, print_func, fp);
print_func(fp, " [sub_count = %ld]\n", pc->expr_count);
break;
@@ -3945,9 +3919,17 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
print_func(fp, "[exec_count = %ld]\n", pc->exec_count);
break;
- case Op_store_var:
+ case Op_store_var:
+ print_memory(pc->memory, func, print_func, fp);
+ if (pc->initval != NULL) {
+ print_func(fp, " = ");
+ print_memory(pc->initval, func, print_func, fp);
+ }
+ print_func(fp, "\n");
+ break;
+
case Op_push_lhs:
- print_memory(pc->memory, fparms, print_func, fp);
+ print_memory(pc->memory, func, print_func, fp);
print_func(fp, " [do_reference = %s]\n",
pc->do_reference ? "TRUE" : "FALSE");
break;
@@ -3968,7 +3950,7 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
case Op_quotient_i:
case Op_mod_i:
case Op_assign_concat:
- print_memory(pc->memory, fparms, print_func, fp);
+ print_memory(pc->memory, func, print_func, fp);
/* fall through */
default:
print_func(fp, "\n");
@@ -4006,7 +3988,8 @@ int
do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
{
FILE *fp;
-
+ NODE **funcs;
+
if (arg != NULL && arg->type == D_string) {
/* dump to a file */
if ((fp = fopen(arg->a_string, "w")) == NULL) {
@@ -4018,25 +4001,27 @@ do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
pf_data.fp = fp;
pf_data.defn = TRUE; /* in_dump = TRUE */
(void) print_code(code_block, &pf_data);
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
- FALSE, /* sort */
- &pf_data /* data */
- );
+ funcs = function_list(TRUE);
+ (void) foreach_func(funcs,
+ (int (*)(INSTRUCTION *, void *)) print_code,
+ &pf_data);
+ efree(funcs);
fclose(fp);
return FALSE;
}
+ funcs = function_list(TRUE);
initialize_pager(out_fp);
if (setjmp(pager_quit_tag) == 0) {
pf_data.print_func = gprintf;
pf_data.fp = out_fp;
pf_data.defn = TRUE; /* in_dump = TRUE */
(void) print_code(code_block, &pf_data);
- (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
- FALSE, /* sort */
- &pf_data /* data */
- );
+ (void) foreach_func(funcs,
+ (int (*)(INSTRUCTION *, void *)) print_code,
+ &pf_data);
}
+ efree(funcs);
return FALSE;
}
@@ -4957,7 +4942,7 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
goto done;
for (; cnt > 0; cnt--) {
- NODE *value, *subs;
+ NODE *value, *subs;
a = a->next;
subs = a->a_node;
value = in_array(r, subs);
@@ -4995,7 +4980,7 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
}
}
- force_string(tmp[0]);
+ tmp[0] = force_string(tmp[0]);
PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
if (setjmp(fatal_tag) == 0)
@@ -5338,35 +5323,6 @@ close_all()
set_gawk_output(NULL); /* closes output_fp if not stdout */
}
-/* install_params --- install function parameters into the symbol table */
-
-static void
-install_params(NODE *func)
-{
- NODE *np;
-
- if (func == NULL)
- return;
- /* function parameters of type Node_param_list */
- np = func->lnode;
- for (np = np->rnode; np != NULL; np = np->rnode)
- install_symbol(np->param, np);
-}
-
-/* remove_params --- remove function parameters out of the symbol table */
-
-static void
-remove_params(NODE *func)
-{
- NODE *np;
-
- if (func == NULL)
- return;
- np = func->lnode;
- for (np = np->rnode; np != NULL; np = np->rnode)
- remove_symbol(np->param);
-}
-
/* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
static int
@@ -5409,12 +5365,15 @@ execute_code(volatile INSTRUCTION *code)
volatile NODE *r = NULL;
volatile jmp_buf fatal_tag_stack;
long save_stack_size;
+ int save_flags = do_flags;
/* We use one global stack for all contexts.
* Save # of items in stack; in case of
* a fatal error, pop stack until it has that many items.
*/
+
save_stack_size = (stack_ptr - stack_bottom) + 1;
+ do_flags = FALSE;
PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
if (setjmp(fatal_tag) == 0) {
@@ -5424,7 +5383,7 @@ execute_code(volatile INSTRUCTION *code)
(void) unwind_stack(save_stack_size);
POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
-
+ do_flags = save_flags;
if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */
exit_val = EXIT_SUCCESS;
return NULL;
@@ -5443,9 +5402,9 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
NODE **sp;
INSTRUCTION *eval, *code = NULL;
AWK_CONTEXT *ctxt;
- char **save_parmlist = NULL;
int ecount = 0, pcount = 0;
int ret;
+ int save_flags = do_flags;
if (prog_running) {
this_frame = find_frame(0);
@@ -5457,7 +5416,9 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
ctxt->install_func = append_symbol; /* keep track of newly installed globals */
push_context(ctxt);
(void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
+ do_flags = FALSE;
ret = parse_program(&code);
+ do_flags = save_flags;
remove_params(this_func);
if (ret != 0) {
pop_context(); /* switch to prev context */
@@ -5479,9 +5440,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
} else {
/* execute as a part of the current function */
int i;
- char **varnames;
INSTRUCTION *t;
- NODE *np;
eval = f->code_ptr; /* Op_func */
eval->source_file = cur_srcfile->src;
@@ -5490,9 +5449,8 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
t->opcode = Op_stop;
/* add or append eval locals to the current frame stack */
- ecount = f->lnode->param_cnt; /* eval local count */
- pcount = this_func->lnode->param_cnt;
- save_parmlist = this_func->parmlist;
+ ecount = f->param_cnt; /* eval local count */
+ pcount = this_func->param_cnt;
if (ecount > 0) {
if (pcount == 0)
@@ -5500,26 +5458,22 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
else
erealloc(this_frame->stack, NODE **, (pcount + ecount) * sizeof(NODE *), "do_eval");
- emalloc(varnames, char **, (pcount + ecount + 1) * sizeof(char *), "do_eval");
- if (pcount > 0)
- memcpy(varnames, save_parmlist, pcount * sizeof(char *));
- for (np = f->lnode->rnode, i = 0; np != NULL; np = np->rnode, i++) {
- varnames[pcount + i] = np->param;
- np->param_cnt += pcount; /* appending eval locals: fixup param_cnt */
- }
- varnames[pcount + ecount] = NULL;
sp = this_frame->stack + pcount;
for (i = 0; i < ecount; i++) {
+ NODE *np;
+
+ np = f->fparms + i;
+ np->param_cnt += pcount; /* appending eval locals: fixup param_cnt */
+
getnode(r);
memset(r, 0, sizeof(NODE));
*sp++ = r;
/* local variable */
r->type = Node_var_new;
- r->vname = varnames[pcount + i];
+ r->vname = np->param;
}
- this_func->parmlist = varnames;
- this_func->lnode->param_cnt += ecount;
+ this_func->param_cnt += ecount;
}
}
@@ -5559,9 +5513,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
} /* else
restore_frame() will free it */
- efree(this_func->parmlist);
- this_func->parmlist = save_parmlist;
- this_func->lnode->param_cnt -= ecount;
+ this_func->param_cnt -= ecount;
}
/* always destroy symbol "@eval", however destroy all newly installed
@@ -5571,7 +5523,7 @@ do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
pop_context(); /* switch to prev context */
free_context(ctxt, (ret_val != NULL)); /* free all instructions and optionally symbols */
if (ret_val != NULL)
- destroy_symbol("@eval"); /* destroy "@eval" */
+ destroy_symbol(f); /* destroy "@eval" */
return FALSE;
}
@@ -5588,13 +5540,13 @@ an error message:
static int invalid_symbol = 0;
-void
-check_symbol(char *name)
+static void
+check_symbol(NODE *r)
{
invalid_symbol++;
- d_error(_("No symbol `%s' in current context"), name);
+ d_error(_("No symbol `%s' in current context"), r->vname);
/* install anyway, but keep track of it */
- append_symbol(name);
+ append_symbol(r);
}
/* parse_condition --- compile a condition expression */
@@ -5610,6 +5562,7 @@ parse_condition(int type, int num, char *expr)
NODE *this_func = NULL;
INSTRUCTION *it, *stop, *rule;
struct condition *cndn = NULL;
+ int save_flags = do_flags;
if (type == D_break && (b = find_breakpoint(num)) != NULL) {
INSTRUCTION *rp;
@@ -5633,7 +5586,9 @@ parse_condition(int type, int num, char *expr)
ctxt->install_func = check_symbol;
push_context(ctxt);
(void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
+ do_flags = FALSE;
ret = parse_program(&code);
+ do_flags = save_flags;
remove_params(this_func);
pop_context();
@@ -5653,8 +5608,8 @@ parse_condition(int type, int num, char *expr)
it = rule->firsti; /* Op_K_print_rec */
assert(it->opcode == Op_K_print_rec);
- it->opcode = Op_push_i;
- it->memory = mk_number((AWKNUM) 1.0, PERM|NUMBER|NUMCUR);
+ it->opcode = Op_push_i;
+ it->memory = make_number(1.0);
it->nexti = bcalloc(Op_jmp, 1, 0);
it->nexti->target_jmp = stop;
it->nexti->nexti = rule->lasti;
@@ -5662,7 +5617,7 @@ parse_condition(int type, int num, char *expr)
it = rule->lasti; /* Op_no_op, target for Op_jmp_false */
assert(it->opcode == Op_no_op);
it->opcode = Op_push_i;
- it->memory = mk_number((AWKNUM) 0.0, PERM|NUMBER|NUMCUR);
+ it->memory = make_number(0.0);
it->nexti = stop;
out:
@@ -5742,7 +5697,7 @@ push_cmd_src(
cs->str = NULL;
cs->next = cmd_src;
cmd_src = cs;
-
+
input_fd = fd;
input_from_tty = istty;
read_a_line = readfunc;
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 2921a919..3a9a9912 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -22,6 +22,10 @@
Jeroen Schot <schot@A-Eskwadraat.nl>.
* gawk.texi: Some minor fixes.
+2011-08-31 John Haque <j.eh@mchsi.com>
+
+ * gawk.texi: Updated gawk dynamic extension doc.
+
2011-07-28 Arnold D. Robbins <arnold@skeeve.com>
* gawk.texi (Gory Details): Restore text on historical behavior
diff --git a/doc/gawk.info b/doc/gawk.info
index 8d9422f2..a8b6450b 100644
--- a/doc/gawk.info
+++ b/doc/gawk.info
@@ -21773,16 +21773,9 @@ when writing extensions. The next minor node shows how they are used:
is current. It may end up calling an internal `gawk' function.
It also guarantees that the wide string is zero-terminated.
-`size_t get_curfunc_arg_count(void)'
- This function returns the actual number of parameters passed to
- the current function. Inside the code of an extension this can be
- used to determine the maximum index which is safe to use with
- `get_actual_argument'. If this value is greater than `nargs', the
- function was called incorrectly from the `awk' program.
-
`nargs'
- Inside an extension function, this is the maximum number of
- expected parameters, as set by the `make_builtin()' function.
+ Inside an extension function, this is the actual number of
+ parameters passed to the current function.
`n->stptr'
`n->stlen'
@@ -21810,12 +21803,10 @@ when writing extensions. The next minor node shows how they are used:
Clears the associative array pointed to by `n'. Make sure that
`n->type == Node_var_array' first.
-`NODE **assoc_lookup(NODE *symbol, NODE *subs, int reference)'
+`NODE **assoc_lookup(NODE *symbol, NODE *subs)'
Finds, and installs if necessary, array elements. `symbol' is the
array, `subs' is the subscript. This is usually a value created
- with `make_string()' (see below). `reference' should be `TRUE' if
- it is an error to use the value before it is created. Typically,
- `FALSE' is the correct value to use from extension functions.
+ with `make_string()' (see below).
`NODE *make_string(char *s, size_t len)'
Take a C string and turn it into a pointer to a `NODE' that can be
@@ -22117,7 +22108,7 @@ other POSIX-compliant systems:(1)
NODE *newdir;
int ret = -1;
- if (do_lint && get_curfunc_arg_count() != 1)
+ if (do_lint && nargs != 1)
lintwarn("chdir: called with incorrect number of arguments");
newdir = get_scalar_argument(0, FALSE);
@@ -22174,7 +22165,7 @@ declarations and argument checking:
char *pmode; /* printable mode */
char *type = "unknown";
- if (do_lint && get_curfunc_arg_count() > 2)
+ if (do_lint && nargs > 2)
lintwarn("stat: called with too many arguments");
Then comes the actual work. First, the function gets the arguments.
@@ -22201,15 +22192,15 @@ link. If there's an error, it sets `ERRNO' and returns:
calls are shown here, since they all follow the same pattern:
/* fill in the array */
- aptr = assoc_lookup(array, tmp = make_string("name", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("name", 4));
*aptr = dupnode(file);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("mode", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("mode", 4));
*aptr = make_number((AWKNUM) sbuf.st_mode);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("pmode", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("pmode", 5));
pmode = format_mode(sbuf.st_mode);
*aptr = make_string(pmode, strlen(pmode));
unref(tmp);
@@ -24970,18 +24961,18 @@ Index
* arguments, command-line, invoking awk: Command Line. (line 6)
* arguments, in function calls: Function Calls. (line 16)
* arguments, processing: Getopt Function. (line 6)
-* arguments, retrieving: Internals. (line 120)
+* arguments, retrieving: Internals. (line 111)
* arithmetic operators: Arithmetic Ops. (line 6)
* arrays: Arrays. (line 6)
* arrays, as parameters to functions: Pass By Value/Reference.
(line 47)
* arrays, associative: Array Intro. (line 50)
-* arrays, associative, clearing: Internals. (line 75)
+* arrays, associative, clearing: Internals. (line 68)
* arrays, associative, library functions and: Library Names. (line 57)
* arrays, deleting entire contents: Delete. (line 39)
* arrays, elements, assigning: Assigning Elements. (line 6)
* arrays, elements, deleting: Delete. (line 6)
-* arrays, elements, installing: Internals. (line 79)
+* arrays, elements, installing: Internals. (line 72)
* arrays, elements, order of: Scanning an Array. (line 48)
* arrays, elements, referencing: Reference to Elements.
(line 6)
@@ -25020,8 +25011,8 @@ Index
* assignment operators, evaluation order: Assignment Ops. (line 111)
* assignment operators, lvalues/rvalues: Assignment Ops. (line 32)
* assignments as filenames: Ignoring Assigns. (line 6)
-* assoc_clear() internal function: Internals. (line 75)
-* assoc_lookup() internal function: Internals. (line 79)
+* assoc_clear() internal function: Internals. (line 68)
+* assoc_lookup() internal function: Internals. (line 72)
* associative arrays: Array Intro. (line 50)
* asterisk (*), * operator, as multiplication operator: Precedence.
(line 55)
@@ -25292,7 +25283,7 @@ Index
* close() function, two-way pipes and: Two-way I/O. (line 77)
* Close, Diane <1>: Contributors. (line 21)
* Close, Diane: Manual History. (line 41)
-* close_func() input method: Internals. (line 160)
+* close_func() input method: Internals. (line 151)
* collating elements: Bracket Expressions. (line 69)
* collating symbols: Bracket Expressions. (line 76)
* Colombo, Antonio: Acknowledgments. (line 60)
@@ -25665,7 +25656,7 @@ Index
* DuBois, John: Acknowledgments. (line 60)
* dump debugger command: Miscellaneous Dgawk Commands.
(line 9)
-* dupnode() internal function: Internals. (line 96)
+* dupnode() internal function: Internals. (line 87)
* dupword.awk program: Dupword Program. (line 31)
* e debugger command (alias for enable): Breakpoint Control. (line 72)
* EBCDIC: Ordinal Functions. (line 45)
@@ -25706,7 +25697,7 @@ Index
* endgrent() user-defined function: Group Functions. (line 218)
* endpwent() function (C library): Passwd Functions. (line 210)
* endpwent() user-defined function: Passwd Functions. (line 213)
-* ENVIRON array <1>: Internals. (line 149)
+* ENVIRON array <1>: Internals. (line 140)
* ENVIRON array: Auto-set. (line 60)
* environment variables: Auto-set. (line 60)
* epoch, definition of: Glossary. (line 239)
@@ -25715,7 +25706,7 @@ Index
* equals sign (=), == operator: Comparison Operators.
(line 11)
* EREs (Extended Regular Expressions): Bracket Expressions. (line 24)
-* ERRNO variable <1>: Internals. (line 139)
+* ERRNO variable <1>: Internals. (line 130)
* ERRNO variable <2>: TCP/IP Networking. (line 54)
* ERRNO variable <3>: Auto-set. (line 72)
* ERRNO variable <4>: BEGINFILE/ENDFILE. (line 26)
@@ -25764,7 +25755,7 @@ Index
(line 9)
* expressions, selecting: Conditional Exp. (line 6)
* Extended Regular Expressions (EREs): Bracket Expressions. (line 24)
-* eXtensible Markup Language (XML): Internals. (line 160)
+* eXtensible Markup Language (XML): Internals. (line 151)
* extension() function (gawk): Using Internal File Ops.
(line 15)
* extensions, Brian Kernighan's awk <1>: Other Versions. (line 13)
@@ -25986,7 +25977,7 @@ Index
* functions, names of <1>: Definition Syntax. (line 20)
* functions, names of: Arrays. (line 18)
* functions, recursive: Definition Syntax. (line 73)
-* functions, return values, setting: Internals. (line 139)
+* functions, return values, setting: Internals. (line 130)
* functions, string-translation: I18N Functions. (line 6)
* functions, undefined: Pass By Value/Reference.
(line 71)
@@ -26100,12 +26091,11 @@ Index
* gensub() function (gawk): Using Constant Regexps.
(line 43)
* gensub() function (gawk), escape processing: Gory Details. (line 6)
-* get_actual_argument() internal function: Internals. (line 125)
-* get_argument() internal function: Internals. (line 120)
-* get_array_argument() internal macro: Internals. (line 136)
-* get_curfunc_arg_count() internal function: Internals. (line 42)
-* get_record() input method: Internals. (line 160)
-* get_scalar_argument() internal macro: Internals. (line 133)
+* get_actual_argument() internal function: Internals. (line 116)
+* get_argument() internal function: Internals. (line 111)
+* get_array_argument() internal macro: Internals. (line 127)
+* get_record() input method: Internals. (line 151)
+* get_scalar_argument() internal macro: Internals. (line 124)
* getaddrinfo() function (C library): TCP/IP Networking. (line 38)
* getgrent() function (C library): Group Functions. (line 6)
* getgrent() user-defined function: Group Functions. (line 6)
@@ -26258,37 +26248,36 @@ Index
* integers: Basic Data Typing. (line 21)
* integers, unsigned: Basic Data Typing. (line 30)
* interacting with other programs: I/O Functions. (line 63)
-* internal constant, INVALID_HANDLE: Internals. (line 160)
-* internal function, assoc_clear(): Internals. (line 75)
-* internal function, assoc_lookup(): Internals. (line 79)
-* internal function, dupnode(): Internals. (line 96)
+* internal constant, INVALID_HANDLE: Internals. (line 151)
+* internal function, assoc_clear(): Internals. (line 68)
+* internal function, assoc_lookup(): Internals. (line 72)
+* internal function, dupnode(): Internals. (line 87)
* internal function, force_number(): Internals. (line 27)
* internal function, force_string(): Internals. (line 32)
* internal function, force_wstring(): Internals. (line 37)
-* internal function, get_actual_argument(): Internals. (line 125)
-* internal function, get_argument(): Internals. (line 120)
-* internal function, get_curfunc_arg_count(): Internals. (line 42)
-* internal function, iop_alloc(): Internals. (line 160)
-* internal function, make_builtin(): Internals. (line 106)
-* internal function, make_number(): Internals. (line 91)
-* internal function, make_string(): Internals. (line 86)
-* internal function, register_deferred_variable(): Internals. (line 149)
-* internal function, register_open_hook(): Internals. (line 160)
-* internal function, unref(): Internals. (line 101)
-* internal function, update_ERRNO(): Internals. (line 139)
-* internal function, update_ERRNO_saved(): Internals. (line 144)
-* internal macro, get_array_argument(): Internals. (line 136)
-* internal macro, get_scalar_argument(): Internals. (line 133)
-* internal structure, IOBUF: Internals. (line 160)
+* internal function, get_actual_argument(): Internals. (line 116)
+* internal function, get_argument(): Internals. (line 111)
+* internal function, iop_alloc(): Internals. (line 151)
+* internal function, make_builtin(): Internals. (line 97)
+* internal function, make_number(): Internals. (line 82)
+* internal function, make_string(): Internals. (line 77)
+* internal function, register_deferred_variable(): Internals. (line 140)
+* internal function, register_open_hook(): Internals. (line 151)
+* internal function, unref(): Internals. (line 92)
+* internal function, update_ERRNO(): Internals. (line 130)
+* internal function, update_ERRNO_saved(): Internals. (line 135)
+* internal macro, get_array_argument(): Internals. (line 127)
+* internal macro, get_scalar_argument(): Internals. (line 124)
+* internal structure, IOBUF: Internals. (line 151)
* internal type, AWKNUM: Internals. (line 19)
* internal type, NODE: Internals. (line 23)
-* internal variable, nargs: Internals. (line 49)
-* internal variable, stlen: Internals. (line 53)
-* internal variable, stptr: Internals. (line 53)
-* internal variable, type: Internals. (line 66)
-* internal variable, vname: Internals. (line 71)
-* internal variable, wstlen: Internals. (line 61)
-* internal variable, wstptr: Internals. (line 61)
+* internal variable, nargs: Internals. (line 42)
+* internal variable, stlen: Internals. (line 46)
+* internal variable, stptr: Internals. (line 46)
+* internal variable, type: Internals. (line 59)
+* internal variable, vname: Internals. (line 64)
+* internal variable, wstlen: Internals. (line 54)
+* internal variable, wstptr: Internals. (line 54)
* internationalization <1>: I18N and L10N. (line 6)
* internationalization: I18N Functions. (line 6)
* internationalization, localization <1>: Internationalization.
@@ -26308,10 +26297,10 @@ Index
* interpreted programs <1>: Glossary. (line 361)
* interpreted programs: Basic High Level. (line 14)
* interval expressions: Regexp Operators. (line 116)
-* INVALID_HANDLE internal constant: Internals. (line 160)
+* INVALID_HANDLE internal constant: Internals. (line 151)
* inventory-shipped file: Sample Data Files. (line 32)
-* IOBUF internal structure: Internals. (line 160)
-* iop_alloc() internal function: Internals. (line 160)
+* IOBUF internal structure: Internals. (line 151)
+* iop_alloc() internal function: Internals. (line 151)
* isarray() function (gawk): Type Functions. (line 11)
* ISO: Glossary. (line 372)
* ISO 8859-1: Glossary. (line 141)
@@ -26438,9 +26427,9 @@ Index
* lvalues/rvalues: Assignment Ops. (line 32)
* mailing labels, printing: Labels Program. (line 6)
* mailing list, GNITS: Acknowledgments. (line 52)
-* make_builtin() internal function: Internals. (line 106)
-* make_number() internal function: Internals. (line 91)
-* make_string() internal function: Internals. (line 86)
+* make_builtin() internal function: Internals. (line 97)
+* make_number() internal function: Internals. (line 82)
+* make_string() internal function: Internals. (line 77)
* mark parity: Ordinal Functions. (line 45)
* marked string extraction (internationalization): String Extraction.
(line 6)
@@ -26455,7 +26444,7 @@ Index
* matching, null strings: Gory Details. (line 164)
* mawk program: Other Versions. (line 35)
* McPhee, Patrick: Contributors. (line 100)
-* memory, releasing: Internals. (line 101)
+* memory, releasing: Internals. (line 92)
* message object files: Explaining gettext. (line 41)
* message object files, converting from portable object files: I18N Example.
(line 62)
@@ -26477,7 +26466,7 @@ Index
* namespace issues <1>: Library Names. (line 6)
* namespace issues: Arrays. (line 18)
* namespace issues, functions: Definition Syntax. (line 20)
-* nargs internal variable: Internals. (line 49)
+* nargs internal variable: Internals. (line 42)
* nawk utility: Names. (line 17)
* negative zero: Unexpected Results. (line 28)
* NetBSD: Glossary. (line 611)
@@ -26519,7 +26508,7 @@ Index
(line 49)
* noassign.awk program: Ignoring Assigns. (line 15)
* NODE internal type: Internals. (line 23)
-* nodes, duplicating: Internals. (line 96)
+* nodes, duplicating: Internals. (line 87)
* not Boolean-logic operator: Boolean Ops. (line 6)
* NR variable <1>: Auto-set. (line 118)
* NR variable: Records. (line 6)
@@ -26540,7 +26529,7 @@ Index
* number sign (#), #! (executable scripts), portability issues with: Executable Scripts.
(line 6)
* number sign (#), commenting: Comments. (line 6)
-* numbers: Internals. (line 91)
+* numbers: Internals. (line 82)
* numbers, as array subscripts: Numeric Array Subscripts.
(line 6)
* numbers, as values of characters: Ordinal Functions. (line 6)
@@ -26643,7 +26632,7 @@ Index
(line 36)
* P1003.1 POSIX standard: Glossary. (line 454)
* P1003.2 POSIX standard: Glossary. (line 454)
-* parameters, number of: Internals. (line 49)
+* parameters, number of: Internals. (line 42)
* parentheses (): Regexp Operators. (line 79)
* parentheses (), pgawk program: Profiling. (line 141)
* password file: Passwd Functions. (line 16)
@@ -26807,7 +26796,7 @@ Index
* private variables: Library Names. (line 11)
* processes, two-way communications with: Two-way I/O. (line 23)
* processing data: Basic High Level. (line 6)
-* PROCINFO array <1>: Internals. (line 149)
+* PROCINFO array <1>: Internals. (line 140)
* PROCINFO array <2>: Id Program. (line 15)
* PROCINFO array <3>: Group Functions. (line 6)
* PROCINFO array <4>: Passwd Functions. (line 6)
@@ -26903,8 +26892,8 @@ Index
* regexp constants, slashes vs. quotes: Computed Regexps. (line 28)
* regexp constants, vs. string constants: Computed Regexps. (line 38)
* regexp, See regular expressions: Regexp. (line 6)
-* register_deferred_variable() internal function: Internals. (line 149)
-* register_open_hook() internal function: Internals. (line 160)
+* register_deferred_variable() internal function: Internals. (line 140)
+* register_open_hook() internal function: Internals. (line 151)
* regular expressions: Regexp. (line 6)
* regular expressions as field separators: Field Separators. (line 50)
* regular expressions, anchors in: Regexp Operators. (line 22)
@@ -27130,8 +27119,8 @@ Index
(line 68)
* stepi debugger command: Dgawk Execution Control.
(line 76)
-* stlen internal variable: Internals. (line 53)
-* stptr internal variable: Internals. (line 53)
+* stlen internal variable: Internals. (line 46)
+* stptr internal variable: Internals. (line 46)
* stream editors <1>: Simple Sed. (line 6)
* stream editors: Field Splitting Summary.
(line 47)
@@ -27142,7 +27131,7 @@ Index
(line 6)
* string operators: Concatenation. (line 9)
* string-matching operators: Regexp Usage. (line 19)
-* strings: Internals. (line 86)
+* strings: Internals. (line 77)
* strings, converting <1>: Bitwise Functions. (line 107)
* strings, converting: Conversion. (line 6)
* strings, converting, numbers to: User-modified. (line 28)
@@ -27272,7 +27261,7 @@ Index
* trunc-mod operation: Arithmetic Ops. (line 66)
* truth values: Truth Values. (line 6)
* type conversion: Conversion. (line 21)
-* type internal variable: Internals. (line 66)
+* type internal variable: Internals. (line 59)
* u debugger command (alias for until): Dgawk Execution Control.
(line 83)
* undefined functions: Pass By Value/Reference.
@@ -27298,15 +27287,15 @@ Index
(line 72)
* Unix, awk scripts and: Executable Scripts. (line 6)
* UNIXROOT variable, on OS/2 systems: PC Using. (line 17)
-* unref() internal function: Internals. (line 101)
+* unref() internal function: Internals. (line 92)
* unsigned integers: Basic Data Typing. (line 30)
* until debugger command: Dgawk Execution Control.
(line 83)
* unwatch debugger command: Viewing And Changing Data.
(line 84)
* up debugger command: Dgawk Stack. (line 33)
-* update_ERRNO() internal function: Internals. (line 139)
-* update_ERRNO_saved() internal function: Internals. (line 144)
+* update_ERRNO() internal function: Internals. (line 130)
+* update_ERRNO_saved() internal function: Internals. (line 135)
* user database, reading: Passwd Functions. (line 6)
* user-defined, functions: User-defined. (line 6)
* user-defined, functions, counts: Profiling. (line 132)
@@ -27357,7 +27346,7 @@ Index
* vertical bar (|), || operator <1>: Precedence. (line 89)
* vertical bar (|), || operator: Boolean Ops. (line 57)
* Vinschen, Corinna: Acknowledgments. (line 60)
-* vname internal variable: Internals. (line 71)
+* vname internal variable: Internals. (line 64)
* w debugger command (alias for watch): Viewing And Changing Data.
(line 67)
* w utility: Constant Size. (line 22)
@@ -27391,11 +27380,11 @@ Index
* words, counting: Wc Program. (line 6)
* words, duplicate, searching for: Dupword Program. (line 6)
* words, usage counts, generating: Word Sorting. (line 6)
-* wstlen internal variable: Internals. (line 61)
-* wstptr internal variable: Internals. (line 61)
+* wstlen internal variable: Internals. (line 54)
+* wstptr internal variable: Internals. (line 54)
* xgawk: Other Versions. (line 119)
* xgettext utility: String Extraction. (line 13)
-* XML (eXtensible Markup Language): Internals. (line 160)
+* XML (eXtensible Markup Language): Internals. (line 151)
* XOR bitwise operation: Bitwise Functions. (line 6)
* xor() function (gawk): Bitwise Functions. (line 54)
* Yawitz, Efraim: Contributors. (line 106)
@@ -27823,26 +27812,26 @@ Node: Adding Code860119
Node: New Ports866086
Node: Dynamic Extensions870199
Node: Internals871575
-Node: Plugin License880678
-Node: Sample Library881312
-Node: Internal File Description881998
-Node: Internal File Ops885713
-Ref: Internal File Ops-Footnote-1890494
-Node: Using Internal File Ops890634
-Node: Future Extensions893011
-Node: Basic Concepts895515
-Node: Basic High Level896272
-Ref: Basic High Level-Footnote-1900307
-Node: Basic Data Typing900492
-Node: Floating Point Issues905017
-Node: String Conversion Precision906100
-Ref: String Conversion Precision-Footnote-1907800
-Node: Unexpected Results907909
-Node: POSIX Floating Point Problems909735
-Ref: POSIX Floating Point Problems-Footnote-1913440
-Node: Glossary913478
-Node: Copying938454
-Node: GNU Free Documentation License976011
-Node: Index1001148
+Node: Plugin License880094
+Node: Sample Library880728
+Node: Internal File Description881414
+Node: Internal File Ops885129
+Ref: Internal File Ops-Footnote-1889853
+Node: Using Internal File Ops889993
+Node: Future Extensions892370
+Node: Basic Concepts894874
+Node: Basic High Level895631
+Ref: Basic High Level-Footnote-1899666
+Node: Basic Data Typing899851
+Node: Floating Point Issues904376
+Node: String Conversion Precision905459
+Ref: String Conversion Precision-Footnote-1907159
+Node: Unexpected Results907268
+Node: POSIX Floating Point Problems909094
+Ref: POSIX Floating Point Problems-Footnote-1912799
+Node: Glossary912837
+Node: Copying937813
+Node: GNU Free Documentation License975370
+Node: Index1000507

End Tag Table
diff --git a/doc/gawk.texi b/doc/gawk.texi
index 33e66d70..dfd620f6 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -29128,22 +29128,12 @@ macro guarantees that a @code{NODE}'s wide-string value is current.
It may end up calling an internal @command{gawk} function.
It also guarantees that the wide string is zero-terminated.
-@cindex @code{get_curfunc_arg_count()} internal function
-@cindex internal function, @code{get_curfunc_arg_count()}
-@item size_t get_curfunc_arg_count(void)
-This function returns the actual number of parameters passed
-to the current function. Inside the code of an extension
-this can be used to determine the maximum index which is
-safe to use with @code{get_actual_argument}. If this value is
-greater than @code{nargs}, the function was
-called incorrectly from the @command{awk} program.
-
@cindex parameters@comma{} number of
@cindex @code{nargs} internal variable
@cindex internal variable, @code{nargs}
@item nargs
-Inside an extension function, this is the maximum number of
-expected parameters, as set by the @code{make_builtin()} function.
+Inside an extension function, this is the actual number of
+parameters passed to the current function.
@cindex @code{stptr} internal variable
@cindex internal variable, @code{stptr}
@@ -29189,13 +29179,10 @@ Make sure that @samp{n->type == Node_var_array} first.
@cindex arrays, elements, installing
@cindex @code{assoc_lookup()} internal function
@cindex internal function, @code{assoc_lookup()}
-@item NODE **assoc_lookup(NODE *symbol, NODE *subs, int reference)
+@item NODE **assoc_lookup(NODE *symbol, NODE *subs)
Finds, and installs if necessary, array elements.
@code{symbol} is the array, @code{subs} is the subscript.
This is usually a value created with @code{make_string()} (see below).
-@code{reference} should be @code{TRUE} if it is an error to use the
-value before it is created. Typically, @code{FALSE} is the
-correct value to use from extension functions.
@cindex strings
@cindex @code{make_string()} internal function
@@ -29579,7 +29566,7 @@ do_chdir(int nargs)
NODE *newdir;
int ret = -1;
- if (do_lint && get_curfunc_arg_count() != 1)
+ if (do_lint && nargs != 1)
lintwarn("chdir: called with incorrect number of arguments");
newdir = get_scalar_argument(0, FALSE);
@@ -29652,7 +29639,7 @@ do_stat(int nargs)
char *pmode; /* printable mode */
char *type = "unknown";
- if (do_lint && get_curfunc_arg_count() > 2)
+ if (do_lint && nargs > 2)
lintwarn("stat: called with too many arguments");
@end example
@@ -29686,15 +29673,15 @@ calls are shown here, since they all follow the same pattern:
@example
/* fill in the array */
- aptr = assoc_lookup(array, tmp = make_string("name", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("name", 4));
*aptr = dupnode(file);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("mode", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("mode", 4));
*aptr = make_number((AWKNUM) sbuf.st_mode);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("pmode", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("pmode", 5));
pmode = format_mode(sbuf.st_mode);
*aptr = make_string(pmode, strlen(pmode));
unref(tmp);
diff --git a/eval.c b/eval.c
index 22f30773..2a29eb9f 100644
--- a/eval.c
+++ b/eval.c
@@ -262,9 +262,12 @@ static const char *const nodetypes[] = {
"Node_var_new",
"Node_param_list",
"Node_func",
+ "Node_ext_func",
"Node_hashnode",
- "Node_ahash",
"Node_array_ref",
+ "Node_array_tree",
+ "Node_array_leaf",
+ "Node_dump_array",
"Node_arrayfor",
"Node_frame",
"Node_instruction",
@@ -349,6 +352,7 @@ static struct optypetab {
{ "Op_K_nextfile", "nextfile" },
{ "Op_builtin", NULL },
{ "Op_sub_builtin", NULL },
+ { "Op_ext_builtin", NULL },
{ "Op_in_array", " in " },
{ "Op_func_call", NULL },
{ "Op_indirect_func_call", NULL },
@@ -376,7 +380,6 @@ static struct optypetab {
{ "Op_field_assign", NULL },
{ "Op_after_beginfile", NULL },
{ "Op_after_endfile", NULL },
- { "Op_ext_func", NULL },
{ "Op_func", NULL },
{ "Op_exec_count", NULL },
{ "Op_breakpoint", NULL },
@@ -446,20 +449,19 @@ flags2str(int flagval)
{
static const struct flagtab values[] = {
{ MALLOC, "MALLOC" },
- { PERM, "PERM" },
{ STRING, "STRING" },
{ STRCUR, "STRCUR" },
{ NUMCUR, "NUMCUR" },
{ NUMBER, "NUMBER" },
{ MAYBE_NUM, "MAYBE_NUM" },
- { ARRAYMAXED, "ARRAYMAXED" },
- { FUNC, "FUNC" },
{ FIELD, "FIELD" },
{ INTLSTR, "INTLSTR" },
- { NUMIND, "NUMIND" },
-#ifdef WSTRCUR
+ { NUMINT, "NUMINT" },
+ { INTIND, "INTIND" },
{ WSTRCUR, "WSTRCUR" },
-#endif
+ { ARRAYMAXED, "ARRAYMAXED" },
+ { HALFHAT, "HALFHAT" },
+ { XARRAY, "XARRAY" },
{ 0, NULL },
};
@@ -484,7 +486,7 @@ genflags2str(int flagval, const struct flagtab *tab)
* the '|' character.
*/
space_needed = (strlen(tab[i].name) + (sp != buffer));
- if (space_left < space_needed)
+ if (space_left <= space_needed)
fatal(_("buffer overflow in genflags2str"));
if (sp != buffer) {
@@ -498,6 +500,7 @@ genflags2str(int flagval, const struct flagtab *tab)
}
}
+ *sp = '\0';
return buffer;
}
@@ -582,7 +585,6 @@ posix_compare(NODE *s1, NODE *s2)
return ret;
}
-
/* cmp_nodes --- compare two nodes, returning negative, 0, positive */
int
@@ -599,6 +601,11 @@ cmp_nodes(NODE *t1, NODE *t2)
(void) force_number(t1);
if (t2->flags & MAYBE_NUM)
(void) force_number(t2);
+ if (t1->flags & INTIND)
+ t1 = force_string(t1);
+ if (t2->flags & INTIND)
+ t2 = force_string(t2);
+
if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) {
if (t1->numbr == t2->numbr)
ret = 0;
@@ -610,8 +617,8 @@ cmp_nodes(NODE *t1, NODE *t2)
return ret;
}
- (void) force_string(t1);
- (void) force_string(t2);
+ t1 = force_string(t1);
+ t2 = force_string(t2);
len1 = t1->stlen;
len2 = t2->stlen;
ldiff = len1 - len2;
@@ -637,7 +644,9 @@ cmp_nodes(NODE *t1, NODE *t2)
ret = casetable[*cp1] - casetable[*cp2];
} else
ret = memcmp(t1->stptr, t2->stptr, l);
- return (ret == 0 ? ldiff : ret);
+
+ ret = ret == 0 ? ldiff : ret;
+ return ret;
}
@@ -678,8 +687,8 @@ pop_frame()
#endif
}
#else /* not PROFILING or DEBUGGING */
-#define push_frame(p) /* nothing */
-#define pop_frame() /* nothing */
+#define push_frame(p) /* nothing */
+#define pop_frame() /* nothing */
#endif
@@ -691,7 +700,7 @@ void
dump_fcall_stack(FILE *fp)
{
NODE *f, *func;
- long i = 0;
+ long i = 0, j, k = 0;
if (fcall_count == 0)
return;
@@ -699,16 +708,18 @@ dump_fcall_stack(FILE *fp)
/* current frame */
func = frame_ptr->func_node;
- fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param);
+ for (j = 0; j <= frame_ptr->num_tail_calls; j++)
+ fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
/* outer frames except main */
for (i = 1; i < fcall_count; i++) {
f = fcall_list[i];
func = f->func_node;
- fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param);
+ for (j = 0; j <= f->num_tail_calls; j++)
+ fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
}
- fprintf(fp, "\t# %3ld. -- main --\n", fcall_count);
+ fprintf(fp, "\t# %3ld. -- main --\n", k);
}
#endif /* PROFILING */
@@ -728,9 +739,10 @@ set_IGNORECASE()
if (do_traditional)
IGNORECASE = FALSE;
else if ((IGNORECASE_node->var_value->flags & (STRING|STRCUR)) != 0) {
- if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0)
- IGNORECASE = (force_string(IGNORECASE_node->var_value)->stlen > 0);
- else
+ if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0) {
+ IGNORECASE_node->var_value = force_string(IGNORECASE_node->var_value);
+ IGNORECASE = (IGNORECASE_node->var_value->stlen > 0);
+ } else
IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0);
} else if ((IGNORECASE_node->var_value->flags & (NUMCUR|NUMBER)) != 0)
IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0);
@@ -823,7 +835,8 @@ set_BINMODE()
void
set_OFS()
{
- OFS = force_string(OFS_node->var_value)->stptr;
+ OFS_node->var_value = force_string(OFS_node->var_value);
+ OFS = OFS_node->var_value->stptr;
OFSlen = OFS_node->var_value->stlen;
OFS[OFSlen] = '\0';
}
@@ -833,7 +846,8 @@ set_OFS()
void
set_ORS()
{
- ORS = force_string(ORS_node->var_value)->stptr;
+ ORS_node->var_value = force_string(ORS_node->var_value);
+ ORS = ORS_node->var_value->stptr;
ORSlen = ORS_node->var_value->stlen;
ORS[ORSlen] = '\0';
}
@@ -849,6 +863,7 @@ fmt_ok(NODE *n)
{
NODE *tmp = force_string(n);
const char *p = tmp->stptr;
+
#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
static const char float_formats[] = "efgEG";
#else
@@ -890,7 +905,7 @@ fmt_index(NODE *n)
if (fmt_list == NULL)
emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index");
- (void) force_string(n);
+ n = force_string(n);
while (ix < fmt_hiwater) {
if (cmp_nodes(fmt_list[ix], n) == 0)
return ix;
@@ -942,41 +957,45 @@ set_LINT()
if ((LINT_node->var_value->flags & MAYBE_NUM) == 0) {
const char *lintval;
size_t lintlen;
+ NODE *tmp;
- do_lint = (force_string(LINT_node->var_value)->stlen > 0);
- lintval = LINT_node->var_value->stptr;
- lintlen = LINT_node->var_value->stlen;
- if (do_lint) {
- do_lint = LINT_ALL;
+ tmp = LINT_node->var_value = force_string(LINT_node->var_value);
+ lintval = tmp->stptr;
+ lintlen = tmp->stlen;
+ if (lintlen > 0) {
+ do_flags |= DO_LINT_ALL;
if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0)
lintfunc = r_fatal;
- else if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0)
- do_lint = LINT_INVALID;
- else
+ else if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0) {
+ do_flags &= ~ DO_LINT_ALL;
+ do_flags |= DO_LINT_INVALID;
+ } else
lintfunc = warning;
- } else
+ } else {
+ do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
lintfunc = warning;
+ }
} else {
if (force_number(LINT_node->var_value) != 0.0)
- do_lint = LINT_ALL;
+ do_flags |= DO_LINT_ALL;
else
- do_lint = FALSE;
+ do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
lintfunc = warning;
}
} else if ((LINT_node->var_value->flags & (NUMCUR|NUMBER)) != 0) {
if (force_number(LINT_node->var_value) != 0.0)
- do_lint = LINT_ALL;
+ do_flags |= DO_LINT_ALL;
else
- do_lint = FALSE;
+ do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
lintfunc = warning;
} else
- do_lint = FALSE; /* shouldn't happen */
+ do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); /* shouldn't happen */
if (! do_lint)
lintfunc = warning;
/* explicitly use warning() here, in case lintfunc == r_fatal */
- if (old_lint != do_lint && old_lint && do_lint == FALSE)
+ if (old_lint != do_lint && old_lint && ! do_lint)
warning(_("turning off `--lint' due to assignment to `LINT'"));
#endif /* ! NO_LINT */
}
@@ -987,9 +1006,11 @@ void
set_TEXTDOMAIN()
{
int len;
+ NODE *tmp;
- TEXTDOMAIN = force_string(TEXTDOMAIN_node->var_value)->stptr;
- len = TEXTDOMAIN_node->var_value->stlen;
+ tmp = TEXTDOMAIN_node->var_value = force_string(TEXTDOMAIN_node->var_value);
+ TEXTDOMAIN = tmp->stptr;
+ len = tmp->stlen;
TEXTDOMAIN[len] = '\0';
/*
* Note: don't call textdomain(); this value is for
@@ -1057,7 +1078,6 @@ update_FNR()
}
-
NODE *frame_ptr; /* current frame */
STACK_ITEM *stack_ptr = NULL;
STACK_ITEM *stack_bottom;
@@ -1079,17 +1099,10 @@ STACK_ITEM *
grow_stack()
{
if (stack_ptr == NULL) {
- char *val;
-
- if ((val = getenv("GAWK_STACKSIZE")) != NULL) {
- if (isdigit((unsigned char) *val)) {
- unsigned long n = 0;
- for (; *val && isdigit((unsigned char) *val); val++)
- n = (n * 10) + *val - '0';
- if (n >= 1)
- STACK_SIZE = n;
- }
- }
+ long newval;
+
+ if ((newval = getenv_long("GAWK_STACKSIZE")) > 0)
+ STACK_SIZE = newval;
emalloc(stack_bottom, STACK_ITEM *, STACK_SIZE * sizeof(STACK_ITEM), "grow_stack");
stack_ptr = stack_bottom - 1;
@@ -1100,6 +1113,7 @@ grow_stack()
frame_ptr->type = Node_frame;
frame_ptr->stack = NULL;
frame_ptr->func_node = NULL; /* in main */
+ frame_ptr->num_tail_calls = 0;
frame_ptr->vname = NULL;
return stack_ptr;
}
@@ -1123,9 +1137,6 @@ r_get_lhs(NODE *n, int reference)
int isparam = FALSE;
if (n->type == Node_param_list) {
- if ((n->flags & FUNC) != 0)
- fatal(_("can't use function name `%s' as variable or array"),
- n->vname);
isparam = TRUE;
n = GET_PARAM(n->param_cnt);
}
@@ -1139,11 +1150,11 @@ r_get_lhs(NODE *n, int reference)
fatal(_("attempt to use array `%s' in a scalar context"),
array_vname(n));
n->orig_array->type = Node_var;
- n->orig_array->var_value = Nnull_string;
+ n->orig_array->var_value = dupnode(Nnull_string);
/* fall through */
case Node_var_new:
n->type = Node_var;
- n->var_value = Nnull_string;
+ n->var_value = dupnode(Nnull_string);
break;
case Node_var:
@@ -1158,7 +1169,7 @@ r_get_lhs(NODE *n, int reference)
_("reference to uninitialized argument `%s'") :
_("reference to uninitialized variable `%s'")),
n->vname);
- return &n->var_value;
+ return & n->var_value;
}
@@ -1239,17 +1250,43 @@ static INSTRUCTION *
setup_frame(INSTRUCTION *pc)
{
NODE *r = NULL;
- NODE *m;
- NODE *f;
+ NODE *m, *f, *fp;
NODE **sp = NULL;
- char **varnames;
- int pcount, arg_count, i;
+ int pcount, arg_count, i, j;
+ int tail_optimize = FALSE;
f = pc->func_body;
- pcount = f->lnode->param_cnt;
- varnames = f->parmlist;
+ pcount = f->param_cnt;
+ fp = f->fparms;
arg_count = (pc + 1)->expr_count;
+#ifndef DEBUGGING
+ /* tail recursion optimization */
+ tail_optimize = (do_optimize > 1 && (pc + 1)->tail_call);
+#endif
+
+ if (tail_optimize) {
+ /* free local vars of calling frame */
+
+ NODE *func;
+ int n;
+
+ func = frame_ptr->func_node;
+ for (n = func->param_cnt, sp = frame_ptr->stack; n > 0; n--) {
+ r = *sp++;
+ if (r->type == Node_var) /* local variable */
+ DEREF(r->var_value);
+ else if (r->type == Node_var_array) /* local array */
+ assoc_clear(r);
+ }
+ sp = frame_ptr->stack;
+
+ } else if (pcount > 0) {
+ emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
+ memset(sp, 0, pcount * sizeof(NODE *));
+ }
+
+
/* check for extra args */
if (arg_count > pcount) {
warning(
@@ -1262,23 +1299,23 @@ setup_frame(INSTRUCTION *pc)
} while (--arg_count > pcount);
}
- if (pcount > 0) {
- emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
- memset(sp, 0, pcount * sizeof(NODE *));
- }
+ for (i = 0, j = arg_count - 1; i < pcount; i++, j--) {
+ if (tail_optimize)
+ r = sp[i];
+ else {
+ getnode(r);
+ memset(r, 0, sizeof(NODE));
+ sp[i] = r;
+ }
- for (i = 0; i < pcount; i++) {
- getnode(r);
- memset(r, 0, sizeof(NODE));
- sp[i] = r;
if (i >= arg_count) {
/* local variable */
r->type = Node_var_new;
- r->vname = varnames[i];
+ r->vname = fp[i].param;
continue;
}
- m = PEEK(arg_count - i - 1); /* arguments in reverse order on runtime stack */
+ m = PEEK(j); /* arguments in reverse order on runtime stack */
if (m->type == Node_param_list)
m = GET_PARAM(m->param_cnt);
@@ -1302,7 +1339,7 @@ setup_frame(INSTRUCTION *pc)
* subsequent param.
*/
r->type = Node_var;
- r->var_value = Nnull_string;
+ r->var_value = dupnode(Nnull_string);
break;
case Node_val:
@@ -1313,10 +1350,16 @@ setup_frame(INSTRUCTION *pc)
default:
cant_happen();
}
- r->vname = varnames[i];
+ r->vname = fp[i].param;
}
+
stack_adj(-arg_count); /* adjust stack pointer */
+ if (tail_optimize) {
+ frame_ptr->num_tail_calls++;
+ return f->code_ptr;
+ }
+
if (pc->opcode == Op_indirect_func_call) {
r = POP(); /* indirect var */
DEREF(r);
@@ -1335,6 +1378,7 @@ setup_frame(INSTRUCTION *pc)
frame_ptr->stack = sp;
frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the previous stack frame */
frame_ptr->func_node = f;
+ frame_ptr->num_tail_calls = 0;
frame_ptr->vname = NULL;
frame_ptr->reti = pc; /* on return execute pc->nexti */
@@ -1354,7 +1398,7 @@ restore_frame(NODE *fp)
INSTRUCTION *ri;
func = frame_ptr->func_node;
- n = func->lnode->param_cnt;
+ n = func->param_cnt;
sp = frame_ptr->stack;
for (; n > 0; n--) {
@@ -1365,6 +1409,7 @@ restore_frame(NODE *fp)
assoc_clear(r);
freenode(r);
}
+
if (frame_ptr->stack != NULL)
efree(frame_ptr->stack);
ri = frame_ptr->reti; /* execution in calling frame
@@ -1388,11 +1433,14 @@ restore_frame(NODE *fp)
static inline void
free_arrayfor(NODE *r)
{
- if (r->var_array != NULL) {
- size_t num_elems = r->table_size;
- NODE **list = r->var_array;
- while (num_elems > 0)
- unref(list[--num_elems]);
+ if (r->for_list != NULL) {
+ NODE *n;
+ size_t num_elems = r->for_list_size;
+ NODE **list = r->for_list;
+ while (num_elems > 0) {
+ n = list[--num_elems];
+ unref(n);
+ }
efree(list);
}
freenode(r);
@@ -1500,38 +1548,37 @@ cmp_scalar()
return di;
}
+
/* op_assign --- assignment operators excluding = */
static void
op_assign(OPCODE op)
{
NODE **lhs;
- NODE *r = NULL;
- AWKNUM x1, x2;
-#ifndef HAVE_FMOD
- AWKNUM x;
-#endif
+ NODE *t1;
+ AWKNUM x = 0.0, x1, x2;
lhs = POP_ADDRESS();
- x1 = force_number(*lhs);
+ t1 = *lhs;
+ x1 = force_number(t1);
TOP_NUMBER(x2);
- unref(*lhs);
+
switch (op) {
case Op_assign_plus:
- r = *lhs = make_number(x1 + x2);
+ x = x1 + x2;
break;
case Op_assign_minus:
- r = *lhs = make_number(x1 - x2);
+ x = x1 - x2;
break;
case Op_assign_times:
- r = *lhs = make_number(x1 * x2);
+ x = x1 * x2;
break;
case Op_assign_quotient:
if (x2 == (AWKNUM) 0) {
decr_sp();
fatal(_("division by zero attempted in `/='"));
}
- r = *lhs = make_number(x1 / x2);
+ x = x1 / x2;
break;
case Op_assign_mod:
if (x2 == (AWKNUM) 0) {
@@ -1539,22 +1586,29 @@ op_assign(OPCODE op)
fatal(_("division by zero attempted in `%%='"));
}
#ifdef HAVE_FMOD
- r = *lhs = make_number(fmod(x1, x2));
+ x = fmod(x1, x2);
#else /* ! HAVE_FMOD */
(void) modf(x1 / x2, &x);
x = x1 - x2 * x;
- r = *lhs = make_number(x);
#endif /* ! HAVE_FMOD */
break;
case Op_assign_exp:
- r = *lhs = make_number((AWKNUM) calc_exp((double) x1, (double) x2));
+ x = calc_exp((double) x1, (double) x2);
break;
default:
break;
}
- UPREF(r);
- REPLACE(r);
+ if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
+ /* optimization */
+ t1->numbr = x;
+ } else {
+ unref(t1);
+ t1 = *lhs = make_number(x);
+ }
+
+ UPREF(t1);
+ REPLACE(t1);
}
@@ -1661,12 +1715,10 @@ pop_exec_state(int *rule, char **src, long *sz)
/* N.B.:
* 1) reference counting done for both number and string values.
- * 2) TEMP flag no longer needed (consequence of the above; valref = 0
- * is the replacement).
- * 3) Stack operations:
+ * 2) Stack operations:
* Use REPLACE[_XX] if last stack operation was TOP[_XX],
* PUSH[_XX] if last operation was POP[_XX] instead.
- * 4) UPREF and DREF -- see awk.h
+ * 3) UPREF and DREF -- see awk.h
*/
@@ -1681,11 +1733,8 @@ r_interpret(INSTRUCTION *code)
NODE *f; /* function definition */
NODE **lhs;
AWKNUM x, x1, x2;
- int di, pre = FALSE;
+ int di;
Regexp *rp;
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG)
- int last_was_stopme = FALSE; /* builtin stopme() called ? */
-#endif
int stdio_problem = FALSE;
@@ -1695,7 +1744,7 @@ r_interpret(INSTRUCTION *code)
erealloc(args_array, NODE **, (max_args + 2)*sizeof(NODE *), "r_interpret");
/* array subscript */
-#define mk_sub(n) (n == 1 ? POP_STRING() : concat_exp(n, TRUE))
+#define mk_sub(n) (n == 1 ? POP_SCALAR() : concat_exp(n, TRUE))
#ifdef DEBUGGING
#define JUMPTO(x) do { post_execute(pc); pc = (x); goto top; } while(FALSE)
@@ -1728,7 +1777,6 @@ top:
currule = pc->in_rule; /* for sole use in Op_K_next, Op_K_nextfile, Op_K_getline* */
/* fall through */
case Op_func:
- case Op_ext_func:
source = pc->source_file;
break;
@@ -1736,7 +1784,7 @@ top:
/* avoid false source indications */
source = NULL;
sourceline = 0;
- (void) nextfile(&curfile, TRUE); /* close input data file */
+ (void) nextfile(& curfile, TRUE); /* close input data file */
/*
* This used to be:
*
@@ -1762,7 +1810,18 @@ top:
case Op_push_i:
m = pc->memory;
- PUSH((m->flags & INTLSTR) != 0 ? format_val(CONVFMT, CONVFMTidx, m): m);
+ if (! do_traditional && (m->flags & INTLSTR) != 0) {
+ char *orig, *trans, save;
+
+ save = m->stptr[m->stlen];
+ m->stptr[m->stlen] = '\0';
+ orig = m->stptr;
+ trans = dgettext(TEXTDOMAIN, orig);
+ m->stptr[m->stlen] = save;
+ m = make_string(trans, strlen(trans));
+ } else
+ UPREF(m);
+ PUSH(m);
break;
case Op_push:
@@ -1773,9 +1832,6 @@ top:
save_symbol = m = pc->memory;
if (m->type == Node_param_list) {
- if ((m->flags & FUNC) != 0)
- fatal(_("can't use function name `%s' as variable or array"),
- m->vname);
isparam = TRUE;
save_symbol = m = GET_PARAM(m->param_cnt);
if (m->type == Node_array_ref)
@@ -1796,13 +1852,14 @@ top:
case Node_var_new:
m->type = Node_var;
- m->var_value = Nnull_string;
+ m->var_value = dupnode(Nnull_string);
if (do_lint)
lintwarn(isparam ?
_("reference to uninitialized argument `%s'") :
_("reference to uninitialized variable `%s'"),
save_symbol->vname);
- PUSH(Nnull_string);
+ m = dupnode(Nnull_string);
+ PUSH(m);
break;
case Node_var_array:
@@ -1843,7 +1900,16 @@ top:
case Op_subscript:
t2 = mk_sub(pc->sub_count);
t1 = POP_ARRAY();
- r = *assoc_lookup(t1, t2, TRUE);
+
+ if (do_lint && in_array(t1, t2) == NULL) {
+ t2 = force_string(t2);
+ lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
+ array_vname(t1), (int) t2->stlen, t2->stptr);
+ if (t2->stlen == 0)
+ lintwarn(_("subscript of array `%s' is null string"), array_vname(t1));
+ }
+
+ r = *assoc_lookup(t1, t2);
DEREF(t2);
if (r->type == Node_val)
UPREF(r);
@@ -1855,15 +1921,17 @@ top:
t1 = POP_ARRAY();
r = in_array(t1, t2);
if (r == NULL) {
- getnode(r);
- r->type = Node_var_array;
- r->var_array = NULL;
- r->vname = estrdup(t2->stptr, t2->stlen); /* the subscript in parent array */
+ r = make_array();
r->parent_array = t1;
- *assoc_lookup(t1, t2, FALSE) = r;
- } else if (r->type != Node_var_array)
+ *assoc_lookup(t1, t2) = r;
+ t2 = force_string(t2);
+ r->vname = estrdup(t2->stptr, t2->stlen); /* the subscript in parent array */
+ } else if (r->type != Node_var_array) {
+ t2 = force_string(t2);
fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"),
array_vname(t1), (int) t2->stlen, t2->stptr);
+ }
+
DEREF(t2);
PUSH(r);
break;
@@ -1871,10 +1939,22 @@ top:
case Op_subscript_lhs:
t2 = mk_sub(pc->sub_count);
t1 = POP_ARRAY();
- lhs = assoc_lookup(t1, t2, pc->do_reference);
- if ((*lhs)->type == Node_var_array)
+ if (do_lint && in_array(t1, t2) == NULL) {
+ t2 = force_string(t2);
+ if (pc->do_reference)
+ lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
+ array_vname(t1), (int) t2->stlen, t2->stptr);
+ if (t2->stlen == 0)
+ lintwarn(_("subscript of array `%s' is null string"), array_vname(t1));
+ }
+
+ lhs = assoc_lookup(t1, t2);
+ if ((*lhs)->type == Node_var_array) {
+ t2 = force_string(t2);
fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
array_vname(t1), (int) t2->stlen, t2->stptr);
+ }
+
DEREF(t2);
PUSH_ADDRESS(lhs);
break;
@@ -1884,10 +1964,6 @@ top:
lhs = r_get_field(t1, (Func_ptr *) 0, TRUE);
decr_sp();
DEREF(t1);
- /* This used to look like this:
- PUSH(dupnode(*lhs));
- but was changed to bypass an apparent bug in the z/OS C compiler.
- Please do not remerge. */
r = dupnode(*lhs); /* can't use UPREF here */
PUSH(r);
break;
@@ -1960,7 +2036,7 @@ top:
break;
case Op_not:
- t1 = TOP_SCALAR();
+ t1 = TOP_SCALAR();
r = make_number((AWKNUM) ! eval_condition(t1));
DEREF(t1);
REPLACE(r);
@@ -2083,27 +2159,38 @@ mod:
break;
case Op_preincrement:
- pre = TRUE;
- case Op_postincrement:
- x2 = 1.0;
-post:
+ case Op_predecrement:
+ x2 = pc->opcode == Op_preincrement ? 1.0 : -1.0;
lhs = TOP_ADDRESS();
- x1 = force_number(*lhs);
- unref(*lhs);
- r = *lhs = make_number(x1 + x2);
- if (pre)
- UPREF(r);
- else
- r = make_number(x1);
- REPLACE(r);
- pre = FALSE;
- break;
+ t1 = *lhs;
+ x1 = force_number(t1);
+ if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
+ /* optimization */
+ t1->numbr = x1 + x2;
+ } else {
+ unref(t1);
+ t1 = *lhs = make_number(x1 + x2);
+ }
+ UPREF(t1);
+ REPLACE(t1);
+ break;
- case Op_predecrement:
- pre = TRUE;
+ case Op_postincrement:
case Op_postdecrement:
- x2 = -1.0;
- goto post;
+ x2 = pc->opcode == Op_postincrement ? 1.0 : -1.0;
+ lhs = TOP_ADDRESS();
+ t1 = *lhs;
+ x1 = force_number(t1);
+ if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
+ /* optimization */
+ t1->numbr = x1 + x2;
+ } else {
+ unref(t1);
+ *lhs = make_number(x1 + x2);
+ }
+ r = make_number(x1);
+ REPLACE(r);
+ break;
case Op_unary_minus:
TOP_NUMBER(x1);
@@ -2117,10 +2204,12 @@ post:
*/
t1 = get_array(pc->memory, TRUE); /* array */
t2 = mk_sub(pc->expr_count); /* subscript */
- lhs = assoc_lookup(t1, t2, FALSE);
- if ((*lhs)->type == Node_var_array)
+ lhs = assoc_lookup(t1, t2);
+ if ((*lhs)->type == Node_var_array) {
+ t2 = force_string(t2);
fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
array_vname(t1), (int) t2->stlen, t2->stptr);
+ }
DEREF(t2);
unref(*lhs);
*lhs = POP_SCALAR();
@@ -2133,7 +2222,13 @@ post:
lhs = get_lhs(pc->memory, FALSE);
unref(*lhs);
- *lhs = POP_SCALAR();
+ r = pc->initval; /* constant initializer */
+ if (r == NULL)
+ *lhs = POP_SCALAR();
+ else {
+ UPREF(r);
+ *lhs = r;
+ }
break;
case Op_store_field:
@@ -2162,12 +2257,19 @@ post:
free_wstr(*lhs);
- if (t1 != t2 && t1->valref == 1 && (t1->flags & PERM) == 0) {
+ if (t1 != *lhs) {
+ unref(*lhs);
+ *lhs = dupnode(t1);
+ }
+
+ if (t1 != t2 && t1->valref == 1) {
size_t nlen = t1->stlen + t2->stlen;
+
erealloc(t1->stptr, char *, nlen + 2, "r_interpret");
memcpy(t1->stptr + t1->stlen, t2->stptr, t2->stlen);
t1->stlen = nlen;
t1->stptr[nlen] = '\0';
+ t1->flags &= ~(NUMCUR|NUMBER|NUMINT);
} else {
size_t nlen = t1->stlen + t2->stlen;
char *p;
@@ -2176,9 +2278,8 @@ post:
memcpy(p, t1->stptr, t1->stlen);
memcpy(p + t1->stlen, t2->stptr, t2->stlen);
unref(*lhs);
- t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED);
+ t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED);
}
- t1->flags &= ~(NUMCUR|NUMBER);
DEREF(t2);
break;
@@ -2239,9 +2340,10 @@ post:
case Op_K_case:
if ((pc + 1)->match_exp) {
/* match a constant regex against switch expression instead of $0. */
+
m = POP(); /* regex */
t2 = TOP_SCALAR(); /* switch expression */
- (void) force_string(t2);
+ t2 = force_string(t2);
rp = re_update(m);
di = (research(rp, t2->stptr, 0, t2->stlen,
avoid_dfa(m, t2->stptr, t2->stlen)) >= 0);
@@ -2252,8 +2354,10 @@ post:
DEREF(t1);
}
- if (di) { /* match found */
- decr_sp();
+ if (di) {
+ /* match found */
+
+ t2 = POP_SCALAR();
DEREF(t2);
JUMPTO(pc->target_jmp);
}
@@ -2291,7 +2395,7 @@ post:
array = POP_ARRAY();
/* sanity: check if empty */
- if (array->var_array == NULL || array->table_size == 0)
+ if (array_empty(array))
goto arrayfor;
num_elems = array->table_size;
@@ -2315,18 +2419,13 @@ post:
list = assoc_list(array, how_to_sort, SORTED_IN);
- /*
- * Actual array for use in lint warning
- * in Op_arrayfor_incr
- */
- list[num_elems] = array;
-
arrayfor:
getnode(r);
r->type = Node_arrayfor;
- r->var_array = list;
- r->table_size = num_elems; /* # of elements in list */
- r->array_size = -1; /* current index */
+ r->for_list = list;
+ r->for_list_size = num_elems; /* # of elements in list */
+ r->cur_idx = -1; /* current index */
+ r->for_array = array; /* array */
PUSH(r);
if (num_elems == 0)
@@ -2336,20 +2435,20 @@ arrayfor:
case Op_arrayfor_incr:
r = TOP(); /* Node_arrayfor */
- if (++r->array_size == r->table_size) {
+ if (++r->cur_idx == r->for_list_size) {
NODE *array;
- array = r->var_array[r->table_size]; /* actual array */
- if (do_lint && array->table_size != r->table_size)
+ array = r->for_array; /* actual array */
+ if (do_lint && array->table_size != r->for_list_size)
lintwarn(_("for loop: array `%s' changed size from %ld to %ld during loop execution"),
- array_vname(array), (long) r->table_size, (long) array->table_size);
+ array_vname(array), (long) r->for_list_size, (long) array->table_size);
JUMPTO(pc->target_jmp); /* Op_arrayfor_final */
}
- t1 = r->var_array[r->array_size];
+ t1 = r->for_list[r->cur_idx];
lhs = get_lhs(pc->array_var, FALSE);
unref(*lhs);
- *lhs = make_string(t1->ahname_str, t1->ahname_len);
- break;
+ *lhs = dupnode(t1);
+ break;
case Op_arrayfor_final:
r = POP();
@@ -2359,12 +2458,23 @@ arrayfor:
case Op_builtin:
r = pc->builtin(pc->expr_count);
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG)
- if (! r)
- last_was_stopme = TRUE;
- else
-#endif
- PUSH(r);
+ PUSH(r);
+ break;
+
+ case Op_ext_builtin:
+ {
+ int arg_count = pc->expr_count;
+
+ PUSH_CODE(pc);
+ r = pc->builtin(arg_count);
+ (void) POP_CODE();
+ while (arg_count-- > 0) {
+ t1 = POP();
+ if (t1->type == Node_val)
+ DEREF(t1);
+ }
+ PUSH(r);
+ }
break;
case Op_sub_builtin: /* sub, gsub and gensub */
@@ -2444,18 +2554,21 @@ match_re:
arg_count = (pc + 1)->expr_count;
t1 = PEEK(arg_count); /* indirect var */
assert(t1->type == Node_val); /* @a[1](p) not allowed in grammar */
- (void) force_string(t1);
+ t1 = force_string(t1);
if (t1->stlen > 0) {
/* retrieve function definition node */
f = pc->func_body;
- if (f != NULL && STREQ(f->vname, t1->stptr))
+ if (f != NULL && STREQ(f->vname, t1->stptr)) {
/* indirect var hasn't been reassigned */
+
goto func_call;
+ }
f = lookup(t1->stptr);
}
if (f == NULL || f->type != Node_func)
- fatal(_("function called indirectly through `%s' does not exist"), pc->func_name);
+ fatal(_("function called indirectly through `%s' does not exist"),
+ pc->func_name);
pc->func_body = f; /* save for next call */
goto func_call;
@@ -2466,26 +2579,32 @@ match_re:
f = pc->func_body;
if (f == NULL) {
f = lookup(pc->func_name);
- if (f == NULL || f->type != Node_func)
+ if (f == NULL || (f->type != Node_func && f->type != Node_ext_func))
fatal(_("function `%s' not defined"), pc->func_name);
pc->func_body = f; /* save for next call */
}
- /* save current frame along with source */
+ if (f->type == Node_ext_func) {
+ INSTRUCTION *bc;
+ char *fname = pc->func_name;
+ int arg_count = (pc + 1)->expr_count;
+
+ bc = f->code_ptr;
+ assert(bc->opcode == Op_symbol);
+ pc->opcode = Op_ext_builtin; /* self modifying code */
+ pc->builtin = bc->builtin;
+ pc->expr_count = arg_count; /* actual argument count */
+ (pc + 1)->func_name = fname; /* name of the builtin */
+ (pc + 1)->expr_count = bc->expr_count; /* defined max # of arguments */
+ ni = pc;
+ JUMPTO(ni);
+ }
func_call:
ni = setup_frame(pc);
- if (ni->opcode == Op_ext_func) {
- /* dynamically set source and line numbers for an extension builtin. */
- ni->source_file = source;
- ni->source_line = sourceline;
- ni->nexti->source_line = sourceline; /* Op_builtin */
- ni->nexti->nexti->source_line = sourceline; /* Op_K_return */
- }
-
/* run the function instructions */
- JUMPTO(ni); /* Op_func or Op_ext_func */
+ JUMPTO(ni); /* Op_func */
case Op_K_return:
m = POP_SCALAR(); /* return value */
@@ -2703,15 +2822,8 @@ func_call:
JUMPTO(pc->target_jmp); /* Op_get_record, read next record */
case Op_pop:
-#if defined(GAWKDEBUG) || defined(ARRAYDEBUG)
- if (last_was_stopme)
- last_was_stopme = FALSE;
- else
-#endif
- {
- r = POP_SCALAR();
- DEREF(r);
- }
+ r = POP_SCALAR();
+ DEREF(r);
break;
case Op_line_range:
@@ -2740,7 +2852,7 @@ func_call:
}
result = ip->triggered || di;
- ip->triggered ^= di; /* update triggered flag */
+ ip->triggered ^= di; /* update triggered flag */
r = make_number((AWKNUM) result); /* final value of condition pair */
REPLACE(r);
JUMPTO(pc->target_jmp);
diff --git a/ext.c b/ext.c
index f0290f99..19e0eec5 100644
--- a/ext.c
+++ b/ext.c
@@ -50,9 +50,6 @@ do_ext(int nargs)
int flags = RTLD_LAZY;
int fatal_error = FALSE;
int *gpl_compat;
-#if 0
- static short warned = FALSE;
-#endif
#ifdef __GNUC__
AWKNUM junk;
@@ -63,14 +60,6 @@ do_ext(int nargs)
if (do_sandbox)
fatal(_("extensions are not allowed in sandbox mode"));
-#if 0
- /* already done in parser */
- if (do_lint && ! warned) {
- warned = TRUE;
- lintwarn(_("`extension' is a gawk extension"));
- }
-#endif
-
if (do_traditional || do_posix)
error(_("`extension' is a gawk extension"));
@@ -97,7 +86,6 @@ do_ext(int nargs)
goto done;
}
-
func = (NODE *(*)(NODE *, void *)) dlsym(dl, fun->stptr);
if (func == NULL) {
msg(_("fatal: extension: library `%s': cannot call function `%s' (%s)\n"),
@@ -108,7 +96,7 @@ do_ext(int nargs)
tmp = (*func)(obj, dl);
if (tmp == NULL)
- tmp = Nnull_string;
+ tmp = dupnode(Nnull_string);
done:
DEREF(obj);
DEREF(fun);
@@ -123,14 +111,10 @@ done:
void
make_builtin(const char *name, NODE *(*func)(int), int count)
{
- NODE *p, *symbol, *f;
- INSTRUCTION *b, *r;
+ NODE *symbol, *f;
+ INSTRUCTION *b;
const char *sp;
- char *pname;
- char **vnames = NULL;
- char c, buf[200];
- size_t space_needed;
- int i;
+ char c;
sp = name;
if (sp == NULL || *sp == '\0')
@@ -146,126 +130,79 @@ make_builtin(const char *name, NODE *(*func)(int), int count)
if (f != NULL) {
if (f->type == Node_func) {
- INSTRUCTION *pc = f->code_ptr;
- if (pc->opcode != Op_ext_func) /* user-defined function */
- fatal(_("extension: can't redefine function `%s'"), name);
- else {
- /* multiple extension() calls etc. */
- if (do_lint)
- lintwarn(_("extension: function `%s' already defined"), name);
- return;
- }
+ /* user-defined function */
+ fatal(_("extension: can't redefine function `%s'"), name);
+ } else if (f->type == Node_ext_func) {
+ /* multiple extension() calls etc. */
+ if (do_lint)
+ lintwarn(_("extension: function `%s' already defined"), name);
+ return;
} else
/* variable name etc. */
fatal(_("extension: function name `%s' previously defined"), name);
} else if (check_special(name) >= 0)
fatal(_("extension: can't use gawk built-in `%s' as function name"), name);
- /* count parameters, create artificial list of param names */
if (count < 0)
fatal(_("make_builtin: negative argument count for function `%s'"),
- name);
-
- if (count > 0) {
- sprintf(buf, "p%d", count);
- space_needed = strlen(buf) + 1;
- emalloc(vnames, char **, count * sizeof(char *), "make_builtin");
- for (i = 0; i < count; i++) {
- emalloc(pname, char *, space_needed, "make_builtin");
- sprintf(pname, "p%d", i);
- vnames[i] = pname;
- }
- }
+ name);
-
- getnode(p);
- p->type = Node_param_list;
- p->flags |= FUNC;
- /* get our own copy for name */
- p->param = estrdup(name, strlen(name));
- p->param_cnt = count;
-
- /* actual source and line numbers set at runtime for these instructions */
- b = bcalloc(Op_builtin, 1, __LINE__);
+ b = bcalloc(Op_symbol, 1, 0);
b->builtin = func;
b->expr_count = count;
- b->nexti = bcalloc(Op_K_return, 1, __LINE__);
- r = bcalloc(Op_ext_func, 1, __LINE__);
- r->source_file = __FILE__;
- r->nexti = b;
/* NB: extension sub must return something */
- symbol = mk_symbol(Node_func, p);
- symbol->parmlist = vnames;
- symbol->code_ptr = r;
- r->func_body = symbol;
- (void) install_symbol(p->param, symbol);
-}
-
-
-/* get_curfunc_arg_count --- return number actual parameters */
-
-size_t
-get_curfunc_arg_count()
-{
- size_t argc;
- INSTRUCTION *pc;
-
- pc = (INSTRUCTION *) frame_ptr->reti; /* Op_func_call instruction */
- argc = (pc + 1)->expr_count; /* # of arguments supplied */
- return argc;
+ symbol = install_symbol(estrdup(name, strlen(name)), Node_ext_func);
+ symbol->code_ptr = b;
}
-/* get_argument --- get the n'th argument of a dynamically linked function */
+/* get_argument --- get the i'th argument of a dynamically linked function */
NODE *
get_argument(int i)
{
- int pcount;
- NODE *t, *f;
- int actual_args;
+ NODE *t;
+ int arg_count, pcount;
INSTRUCTION *pc;
- f = frame_ptr->func_node;
- pcount = f->lnode->param_cnt;
+ pc = TOP()->code_ptr; /* Op_ext_builtin instruction */
+ pcount = (pc + 1)->expr_count; /* max # of arguments */
+ arg_count = pc->expr_count; /* # of arguments supplied */
- pc = (INSTRUCTION *) frame_ptr->reti; /* Op_func_call instruction */
- actual_args = (pc + 1)->expr_count; /* # of arguments supplied */
-
- if (i < 0 || i >= pcount || i >= actual_args)
+ if (i < 0 || i >= pcount || i >= arg_count)
return NULL;
-
- t = GET_PARAM(i);
-
+ i++;
+ t = PEEK(i);
if (t->type == Node_array_ref)
- return t->orig_array; /* Node_var_new or Node_var_array */
- if (t->type == Node_var_new || t->type == Node_var_array)
- return t;
- return t->var_value;
+ t = t->orig_array;
+ if (t->type == Node_var) /* See Case Node_var in setup_frame(), eval.c */
+ return Nnull_string;
+ /* Node_var_new, Node_var_array or Node_val */
+ return t;
}
-/* get_actual_argument --- get a scalar or array, allowed to be optional */
+/* get_actual_argument --- get the i'th scalar or array argument of a
+ dynamically linked function, allowed to be optional.
+*/
NODE *
get_actual_argument(int i, int optional, int want_array)
{
- /* optional : if TRUE and i th argument not present return NULL, else fatal. */
-
- NODE *t, *f;
- int pcount;
+ NODE *t;
char *fname;
-
+ int pcount;
+ INSTRUCTION *pc;
+
+ pc = TOP()->code_ptr; /* Op_ext_builtin instruction */
+ fname = (pc + 1)->func_name;
+ pcount = (pc + 1)->expr_count;
+
t = get_argument(i);
-
- f = frame_ptr->func_node;
- pcount = f->lnode->param_cnt;
- fname = f->lnode->param;
-
if (t == NULL) {
- if (i >= pcount) /* must be fatal */
+ if (i >= pcount) /* must be fatal */
fatal(_("function `%s' defined to take no more than %d argument(s)"),
fname, pcount);
if (! optional)
@@ -279,8 +216,8 @@ get_actual_argument(int i, int optional, int want_array)
return get_array(t, FALSE);
else {
t->type = Node_var;
- t->var_value = Nnull_string;
- return Nnull_string;
+ t->var_value = dupnode(Nnull_string);
+ return t->var_value;
}
}
@@ -293,6 +230,7 @@ get_actual_argument(int i, int optional, int want_array)
fatal(_("function `%s': argument #%d: attempt to use array as a scalar"),
fname, i + 1);
}
+ assert(t->type == Node_var_array || t->type == Node_val);
return t;
}
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 8aaeb418..dff4cf67 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,7 @@
+2011-08-31 John Haque <j.eh@mchsi.com>
+ * arrayparm.c, filefuncs.c, fork.c, ordchr.c, readfile.c,
+ rwarray.c, testarg.c: Updated.
+
2011-06-23 Arnold D. Robbins <arnold@skeeve.com>
* ChangeLog.0: Rotated ChangeLog into this file.
diff --git a/extension/arrayparm.c b/extension/arrayparm.c
index 8a550ace..b0aee33d 100644
--- a/extension/arrayparm.c
+++ b/extension/arrayparm.c
@@ -43,13 +43,13 @@ int plugin_is_GPL_compatible;
*/
static NODE *
-do_mkarray(int args)
+do_mkarray(int nargs)
{
int ret = -1;
NODE *var, *sub, *val;
NODE **elemval;
- if (do_lint && get_curfunc_arg_count() > 3)
+ if (do_lint && nargs > 3)
lintwarn("mkarray: called with too many arguments");
var = get_array_argument(0, FALSE);
@@ -60,9 +60,9 @@ do_mkarray(int args)
printf("sub->type = %s\n", nodetype2str(sub->type));
printf("val->type = %s\n", nodetype2str(val->type));
- assoc_clear(var);
+ assoc_clear(var, NULL);
- elemval = assoc_lookup(var, sub, 0);
+ elemval = assoc_lookup(var, sub);
*elemval = dupnode(val);
ret = 0;
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index ad7828f3..1a0a86ef 100644
--- a/extension/filefuncs.c
+++ b/extension/filefuncs.c
@@ -41,7 +41,7 @@ do_chdir(int nargs)
NODE *newdir;
int ret = -1;
- if (do_lint && get_curfunc_arg_count() != 1)
+ if (do_lint && nargs != 1)
lintwarn("chdir: called with incorrect number of arguments");
newdir = get_scalar_argument(0, FALSE);
@@ -169,7 +169,7 @@ do_stat(int nargs)
char *pmode; /* printable mode */
char *type = "unknown";
- if (do_lint && get_curfunc_arg_count() > 2)
+ if (do_lint && nargs > 2)
lintwarn("stat: called with too many arguments");
/* file is first arg, array to hold results is second */
@@ -177,7 +177,7 @@ do_stat(int nargs)
array = get_array_argument(1, FALSE);
/* empty out the array */
- assoc_clear(array);
+ assoc_clear(array, NULL);
/* lstat the file, if error, set ERRNO and return */
(void) force_string(file);
@@ -188,76 +188,76 @@ do_stat(int nargs)
}
/* fill in the array */
- aptr = assoc_lookup(array, tmp = make_string("name", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("name", 4));
*aptr = dupnode(file);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("dev", 3), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("dev", 3));
*aptr = make_number((AWKNUM) sbuf.st_dev);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("ino", 3), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("ino", 3));
*aptr = make_number((AWKNUM) sbuf.st_ino);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("mode", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("mode", 4));
*aptr = make_number((AWKNUM) sbuf.st_mode);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("nlink", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("nlink", 5));
*aptr = make_number((AWKNUM) sbuf.st_nlink);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("uid", 3), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("uid", 3));
*aptr = make_number((AWKNUM) sbuf.st_uid);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("gid", 3), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("gid", 3));
*aptr = make_number((AWKNUM) sbuf.st_gid);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("size", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("size", 4));
*aptr = make_number((AWKNUM) sbuf.st_size);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("blocks", 6), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("blocks", 6));
*aptr = make_number((AWKNUM) sbuf.st_blocks);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("atime", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("atime", 5));
*aptr = make_number((AWKNUM) sbuf.st_atime);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("mtime", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("mtime", 5));
*aptr = make_number((AWKNUM) sbuf.st_mtime);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("ctime", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("ctime", 5));
*aptr = make_number((AWKNUM) sbuf.st_ctime);
unref(tmp);
/* for block and character devices, add rdev, major and minor numbers */
if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
- aptr = assoc_lookup(array, tmp = make_string("rdev", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("rdev", 4));
*aptr = make_number((AWKNUM) sbuf.st_rdev);
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("major", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("major", 5));
*aptr = make_number((AWKNUM) major(sbuf.st_rdev));
unref(tmp);
- aptr = assoc_lookup(array, tmp = make_string("minor", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("minor", 5));
*aptr = make_number((AWKNUM) minor(sbuf.st_rdev));
unref(tmp);
}
#ifdef HAVE_ST_BLKSIZE
- aptr = assoc_lookup(array, tmp = make_string("blksize", 7), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("blksize", 7));
*aptr = make_number((AWKNUM) sbuf.st_blksize);
unref(tmp);
#endif /* HAVE_ST_BLKSIZE */
- aptr = assoc_lookup(array, tmp = make_string("pmode", 5), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("pmode", 5));
pmode = format_mode(sbuf.st_mode);
*aptr = make_string(pmode, strlen(pmode));
unref(tmp);
@@ -277,7 +277,7 @@ do_stat(int nargs)
*/
buf[linksize] = '\0';
- aptr = assoc_lookup(array, tmp = make_string("linkval", 7), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("linkval", 7));
*aptr = make_str_node(buf, linksize, ALREADY_MALLOCED);
unref(tmp);
}
@@ -319,7 +319,7 @@ do_stat(int nargs)
#endif
}
- aptr = assoc_lookup(array, tmp = make_string("type", 4), FALSE);
+ aptr = assoc_lookup(array, tmp = make_string("type", 4));
*aptr = make_string(type, strlen(type));
unref(tmp);
diff --git a/extension/fork.c b/extension/fork.c
index aff9b568..88353879 100644
--- a/extension/fork.c
+++ b/extension/fork.c
@@ -38,7 +38,7 @@ do_fork(int nargs)
NODE **aptr;
NODE *tmp;
- if (do_lint && get_curfunc_arg_count() > 0)
+ if (do_lint && nargs > 0)
lintwarn("fork: called with too many arguments");
ret = fork();
@@ -48,11 +48,11 @@ do_fork(int nargs)
else if (ret == 0) {
/* update PROCINFO in the child */
- aptr = assoc_lookup(PROCINFO_node, tmp = make_string("pid", 3), FALSE);
+ aptr = assoc_lookup(PROCINFO_node, tmp = make_string("pid", 3));
(*aptr)->numbr = (AWKNUM) getpid();
unref(tmp);
- aptr = assoc_lookup(PROCINFO_node, tmp = make_string("ppid", 4), FALSE);
+ aptr = assoc_lookup(PROCINFO_node, tmp = make_string("ppid", 4));
(*aptr)->numbr = (AWKNUM) getppid();
unref(tmp);
}
@@ -73,7 +73,7 @@ do_waitpid(int nargs)
pid_t pid;
int options = 0;
- if (do_lint && get_curfunc_arg_count() > 1)
+ if (do_lint && nargs > 1)
lintwarn("waitpid: called with too many arguments");
pidnode = get_scalar_argument(0, FALSE);
diff --git a/extension/ordchr.c b/extension/ordchr.c
index efbc6d56..8926a949 100644
--- a/extension/ordchr.c
+++ b/extension/ordchr.c
@@ -40,7 +40,7 @@ do_ord(int nargs)
NODE *str;
int ret = -1;
- if (do_lint && get_curfunc_arg_count() > 1)
+ if (do_lint && nargs > 1)
lintwarn("ord: called with too many arguments");
str = get_scalar_argument(0, FALSE);
@@ -67,7 +67,7 @@ do_chr(int nargs)
str[0] = str[1] = '\0';
- if (do_lint && get_curfunc_arg_count() > 1)
+ if (do_lint && nargs > 1)
lintwarn("chr: called with too many arguments");
num = get_scalar_argument(0, FALSE);
diff --git a/extension/readfile.c b/extension/readfile.c
index e6ee0f22..c9b1efc3 100644
--- a/extension/readfile.c
+++ b/extension/readfile.c
@@ -50,7 +50,7 @@ do_readfile(int nargs)
char *text;
int fd;
- if (do_lint && get_curfunc_arg_count() > 1)
+ if (do_lint && nargs > 1)
lintwarn("readfile: called with too many arguments");
filename = get_scalar_argument(0, FALSE);
diff --git a/extension/rwarray.c b/extension/rwarray.c
index 3c629579..8175c7c0 100644
--- a/extension/rwarray.c
+++ b/extension/rwarray.c
@@ -82,7 +82,7 @@ do_writea(int nargs)
uint32_t major = MAJOR;
uint32_t minor = MINOR;
- if (do_lint && get_curfunc_arg_count() > 2)
+ if (do_lint && nargs > 2)
lintwarn("writea: called with too many arguments");
/* directory is first arg, array to dump is second */
@@ -250,7 +250,7 @@ do_reada(int nargs)
uint32_t minor;
char magic_buf[30];
- if (do_lint && get_curfunc_arg_count() > 2)
+ if (do_lint && nargs > 2)
lintwarn("reada: called with too many arguments");
/* directory is first arg, array to dump is second */
@@ -289,7 +289,7 @@ do_reada(int nargs)
goto done1;
}
- assoc_clear(array);
+ assoc_clear(array, NULL);
ret = read_array(fd, array);
if (ret == 0)
diff --git a/extension/testarg.c b/extension/testarg.c
index ba4d56ff..4d012db5 100644
--- a/extension/testarg.c
+++ b/extension/testarg.c
@@ -5,17 +5,15 @@ int plugin_is_GPL_compatible;
static NODE *
do_check_arg(int nargs)
{
- int ret = 0, argc;
+ int ret = 0;
NODE *arg1, *arg2, *arg3;
- argc = get_curfunc_arg_count();
- printf("arg count: defined = %d, supplied = %d\n",
- nargs, argc);
+ printf("arg count: defined = 3, supplied = %d\n", nargs);
arg1 = get_scalar_argument(0, FALSE);
arg2 = get_array_argument(1, FALSE);
arg3 = get_scalar_argument(2, TRUE); /* optional */
- if (argc > 3) {
+ if (nargs > 3) {
/* try to use an extra arg */
NODE *arg4;
arg4 = get_array_argument(3, TRUE);
diff --git a/field.c b/field.c
index 2e7c1505..91789d2f 100644
--- a/field.c
+++ b/field.c
@@ -85,13 +85,13 @@ void
init_fields()
{
emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
- fields_arr[0] = Nnull_string;
+ fields_arr[0] = dupnode(Nnull_string);
parse_extent = fields_arr[0]->stptr;
save_FS = dupnode(FS_node->var_value);
getnode(Null_field);
*Null_field = *Nnull_string;
- Null_field->flags |= FIELD;
- Null_field->flags &= ~(NUMCUR|NUMBER|MAYBE_NUM|PERM|MALLOC);
+ Null_field->valref = 1;
+ Null_field->flags = (FIELD|STRCUR|STRING);
field0_valid = TRUE;
}
@@ -207,7 +207,7 @@ rebuild_record()
}
} else {
*n = *(fields_arr[i]);
- n->flags &= ~(MALLOC|PERM|STRING);
+ n->flags &= ~(MALLOC|STRING);
}
n->stptr = cops;
@@ -289,7 +289,7 @@ reset_record()
int i;
NODE *n;
- (void) force_string(fields_arr[0]);
+ fields_arr[0] = force_string(fields_arr[0]);
NF = -1;
for (i = 1; i <= parse_high_water; i++) {
@@ -927,7 +927,7 @@ set_element(long num, char *s, long len, NODE *n)
it = make_string(s, len);
it->flags |= MAYBE_NUM;
sub = make_number((AWKNUM) (num));
- lhs = assoc_lookup(n, sub, FALSE);
+ lhs = assoc_lookup(n, sub);
unref(sub);
unref(*lhs);
*lhs = it;
@@ -988,8 +988,8 @@ do_split(int nargs)
/*
* Skip the work if first arg is the null string.
*/
- decr_sp();
- DEREF(src);
+ tmp = POP_SCALAR();
+ DEREF(tmp);
return make_number((AWKNUM) 0);
}
@@ -1027,7 +1027,7 @@ do_split(int nargs)
tmp = make_number((AWKNUM) (*parseit)(UNLIMITED, &s, (int) src->stlen,
fs, rp, set_element, arr, sep_arr, FALSE));
- decr_sp();
+ src = POP_SCALAR(); /* really pop off stack */
DEREF(src);
return tmp;
}
@@ -1088,7 +1088,7 @@ do_patsplit(int nargs)
set_element, arr, sep_arr, FALSE));
}
- decr_sp(); /* 1st argument not POP-ed */
+ src = POP_SCALAR(); /* really pop off stack */
DEREF(src);
return tmp;
}
@@ -1104,6 +1104,7 @@ set_FIELDWIDTHS()
static int fw_alloc = 4;
static short warned = FALSE;
int fatal_error = FALSE;
+ NODE *tmp;
if (do_lint && ! warned) {
warned = TRUE;
@@ -1120,7 +1121,8 @@ set_FIELDWIDTHS()
(void) get_field(UNLIMITED - 1, 0);
parse_field = fw_parse_field;
- scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
+ tmp = force_string(FIELDWIDTHS_node->var_value);
+ scan = tmp->stptr;
if (FIELDWIDTHS == NULL)
emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
@@ -1331,7 +1333,7 @@ update_PROCINFO_str(const char *subscript, const char *str)
if (PROCINFO_node == NULL)
return;
tmp = make_string(subscript, strlen(subscript));
- aptr = assoc_lookup(PROCINFO_node, tmp, FALSE);
+ aptr = assoc_lookup(PROCINFO_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(str, strlen(str));
@@ -1348,7 +1350,7 @@ update_PROCINFO_num(const char *subscript, AWKNUM val)
if (PROCINFO_node == NULL)
return;
tmp = make_string(subscript, strlen(subscript));
- aptr = assoc_lookup(PROCINFO_node, tmp, FALSE);
+ aptr = assoc_lookup(PROCINFO_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_number(val);
diff --git a/int_array.c b/int_array.c
new file mode 100644
index 00000000..fd58de26
--- /dev/null
+++ b/int_array.c
@@ -0,0 +1,826 @@
+/*
+ * int_array.c - routines for arrays of integer indices.
+ */
+
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-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
+ */
+
+#include "awk.h"
+
+extern FILE *output_fp;
+extern void indent(int indent_level);
+extern NODE **is_integer(NODE *symbol, NODE *subs);
+
+static size_t INT_CHAIN_MAX = 2;
+
+static NODE **int_array_init(NODE *symbol, NODE *subs);
+static NODE **int_lookup(NODE *symbol, NODE *subs);
+static NODE **int_exists(NODE *symbol, NODE *subs);
+static NODE **int_clear(NODE *symbol, NODE *subs);
+static NODE **int_remove(NODE *symbol, NODE *subs);
+static NODE **int_list(NODE *symbol, NODE *t);
+static NODE **int_copy(NODE *symbol, NODE *newsymb);
+static NODE **int_dump(NODE *symbol, NODE *ndump);
+
+#ifdef ARRAYDEBUG
+static NODE **int_option(NODE *opt, NODE *val);
+#endif
+
+static uint32_t int_hash(uint32_t k, uint32_t hsize);
+static inline NODE **int_find(NODE *symbol, long k, uint32_t hash1);
+static NODE **int_insert(NODE *symbol, long k, uint32_t hash1);
+static void grow_int_table(NODE *symbol);
+
+array_ptr int_array_func[] = {
+ int_array_init,
+ is_integer,
+ int_lookup,
+ int_exists,
+ int_clear,
+ int_remove,
+ int_list,
+ int_copy,
+ int_dump,
+#ifdef ARRAYDEBUG
+ int_option,
+#endif
+};
+
+
+/* int_array_init --- check relevant environment variables */
+
+static NODE **
+int_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
+{
+ long newval;
+
+ if ((newval = getenv_long("INT_CHAIN_MAX")) > 0)
+ INT_CHAIN_MAX = newval;
+ return (NODE **) ! NULL;
+}
+
+
+/* is_integer --- check if subscript is an integer */
+
+NODE **
+is_integer(NODE *symbol, NODE *subs)
+{
+ long l;
+ AWKNUM d;
+
+ if (subs == Nnull_string)
+ return NULL;
+
+ if ((subs->flags & NUMINT) != 0)
+ return (NODE **) ! NULL;
+
+ if ((subs->flags & NUMBER) != 0) {
+ d = subs->numbr;
+ if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) {
+ subs->flags |= NUMINT;
+ return (NODE **) ! NULL;
+ }
+ return NULL;
+ }
+
+ /* a[3]=1; print "3" in a -- TRUE
+ * a[3]=1; print "+3" in a -- FALSE
+ * a[3]=1; print "03" in a -- FALSE
+ * a[-3]=1; print "-3" in a -- TRUE
+ */
+
+ if ((subs->flags & (STRING|STRCUR)) != 0) {
+ char *cp = subs->stptr, *cpend, *ptr;
+ char save;
+ size_t len = subs->stlen;
+
+ if (len == 0 || (! isdigit((unsigned char) *cp) && *cp != '-'))
+ return NULL;
+ if (len > 1 &&
+ ((*cp == '0') /* "00", "011" .. */
+ || (*cp == '-' && *(cp + 1) == '0') /* "-0", "-011" .. */
+ )
+ )
+ return NULL;
+ if (len == 1 && *cp != '-') { /* single digit */
+ subs->numbr = (long) (*cp - '0');
+ if ((subs->flags & MAYBE_NUM) != 0) {
+ subs->flags &= ~MAYBE_NUM;
+ subs->flags |= NUMBER;
+ }
+ subs->flags |= (NUMCUR|NUMINT);
+ return (NODE **) ! NULL;
+ }
+
+ cpend = cp + len;
+ save = *cpend;
+ *cpend = '\0';
+
+ errno = 0;
+ l = strtol(cp, & ptr, 10);
+ *cpend = save;
+ if (errno != 0 || ptr != cpend)
+ return NULL;
+ subs->numbr = l;
+ if ((subs->flags & MAYBE_NUM) != 0) {
+ subs->flags &= ~MAYBE_NUM;
+ subs->flags |= NUMBER;
+ }
+ subs->flags |= NUMCUR;
+ if (l <= INT32_MAX && l >= INT32_MIN) {
+ subs->flags |= NUMINT;
+ return (NODE **) ! NULL;
+ }
+ }
+ return NULL;
+}
+
+
+/* int_lookup --- Find SYMBOL[SUBS] in the assoc array. Install it with value ""
+ * if it isn't there. Returns a pointer ala get_lhs to where its value is stored.
+ */
+
+static NODE **
+int_lookup(NODE *symbol, NODE *subs)
+{
+ uint32_t hash1;
+ long k;
+ unsigned long size;
+ NODE **lhs;
+ NODE *xn;
+
+ /* N.B: symbol->table_size is the total # of non-integers (symbol->xarray)
+ * and integer elements. Also, symbol->xarray must have at least one
+ * item in it, and can not exist if there are no integer elements.
+ * In that case, symbol->xarray is promoted to 'symbol' (See int_remove).
+ */
+
+
+ if (! is_integer(symbol, subs)) {
+ xn = symbol->xarray;
+ if (xn == NULL) {
+ xn = symbol->xarray = make_array();
+ xn->vname = symbol->vname; /* shallow copy */
+ xn->flags |= XARRAY;
+ } else if ((lhs = xn->aexists(xn, subs)) != NULL)
+ return lhs;
+ symbol->table_size++;
+ return assoc_lookup(xn, subs);
+ }
+
+ k = subs->numbr;
+ if (symbol->buckets == NULL)
+ grow_int_table(symbol);
+
+ hash1 = int_hash(k, symbol->array_size);
+ if ((lhs = int_find(symbol, k, hash1)) != NULL)
+ return lhs;
+
+ /* It's not there, install it */
+
+ symbol->table_size++;
+
+ /* first see if we would need to grow the array, before installing */
+ size = symbol->table_size;
+ if ((xn = symbol->xarray) != NULL)
+ size -= xn->table_size;
+
+ if ((symbol->flags & ARRAYMAXED) == 0
+ && (size / symbol->array_size) > INT_CHAIN_MAX) {
+ grow_int_table(symbol);
+ /* have to recompute hash value for new size */
+ hash1 = int_hash(k, symbol->array_size);
+ }
+
+ return int_insert(symbol, k, hash1);
+}
+
+
+/* int_exists --- test whether the array element symbol[subs] exists or not,
+ * return pointer to value if it does.
+ */
+
+static NODE **
+int_exists(NODE *symbol, NODE *subs)
+{
+ long k;
+ uint32_t hash1;
+
+ if (! is_integer(symbol, subs)) {
+ NODE *xn = symbol->xarray;
+ if (xn == NULL)
+ return NULL;
+ return xn->aexists(xn, subs);
+ }
+ if (symbol->buckets == NULL)
+ return NULL;
+
+ k = subs->numbr;
+ hash1 = int_hash(k, symbol->array_size);
+ return int_find(symbol, k, hash1);
+}
+
+/* int_clear --- flush all the values in symbol[] */
+
+static NODE **
+int_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
+{
+ unsigned long i;
+ int j;
+ BUCKET *b, *next;
+ NODE *r;
+
+ if (symbol->xarray != NULL) {
+ NODE *xn = symbol->xarray;
+ assoc_clear(xn);
+ freenode(xn);
+ symbol->xarray = NULL;
+ }
+
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = next) {
+ next = b->ainext;
+ for (j = 0; j < b->aicount; j++) {
+ r = b->aivalue[j];
+ if (r->type == Node_var_array) {
+ assoc_clear(r); /* recursively clear all sub-arrays */
+ efree(r->vname);
+ freenode(r);
+ } else
+ unref(r);
+ }
+ freebucket(b);
+ }
+ symbol->buckets[i] = NULL;
+ }
+ if (symbol->buckets != NULL)
+ efree(symbol->buckets);
+ init_array(symbol); /* re-initialize symbol */
+ symbol->flags &= ~ARRAYMAXED;
+ return NULL;
+}
+
+
+/* int_remove --- If SUBS is already in the table, remove it. */
+
+static NODE **
+int_remove(NODE *symbol, NODE *subs)
+{
+ uint32_t hash1;
+ BUCKET *b, *prev = NULL;
+ long k;
+ int i;
+ NODE *xn = symbol->xarray;
+
+ assert(symbol->buckets != NULL);
+
+ if (! is_integer(symbol, subs)) {
+ if (xn == NULL || xn->aremove(xn, subs) == NULL)
+ return NULL;
+ if (xn->table_size == 0) {
+ freenode(xn);
+ symbol->xarray = NULL;
+ }
+ symbol->table_size--;
+ assert(symbol->table_size > 0);
+ return (NODE **) ! NULL;
+ }
+
+ k = subs->numbr;
+ hash1 = int_hash(k, symbol->array_size);
+
+ for (b = symbol->buckets[hash1]; b != NULL; prev = b, b = b->ainext) {
+ for (i = 0; i < b->aicount; i++) {
+ if (k != b->ainum[i])
+ continue;
+
+ /* item found */
+ if (i == 0 && b->aicount == 2) {
+ /* removing the 1st item; move 2nd item from position 1 to 0 */
+
+ b->ainum[0] = b->ainum[1];
+ b->aivalue[0] = b->aivalue[1];
+ } /* else
+ removing the only item or the 2nd item */
+
+ goto removed;
+ }
+ }
+
+ if (b == NULL) /* item not in array */
+ return NULL;
+
+removed:
+ b->aicount--;
+
+ if (b->aicount == 0) {
+ /* detach bucket */
+ if (prev != NULL)
+ prev->ainext = b->ainext;
+ else
+ symbol->buckets[hash1] = b->ainext;
+
+ /* delete bucket */
+ freebucket(b);
+ } else if (b != symbol->buckets[hash1]) {
+ BUCKET *head = symbol->buckets[hash1];
+
+ assert(b->aicount == 1);
+ /* move the last element from head
+ * to bucket to make it full.
+ */
+ i = --head->aicount; /* head has one less element */
+ b->ainum[1] = head->ainum[i];
+ b->aivalue[1] = head->aivalue[i];
+ b->aicount++; /* bucket has one more element */
+ if (i == 0) {
+ /* head is now empty; delete head */
+ symbol->buckets[hash1] = head->ainext;
+ freebucket(head);
+ }
+ } /* else
+ do nothing */
+
+ symbol->table_size--;
+ if (xn == NULL && symbol->table_size == 0) {
+ efree(symbol->buckets);
+ init_array(symbol); /* re-initialize array 'symbol' */
+ symbol->flags &= ~ARRAYMAXED;
+ } else if (xn != NULL && symbol->table_size == xn->table_size) {
+ /* promote xn (str_array) to symbol */
+ xn->flags &= ~XARRAY;
+ xn->parent_array = symbol->parent_array;
+ efree(symbol->buckets);
+ *symbol = *xn;
+ freenode(xn);
+ }
+
+ return (NODE **) ! NULL; /* return success */
+}
+
+
+/* int_copy --- duplicate input array "symbol" */
+
+static NODE **
+int_copy(NODE *symbol, NODE *newsymb)
+{
+ BUCKET **old, **new, **pnew;
+ BUCKET *chain, *newchain;
+ int j;
+ unsigned long i, cursize;
+
+ assert(symbol->buckets != NULL);
+
+ /* find the current hash size */
+ cursize = symbol->array_size;
+
+ /* allocate new table */
+ emalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "int_copy");
+ memset(new, '\0', cursize * sizeof(BUCKET *));
+
+ old = symbol->buckets;
+
+ for (i = 0; i < cursize; i++) {
+ for (chain = old[i], pnew = & new[i]; chain != NULL;
+ chain = chain->ainext
+ ) {
+ getbucket(newchain);
+ newchain->aicount = chain->aicount;
+ for (j = 0; j < chain->aicount; j++) {
+ NODE *oldval;
+
+ /*
+ * copy the corresponding key and
+ * value from the original input list
+ */
+ newchain->ainum[j] = chain->ainum[j];
+
+ oldval = chain->aivalue[j];
+ if (oldval->type == Node_val)
+ newchain->aivalue[j] = dupnode(oldval);
+ else {
+ NODE *r;
+ r = make_array();
+ r->vname = estrdup(oldval->vname, strlen(oldval->vname));
+ r->parent_array = newsymb;
+ newchain->aivalue[j] = assoc_copy(oldval, r);
+ }
+ }
+
+ *pnew = newchain;
+ pnew = & newchain->ainext;
+ }
+ }
+
+ if (symbol->xarray != NULL) {
+ NODE *xn, *n;
+ xn = symbol->xarray;
+ n = make_array();
+ n->vname = newsymb->vname; /* shallow copy */
+ (void) xn->acopy(xn, n);
+ newsymb->xarray = n;
+ } else
+ newsymb->xarray = NULL;
+
+ newsymb->table_size = symbol->table_size;
+ newsymb->buckets = new;
+ newsymb->array_size = cursize;
+ newsymb->flags = symbol->flags;
+
+ return NULL;
+}
+
+
+/* int_list --- return a list of array items */
+
+static NODE**
+int_list(NODE *symbol, NODE *t)
+{
+ NODE **list = NULL;
+ unsigned long num_elems, list_size, i, k = 0;
+ BUCKET *b;
+ NODE *r, *subs, *xn;
+ int j, elem_size = 1;
+ long num;
+ static char buf[100];
+
+ assert(symbol->table_size > 0);
+
+ num_elems = symbol->table_size;
+ if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+ num_elems = 1;
+
+ if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+ elem_size = 2;
+ list_size = elem_size * num_elems;
+
+ if (symbol->xarray != NULL) {
+ xn = symbol->xarray;
+ list = xn->alist(xn, t);
+ assert(list != NULL);
+ if (num_elems == 1 || num_elems == xn->table_size)
+ return list;
+ erealloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
+ k = elem_size * xn->table_size;
+ } else
+ emalloc(list, NODE **, list_size * sizeof(NODE *), "int_list");
+
+ /* populate it */
+
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
+ for (j = 0; j < b->aicount; j++) {
+ /* index */
+ num = b->ainum[j];
+ if (t->flags & AISTR) {
+ sprintf(buf, "%ld", num);
+ subs = make_string(buf, strlen(buf));
+ subs->numbr = num;
+ subs->flags |= (NUMCUR|NUMINT);
+ } else {
+ subs = make_number((AWKNUM) num);
+ subs->flags |= (INTIND|NUMINT);
+ }
+ list[k++] = subs;
+
+ /* value */
+ if (t->flags & AVALUE) {
+ r = b->aivalue[j];
+ if (r->type == Node_val) {
+ if ((t->flags & AVNUM) != 0)
+ (void) force_number(r);
+ else if ((t->flags & AVSTR) != 0)
+ r = force_string(r);
+ }
+ list[k++] = r;
+ }
+
+ if (k >= list_size)
+ return list;
+ }
+ }
+ }
+ return list;
+}
+
+
+/* int_kilobytes --- calculate memory consumption of the assoc array */
+
+AWKNUM
+int_kilobytes(NODE *symbol)
+{
+ unsigned long i, bucket_cnt = 0;
+ BUCKET *b;
+ AWKNUM kb;
+ extern AWKNUM str_kilobytes(NODE *symbol);
+
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
+ bucket_cnt++;
+ }
+ kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
+ ((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
+
+ if (symbol->xarray != NULL)
+ kb += str_kilobytes(symbol->xarray);
+
+ return kb;
+}
+
+
+/* int_dump --- dump array info */
+
+static NODE **
+int_dump(NODE *symbol, NODE *ndump)
+{
+#define HCNT 31
+
+ int indent_level;
+ BUCKET *b;
+ NODE *xn = NULL;
+ unsigned long str_size = 0, int_size = 0;
+ unsigned long i;
+ size_t j, bucket_cnt;
+ static size_t hash_dist[HCNT + 1];
+
+ indent_level = ndump->alevel;
+
+ if (symbol->xarray != NULL) {
+ xn = symbol->xarray;
+ str_size = xn->table_size;
+ }
+ int_size = symbol->table_size - str_size;
+
+ if ((symbol->flags & XARRAY) == 0)
+ fprintf(output_fp, "%s `%s'\n",
+ (symbol->parent_array == NULL) ? "array" : "sub-array",
+ array_vname(symbol));
+
+ indent_level++;
+ indent(indent_level);
+ fprintf(output_fp, "array_func: int_array_func\n");
+ if (symbol->flags != 0) {
+ indent(indent_level);
+ fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
+ }
+ indent(indent_level);
+ fprintf(output_fp, "INT_CHAIN_MAX: %lu\n", INT_CHAIN_MAX);
+ indent(indent_level);
+ fprintf(output_fp, "array_size: %lu (int)\n", (unsigned long) symbol->array_size);
+ indent(indent_level);
+ fprintf(output_fp, "table_size: %lu (total), %lu (int), %lu (str)\n",
+ (unsigned long) symbol->table_size, int_size, str_size);
+ indent(indent_level);
+ fprintf(output_fp, "Avg # of items per chain (int): %.2g\n",
+ ((AWKNUM) int_size) / symbol->array_size);
+
+ indent(indent_level);
+ fprintf(output_fp, "memory: %.2g kB (total)\n", int_kilobytes(symbol));
+
+ /* hash value distribution */
+
+ memset(hash_dist, '\0', (HCNT + 1) * sizeof(size_t));
+ for (i = 0; i < symbol->array_size; i++) {
+ bucket_cnt = 0;
+ for (b = symbol->buckets[i]; b != NULL; b = b->ainext)
+ bucket_cnt += b->aicount;
+ if (bucket_cnt >= HCNT)
+ bucket_cnt = HCNT;
+ hash_dist[bucket_cnt]++;
+ }
+
+ indent(indent_level);
+ fprintf(output_fp, "Hash distribution:\n");
+ indent_level++;
+ for (j = 0; j <= HCNT; j++) {
+ if (hash_dist[j] > 0) {
+ indent(indent_level);
+ if (j == HCNT)
+ fprintf(output_fp, "[>=%lu]:%lu\n",
+ (unsigned long) HCNT, (unsigned long) hash_dist[j]);
+ else
+ fprintf(output_fp, "[%lu]:%lu\n",
+ (unsigned long) j, (unsigned long) hash_dist[j]);
+ }
+ }
+ indent_level--;
+
+ /* dump elements */
+
+ if (ndump->adepth >= 0) {
+ NODE *subs;
+ const char *aname;
+
+ fprintf(output_fp, "\n");
+
+ aname = make_aname(symbol);
+ subs = make_number((AWKNUM) 0);
+ subs->flags |= (INTIND|NUMINT);
+
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = b->ainext) {
+ for (j = 0; j < b->aicount; j++) {
+ subs->numbr = b->ainum[j];
+ assoc_info(subs, b->aivalue[j], ndump, aname);
+ }
+ }
+ }
+ unref(subs);
+ }
+
+ if (xn != NULL) {
+ fprintf(output_fp, "\n");
+ xn->adump(xn, ndump);
+ }
+
+ return NULL;
+
+#undef HCNT
+}
+
+
+/* int_hash --- calculate the hash function of the integer subs */
+
+static uint32_t
+int_hash(uint32_t k, uint32_t hsize)
+{
+
+/* Code snippet copied from:
+ * Hash functions (http://www.azillionmonkeys.com/qed/hash.html).
+ * Copyright 2004-2008 by Paul Hsieh. Licenced under LGPL 2.1.
+ */
+
+ /* This is the final mixing function used by Paul Hsieh
+ * in SuperFastHash.
+ */
+
+ k ^= k << 3;
+ k += k >> 5;
+ k ^= k << 4;
+ k += k >> 17;
+ k ^= k << 25;
+ k += k >> 6;
+
+ if (k >= hsize)
+ k %= hsize;
+ return k;
+}
+
+/* int_find --- locate symbol[subs] */
+
+static inline NODE **
+int_find(NODE *symbol, long k, uint32_t hash1)
+{
+ BUCKET *b;
+ int i;
+
+ assert(symbol->buckets != NULL);
+ for (b = symbol->buckets[hash1]; b != NULL; b = b->ainext) {
+ for (i = 0; i < b->aicount; i++) {
+ if (b->ainum[i] == k)
+ return (b->aivalue + i);
+ }
+ }
+ return NULL;
+}
+
+
+/* int_insert --- install subs in the assoc array */
+
+static NODE **
+int_insert(NODE *symbol, long k, uint32_t hash1)
+{
+ BUCKET *b;
+ int i;
+
+ b = symbol->buckets[hash1];
+
+ /* Only the first bucket in the chain can be partially full,
+ * but is never empty.
+ */
+
+ if (b == NULL || (i = b->aicount) == 2) {
+ getbucket(b);
+ b->aicount = 0;
+ b->ainext = symbol->buckets[hash1];
+ symbol->buckets[hash1] = b;
+ i = 0;
+ }
+
+ b->ainum[i] = k;
+ b->aivalue[i] = dupnode(Nnull_string);
+ b->aicount++;
+ return & b->aivalue[i];
+}
+
+
+/* grow_int_table --- grow the hash table */
+
+static void
+grow_int_table(NODE *symbol)
+{
+ BUCKET **old, **new;
+ BUCKET *chain, *next;
+ int i, j;
+ unsigned long oldsize, newsize, k;
+
+ /*
+ * This is an array of primes. We grow the table by an order of
+ * magnitude each time (not just doubling) so that growing is a
+ * rare operation. We expect, on average, that it won't happen
+ * more than twice. The final size is also chosen to be small
+ * enough so that MS-DOG mallocs can handle it. When things are
+ * very large (> 8K), we just double more or less, instead of
+ * just jumping from 8K to 64K.
+ */
+
+ static const unsigned long sizes[] = {
+ 13, 127, 1021, 8191, 16381, 32749, 65497,
+ 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467,
+ 67108879, 134217757, 268435459, 536870923,
+ 1073741827
+ };
+
+ /* find next biggest hash size */
+ newsize = oldsize = symbol->array_size;
+
+ for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
+ if (oldsize < sizes[i]) {
+ newsize = sizes[i];
+ break;
+ }
+ }
+ if (newsize == oldsize) { /* table already at max (!) */
+ symbol->flags |= ARRAYMAXED;
+ return;
+ }
+
+ /* allocate new table */
+ emalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_int_table");
+ memset(new, '\0', newsize * sizeof(BUCKET *));
+
+ old = symbol->buckets;
+ symbol->buckets = new;
+ symbol->array_size = newsize;
+
+ /* brand new hash table */
+ if (old == NULL)
+ return; /* DO NOT initialize symbol->table_size */
+
+ /* old hash table there, move stuff to new, free old */
+ /* note that symbol->table_size does not change if an old array. */
+
+ for (k = 0; k < oldsize; k++) {
+ long num;
+ for (chain = old[k]; chain != NULL; chain = next) {
+ for (i = 0; i < chain->aicount; i++) {
+ num = chain->ainum[i];
+ *int_insert(symbol, num, int_hash(num, newsize)) = chain->aivalue[i];
+ }
+ next = chain->ainext;
+ freebucket(chain);
+ }
+ }
+ efree(old);
+}
+
+
+#ifdef ARRAYDEBUG
+
+static NODE **
+int_option(NODE *opt, NODE *val)
+{
+ int newval;
+ NODE *tmp;
+ NODE **ret = (NODE **) ! NULL;
+
+ tmp = force_string(opt);
+ (void) force_number(val);
+ if (STREQ(tmp->stptr, "INT_CHAIN_MAX")) {
+ newval = (int) val->numbr;
+ if (newval > 0)
+ INT_CHAIN_MAX = newval;
+ } else
+ ret = NULL;
+ return ret;
+}
+#endif
diff --git a/io.c b/io.c
index 9c827eda..a2afeca1 100644
--- a/io.c
+++ b/io.c
@@ -211,7 +211,7 @@ static int inetfile(const char *str, int *length, int *family);
#endif
static struct redirect *red_head = NULL;
-static NODE *RS;
+static NODE *RS = NULL;
static Regexp *RS_re_yes_case;
static Regexp *RS_re_no_case;
static Regexp *RS_regexp;
@@ -611,7 +611,7 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
if (do_lint && (redir_exp->flags & STRCUR) == 0)
lintwarn(_("expression in `%s' redirection only has numeric value"),
what);
- redir_exp = force_string(redir_exp);
+ redir_exp= force_string(redir_exp);
str = redir_exp->stptr;
if (str == NULL || *str == '\0')
@@ -2531,7 +2531,7 @@ iop_alloc(int fd, const char *name, IOBUF *iop, int do_openhooks)
#define set_RT_to_null() \
(void)(! do_traditional && (unref(RT_node->var_value), \
- RT_node->var_value = Nnull_string))
+ RT_node->var_value = dupnode(Nnull_string)))
#define set_RT(str, len) \
(void)(! do_traditional && (unref(RT_node->var_value), \
@@ -3147,8 +3147,7 @@ pty_vs_pipe(const char *command)
#ifdef HAVE_TERMIOS_H
char *full_index;
size_t full_len;
- NODE *val;
- NODE *sub;
+ NODE *val, *sub;
if (PROCINFO_node == NULL)
return FALSE;
diff --git a/main.c b/main.c
index 43a3e4a5..6b24a80b 100644
--- a/main.c
+++ b/main.c
@@ -129,23 +129,11 @@ static int disallow_var_assigns = FALSE; /* true for --exec */
static void add_preassign(enum assign_type type, char *val);
-#undef do_lint
-#undef do_lint_old
-
-int do_traditional = FALSE; /* no gnu extensions, add traditional weirdnesses */
-int do_posix = FALSE; /* turn off gnu and unix extensions */
-int do_lint = FALSE; /* provide warnings about questionable stuff */
-int do_lint_old = FALSE; /* warn about stuff not in V7 awk */
-int do_intl = FALSE; /* dump locale-izable strings to stdout */
-int do_non_decimal_data = FALSE; /* allow octal/hex C style DATA. Use with caution! */
-int do_nostalgia = FALSE; /* provide a blast from the past */
-int do_intervals = FALSE; /* allow {...,...} in regexps, see resetup() */
-int do_profiling = FALSE; /* profile and pretty print the program */
-int do_dump_vars = FALSE; /* dump all global variables at end */
-int do_tidy_mem = FALSE; /* release vars when done */
-int do_optimize = TRUE; /* apply default optimizations */
-int do_binary = FALSE; /* hands off my data! */
-int do_sandbox = FALSE; /* sandbox mode - disable 'system' function & redirections */
+int do_flags = FALSE;
+int do_optimize = TRUE; /* apply default optimizations */
+static int do_nostalgia = FALSE; /* provide a blast from the past */
+static int do_binary = FALSE; /* hands off my data! */
+
int use_lc_numeric = FALSE; /* obey locale for decimal point */
#if MBS_SUPPORT
@@ -172,20 +160,20 @@ void (*lintfunc)(const char *mesg, ...) = warning;
* Note: reserve -l for future use, for xgawk's -l option.
*/
static const struct option optab[] = {
- { "traditional", no_argument, & do_traditional, 1 },
+ { "traditional", no_argument, NULL, 'c' },
{ "lint", optional_argument, NULL, 'L' },
- { "lint-old", no_argument, & do_lint_old, 1 },
- { "optimize", no_argument, & do_optimize, 'O' },
- { "posix", no_argument, & do_posix, 1 },
+ { "lint-old", no_argument, NULL, 't' },
+ { "optimize", no_argument, NULL, 'O' },
+ { "posix", no_argument, NULL, 'P' },
{ "command", required_argument, NULL, 'R' },
{ "nostalgia", no_argument, & do_nostalgia, 1 },
- { "gen-pot", no_argument, & do_intl, 1 },
- { "non-decimal-data", no_argument, & do_non_decimal_data, 1 },
+ { "gen-pot", no_argument, NULL, 'g' },
+ { "non-decimal-data", no_argument, NULL, 'n' },
{ "profile", optional_argument, NULL, 'p' },
{ "copyright", no_argument, NULL, 'C' },
{ "field-separator", required_argument, NULL, 'F' },
{ "file", required_argument, NULL, 'f' },
- { "re-interval", no_argument, & do_intervals, 1 },
+ { "re-interval", no_argument, NULL, 'r' },
{ "source", required_argument, NULL, 'e' },
{ "dump-variables", optional_argument, NULL, 'd' },
{ "assign", required_argument, NULL, 'v' },
@@ -194,17 +182,13 @@ static const struct option optab[] = {
{ "exec", required_argument, NULL, 'E' },
{ "use-lc-numeric", no_argument, & use_lc_numeric, 1 },
{ "characters-as-bytes", no_argument, & do_binary, 'b' },
- { "sandbox", no_argument, & do_sandbox, 1 },
+ { "sandbox", no_argument, NULL, 'S' },
#if defined(YYDEBUG) || defined(GAWKDEBUG)
{ "parsedebug", no_argument, NULL, 'Y' },
#endif
{ NULL, 0, NULL, '\0' }
};
-#ifdef NO_LINT
-#define do_lint 0
-#define do_lint_old 0
-#endif
/* main --- process args, parse program, run it, clean up */
@@ -225,7 +209,8 @@ main(int argc, char **argv)
char *extra_stack;
/* do these checks early */
- do_tidy_mem = (getenv("TIDYMEM") != NULL);
+ if (getenv("TIDYMEM") != NULL)
+ do_flags |= DO_TIDY_MEM;
#ifdef HAVE_MCHECK_H
#ifdef HAVE_MTRACE
@@ -371,7 +356,7 @@ main(int argc, char **argv)
break;
case 'c':
- do_traditional = TRUE;
+ do_flags |= DO_TRADITIONAL;
break;
case 'C':
@@ -379,7 +364,7 @@ main(int argc, char **argv)
break;
case 'd':
- do_dump_vars = TRUE;
+ do_flags |= DO_DUMP_VARS;
if (optarg != NULL && optarg[0] != '\0')
varfile = optarg;
break;
@@ -392,7 +377,7 @@ main(int argc, char **argv)
break;
case 'g':
- do_intl = TRUE;
+ do_flags |= DO_INTL;
break;
case 'h':
@@ -400,19 +385,21 @@ main(int argc, char **argv)
usage(EXIT_SUCCESS, stdout);
break;
-#ifndef NO_LINT
case 'L':
- do_lint = LINT_ALL;
+#ifndef NO_LINT
+ do_flags |= DO_LINT_ALL;
if (optarg != NULL) {
if (strcmp(optarg, "fatal") == 0)
lintfunc = r_fatal;
- else if (strcmp(optarg, "invalid") == 0)
- do_lint = LINT_INVALID;
+ else if (strcmp(optarg, "invalid") == 0) {
+ do_flags &= ~DO_LINT_ALL;
+ do_flags |= DO_LINT_INVALID;
+ }
}
break;
case 't':
- do_lint_old = TRUE;
+ do_flags |= DO_LINT_OLD;
break;
#else
case 'L':
@@ -421,7 +408,7 @@ main(int argc, char **argv)
#endif
case 'n':
- do_non_decimal_data = TRUE;
+ do_flags |= DO_NON_DEC_DATA;
break;
case 'N':
@@ -433,7 +420,7 @@ main(int argc, char **argv)
break;
case 'p':
- do_profiling = TRUE;
+ do_flags |= DO_PROFILING;
if (optarg != NULL)
set_prof_file(optarg);
else
@@ -441,15 +428,15 @@ main(int argc, char **argv)
break;
case 'P':
- do_posix = TRUE;
+ do_flags |= DO_POSIX;
break;
case 'r':
- do_intervals = TRUE;
+ do_flags |= DO_INTERVALS;
break;
case 'S':
- do_sandbox = TRUE;
+ do_flags |= DO_SANDBOX;
break;
case 'V':
@@ -528,7 +515,7 @@ out:
/* check for POSIXLY_CORRECT environment variable */
if (! do_posix && getenv("POSIXLY_CORRECT") != NULL) {
- do_posix = TRUE;
+ do_flags |= DO_POSIX;
if (do_lint)
lintwarn(
_("environment variable `POSIXLY_CORRECT' set: turning on `--posix'"));
@@ -539,7 +526,7 @@ out:
if (do_traditional) /* both on command line */
warning(_("`--posix' overrides `--traditional'"));
else
- do_traditional = TRUE;
+ do_flags |= DO_TRADITIONAL;
/*
* POSIX compliance also implies
* no GNU extensions either.
@@ -547,7 +534,7 @@ out:
}
if (do_traditional && do_non_decimal_data) {
- do_non_decimal_data = FALSE;
+ do_flags &= ~DO_NON_DEC_DATA;
warning(_("`--posix'/`--traditional' overrides `--non-decimal-data'"));
}
@@ -568,7 +555,7 @@ out:
* Don't bother if the command line already set profiling up.
*/
if (! do_profiling)
- init_profiling(& do_profiling, DEFAULT_PROFILE);
+ init_profiling(& do_flags, DEFAULT_PROFILE);
/* load group set */
init_groupset();
@@ -576,8 +563,7 @@ out:
/* initialize the null string */
Nnull_string = make_string("", 0);
Nnull_string->numbr = 0.0;
- Nnull_string->type = Node_val;
- Nnull_string->flags = (PERM|STRCUR|STRING|NUMCUR|NUMBER);
+ Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
/*
* Tell the regex routines how they should work.
@@ -732,8 +718,9 @@ usage(int exitval, FILE *fp)
/* Not factoring out common stuff makes it easier to translate. */
fprintf(fp, _("Usage: %s [POSIX or GNU style options] -f progfile [--] file ...\n"),
myname);
- fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] %cprogram%c file ...\n"),
- myname, quote, quote);
+ if (which_gawk != exe_debugging)
+ fprintf(fp, _("Usage: %s [POSIX or GNU style options] [--] %cprogram%c file ...\n"),
+ myname, quote, quote);
/* GNU long options info. This is too many options. */
@@ -856,6 +843,7 @@ cmdline_fs(char *str)
if (do_traditional && ! do_posix)
str[0] = '\t';
}
+
*tmp = make_str_node(str, strlen(str), SCAN); /* do process escapes */
set_FS();
}
@@ -869,26 +857,27 @@ init_args(int argc0, int argc, const char *argv0, char **argv)
NODE **aptr;
NODE *tmp;
- ARGV_node = install_symbol(estrdup("ARGV", 4), mk_symbol(Node_var_array, (NODE *) NULL));
+ ARGV_node = install_symbol(estrdup("ARGV", 4), Node_var_array);
tmp = make_number(0.0);
- aptr = assoc_lookup(ARGV_node, tmp, FALSE);
+ aptr = assoc_lookup(ARGV_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(argv0, strlen(argv0));
(*aptr)->flags |= MAYBE_NUM;
for (i = argc0, j = 1; i < argc; i++, j++) {
tmp = make_number((AWKNUM) j);
- aptr = assoc_lookup(ARGV_node, tmp, FALSE);
+ aptr = assoc_lookup(ARGV_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(argv[i], strlen(argv[i]));
(*aptr)->flags |= MAYBE_NUM;
}
- ARGC_node = install_symbol(estrdup("ARGC", 4),
- mk_symbol(Node_var, make_number((AWKNUM) j)));
+ ARGC_node = install_symbol(estrdup("ARGC", 4), Node_var);
+ ARGC_node->var_value = make_number((AWKNUM) j);
}
+
/*
* Set all the special variables to their initial values.
* Note that some of the variables that have set_FOO routines should
@@ -951,13 +940,11 @@ init_vars()
for (vp = varinit; vp->name != NULL; vp++) {
if ((vp->flags & NO_INSTALL) != 0)
continue;
- n = mk_symbol(Node_var, vp->strval == NULL
- ? make_number(vp->numval)
- : make_string(vp->strval, strlen(vp->strval)));
+ n = *(vp->spec) = install_symbol(estrdup(vp->name, strlen(vp->name)), Node_var);
+ n->var_value = vp->strval == NULL ? make_number(vp->numval)
+ : make_string(vp->strval, strlen(vp->strval));
n->var_assign = (Func_ptr) vp->assign;
n->var_update = (Func_ptr) vp->update;
-
- *(vp->spec) = install_symbol(estrdup(vp->name, strlen(vp->name)), n);
if (vp->do_assign)
(*(vp->assign))();
}
@@ -981,9 +968,7 @@ load_environ()
int i;
NODE *tmp;
- ENVIRON_node = install_symbol(estrdup("ENVIRON", 7),
- mk_symbol(Node_var_array, (NODE *) NULL));
-
+ ENVIRON_node = install_symbol(estrdup("ENVIRON", 7), Node_var_array);
for (i = 0; environ[i] != NULL; i++) {
static char nullstr[] = "";
@@ -994,7 +979,7 @@ load_environ()
else
val = nullstr;
tmp = make_string(var, strlen(var));
- aptr = assoc_lookup(ENVIRON_node, tmp, FALSE);
+ aptr = assoc_lookup(ENVIRON_node, tmp);
unref(tmp);
unref(*aptr);
*aptr = make_string(val, strlen(val));
@@ -1017,7 +1002,7 @@ load_environ()
val = getenv("AWKPATH");
if (val == NULL)
val = defpath;
- aptr = assoc_lookup(ENVIRON_node, tmp, FALSE);
+ aptr = assoc_lookup(ENVIRON_node, tmp);
unref(*aptr);
*aptr = make_string(val, strlen(val));
}
@@ -1036,8 +1021,7 @@ load_procinfo()
#endif
AWKNUM value;
- PROCINFO_node = install_symbol(estrdup("PROCINFO", 8),
- mk_symbol(Node_var_array, (NODE *) NULL));
+ PROCINFO_node = install_symbol(estrdup("PROCINFO", 8), Node_var_array);
update_PROCINFO_str("version", VERSION);
update_PROCINFO_str("strftime", def_strftime_format);
@@ -1233,7 +1217,7 @@ arg_assign(char *arg, int initing)
cp2 = estrdup(arg, cp - arg); /* var name */
- var = variable(cp2, Node_var);
+ var = variable(0, cp2, Node_var);
if (var == NULL) /* error */
exit(EXIT_FATAL);
if (var->type == Node_var && var->var_update)
@@ -1457,3 +1441,18 @@ update_global_values()
vp->update();
}
}
+
+/* getenv_long --- read a long value (>= 0) from an environment var. */
+
+long
+getenv_long(const char *name)
+{
+ const char *val;
+ long newval;
+ if ((val = getenv(name)) != NULL && isdigit((unsigned char) *val)) {
+ for (newval = 0; *val && isdigit((unsigned char) *val); val++)
+ newval = (newval * 10) + *val - '0';
+ return newval;
+ }
+ return -1;
+}
diff --git a/node.c b/node.c
index 204a91f9..73d3ec41 100644
--- a/node.c
+++ b/node.c
@@ -29,6 +29,8 @@
static int is_ieee_magic_val(const char *val);
static AWKNUM get_ieee_magic_val(const char *val);
+extern NODE **fmt_list; /* declared in eval.c */
+
/* force_number --- force a value to be numeric */
@@ -104,6 +106,8 @@ r_force_number(NODE *n)
n->numbr = (AWKNUM)(*cp - '0');
n->flags |= newflags;
n->flags |= NUMCUR;
+ if (cp == n->stptr) /* no leading spaces */
+ n->flags |= NUMINT;
}
return n->numbr;
}
@@ -166,18 +170,6 @@ format_val(const char *format, int index, NODE *s)
char buf[BUFSIZ];
char *sp = buf;
double val;
- char *orig, *trans, save;
-
- if (! do_traditional && (s->flags & INTLSTR) != 0) {
- save = s->stptr[s->stlen];
- s->stptr[s->stlen] = '\0';
-
- orig = s->stptr;
- trans = dgettext(TEXTDOMAIN, orig);
-
- s->stptr[s->stlen] = save;
- return make_string(trans, strlen(trans));
- }
/*
* 2/2007: Simplify our lives here. Instead of worrying about
@@ -210,7 +202,6 @@ format_val(const char *format, int index, NODE *s)
NODE *dummy[2], *r;
unsigned short oflags;
- extern NODE **fmt_list; /* declared in eval.c */
/* create dummy node for a sole use of format_tree */
dummy[1] = s;
@@ -234,8 +225,7 @@ format_val(const char *format, int index, NODE *s)
goto no_malloc;
} else {
/*
- * integral value
- * force conversion to long only once
+ * integral value; force conversion to long only once.
*/
long num = (long) val;
@@ -247,19 +237,25 @@ format_val(const char *format, int index, NODE *s)
s->stlen = strlen(sp);
}
s->stfmt = -1;
+ if (s->flags & INTIND) {
+ s->flags &= ~(INTIND|NUMBER);
+ s->flags |= STRING;
+ }
}
if (s->stptr != NULL)
efree(s->stptr);
emalloc(s->stptr, char *, s->stlen + 2, "format_val");
- memcpy(s->stptr, sp, s->stlen+1);
+ memcpy(s->stptr, sp, s->stlen + 1);
no_malloc:
s->flags |= STRCUR;
free_wstr(s);
return s;
}
-/* force_string --- force a value to be a string */
+/* r_force_string --- force a value to be a string */
+
+#ifdef GAWKDEBUG
NODE *
r_force_string(NODE *s)
{
@@ -269,28 +265,23 @@ r_force_string(NODE *s)
return s;
return format_val(CONVFMT, CONVFMTidx, s);
}
+#endif
-/* dupnode --- duplicate a node */
+/* r_dupnode --- duplicate a node */
NODE *
-dupnode(NODE *n)
+r_dupnode(NODE *n)
{
NODE *r;
- if (n->type == Node_ahash) {
- n->ahname_ref++;
- return n;
- }
-
assert(n->type == Node_val);
- if ((n->flags & PERM) != 0)
- return n;
-
+#ifdef GAWKDEBUG
if ((n->flags & MALLOC) != 0) {
n->valref++;
return n;
}
+#endif
getnode(r);
*r = *n;
@@ -308,13 +299,13 @@ dupnode(NODE *n)
#endif /* MBS_SUPPORT */
if ((n->flags & STRCUR) != 0) {
- emalloc(r->stptr, char *, n->stlen + 2, "dupnode");
+ emalloc(r->stptr, char *, n->stlen + 2, "r_dupnode");
memcpy(r->stptr, n->stptr, n->stlen);
r->stptr[n->stlen] = '\0';
#if MBS_SUPPORT
if ((n->flags & WSTRCUR) != 0) {
r->wstlen = n->wstlen;
- emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 2), "dupnode");
+ emalloc(r->wstptr, wchar_t *, sizeof(wchar_t) * (n->wstlen + 2), "r_dupnode");
memcpy(r->wstptr, n->wstptr, n->wstlen * sizeof(wchar_t));
r->wstptr[n->wstlen] = L'\0';
r->flags |= WSTRCUR;
@@ -325,35 +316,40 @@ dupnode(NODE *n)
return r;
}
-/* mk_number --- allocate a node with defined number */
+/* make_number --- allocate a node with defined number */
NODE *
-mk_number(AWKNUM x, unsigned int flags)
+make_number(AWKNUM x)
{
NODE *r;
-
getnode(r);
r->type = Node_val;
r->numbr = x;
r->valref = 1;
- r->flags = flags;
+ r->flags = MALLOC|NUMBER|NUMCUR;
r->stptr = NULL;
r->stlen = 0;
- free_wstr(r);
+#if MBS_SUPPORT
+ r->wstptr = NULL;
+ r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
return r;
}
-/* make_str_node --- make a string node */
+
+/* r_make_str_node --- make a string node */
NODE *
-r_make_str_node(const char *s, unsigned long len, int flags)
+r_make_str_node(const char *s, size_t len, int flags)
{
NODE *r;
-
getnode(r);
r->type = Node_val;
r->numbr = 0;
- r->flags = (STRING|STRCUR|MALLOC);
+ r->flags = (MALLOC|STRING|STRCUR);
+ r->valref = 1;
+ r->stfmt = -1;
+
#if MBS_SUPPORT
r->wstptr = NULL;
r->wstlen = 0;
@@ -362,11 +358,11 @@ r_make_str_node(const char *s, unsigned long len, int flags)
if (flags & ALREADY_MALLOCED)
r->stptr = (char *) s;
else {
- emalloc(r->stptr, char *, len + 2, "make_str_node");
+ emalloc(r->stptr, char *, len + 2, "r_make_str_node");
memcpy(r->stptr, s, len);
}
r->stptr[len] = '\0';
-
+
if ((flags & SCAN) != 0) { /* scan for escape sequences */
const char *pf;
char *ptm;
@@ -411,70 +407,36 @@ r_make_str_node(const char *s, unsigned long len, int flags)
*ptm++ = c;
}
len = ptm - r->stptr;
- erealloc(r->stptr, char *, len + 1, "make_str_node");
+ erealloc(r->stptr, char *, len + 1, "r_make_str_node");
r->stptr[len] = '\0';
- r->flags &= ~MALLOC;
- r->flags |= PERM;
}
r->stlen = len;
- r->valref = 1;
- r->stfmt = -1;
return r;
}
-/* more_nodes --- allocate more nodes */
-
-#define NODECHUNK 100
-
-NODE *nextfree = NULL;
-
-NODE *
-more_nodes()
-{
- NODE *np;
-
- /* get more nodes and initialize list */
- emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "more_nodes");
- memset(nextfree, 0, NODECHUNK * sizeof(NODE));
- for (np = nextfree; np <= &nextfree[NODECHUNK - 1]; np++) {
- np->nextp = np + 1;
- }
- --np;
- np->nextp = NULL;
- np = nextfree;
- nextfree = nextfree->nextp;
- return np;
-}
/* unref --- remove reference to a particular node */
void
-unref(NODE *tmp)
+r_unref(NODE *tmp)
{
+#ifdef GAWKDEBUG
if (tmp == NULL)
return;
- if ((tmp->flags & PERM) != 0)
- return;
-
- if (tmp->type == Node_ahash) {
- if (tmp->ahname_ref > 1)
- tmp->ahname_ref--;
- else {
- efree(tmp->ahname_str);
- freenode(tmp);
- }
- return;
- }
-
if ((tmp->flags & MALLOC) != 0) {
if (tmp->valref > 1) {
- tmp->valref--;
+ tmp->valref--;
return;
- }
+ }
if (tmp->flags & STRCUR)
efree(tmp->stptr);
}
+#else
+ if ((tmp->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
+ efree(tmp->stptr);
+#endif
+
free_wstr(tmp);
freenode(tmp);
}
@@ -963,3 +925,41 @@ void init_btowc_cache()
}
}
#endif
+
+#define BLOCKCHUNK 100
+
+BLOCK nextfree[BLOCK_MAX] = {
+ { 0, NULL}, /* invalid */
+ { sizeof(NODE), NULL },
+ { sizeof(BUCKET), NULL },
+};
+
+
+/* more_blocks --- get more blocks of memory and add to the free list;
+ size of a block must be >= sizeof(BLOCK)
+ */
+
+void *
+more_blocks(int id)
+{
+ BLOCK *freep, *np, *next;
+ char *p, *endp;
+ size_t size;
+
+ size = nextfree[id].size;
+
+ emalloc(freep, BLOCK *, BLOCKCHUNK * size, "more_blocks");
+ p = (char *) freep;
+ endp = p + BLOCKCHUNK * size;
+
+ for (np = freep; ; np = next) {
+ next = (BLOCK *) (p += size);
+ if (p >= endp) {
+ np->freep = NULL;
+ break;
+ }
+ np->freep = next;
+ }
+ nextfree[id].freep = freep->freep;
+ return freep;
+}
diff --git a/pc/ChangeLog b/pc/ChangeLog
index 429a88ed..5f287dd8 100644
--- a/pc/ChangeLog
+++ b/pc/ChangeLog
@@ -1,3 +1,7 @@
+2011-12-12 Scott Deifik <scottd.mail@sbcglobal.net>
+
+ * Makefile.tst: Sync with mainline version.
+
2011-12-06 Scott Deifik <scottd.mail@sbcglobal.net>
* Makefile.tst: Sync with mainline version.
diff --git a/pc/Makefile.tst b/pc/Makefile.tst
index db214348..f14341c8 100644
--- a/pc/Makefile.tst
+++ b/pc/Makefile.tst
@@ -306,7 +306,7 @@ argarray::
.) : ;; \
*) rm -f ./argarray.in ;; \
esac
- @-$(CMP) $(srcdir)/argarray.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
regtest::
@echo 'Some of the output from regtest is very system specific, do not'
@@ -321,44 +321,45 @@ manyfiles::
@$(AWK) 'BEGIN { for (i = 1; i <= 1030; i++) print i, i}' >_$@
@$(AWK) -f $(srcdir)/manyfiles.awk _$@ _$@
@wc -l junk/* | $(AWK) '$$1 != 2' | wc -l | sed "s/ *//g" > _$@
- @rm -rf junk ; $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
+ @rm -rf junk
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
compare::
@echo $@
@$(AWK) -f $(srcdir)/compare.awk 0 1 $(srcdir)/compare.in >_$@
- @-$(CMP) $(srcdir)/compare.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
inftest::
@echo $@
@echo This test is very machine specific...
@echo Expect inftest to fail with DJGPP.
@$(AWK) -f $(srcdir)/inftest.awk | sed "s/inf/Inf/g" >_$@
- @-$(CMP) $(srcdir)/inftest.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
getline2::
@echo $@
@$(AWK) -f $(srcdir)/getline2.awk $(srcdir)/getline2.awk $(srcdir)/getline2.awk >_$@
- @-$(CMP) $(srcdir)/getline2.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
awkpath::
@echo $@
@AWKPATH="$(srcdir)$(PATH_SEPARATOR)$(srcdir)/lib" $(AWK) -f awkpath.awk >_$@
- @-$(CMP) $(srcdir)/awkpath.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
argtest::
@echo $@
@$(AWK) -f $(srcdir)/argtest.awk -x -y abc >_$@
- @-$(CMP) $(srcdir)/argtest.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
badargs::
@echo $@
@-$(AWK) -f 2>&1 | grep -v patchlevel >_$@
- @-$(CMP) $(srcdir)/badargs.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
nonl::
@echo $@
@-AWKPATH=$(srcdir) $(AWK) --lint -f nonl.awk /dev/null >_$@ 2>&1
- @-$(CMP) $(srcdir)/nonl.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
strftime::
@echo This test could fail on slow machines or on a minute boundary,
@@ -375,7 +376,7 @@ strftime::
litoct::
@echo $@
@echo ab | $(AWK) --traditional -f $(srcdir)/litoct.awk >_$@
- @-$(CMP) $(srcdir)/litoct.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
devfd::
@echo $@
@@ -386,13 +387,13 @@ devfd::
fflush::
@echo $@
@$(srcdir)/fflush.sh >_$@
- @-$(CMP) $(srcdir)/fflush.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
tweakfld::
@echo $@
@$(AWK) -f $(srcdir)/tweakfld.awk $(srcdir)/tweakfld.in >_$@
@rm -f errors.cleanup
- @-$(CMP) $(srcdir)/tweakfld.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
mmap8k::
@echo $@
@@ -402,7 +403,7 @@ mmap8k::
tradanch::
@echo $@
@$(AWK) --traditional -f $(srcdir)/tradanch.awk $(srcdir)/tradanch.in >_$@
- @-$(CMP) $(srcdir)/tradanch.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
# AIX /bin/sh exec's the last command in a list, therefore issue a ":"
# command so that pid.sh is fork'ed as a child before being exec'ed.
@@ -418,12 +419,12 @@ strftlng::
@if $(CMP) $(srcdir)/strftlng.ok _$@ >/dev/null 2>&1 ; then : ; else \
TZ=UTC0; export TZ; $(AWK) -f $(srcdir)/strftlng.awk >_$@ ; \
fi
- @-$(CMP) $(srcdir)/strftlng.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
nors::
@echo $@
@echo A B C D E | tr -d '\12\15' | $(AWK) '{ print $$NF }' - $(srcdir)/nors.in > _$@
- @-$(CMP) $(srcdir)/nors.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
fmtspcl.ok: fmtspcl.tok
@$(AWK) -v "sd=$(srcdir)" 'BEGIN {pnan = sprintf("%g",sqrt(-1)); nnan = sprintf("%g",-sqrt(-1)); pinf = sprintf("%g",-log(0)); ninf = sprintf("%g",log(0))} {sub(/positive_nan/,pnan); sub(/negative_nan/,nnan); sub(/positive_infinity/,pinf); sub(/negative_infinity/,ninf); sub(/fmtspcl/,(sd"/fmtspcl")); print}' < $(srcdir)/fmtspcl.tok > $@ 2>/dev/null
@@ -437,18 +438,18 @@ fmtspcl: fmtspcl.ok
reint::
@echo $@
@$(AWK) --re-interval -f $(srcdir)/reint.awk $(srcdir)/reint.in >_$@
- @-$(CMP) $(srcdir)/reint.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
pipeio1::
@echo $@
@$(AWK) -f $(srcdir)/pipeio1.awk >_$@
@rm -f test1 test2
- @-$(CMP) $(srcdir)/pipeio1.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
pipeio2::
@echo $@
@$(AWK) -v SRCDIR=$(srcdir) -f $(srcdir)/pipeio2.awk >_$@
- @-$(CMP) $(srcdir)/pipeio2.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
clobber::
@echo $@
@@ -459,7 +460,7 @@ clobber::
arynocls::
@echo $@
@-AWKPATH=$(srcdir) $(AWK) -v INPUT=$(srcdir)/arynocls.in -f arynocls.awk >_$@
- @-$(CMP) $(srcdir)/arynocls.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
getlnbuf::
@echo $@
@@ -503,12 +504,12 @@ inetdayt::
redfilnm::
@echo $@
@$(AWK) -f $(srcdir)/redfilnm.awk srcdir=$(srcdir) $(srcdir)/redfilnm.in >_$@
- @-$(CMP) $(srcdir)/redfilnm.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
leaddig::
@echo $@
@$(AWK) -v x=2E -f $(srcdir)/leaddig.awk >_$@
- @-$(CMP) $(srcdir)/leaddig.ok _$@ && rm -f _$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
gsubtst3::
@echo $@
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 00000000..2a1c0abe
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1,4 @@
+# Ignore files that are created by a build.
+Makefile.in
+POTFILES
+
diff --git a/po/ast.gmo b/po/ast.gmo
deleted file mode 100644
index 7c2ac4e2..00000000
--- a/po/ast.gmo
+++ /dev/null
Binary files differ
diff --git a/po/ca.gmo b/po/ca.gmo
deleted file mode 100644
index 426541dc..00000000
--- a/po/ca.gmo
+++ /dev/null
Binary files differ
diff --git a/po/ga.gmo b/po/ga.gmo
deleted file mode 100644
index 21141c51..00000000
--- a/po/ga.gmo
+++ /dev/null
Binary files differ
diff --git a/po/he.gmo b/po/he.gmo
deleted file mode 100644
index b9cb6d3c..00000000
--- a/po/he.gmo
+++ /dev/null
Binary files differ
diff --git a/po/id.gmo b/po/id.gmo
deleted file mode 100644
index 272d5f8c..00000000
--- a/po/id.gmo
+++ /dev/null
Binary files differ
diff --git a/po/pt_BR.gmo b/po/pt_BR.gmo
deleted file mode 100644
index 4cbc6792..00000000
--- a/po/pt_BR.gmo
+++ /dev/null
Binary files differ
diff --git a/po/ro.gmo b/po/ro.gmo
deleted file mode 100644
index e3534b89..00000000
--- a/po/ro.gmo
+++ /dev/null
Binary files differ
diff --git a/po/rw.gmo b/po/rw.gmo
deleted file mode 100644
index a08f9183..00000000
--- a/po/rw.gmo
+++ /dev/null
Binary files differ
diff --git a/po/tr.gmo b/po/tr.gmo
deleted file mode 100644
index 146da41d..00000000
--- a/po/tr.gmo
+++ /dev/null
Binary files differ
diff --git a/po/vi.gmo b/po/vi.gmo
deleted file mode 100644
index e3a5e619..00000000
--- a/po/vi.gmo
+++ /dev/null
Binary files differ
diff --git a/po/zh_CN.gmo b/po/zh_CN.gmo
deleted file mode 100644
index 7ed096c3..00000000
--- a/po/zh_CN.gmo
+++ /dev/null
Binary files differ
diff --git a/profile.c b/profile.c
index eb788377..c721180f 100644
--- a/profile.c
+++ b/profile.c
@@ -51,7 +51,7 @@ static RETSIGTYPE just_dump(int signum);
/* pretty printing related functions and variables */
static NODE *pp_stack = NULL;
-static char **fparms; /* function parameter names */
+static NODE *func_params; /* function parameters */
static FILE *prof_fp; /* where to send the profile */
static long indent_level = 0;
@@ -66,7 +66,7 @@ init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED
{
#ifdef PROFILING
if (*flag == FALSE) {
- *flag = TRUE;
+ *flag |= DO_PROFILING;
set_prof_file(def_file);
}
#endif
@@ -257,6 +257,9 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
break;
case Op_store_var:
+ if (pc->initval != NULL)
+ pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE);
+ /* fall through */
case Op_store_sub:
case Op_assign_concat:
case Op_push_lhs:
@@ -267,7 +270,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
m = pc->memory;
switch (m->type) {
case Node_param_list:
- pp_push(pc->opcode, fparms[m->param_cnt], DONT_FREE);
+ pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE);
break;
case Node_var:
@@ -522,9 +525,13 @@ cleanup:
break;
case Op_builtin:
+ case Op_ext_builtin:
{
- static char *ext_func = "extension_function()";
- const char *fname = getfname(pc->builtin);
+ const char *fname;
+ if (pc->opcode == Op_builtin)
+ fname = getfname(pc->builtin);
+ else
+ fname = (pc + 1)->func_name;
if (fname != NULL) {
if (pc->expr_count > 0) {
tmp = pp_list(pc->expr_count, "()", ", ");
@@ -534,10 +541,10 @@ cleanup:
str = pp_concat(fname, "()", "");
pp_push(Op_builtin, str, CAN_FREE);
} else
- pp_push(Op_builtin, ext_func, DONT_FREE);
+ fatal(_("internal error: builtin with null fname"));
}
break;
-
+
case Op_K_print:
case Op_K_printf:
case Op_K_print_rec:
@@ -756,14 +763,15 @@ cleanup:
case Op_K_arrayfor:
{
- char *array, *item;
+ char *array;
+ const char *item;
ip = pc + 1;
t1 = pp_pop();
array = t1->pp_str;
m = ip->forloop_cond->array_var;
if (m->type == Node_param_list)
- item = fparms[m->param_cnt];
+ item = func_params[m->param_cnt].param;
else
item = m->vname;
indent(ip->forloop_body->exec_count);
@@ -1321,9 +1329,8 @@ int
pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
{
int j;
- char **pnames;
- NODE *f;
static int first = TRUE;
+ NODE *func;
int pcount;
if (first) {
@@ -1331,15 +1338,14 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
}
- f = pc->func_body;
+ func = pc->func_body;
fprintf(prof_fp, "\n");
indent(pc->nexti->exec_count);
- fprintf(prof_fp, "%s %s(", op2str(Op_K_function), f->lnode->param);
- pnames = f->parmlist;
- fparms = pnames;
- pcount = f->lnode->param_cnt;
+ fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname);
+ pcount = func->param_cnt;
+ func_params = func->fparms;
for (j = 0; j < pcount; j++) {
- fprintf(prof_fp, "%s", pnames[j]);
+ fprintf(prof_fp, "%s", func_params[j].param);
if (j < pcount - 1)
fprintf(prof_fp, ", ");
}
diff --git a/str_array.c b/str_array.c
new file mode 100644
index 00000000..8fb6ba8a
--- /dev/null
+++ b/str_array.c
@@ -0,0 +1,759 @@
+/*
+ * str_array.c - routines for associative arrays of string indices.
+ */
+
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-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
+ */
+
+#include "awk.h"
+
+/*
+ * Tree walks (``for (iggy in foo)'') and array deletions use expensive
+ * linear searching. So what we do is start out with small arrays and
+ * grow them as needed, so that our arrays are hopefully small enough,
+ * most of the time, that they're pretty full and we're not looking at
+ * wasted space.
+ *
+ * The decision is made to grow the array if the average chain length is
+ * ``too big''. This is defined as the total number of entries in the table
+ * divided by the size of the array being greater than some constant.
+ *
+ * 11/2002: We make the constant a variable, so that it can be tweaked
+ * via environment variable.
+ * 11/2002: Modern machines are bigger, cut this down from 10.
+ */
+
+static size_t STR_CHAIN_MAX = 2;
+
+extern FILE *output_fp;
+extern void indent(int indent_level);
+
+static NODE **str_array_init(NODE *symbol, NODE *subs);
+static NODE **str_lookup(NODE *symbol, NODE *subs);
+static NODE **str_exists(NODE *symbol, NODE *subs);
+static NODE **str_clear(NODE *symbol, NODE *subs);
+static NODE **str_remove(NODE *symbol, NODE *subs);
+static NODE **str_list(NODE *symbol, NODE *subs);
+static NODE **str_copy(NODE *symbol, NODE *newsymb);
+static NODE **str_dump(NODE *symbol, NODE *ndump);
+
+#ifdef ARRAYDEBUG
+static NODE **str_option(NODE *opt, NODE *val);
+#endif
+
+
+array_ptr str_array_func[] = {
+ str_array_init,
+ (array_ptr) 0,
+ str_lookup,
+ str_exists,
+ str_clear,
+ str_remove,
+ str_list,
+ str_copy,
+ str_dump,
+#ifdef ARRAYDEBUG
+ str_option
+#endif
+};
+
+static inline NODE **str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1);
+static void grow_table(NODE *symbol);
+
+static unsigned long gst_hash_string(const char *str, size_t len, unsigned long hsize, size_t *code);
+static unsigned long scramble(unsigned long x);
+static unsigned long awk_hash(const char *s, size_t len, unsigned long hsize, size_t *code);
+
+unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, size_t *code) = awk_hash;
+
+
+/* str_array_init --- check relevant environment variables */
+
+static NODE **
+str_array_init(NODE *symbol ATTRIBUTE_UNUSED, NODE *subs ATTRIBUTE_UNUSED)
+{
+ long newval;
+ const char *val;
+
+ if ((newval = getenv_long("STR_CHAIN_MAX")) > 0)
+ STR_CHAIN_MAX = newval;
+ if ((val = getenv("AWK_HASH")) != NULL && strcmp(val, "gst") == 0)
+ hash = gst_hash_string;
+ return (NODE **) ! NULL;
+}
+
+
+/*
+ * assoc_lookup:
+ * Find SYMBOL[SUBS] in the assoc array. Install it with value "" if it
+ * isn't there. Returns a pointer ala get_lhs to where its value is stored.
+ *
+ * SYMBOL is the address of the node (or other pointer) being dereferenced.
+ * SUBS is a number or string used as the subscript.
+ */
+
+static NODE **
+str_lookup(NODE *symbol, NODE *subs)
+{
+ unsigned long hash1;
+ NODE **lhs;
+ BUCKET *b;
+ size_t code1;
+
+ subs = force_string(subs);
+
+ if (symbol->buckets == NULL)
+ grow_table(symbol);
+ hash1 = hash(subs->stptr, subs->stlen,
+ (unsigned long) symbol->array_size, & code1);
+ if ((lhs = str_find(symbol, subs, code1, hash1)) != NULL)
+ return lhs;
+
+ /* It's not there, install it. */
+ /* first see if we would need to grow the array, before installing */
+
+ symbol->table_size++;
+ if ((symbol->flags & ARRAYMAXED) == 0
+ && (symbol->table_size / symbol->array_size) > STR_CHAIN_MAX) {
+ grow_table(symbol);
+ /* have to recompute hash value for new size */
+ hash1 = code1 % (unsigned long) symbol->array_size;
+ }
+
+ if (subs->stfmt != -1) {
+ NODE *tmp;
+
+ /*
+ * Need to freeze this string value --- it must never
+ * change, no matter what happens to the value
+ * that created it or to CONVFMT, etc.; So, get
+ * a private copy.
+ */
+
+ tmp = make_string(subs->stptr, subs->stlen);
+
+ /*
+ * Set the numeric value for the index if it's available. Useful
+ * for numeric sorting by index. Do this only if the numeric
+ * value is available, instead of all the time, since doing it
+ * all the time is a big performance hit for something that may
+ * never be used.
+ */
+
+ if (subs->flags & NUMCUR) {
+ tmp->numbr = subs->numbr;
+ tmp->flags |= NUMCUR;
+ }
+ subs = tmp;
+ } else {
+ /* string value already "frozen" */
+
+ subs = dupnode(subs);
+ }
+
+ getbucket(b);
+ b->ahnext = symbol->buckets[hash1];
+ symbol->buckets[hash1] = b;
+ b->ahname = subs;
+ b->ahname_str = subs->stptr;
+ b->ahname_len = subs->stlen;
+ b->ahvalue = dupnode(Nnull_string);
+ b->ahcode = code1;
+ return & (b->ahvalue);
+}
+
+/* str_exists --- test whether the array element symbol[subs] exists or not,
+ * return pointer to value if it does.
+ */
+
+static NODE **
+str_exists(NODE *symbol, NODE *subs)
+{
+ NODE **lhs;
+ unsigned long hash1;
+ size_t code1;
+
+ assert(symbol->table_size > 0);
+
+ subs = force_string(subs);
+ hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size, & code1);
+ lhs = str_find(symbol, subs, code1, hash1);
+ return lhs;
+}
+
+/* str_clear --- flush all the values in symbol[] */
+
+static NODE **
+str_clear(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED)
+{
+ unsigned long i;
+ BUCKET *b, *next;
+ NODE *r;
+
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = next) {
+ next = b->ahnext;
+ r = b->ahvalue;
+ if (r->type == Node_var_array) {
+ assoc_clear(r); /* recursively clear all sub-arrays */
+ efree(r->vname);
+ freenode(r);
+ } else
+ unref(r);
+ unref(b->ahname);
+ freebucket(b);
+ }
+ symbol->buckets[i] = NULL;
+ }
+
+ if (symbol->buckets != NULL)
+ efree(symbol->buckets);
+ init_array(symbol); /* re-initialize symbol */
+ symbol->flags &= ~ARRAYMAXED;
+ return NULL;
+}
+
+
+/* str_remove --- If SUBS is already in the table, remove it. */
+
+static NODE **
+str_remove(NODE *symbol, NODE *subs)
+{
+ unsigned long hash1;
+ BUCKET *b, *prev;
+ NODE *s2;
+ size_t s1_len;
+
+ assert(symbol->table_size > 0);
+
+ s2 = force_string(subs);
+ hash1 = hash(s2->stptr, s2->stlen, (unsigned long) symbol->array_size, NULL);
+
+ for (b = symbol->buckets[hash1], prev = NULL; b != NULL;
+ prev = b, b = b->ahnext) {
+
+ /* Array indexes are strings; compare as such, always! */
+ s1_len = b->ahname_len;
+
+ if (s1_len != s2->stlen)
+ continue;
+ if (s1_len == 0 /* "" is a valid index */
+ || memcmp(b->ahname_str, s2->stptr, s1_len) == 0) {
+ /* item found */
+
+ unref(b->ahname);
+ if (prev != NULL)
+ prev->ahnext = b->ahnext;
+ else
+ symbol->buckets[hash1] = b->ahnext;
+
+ /* delete bucket */
+ freebucket(b);
+
+ /* one less element in array */
+ if (--symbol->table_size == 0) {
+ if (symbol->buckets != NULL)
+ efree(symbol->buckets);
+ init_array(symbol); /* re-initialize symbol */
+ symbol->flags &= ~ARRAYMAXED;
+ }
+
+ return (NODE **) ! NULL; /* return success */
+ }
+ }
+
+ return NULL;
+}
+
+
+/* str_copy --- duplicate input array "symbol" */
+
+static NODE **
+str_copy(NODE *symbol, NODE *newsymb)
+{
+ BUCKET **old, **new, **pnew;
+ BUCKET *chain, *newchain;
+ unsigned long cursize, i;
+
+ assert(symbol->table_size > 0);
+
+ /* find the current hash size */
+ cursize = symbol->array_size;
+
+ /* allocate new table */
+ emalloc(new, BUCKET **, cursize * sizeof(BUCKET *), "str_copy");
+ memset(new, '\0', cursize * sizeof(BUCKET *));
+
+ old = symbol->buckets;
+
+ for (i = 0; i < cursize; i++) {
+ for (chain = old[i], pnew = & new[i]; chain != NULL;
+ chain = chain->ahnext
+ ) {
+ NODE *oldval, *newsubs;
+
+ getbucket(newchain);
+
+ /*
+ * copy the corresponding name and
+ * value from the original input list
+ */
+
+ newsubs = newchain->ahname = dupnode(chain->ahname);
+ newchain->ahname_str = newsubs->stptr;
+ newchain->ahname_len = newsubs->stlen;
+
+ oldval = chain->ahvalue;
+ if (oldval->type == Node_val)
+ newchain->ahvalue = dupnode(oldval);
+ else {
+ NODE *r;
+
+ r = make_array();
+ r->vname = estrdup(oldval->vname, strlen(oldval->vname));
+ r->parent_array = newsymb;
+ newchain->ahvalue = assoc_copy(oldval, r);
+ }
+ newchain->ahcode = chain->ahcode;
+
+ *pnew = newchain;
+ pnew = & newchain->ahnext;
+ }
+ }
+
+ newsymb->table_size = symbol->table_size;
+ newsymb->buckets = new;
+ newsymb->array_size = cursize;
+ newsymb->flags = symbol->flags;
+ return NULL;
+}
+
+
+/* str_list --- return a list of array items */
+
+static NODE**
+str_list(NODE *symbol, NODE *t)
+{
+ NODE **list;
+ NODE *subs, *val;
+ BUCKET *b;
+ unsigned long num_elems, list_size, i, k = 0;
+ int elem_size = 1;
+
+ assert(symbol->table_size > 0);
+
+ if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE))
+ elem_size = 2;
+
+ /* allocate space for array */
+ num_elems = symbol->table_size;
+ if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE))
+ num_elems = 1;
+ list_size = elem_size * num_elems;
+
+ emalloc(list, NODE **, list_size * sizeof(NODE *), "str_list");
+
+ /* populate it */
+
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = b->ahnext) {
+ /* index */
+ subs = b->ahname;
+ if (t->flags & AINUM)
+ (void) force_number(subs);
+ list[k++] = dupnode(subs);
+
+ /* value */
+ if (t->flags & AVALUE) {
+ val = b->ahvalue;
+ if (val->type == Node_val) {
+ if ((t->flags & AVNUM) != 0)
+ (void) force_number(val);
+ else if ((t->flags & AVSTR) != 0)
+ val = force_string(val);
+ }
+ list[k++] = val;
+ }
+ if (k >= list_size)
+ return list;
+ }
+ }
+ return list;
+}
+
+
+/* str_kilobytes --- calculate memory consumption of the assoc array */
+
+AWKNUM
+str_kilobytes(NODE *symbol)
+{
+ unsigned long bucket_cnt;
+ AWKNUM kb;
+
+ bucket_cnt = symbol->table_size;
+
+ /* This does not include extra memory for indices with stfmt != -1 */
+ kb = (((AWKNUM) bucket_cnt) * sizeof (BUCKET) +
+ ((AWKNUM) symbol->array_size) * sizeof (BUCKET *)) / 1024.0;
+ return kb;
+}
+
+
+/* str_dump --- dump array info */
+
+static NODE **
+str_dump(NODE *symbol, NODE *ndump)
+{
+#define HCNT 31
+
+ int indent_level;
+ unsigned long i, bucket_cnt;
+ BUCKET *b;
+ static size_t hash_dist[HCNT + 1];
+
+ indent_level = ndump->alevel;
+
+ if ((symbol->flags & XARRAY) == 0)
+ fprintf(output_fp, "%s `%s'\n",
+ (symbol->parent_array == NULL) ? "array" : "sub-array",
+ array_vname(symbol));
+ indent_level++;
+ indent(indent_level);
+ fprintf(output_fp, "array_func: str_array_func\n");
+ if (symbol->flags != 0) {
+ indent(indent_level);
+ fprintf(output_fp, "flags: %s\n", flags2str(symbol->flags));
+ }
+ indent(indent_level);
+ fprintf(output_fp, "STR_CHAIN_MAX: %lu\n", STR_CHAIN_MAX);
+ indent(indent_level);
+ fprintf(output_fp, "array_size: %lu\n", (unsigned long) symbol->array_size);
+ indent(indent_level);
+ fprintf(output_fp, "table_size: %lu\n", (unsigned long) symbol->table_size);
+ indent(indent_level);
+ fprintf(output_fp, "Avg # of items per chain: %.2g\n",
+ ((AWKNUM) symbol->table_size) / symbol->array_size);
+
+ indent(indent_level);
+ fprintf(output_fp, "memory: %.2g kB\n", str_kilobytes(symbol));
+
+ /* hash value distribution */
+
+ memset(hash_dist, '\0', (HCNT + 1) * sizeof(size_t));
+ for (i = 0; i < symbol->array_size; i++) {
+ bucket_cnt = 0;
+ for (b = symbol->buckets[i]; b != NULL; b = b->ahnext)
+ bucket_cnt++;
+ if (bucket_cnt >= HCNT)
+ bucket_cnt = HCNT;
+ hash_dist[bucket_cnt]++;
+ }
+
+ indent(indent_level);
+ fprintf(output_fp, "Hash distribution:\n");
+ indent_level++;
+ for (i = 0; i <= HCNT; i++) {
+ if (hash_dist[i] > 0) {
+ indent(indent_level);
+ if (i == HCNT)
+ fprintf(output_fp, "[>=%lu]:%lu\n",
+ (unsigned long) HCNT, (unsigned long) hash_dist[i]);
+ else
+ fprintf(output_fp, "[%lu]:%lu\n",
+ (unsigned long) i, (unsigned long) hash_dist[i]);
+ }
+ }
+ indent_level--;
+
+ /* dump elements */
+
+ if (ndump->adepth >= 0) {
+ const char *aname;
+
+ fprintf(output_fp, "\n");
+ aname = make_aname(symbol);
+ for (i = 0; i < symbol->array_size; i++) {
+ for (b = symbol->buckets[i]; b != NULL; b = b->ahnext)
+ assoc_info(b->ahname, b->ahvalue, ndump, aname);
+ }
+ }
+
+ return NULL;
+
+#undef HCNT
+}
+
+
+/* awk_hash --- calculate the hash function of the string in subs */
+
+static unsigned long
+awk_hash(const char *s, size_t len, unsigned long hsize, size_t *code)
+{
+ unsigned long h = 0;
+ unsigned long htmp;
+
+ /*
+ * Ozan Yigit's original sdbm hash, copied from Margo Seltzers
+ * db package.
+ *
+ * This is INCREDIBLY ugly, but fast. We break the string up into
+ * 8 byte units. On the first time through the loop we get the
+ * "leftover bytes" (strlen % 8). On every other iteration, we
+ * perform 8 HASHC's so we handle all 8 bytes. Essentially, this
+ * saves us 7 cmp & branch instructions. If this routine is
+ * heavily used enough, it's worth the ugly coding.
+ */
+
+ /*
+ * Even more speed:
+ * #define HASHC h = *s++ + 65599 * h
+ * Because 65599 = pow(2, 6) + pow(2, 16) - 1 we multiply by shifts
+ *
+ * 4/2011: Force the results to 32 bits, to get the same
+ * result on both 32- and 64-bit systems. This may be a
+ * bad idea.
+ */
+#define HASHC htmp = (h << 6); \
+ h = *s++ + htmp + (htmp << 10) - h ; \
+ htmp &= 0xFFFFFFFF; \
+ h &= 0xFFFFFFFF
+
+ h = 0;
+
+ /* "Duff's Device" */
+ if (len > 0) {
+ size_t loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1)) {
+ case 0:
+ do { /* All fall throughs */
+ HASHC;
+ case 7: HASHC;
+ case 6: HASHC;
+ case 5: HASHC;
+ case 4: HASHC;
+ case 3: HASHC;
+ case 2: HASHC;
+ case 1: HASHC;
+ } while (--loop);
+ }
+ }
+
+ if (code != NULL)
+ *code = h;
+
+ if (h >= hsize)
+ h %= hsize;
+ return h;
+}
+
+
+/* str_find --- locate symbol[subs] */
+
+static inline NODE **
+str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1)
+{
+ BUCKET *b;
+ size_t s2_len;
+
+ for (b = symbol->buckets[hash1]; b != NULL; b = b->ahnext) {
+ /*
+ * This used to use cmp_nodes() here. That's wrong.
+ * Array indexes are strings; compare as such, always!
+ */
+ s2_len = b->ahname_len;
+
+ if (code1 == b->ahcode
+ && s1->stlen == s2_len
+ && (s2_len == 0 /* "" is a valid index */
+ || memcmp(s1->stptr, b->ahname_str, s2_len) == 0)
+ )
+ return & (b->ahvalue);
+ }
+ return NULL;
+}
+
+
+/* grow_table --- grow a hash table */
+
+static void
+grow_table(NODE *symbol)
+{
+ BUCKET **old, **new;
+ BUCKET *chain, *next;
+ int i, j;
+ unsigned long oldsize, newsize, k;
+ unsigned long hash1;
+
+ /*
+ * This is an array of primes. We grow the table by an order of
+ * magnitude each time (not just doubling) so that growing is a
+ * rare operation. We expect, on average, that it won't happen
+ * more than twice. The final size is also chosen to be small
+ * enough so that MS-DOG mallocs can handle it. When things are
+ * very large (> 8K), we just double more or less, instead of
+ * just jumping from 8K to 64K.
+ */
+
+ static const unsigned long sizes[] = {
+ 13, 127, 1021, 8191, 16381, 32749, 65497,
+ 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467,
+ 67108879, 134217757, 268435459, 536870923,
+ 1073741827
+ };
+
+ /* find next biggest hash size */
+ newsize = oldsize = symbol->array_size;
+
+ for (i = 0, j = sizeof(sizes)/sizeof(sizes[0]); i < j; i++) {
+ if (oldsize < sizes[i]) {
+ newsize = sizes[i];
+ break;
+ }
+ }
+ if (newsize == oldsize) { /* table already at max (!) */
+ symbol->flags |= ARRAYMAXED;
+ return;
+ }
+
+ /* allocate new table */
+ emalloc(new, BUCKET **, newsize * sizeof(BUCKET *), "grow_table");
+ memset(new, '\0', newsize * sizeof(BUCKET *));
+
+ old = symbol->buckets;
+ symbol->buckets = new;
+ symbol->array_size = newsize;
+
+ /* brand new hash table, set things up and return */
+ if (old == NULL) {
+ symbol->table_size = 0;
+ return;
+ }
+
+ /* old hash table there, move stuff to new, free old */
+
+ /*
+ * note that symbol->table_size does not change if an old array,
+ * and is explicitly set to 0 if a new one.
+ */
+
+ for (k = 0; k < oldsize; k++) {
+ for (chain = old[k]; chain != NULL; chain = next) {
+ next = chain->ahnext;
+ hash1 = chain->ahcode % newsize;
+
+ /* remove from old list, add to new */
+ chain->ahnext = new[hash1];
+ new[hash1] = chain;
+ }
+ }
+ efree(old);
+}
+
+
+#ifdef ARRAYDEBUG
+
+static NODE **
+str_option(NODE *opt, NODE *val)
+{
+ int newval;
+ NODE *tmp;
+ NODE **ret = (NODE **) ! NULL;
+
+ tmp = force_string(opt);
+ (void) force_number(val);
+ if (STREQ(tmp->stptr, "STR_CHAIN_MAX")) {
+ newval = (int) val->numbr;
+ if (newval > 0)
+ STR_CHAIN_MAX = newval;
+ } else
+ ret = NULL;
+ return ret;
+}
+#endif
+
+
+/*
+From bonzini@gnu.org Mon Oct 28 16:05:26 2002
+Date: Mon, 28 Oct 2002 13:33:03 +0100
+From: Paolo Bonzini <bonzini@gnu.org>
+To: arnold@skeeve.com
+Subject: Hash function
+Message-ID: <20021028123303.GA6832@biancaneve>
+
+Here is the hash function I'm using in GNU Smalltalk. The scrambling is
+needed if you use powers of two as the table sizes. If you use primes it
+is not needed.
+
+To use double-hashing with power-of-two size, you should use the
+_gst_hash_string(str, len) as the primary hash and
+scramble(_gst_hash_string (str, len)) | 1 as the secondary hash.
+
+Paolo
+
+*/
+/*
+ * ADR: Slightly modified to work w/in the context of gawk.
+ */
+
+static unsigned long
+gst_hash_string(const char *str, size_t len, unsigned long hsize, size_t *code)
+{
+ unsigned long hashVal = 1497032417; /* arbitrary value */
+ unsigned long ret;
+
+ while (len--) {
+ hashVal += *str++;
+ hashVal += (hashVal << 10);
+ hashVal ^= (hashVal >> 6);
+ }
+
+ ret = scramble(hashVal);
+
+ if (code != NULL)
+ *code = ret;
+
+ if (ret >= hsize)
+ ret %= hsize;
+
+ return ret;
+}
+
+static unsigned long
+scramble(unsigned long x)
+{
+ if (sizeof(long) == 4) {
+ int y = ~x;
+
+ x += (y << 10) | (y >> 22);
+ x += (x << 6) | (x >> 26);
+ x -= (x << 16) | (x >> 16);
+ } else {
+ x ^= (~x) >> 31;
+ x += (x << 21) | (x >> 11);
+ x += (x << 5) | (x >> 27);
+ x += (x << 27) | (x >> 5);
+ x += (x << 31);
+ }
+
+ return x;
+}
diff --git a/symbol.c b/symbol.c
new file mode 100644
index 00000000..57ca7be0
--- /dev/null
+++ b/symbol.c
@@ -0,0 +1,718 @@
+/*
+ * symbol.c - routines for symbol table management and code allocation
+ */
+
+/*
+ * Copyright (C) 1986, 1988, 1989, 1991-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
+ */
+
+#include "awk.h"
+
+extern SRCFILE *srcfiles;
+extern INSTRUCTION *rule_list;
+
+#define HASHSIZE 1021
+
+static NODE *variables[HASHSIZE];
+static int func_count; /* total number of functions */
+static int var_count; /* total number of global variables and functions */
+
+static NODE *symbol_list;
+static void (*install_func)(NODE *) = NULL;
+static NODE *make_symbol(char *name, NODETYPE type);
+static NODE *install(char *name, NODE *hp, NODETYPE type);
+static void free_bcpool(INSTRUCTION *pl);
+
+static AWK_CONTEXT *curr_ctxt = NULL;
+static int ctxt_level;
+
+
+/*
+ * install_symbol:
+ * Install a global name in the symbol table, even if it is already there.
+ * Caller must check against redefinition if that is desired.
+ */
+
+NODE *
+install_symbol(char *name, NODETYPE type)
+{
+ return install(name, NULL, type);
+}
+
+
+/* lookup --- find the most recent global or param node for name
+ * installed by install_symbol
+ */
+
+NODE *
+lookup(const char *name)
+{
+ NODE *hp;
+ size_t len;
+ int hash1;
+
+ len = strlen(name);
+ hash1 = hash(name, len, (unsigned long) HASHSIZE, NULL);
+ for (hp = variables[hash1]; hp != NULL; hp = hp->hnext) {
+ if (hp->hlength == len && strncmp(hp->hname, name, len) == 0)
+ return hp->hvalue;
+ }
+ return NULL;
+}
+
+/* make_params --- allocate function parameters for the symbol table */
+
+NODE *
+make_params(char **pnames, int pcount)
+{
+ NODE *hp, *parms;
+ int i;
+
+ if (pcount <= 0 || pnames == NULL)
+ return NULL;
+
+ emalloc(parms, NODE *, pcount * sizeof(NODE), "make_params");
+ memset(parms, '\0', pcount * sizeof(NODE));
+
+ for (i = 0, hp = parms; i < pcount; i++, hp++) {
+ hp->type = Node_param_list;
+ hp->hname = pnames[i]; /* shadows pname and vname */
+ hp->hlength = strlen(pnames[i]);
+ hp->param_cnt = i;
+ hp->hvalue = hp; /* points to itself */
+ }
+
+ return parms;
+}
+
+/* install_params --- install function parameters into the symbol table */
+
+void
+install_params(NODE *func)
+{
+ int i, pcount;
+ NODE *parms;
+
+ if (func == NULL)
+ return;
+ assert(func->type == Node_func);
+ if ((pcount = func->param_cnt) <= 0
+ || (parms = func->fparms) == NULL
+ )
+ return;
+ for (i = 0; i < pcount; i++)
+ (void) install(NULL, parms + i, Node_param_list);
+}
+
+
+/*
+ * remove_params --- remove function parameters out of the symbol table.
+ */
+
+void
+remove_params(NODE *func)
+{
+ NODE *parms, *p, *prev, *n;
+ int i, pcount, hash1;
+
+ if (func == NULL)
+ return;
+ assert(func->type == Node_func);
+ if ((pcount = func->param_cnt) <= 0
+ || (parms = func->fparms) == NULL
+ )
+ return;
+
+ for (i = pcount - 1; i >= 0; i--) {
+ p = parms + i;
+ hash1 = p->hcode;
+ if (hash1 < 0 || hash1 >= HASHSIZE)
+ continue;
+ for (prev = NULL, n = variables[hash1]; n != NULL;
+ prev = n, n = n->hnext) {
+ if (n == p)
+ break;
+ }
+ if (n == NULL)
+ continue;
+ if (prev == NULL)
+ variables[hash1] = n->hnext; /* param at the head of the chain */
+ else
+ prev->hnext = n->hnext; /* param not at the head */
+ }
+}
+
+
+/* remove_symbol --- remove a symbol from the symbol table */
+
+NODE *
+remove_symbol(NODE *r)
+{
+ NODE *prev, *hp;
+ int hash1;
+
+ hash1 = hash(r->vname, strlen(r->vname), (unsigned long) HASHSIZE, NULL);
+ for (prev = NULL, hp = variables[hash1]; hp != NULL;
+ prev = hp, hp = hp->hnext) {
+ if (hp->hvalue == r)
+ break;
+ }
+
+ if (hp == NULL)
+ return NULL;
+ assert(hp->hcode == hash1);
+
+ if (prev == NULL)
+ variables[hash1] = hp->hnext; /* symbol at the head of chain */
+ else
+ prev->hnext = hp->hnext; /* symbol not at the head */
+
+ if (r->type == Node_param_list)
+ return r; /* r == hp */
+ if (r->type == Node_func)
+ func_count--;
+ if (r->type != Node_ext_func)
+ var_count--;
+ freenode(hp);
+ return r;
+}
+
+
+/* destroy_symbol --- remove a symbol from symbol table
+* and free all associated memory.
+*/
+
+void
+destroy_symbol(NODE *r)
+{
+ r = remove_symbol(r);
+ if (r == NULL)
+ return;
+
+ switch (r->type) {
+ case Node_func:
+ if (r->param_cnt > 0) {
+ NODE *n;
+ int i;
+ int pcount = r->param_cnt;
+
+ /* function parameters of type Node_param_list */
+ for (i = 0; i < pcount; i++) {
+ n = r->fparms + i;
+ efree(n->param);
+ }
+ efree(r->fparms);
+ }
+ break;
+
+ case Node_ext_func:
+ bcfree(r->code_ptr);
+ break;
+
+ case Node_var_array:
+ assoc_clear(r);
+ break;
+
+ case Node_var:
+ unref(r->var_value);
+ break;
+
+ default:
+ /* Node_param_list -- YYABORT */
+ return;
+ }
+
+ efree(r->vname);
+ freenode(r);
+}
+
+
+/* make_symbol --- allocates a global symbol for the symbol table. */
+
+static NODE *
+make_symbol(char *name, NODETYPE type)
+{
+ NODE *hp, *r;
+
+ getnode(hp);
+ hp->type = Node_hashnode;
+ hp->hlength = strlen(name);
+ hp->hname = name;
+ getnode(r);
+ memset(r, '\0', sizeof(NODE));
+ hp->hvalue = r;
+ if (type == Node_var_array)
+ init_array(r);
+ else if (type == Node_var)
+ r->var_value = dupnode(Nnull_string);
+ r->vname = name;
+ r->type = type;
+ return hp;
+}
+
+/* install --- install a global name or function parameter in the symbol table */
+
+static NODE *
+install(char *name, NODE *hp, NODETYPE type)
+{
+ int hash1;
+ NODE *r;
+
+ if (hp == NULL) {
+ /* global symbol */
+ hp = make_symbol(name, type);
+ if (type == Node_func)
+ func_count++;
+ if (type != Node_ext_func)
+ var_count++; /* total, includes Node_func */
+ }
+
+ r = hp->hvalue;
+ hash1 = hash(hp->hname, hp->hlength, (unsigned long) HASHSIZE, NULL);
+ hp->hcode = hash1;
+ hp->hnext = variables[hash1];
+ variables[hash1] = hp;
+
+ if (install_func)
+ (*install_func)(r);
+
+ return r;
+}
+
+
+/* comp_symbol --- compare two (variable or function) names */
+
+static int
+comp_symbol(const void *v1, const void *v2)
+{
+ const NODE *const *npp1, *const *npp2;
+ const NODE *n1, *n2;
+
+ npp1 = (const NODE *const *) v1;
+ npp2 = (const NODE *const *) v2;
+ n1 = *npp1;
+ n2 = *npp2;
+
+ return strcmp(n1->vname, n2->vname);
+}
+
+
+typedef enum { FUNCTION = 1, VARIABLE } SYMBOL_TYPE;
+
+/* get_symbols --- return a list of optionally sorted symbols */
+
+static NODE **
+get_symbols(SYMBOL_TYPE what, int sort)
+{
+ int i;
+ NODE **table;
+ NODE *hp, *r;
+ long j, count = 0;
+
+ if (what == FUNCTION)
+ count = func_count;
+ else /* if (what == VARIABLE) */
+ count = var_count;
+
+ emalloc(table, NODE **, (count + 1) * sizeof(NODE *), "symbol_list");
+ if (what == VARIABLE)
+ update_global_values();
+
+ for (i = j = 0; i < HASHSIZE; i++)
+ for (hp = variables[i]; hp != NULL; hp = hp->hnext) {
+ if (hp->type != Node_hashnode)
+ continue;
+ r = hp->hvalue;
+ if (r->type == Node_ext_func)
+ continue;
+ if (what == FUNCTION && r->type == Node_func)
+ table[j++] = r;
+ else if (what == VARIABLE)
+ table[j++] = r;
+ }
+
+ if (sort && count > 1)
+ qsort(table, count, sizeof(NODE *), comp_symbol); /* Shazzam! */
+ table[count] = NULL; /* null terminate the list */
+ return table;
+}
+
+
+/* variable_list --- list of global variables */
+
+NODE **
+variable_list()
+{
+ return get_symbols(VARIABLE, TRUE);
+}
+
+/* function_list --- list of functions */
+
+NODE **
+function_list(int sort)
+{
+ return get_symbols(FUNCTION, sort);
+}
+
+/* print_vars --- print names and values of global variables */
+
+void
+print_vars(NODE **table, int (*print_func)(FILE *, const char *, ...), FILE *fp)
+{
+ int i;
+ NODE *r;
+
+ assert(table != NULL);
+
+ for (i = 0; (r = table[i]) != NULL; i++) {
+ if (r->type == Node_func || r->type == Node_ext_func)
+ continue;
+ print_func(fp, "%s: ", r->vname);
+ if (r->type == Node_var_array)
+ print_func(fp, "array, %ld elements\n", r->table_size);
+ else if (r->type == Node_var_new)
+ print_func(fp, "untyped variable\n");
+ else if (r->type == Node_var)
+ valinfo(r->var_value, print_func, fp);
+ }
+}
+
+
+/* foreach_func --- execute given function for each awk function in table. */
+
+int
+foreach_func(NODE **table, int (*pfunc)(INSTRUCTION *, void *), void *data)
+{
+ int i;
+ NODE *r;
+ int ret = 0;
+
+ assert(table != NULL);
+
+ for (i = 0; (r = table[i]) != NULL; i++) {
+ if ((ret = pfunc(r->code_ptr, data)) != 0)
+ break;
+ }
+ return ret;
+}
+
+/* release_all_vars --- free all variable memory */
+
+void
+release_all_vars()
+{
+ int i;
+ NODE *hp, *r, *next;
+
+ for (i = 0; i < HASHSIZE; i++)
+ for (hp = variables[i]; hp != NULL; hp = next) {
+ next = hp->hnext;
+ if (hp->type != Node_hashnode)
+ continue;
+ r = hp->hvalue;
+ if (r->type == Node_func || r->type == Node_ext_func)
+ continue;
+ if (r->type == Node_var_array)
+ assoc_clear(r);
+ else if (r->type == Node_var)
+ unref(r->var_value);
+ efree(r->vname);
+ freenode(r);
+ freenode(hp);
+ }
+}
+
+
+/* append_symbol --- append symbol to the list of symbols
+ * installed in the symbol table.
+ */
+
+void
+append_symbol(NODE *r)
+{
+ NODE *hp;
+
+ getnode(hp);
+ hp->lnode = r;
+ hp->rnode = symbol_list->rnode;
+ symbol_list->rnode = hp;
+}
+
+/* release_symbol --- free symbol list and optionally remove symbol from symbol table */
+
+void
+release_symbols(NODE *symlist, int keep_globals)
+{
+ NODE *hp, *next;
+
+ for (hp = symlist->rnode; hp != NULL; hp = next) {
+ if (! keep_globals) {
+ /* destroys globals, function, and params
+ * if still in symbol table
+ */
+ destroy_symbol(hp->lnode);
+ }
+ next = hp->rnode;
+ freenode(hp);
+ }
+ symlist->rnode = NULL;
+}
+
+#define pool_size d.dl
+#define freei x.xi
+static INSTRUCTION *pool_list;
+
+/* INSTR_CHUNK must be > largest code size (3) */
+#define INSTR_CHUNK 127
+
+/* bcfree --- deallocate instruction */
+
+void
+bcfree(INSTRUCTION *cp)
+{
+ cp->opcode = 0;
+ cp->nexti = pool_list->freei;
+ pool_list->freei = cp;
+}
+
+/* bcalloc --- allocate a new instruction */
+
+INSTRUCTION *
+bcalloc(OPCODE op, int size, int srcline)
+{
+ INSTRUCTION *cp;
+
+ if (size > 1) {
+ /* wide instructions Op_rule, Op_func_call .. */
+ emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), "bcalloc");
+ cp->pool_size = size;
+ cp->nexti = pool_list->nexti;
+ pool_list->nexti = cp++;
+ } else {
+ INSTRUCTION *pool;
+
+ pool = pool_list->freei;
+ if (pool == NULL) {
+ INSTRUCTION *last;
+ emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * sizeof(INSTRUCTION), "bcalloc");
+
+ cp->pool_size = INSTR_CHUNK;
+ cp->nexti = pool_list->nexti;
+ pool_list->nexti = cp;
+ pool = ++cp;
+ last = &pool[INSTR_CHUNK - 1];
+ for (; cp <= last; cp++) {
+ cp->opcode = 0;
+ cp->nexti = cp + 1;
+ }
+ --cp;
+ cp->nexti = NULL;
+ }
+ cp = pool;
+ pool_list->freei = cp->nexti;
+ }
+
+ memset(cp, 0, size * sizeof(INSTRUCTION));
+ cp->opcode = op;
+ cp->source_line = srcline;
+ return cp;
+}
+
+/* new_context --- create a new execution context. */
+
+AWK_CONTEXT *
+new_context()
+{
+ AWK_CONTEXT *ctxt;
+
+ emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context");
+ memset(ctxt, 0, sizeof(AWK_CONTEXT));
+ ctxt->srcfiles.next = ctxt->srcfiles.prev = & ctxt->srcfiles;
+ ctxt->rule_list.opcode = Op_list;
+ ctxt->rule_list.lasti = & ctxt->rule_list;
+ return ctxt;
+}
+
+/* set_context --- change current execution context. */
+
+static void
+set_context(AWK_CONTEXT *ctxt)
+{
+ pool_list = & ctxt->pools;
+ symbol_list = & ctxt->symbols;
+ srcfiles = & ctxt->srcfiles;
+ rule_list = & ctxt->rule_list;
+ install_func = ctxt->install_func;
+ curr_ctxt = ctxt;
+}
+
+/*
+ * push_context:
+ *
+ * Switch to the given context after saving the current one. The set
+ * of active execution contexts forms a stack; the global or main context
+ * is at the bottom of the stack.
+ */
+
+void
+push_context(AWK_CONTEXT *ctxt)
+{
+ ctxt->prev = curr_ctxt;
+ /* save current source and sourceline */
+ if (curr_ctxt != NULL) {
+ curr_ctxt->sourceline = sourceline;
+ curr_ctxt->source = source;
+ }
+ sourceline = 0;
+ source = NULL;
+ set_context(ctxt);
+ ctxt_level++;
+}
+
+/* pop_context --- switch to previous execution context. */
+
+void
+pop_context()
+{
+ AWK_CONTEXT *ctxt;
+
+ assert(curr_ctxt != NULL);
+ if (curr_ctxt->prev == NULL)
+ fatal(_("can not pop main context"));
+ ctxt = curr_ctxt->prev;
+ /* restore source and sourceline */
+ sourceline = ctxt->sourceline;
+ source = ctxt->source;
+ set_context(ctxt);
+ ctxt_level--;
+}
+
+/* in_main_context --- are we in the main context ? */
+
+int
+in_main_context()
+{
+ assert(ctxt_level > 0);
+ return (ctxt_level == 1);
+}
+
+/* free_context --- free context structure and related data. */
+
+void
+free_context(AWK_CONTEXT *ctxt, int keep_globals)
+{
+ SRCFILE *s, *sn;
+
+ if (ctxt == NULL)
+ return;
+
+ assert(curr_ctxt != ctxt);
+
+ /* free all code including function codes */
+
+ free_bcpool(& ctxt->pools);
+
+ /* free symbols */
+
+ release_symbols(& ctxt->symbols, keep_globals);
+
+ /* free srcfiles */
+
+ for (s = & ctxt->srcfiles; s != & ctxt->srcfiles; s = sn) {
+ sn = s->next;
+ if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN)
+ efree(s->fullpath);
+ efree(s->src);
+ efree(s);
+ }
+
+ efree(ctxt);
+}
+
+/* free_bc_internal --- free internal memory of an instruction. */
+
+static void
+free_bc_internal(INSTRUCTION *cp)
+{
+ NODE *m;
+
+ switch(cp->opcode) {
+ case Op_func_call:
+ if (cp->func_name != NULL)
+ efree(cp->func_name);
+ break;
+ case Op_push_re:
+ case Op_match_rec:
+ case Op_match:
+ case Op_nomatch:
+ m = cp->memory;
+ if (m->re_reg != NULL)
+ refree(m->re_reg);
+ if (m->re_exp != NULL)
+ unref(m->re_exp);
+ if (m->re_text != NULL)
+ unref(m->re_text);
+ freenode(m);
+ break;
+ case Op_token:
+ /* token lost during error recovery in yyparse */
+ if (cp->lextok != NULL)
+ efree(cp->lextok);
+ break;
+ case Op_push_i:
+ m = cp->memory;
+ unref(m);
+ break;
+ case Op_store_var:
+ m = cp->initval;
+ if (m != NULL)
+ unref(m);
+ break;
+ case Op_illegal:
+ cant_happen();
+ default:
+ break;
+ }
+}
+
+/* free_bcpool --- free list of instruction memory pools */
+
+static void
+free_bcpool(INSTRUCTION *pl)
+{
+ INSTRUCTION *pool, *tmp;
+
+ for (pool = pl->nexti; pool != NULL; pool = tmp) {
+ INSTRUCTION *cp, *last;
+ long psiz;
+ psiz = pool->pool_size;
+ if (psiz == INSTR_CHUNK)
+ last = pool + psiz;
+ else
+ last = pool + 1;
+ for (cp = pool + 1; cp <= last ; cp++) {
+ if (cp->opcode != 0)
+ free_bc_internal(cp);
+ }
+ tmp = pool->nexti;
+ efree(pool);
+ }
+ memset(pl, 0, sizeof(INSTRUCTION));
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index f7d50b28..1bf4456e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -217,6 +217,7 @@ EXTRA_DIST = \
fnarray.awk \
fnarray.ok \
fnarray2.awk \
+ fnarray2.in \
fnarray2.ok \
fnarydel.awk \
fnarydel.ok \
diff --git a/test/Makefile.in b/test/Makefile.in
index 05946f32..6eaeb72d 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -401,6 +401,7 @@ EXTRA_DIST = \
fnarray.awk \
fnarray.ok \
fnarray2.awk \
+ fnarray2.in \
fnarray2.ok \
fnarydel.awk \
fnarydel.ok \
@@ -2036,7 +2037,7 @@ fnarray:
fnarray2:
@echo fnarray2
- @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
fnaryscl:
diff --git a/test/Maketests b/test/Maketests
index c76769f4..5c1a6b38 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -242,7 +242,7 @@ fnarray:
fnarray2:
@echo fnarray2
- @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
fnaryscl:
diff --git a/test/delfunc.ok b/test/delfunc.ok
index d12f0bc9..29a7450d 100644
--- a/test/delfunc.ok
+++ b/test/delfunc.ok
@@ -1,2 +1,3 @@
-gawk: delfunc.awk:4: fatal: attempt to use function `f' as an array
-EXIT CODE: 2
+gawk: delfunc.awk:4: error: function `f' called with space between name and `(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/test/fnamedat.ok b/test/fnamedat.ok
index d32acff4..d7b71c41 100644
--- a/test/fnamedat.ok
+++ b/test/fnamedat.ok
@@ -1,2 +1,3 @@
-gawk: fnamedat.awk:1: (FILENAME=- FNR=1) fatal: can't use function name `foo' as variable or array
-EXIT CODE: 2
+gawk: fnamedat.awk:1: error: function `foo' called with space between name and `(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/test/fnarray.ok b/test/fnarray.ok
index 04260b0f..6cab9134 100644
--- a/test/fnarray.ok
+++ b/test/fnarray.ok
@@ -1,5 +1,3 @@
-gawk: fnarray.awk:5: Num = foo[c]
-gawk: fnarray.awk:5: ^ use of non-array as array
gawk: fnarray.awk:5: error: function `foo' called with space between name and `(',
or used as a variable or an array
EXIT CODE: 1
diff --git a/test/fnarray2.in b/test/fnarray2.in
new file mode 100644
index 00000000..587be6b4
--- /dev/null
+++ b/test/fnarray2.in
@@ -0,0 +1 @@
+x
diff --git a/test/fnarray2.ok b/test/fnarray2.ok
index 243e4cc3..82815055 100644
--- a/test/fnarray2.ok
+++ b/test/fnarray2.ok
@@ -1,3 +1,3 @@
-gawk: fnarray2.awk:3: r = ++pile[c]
-gawk: fnarray2.awk:3: ^ use of non-array as array
+gawk: fnarray2.awk:3: error: function `pile' called with space between name and `(',
+or used as a variable or an array
EXIT CODE: 1
diff --git a/test/fnarydel.ok b/test/fnarydel.ok
index 7f3e4531..7078c015 100644
--- a/test/fnarydel.ok
+++ b/test/fnarydel.ok
@@ -1,24 +1,24 @@
first loop
+1
+2
+3
4
5
6
7
8
9
+second loop
+third loop
1
2
3
-second loop
-third loop
4
5
6
7
8
9
-1
-2
-3
call func
fourth loop
You should just see: 4 4
diff --git a/test/fnasgnm.ok b/test/fnasgnm.ok
index 0db5c6d8..5cacff27 100644
--- a/test/fnasgnm.ok
+++ b/test/fnasgnm.ok
@@ -1,2 +1,3 @@
-gawk: fnasgnm.awk:14: (FILENAME=- FNR=1) fatal: can't use function name `ShowMe' as variable or array
-EXIT CODE: 2
+gawk: fnasgnm.awk:14: error: function `ShowMe' called with space between name and `(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/test/fnparydl.ok b/test/fnparydl.ok
index 26a5c390..9f798224 100644
--- a/test/fnparydl.ok
+++ b/test/fnparydl.ok
@@ -1,10 +1,10 @@
BEFORE LOOP
+DELETING KEY 1
+DELETING KEY 2
+DELETING KEY 3
DELETING KEY 4
DELETING KEY 5
DELETING KEY 6
DELETING KEY 7
-DELETING KEY 1
-DELETING KEY 2
-DELETING KEY 3
AFTER LOOP
0 elements still in q[]
diff --git a/test/funsmnam.ok b/test/funsmnam.ok
index e4f2174a..cce0d275 100644
--- a/test/funsmnam.ok
+++ b/test/funsmnam.ok
@@ -1,2 +1,2 @@
-gawk: funsmnam.awk:1: error: function `foo': can't use function name as parameter name
+gawk: funsmnam.awk:2: error: function `foo': can't use function name as parameter name
EXIT CODE: 1
diff --git a/test/gsubasgn.ok b/test/gsubasgn.ok
index 8817c36d..8a309c7c 100644
--- a/test/gsubasgn.ok
+++ b/test/gsubasgn.ok
@@ -1,5 +1,5 @@
-gawk: gsubasgn.awk:4: function test1 (r) { gsub(r, "x", test1) }
-gawk: gsubasgn.awk:4: ^ gsub third parameter is not a changeable object
-gawk: gsubasgn.awk:8: function test2 () { gsub(/a/, "x", test2) }
-gawk: gsubasgn.awk:8: ^ gsub third parameter is not a changeable object
+gawk: gsubasgn.awk:4: error: function `test1' called with space between name and `(',
+or used as a variable or an array
+gawk: gsubasgn.awk:8: error: function `test2' called with space between name and `(',
+or used as a variable or an array
EXIT CODE: 1
diff --git a/test/match2.ok b/test/match2.ok
index a4a91e85..ad2e324c 100644
--- a/test/match2.ok
+++ b/test/match2.ok
@@ -1,2 +1,3 @@
-gawk: match2.awk:3: fatal: match: third argument is not an array
-EXIT CODE: 2
+gawk: match2.awk:3: error: function `f' called with space between name and `(',
+or used as a variable or an array
+EXIT CODE: 1
diff --git a/version.c b/version.c
index 4e391bba..4c1b6402 100644
--- a/version.c
+++ b/version.c
@@ -1,3 +1,3 @@
#include "config.h"
-const char *version_string = "GNU Awk 4.0.0g";
+const char *version_string = "GNU Awk 4.0.70";