diff options
-rw-r--r-- | .gitignore | 18 | ||||
-rw-r--r-- | ChangeLog | 126 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | Makefile.in | 20 | ||||
-rw-r--r-- | README.git | 218 | ||||
-rw-r--r-- | array.c | 1384 | ||||
-rw-r--r-- | awk.h | 530 | ||||
-rw-r--r-- | awkgram.c | 2700 | ||||
-rw-r--r-- | awkgram.y | 1159 | ||||
-rw-r--r-- | awklib/.gitignore | 8 | ||||
-rw-r--r-- | builtin.c | 63 | ||||
-rw-r--r-- | cint_array.c | 1232 | ||||
-rw-r--r-- | cmd.h | 3 | ||||
-rw-r--r-- | command.c | 254 | ||||
-rw-r--r-- | command.y | 74 | ||||
-rwxr-xr-x | configure | 24 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | debug.c | 317 | ||||
-rw-r--r-- | doc/ChangeLog | 4 | ||||
-rw-r--r-- | doc/gawk.info | 203 | ||||
-rw-r--r-- | doc/gawk.texi | 29 | ||||
-rw-r--r-- | eval.c | 522 | ||||
-rw-r--r-- | ext.c | 150 | ||||
-rw-r--r-- | extension/ChangeLog | 4 | ||||
-rw-r--r-- | extension/arrayparm.c | 8 | ||||
-rw-r--r-- | extension/filefuncs.c | 44 | ||||
-rw-r--r-- | extension/fork.c | 8 | ||||
-rw-r--r-- | extension/ordchr.c | 4 | ||||
-rw-r--r-- | extension/readfile.c | 2 | ||||
-rw-r--r-- | extension/rwarray.c | 6 | ||||
-rw-r--r-- | extension/testarg.c | 8 | ||||
-rw-r--r-- | field.c | 28 | ||||
-rw-r--r-- | int_array.c | 826 | ||||
-rw-r--r-- | io.c | 9 | ||||
-rw-r--r-- | main.c | 137 | ||||
-rw-r--r-- | node.c | 168 | ||||
-rw-r--r-- | pc/ChangeLog | 4 | ||||
-rw-r--r-- | pc/Makefile.tst | 43 | ||||
-rw-r--r-- | po/.gitignore | 4 | ||||
-rw-r--r-- | po/ast.gmo | bin | 37068 -> 0 bytes | |||
-rw-r--r-- | po/ca.gmo | bin | 25787 -> 0 bytes | |||
-rw-r--r-- | po/ga.gmo | bin | 33929 -> 0 bytes | |||
-rw-r--r-- | po/he.gmo | bin | 24651 -> 0 bytes | |||
-rw-r--r-- | po/id.gmo | bin | 35809 -> 0 bytes | |||
-rw-r--r-- | po/pt_BR.gmo | bin | 29120 -> 0 bytes | |||
-rw-r--r-- | po/ro.gmo | bin | 25383 -> 0 bytes | |||
-rw-r--r-- | po/rw.gmo | bin | 487 -> 0 bytes | |||
-rw-r--r-- | po/tr.gmo | bin | 33826 -> 0 bytes | |||
-rw-r--r-- | po/vi.gmo | bin | 40445 -> 0 bytes | |||
-rw-r--r-- | po/zh_CN.gmo | bin | 33717 -> 0 bytes | |||
-rw-r--r-- | profile.c | 40 | ||||
-rw-r--r-- | str_array.c | 759 | ||||
-rw-r--r-- | symbol.c | 718 | ||||
-rw-r--r-- | test/Makefile.am | 1 | ||||
-rw-r--r-- | test/Makefile.in | 3 | ||||
-rw-r--r-- | test/Maketests | 2 | ||||
-rw-r--r-- | test/delfunc.ok | 5 | ||||
-rw-r--r-- | test/fnamedat.ok | 5 | ||||
-rw-r--r-- | test/fnarray.ok | 2 | ||||
-rw-r--r-- | test/fnarray2.in | 1 | ||||
-rw-r--r-- | test/fnarray2.ok | 4 | ||||
-rw-r--r-- | test/fnarydel.ok | 10 | ||||
-rw-r--r-- | test/fnasgnm.ok | 5 | ||||
-rw-r--r-- | test/fnparydl.ok | 6 | ||||
-rw-r--r-- | test/funsmnam.ok | 2 | ||||
-rw-r--r-- | test/gsubasgn.ok | 8 | ||||
-rw-r--r-- | test/match2.ok | 5 | ||||
-rw-r--r-- | version.c | 2 |
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 + @@ -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: @@ -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 @@ -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; } @@ -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 @@ -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) { @@ -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 + @@ -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 @@ -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 */ @@ -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 - @@ -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 - @@ -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 @@ -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); @@ -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); @@ -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); @@ -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 @@ -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; @@ -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; +} @@ -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 Binary files differdeleted file mode 100644 index 7c2ac4e2..00000000 --- a/po/ast.gmo +++ /dev/null diff --git a/po/ca.gmo b/po/ca.gmo Binary files differdeleted file mode 100644 index 426541dc..00000000 --- a/po/ca.gmo +++ /dev/null diff --git a/po/ga.gmo b/po/ga.gmo Binary files differdeleted file mode 100644 index 21141c51..00000000 --- a/po/ga.gmo +++ /dev/null diff --git a/po/he.gmo b/po/he.gmo Binary files differdeleted file mode 100644 index b9cb6d3c..00000000 --- a/po/he.gmo +++ /dev/null diff --git a/po/id.gmo b/po/id.gmo Binary files differdeleted file mode 100644 index 272d5f8c..00000000 --- a/po/id.gmo +++ /dev/null diff --git a/po/pt_BR.gmo b/po/pt_BR.gmo Binary files differdeleted file mode 100644 index 4cbc6792..00000000 --- a/po/pt_BR.gmo +++ /dev/null diff --git a/po/ro.gmo b/po/ro.gmo Binary files differdeleted file mode 100644 index e3534b89..00000000 --- a/po/ro.gmo +++ /dev/null diff --git a/po/rw.gmo b/po/rw.gmo Binary files differdeleted file mode 100644 index a08f9183..00000000 --- a/po/rw.gmo +++ /dev/null diff --git a/po/tr.gmo b/po/tr.gmo Binary files differdeleted file mode 100644 index 146da41d..00000000 --- a/po/tr.gmo +++ /dev/null diff --git a/po/vi.gmo b/po/vi.gmo Binary files differdeleted file mode 100644 index e3a5e619..00000000 --- a/po/vi.gmo +++ /dev/null diff --git a/po/zh_CN.gmo b/po/zh_CN.gmo Binary files differdeleted file mode 100644 index 7ed096c3..00000000 --- a/po/zh_CN.gmo +++ /dev/null @@ -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 @@ -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"; |