diff --git a/usr.bin/awk/FIXES b/usr.bin/awk/FIXES new file mode 100644 index 0000000..a1c4c47 --- /dev/null +++ b/usr.bin/awk/FIXES @@ -0,0 +1,546 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +This file lists all bug fixes, changes, etc., made since the AWK book +was sent to the printers in August, 1987. + +Sep 12, 1987: + Very long printf strings caused core dump; + fixed aprintf, asprintf, format to catch them. + Can still get a core dump in printf itself. + +Sep 17, 1987: + Error-message printer had printf(s) instead of + printf("%s",s); got core dumps when the message + included a %. + +Oct xx, 1987: + Reluctantly added toupper and tolower functions. + Subject to rescinding without notice. + +Dec 2, 1987: + Newer C compilers apply a strict scope rule to extern + declarations within functions. Two extern declarations in + lib.c and tran.c have been moved to obviate this problem. + +Mar 25, 1988: + main.c fixed to recognize -- as terminator of command- + line options. Illegal options flagged. + Error reporting slightly cleaned up. + +May 10, 1988: + Fixed lib.c to permit _ in commandline variable names. + +May 22, 1988: + Removed limit on depth of function calls. + +May 28, 1988: + srand returns seed value it's using. + see 1/18/90 + +June 1, 1988: + check error status on close + +July 2, 1988: + performance bug in b.c/cgoto(): not freeing some sets of states. + partial fix only right now, and the number of states increased + to make it less obvious. + +July 2, 1988: + flush stdout before opening file or pipe + +July 24, 1988: + fixed egregious error in toupper/tolower functions. + still subject to rescinding, however. + +Aug 23, 1988: + setting FILENAME in BEGIN caused core dump, apparently + because it was freeing space not allocated by malloc. + +Sep 30, 1988: + Now guarantees to evaluate all arguments of built-in + functions, as in C; the appearance is that arguments + are evaluated before the function is called. Places + affected are sub (gsub was ok), substr, printf, and + all the built-in arithmetic functions in bltin(). + A warning is generated if a bltin() is called with + the wrong number of arguments. + + This requires changing makeprof on p167 of the book. + +Oct 12, 1988: + Fixed bug in call() that freed local arrays twice. + + Fixed to handle deletion of non-existent array right; + complains about attempt to delete non-array element. + +Oct 20, 1988: + Fixed %c: if expr is numeric, use numeric value; + otherwise print 1st char of string value. still + doesn't work if the value is 0 -- won't print \0. + + Added a few more checks for running out of malloc. + +Oct 30, 1988: + Fixed bug in call() that failed to recover storage. + + A warning is now generated if there are more arguments + in the call than in the definition (in lieu of fixing + another storage leak). + +Nov 27, 1988: + With fear and trembling, modified the grammar to permit + multiple pattern-action statements on one line without + an explicit separator. By definition, this capitulation + to the ghost of ancient implementations remains undefined + and thus subject to change without notice or apology. + DO NOT COUNT ON IT. + +Dec 7, 1988: + Added a bit of code to error printing to avoid printing nulls. + (Not clear that it actually would.) + +Dec 17, 1988: + Catches some more commandline errors in main. + Removed redundant decl of modf in run.c (confuses some compilers). + Warning: there's no single declaration of malloc, etc., in awk.h + that seems to satisfy all compilers. + +Jan 9, 1989: + Fixed bug that caused tempcell list to contain a duplicate. + The fix is kludgy. + +Apr 9, 1989: + Changed grammar to prohibit constants as 3rd arg of sub and gsub; + prevents class of overwriting-a-constant errors. (Last one?) + This invalidates the "banana" example on page 43 of the book. + + Added \a ("alert"), \v (vertical tab), \xhhh (hexadecimal), + as in ANSI, for strings. Rescinded the sloppiness that permitted + non-octal digits in \ooo. Warning: not all compilers and libraries + will be able to deal with \x correctly. + +Apr 26, 1989: + Debugging output now includes a version date, + if one compiles it into the source each time. + +Apr 27, 1989: + Line number now accumulated correctly for comment lines. + +Jun 4, 1989: + ENVIRON array contains environment: if shell variable V=thing, + ENVIRON["V"] is "thing" + + multiple -f arguments permitted. error reporting is naive. + (they were permitted before, but only the last was used.) + + fixed a really stupid botch in the debugging macro dprintf + + fixed order of evaluation of commandline assignments to match + what the book claims: an argument of the form x=e is evaluated + at the time it would have been opened if it were a filename (p 63). + this invalidates the suggested answer to ex 4-1 (p 195). + + removed some code that permitted -F (space) fieldseparator, + since it didn't quite work right anyway. (restored aug 2) + +Jun 14, 1989: + added some missing ansi printf conversion letters: %i %X %E %G. + no sensible meaning for h or L, so they may not do what one expects. + + made %* conversions work. + + changed x^y so that if n is a positive integer, it's done + by explicit multiplication, thus achieving maximum accuracy. + (this should be done by pow() but it seems not to be locally.) + done to x ^= y as well. + +Jun 23, 1989: + add newline to usage message. + +Jul 10, 1989: + fixed ref-thru-zero bug in environment code in tran.c + +Jul 30, 1989: + added -v x=1 y=2 ... for immediate commandline variable assignment; + done before the BEGIN block for sure. they have to precede the + program if the program is on the commandline. + Modified Aug 2 to require a separate -v for each assignment. + +Aug 2, 1989: + restored -F (space) separator + +Aug 11, 1989: + fixed bug: commandline variable assignment has to look like + var=something. (consider the man page for =, in file =.1) + + changed number of arguments to functions to static arrays + to avoid repeated malloc calls. + +Aug 24, 1989: + removed redundant relational tests against nullnode if parse + tree already had a relational at that point. + +Oct 11, 1989: + FILENAME is now defined in the BEGIN block -- too many old + programs broke. + + "-" means stdin in getline as well as on the commandline. + + added a bunch of casts to the code to tell the truth about + char * vs. unsigned char *, a right royal pain. added a + setlocale call to the front of main, though probably no one + has it usefully implemented yet. + +Oct 18, 1989: + another try to get the max number of open files set with + relatively machine-independent code. + + small fix to input() in case of multiple reads after EOF. + +Jan 5, 1990: + fix potential problem in tran.c -- something was freed, + then used in freesymtab. + +Jan 18, 1990: + srand now returns previous seed value (0 to start). + +Feb 9, 1990: + fixed null pointer dereference bug in main.c: -F[nothing]. sigh. + + restored srand behavior: it returns the current seed. + +May 6, 1990: + AVA fixed the grammar so that ! is uniformly of the same precedence as + unary + and -. This renders illegal some constructs like !x=y, which + now has to be parenthesized as !(x=y), and makes others work properly: + !x+y is (!x)+y, and x!y is x !y, not two pattern-action statements. + (These problems were pointed out by Bob Lenk of Posix.) + + Added \x to regular expressions (already in strings). + Limited octal to octal digits; \8 and \9 are not octal. + Centralized the code for parsing escapes in regular expressions. + Added a bunch of tests to T.re and T.sub to verify some of this. + +Jun 26, 1990: + changed struct rrow (awk.h) to use long instead of int for lval, + since cfoll() stores a pointer in it. now works better when int's + are smaller than pointers! + +Aug 24, 1990: + changed NCHARS to 256 to handle 8-bit characters in strings + presented to match(), etc. + +Oct 8, 1990: + fixed horrible bug: types and values were not preserved in + some kinds of self-assignment. (in assign().) + +Oct 14, 1990: + fixed the bug on p. 198 in which it couldn't deduce that an + argument was an array in some contexts. replaced the error + message in intest() by code that damn well makes it an array. + +Oct 29, 1990: + fixed sleazy buggy code in lib.c that looked (incorrectly) for + too long input lines. + +Nov 2, 1990: + fixed sleazy test for integrality in getsval; use modf. + +Jan 11, 1991: + failed to set numeric state on $0 in cmd|getline context in run.c. + +Jan 28, 1991: + awk -f - reads the program from stdin. + +Feb 10, 1991: + check error status on all writes, to avoid banging on full disks. + +May 6, 1991: + fixed silly bug in hex parsing in hexstr(). + removed an apparently unnecessary test in isnumber(). + warn about weird printf conversions. + fixed unchecked array overwrite in relex(). + + changed for (i in array) to access elements in sorted order. + then unchanged it -- it really does run slower in too many cases. + left the code in place, commented out. + +May 13, 1991: + removed extra arg on gettemp, tempfree. minor error message rewording. + +Jun 2, 1991: + better defense against very long printf strings. + made break and continue illegal outside of loops. + +Jun 30, 1991: + better test for detecting too-long output record. + +Jul 21, 1991: + fixed so that in self-assignment like $1=$1, side effects + like recomputing $0 take place. (this is getting subtle.) + +Jul 27, 1991: + allow newline after ; in for statements. + +Aug 18, 1991: + enforce variable name syntax for commandline variables: has to + start with letter or _. + +Sep 24, 1991: + increased buffer in gsub. a very crude fix to a general problem. + and again on Sep 26. + +Nov 12, 1991: + cranked up some fixed-size arrays in b.c, and added a test for + overflow in penter. thanks to mark larsen. + +Nov 19, 1991: + use RAND_MAX instead of literal in builtin(). + +Nov 30, 1991: + fixed storage leak in freefa, failing to recover [N]CCL. + thanks to Bill Jones (jones@skorpio.usask.ca) + +Dec 2, 1991: + die-casting time: converted to ansi C, installed that. + +Feb 20, 1992: + recompile after abortive changes; should be unchanged. + +Apr 12, 1992: + added explicit check for /dev/std(in,out,err) in redirection. + unlike gawk, no /dev/fd/n yet. + + added (file/pipe) builtin. hard to test satisfactorily. + not posix. + +Apr 24, 1992: + remove redundant close of stdin when using -f -. + + got rid of core dump with -d; awk -d just prints date. + +May 31, 1992: + added -mr N and -mf N options: more record and fields. + these really ought to adjust automatically. + + cleaned up some error messages; "out of space" now means + malloc returned NULL in all cases. + + changed rehash so that if it runs out, it just returns; + things will continue to run slow, but maybe a bit longer. + +Nov 28, 1992: + deleted yyunput and yyoutput from proto.h; + different versions of lex give these different declarations. + +Jul 23, 1993: + cosmetic changes: increased sizes of some arrays, + reworded some error messages. + + added CONVFMT as in posix (just replaced OFMT in getsval) + + FILENAME is now "" until the first thing that causes a file + to be opened. + +Feb 2, 1994: + changed error() to print line number as %d, not %g. + +Apr 22, 1994: + fixed yet another subtle self-assignment problem: + $1 = $2; $1 = $1 clobbered $1. + + Regression tests now use private echo, to avoid quoting problems. + +May 11, 1994: + trivial fix to printf to limit string size in sub(). + +Aug 24, 1994: + detect duplicate arguments in function definitions (mdm). + +Jul 17, 1995: + added dynamically growing strings to awk.lx.l and b.c + to permit regular expressions to be much bigger. + the state arrays can still overflow. + +Aug 15, 1995: + initialized Cells in setsymtab more carefully; some fields + were not set. (thanks to purify, all of whose complaints i + think i now understand.) + + fixed at least one error in gsub that looked at -1-th element + of an array when substituting for a null match (e.g., $). + + delete arrayname is now legal; it clears the elements but leaves + the array, which may not be the right behavior. + + modified makefile: my current make can't cope with the test used + to avoid unnecessary yacc invocations. + +Apr 29, 1996: + replaced uchar by uschar everwhere; apparently some compilers + usurp this name and this causes conflicts. + + fixed call to time in run.c (bltin); arg is time_t *. + + replaced horrible pointer/long punning in b.c by a legitimate + union. should be safer on 64-bit machines and cleaner everywhere. + (thanks to nelson beebe for pointing out some of these problems.) + + replaced nested comments by #if 0...#endif in run.c, lib.c. + + removed getsval, setsval, execute macros from run.c and lib.c. + machines are 100x faster than they were when these macros were + first used. + + revised filenames: awk.g.y => awkgram.y, awk.lx.l => awklex.l, + y.tab.[ch] => ytab.[ch], lex.yy.c => lexyy.c, all in the aid of + portability to nameless systems. + + "make bundle" now includes yacc and lex output files for recipients + who don't have yacc or lex. + +May 2, 1996: + removed all register declarations. + + enhanced split(), as in gawk, etc: split(s, a, "") splits s into + a[1]...a[length(s)] with each character a single element. + + made the same changes for field-splitting if FS is "". + + added nextfile, as in gawk: causes immediate advance to next + input file. (thanks to arnold robbins for inspiration and code). + + small fixes to regexpr code: can now handle []], [[], and + variants; [] is now a syntax error, rather than matching + everything; [z-a] is now empty, not z. far from complete + or correct, however. (thanks to jeffrey friedl for pointing out + some awful behaviors.) + +May 26, 1996: + an attempt to rationalize the (unsigned) char issue. almost all + instances of unsigned char have been removed; the handful of places + in b.c where chars are used as table indices have been hand-crafted. + added some latin-1 tests to the regression, but i'm not confident; + none of my compilers seem to care much. thanks to nelson beebe for + pointing out some others that do care. + +May 27, 1996: + cleaned up some declarations so gcc -Wall is now almost silent. + + makefile now includes backup copies of ytab.c and lexyy.c in case + one makes before looking; it also avoids recreating lexyy.c unless + really needed. + + s/aprintf/awkprint, s/asprintf/awksprintf/ to avoid some name clashes + with unwisely-written header files. + + thanks to jeffrey friedl for several of these. + +May 28, 1996: + fixed appalling but apparently unimportant bug in parsing octal + numbers in reg exprs. + + explicit hex in reg exprs now limited to 2 chars: \xa, \xaa. + +Jun 28, 1996: + changed field-splitting to conform to posix definition: fields are + split using the value of FS at the time of input; it used to be + the value when the field or NF was first referred to, a much less + predictable definition. thanks to arnold robbins for encouragement + to do the right thing. + +Jun 29, 1996: + fixed awful bug in new field splitting; didn't get all the places + where input was done. + +Jul 8, 1996: + fixed long-standing bug in sub, gsub(/a/, "\\\\&"); thanks to + ralph corderoy. + +Jun 17, 1997: + replaced several fixed-size arrays by dynamically-created ones + in run.c; added overflow tests to some previously unchecked cases. + getline, toupper, tolower. + + getline code is still broken in that recursive calls may wind + up using the same space. [fixed later] + + increased RECSIZE to 8192 to push problems further over the horizon. + + added \r to \n as input line separator for programs, not data. + damn CRLFs. + + modified format() to permit explicit printf("%c", 0) to include + a null byte in output. thanks to ken stailey for the fix. + + added a "-safe" argument that disables file output (print >, + print >>), process creation (cmd|getline, print |, system), and + access to the environment (ENVIRON). this is a first approximation + to a "safe" version of awk, but don't rely on it too much. thanks + to joan feigenbaum and matt blaze for the inspiration long ago. + +Jul 23, 1997: + falling off the end of a function returns "" and 0, not 0. + thanks to arnold robbins. + +Jul 30, 1997: + using code provided by dan levy (to whom profuse thanks), replaced + fixed-size arrays and awkward kludges by a fairly uniform mechanism + to grow arrays as needed for printf, sub, gsub, etc. + +Aug 4, 1997: + with some trepidation, replaced the ancient code that managed + fields and $0 in fixed-size arrays with arrays that grow on + demand. there is still some tension between trying to make this + run fast and making it clean; not sure it's right yet. + + the ill-conceived -mr and -mf arguments are now useful only + for debugging. previous dynamic string code removed. + + numerous other minor cleanups along the way. + +Aug 9, 1997: + somewhat regretfully, replaced the ancient lex-based lexical + analyzer with one written in C. it's longer, generates less code, + and more portable; the old one depended too much on mysterious + properties of lex that were not preserved in other environments. + in theory these recognize the same language. + + now using strtod to test whether a string is a number, instead of + the convoluted original function. should be more portable and + reliable if strtod is implemented right. + + removed now-pointless optimization in makefile that tries to avoid + recompilation when awkgram.y is changed but symbols are not. + + removed most fixed-size arrays, though a handful remain, some + of which are unchecked. you have been warned. + +Aug 21, 1997: + fixed some bugs in sub and gsub when replacement includes \\. + this is a dark, horrible corner, but at least now i believe that + the behavior is the same as gawk and the intended posix standard. + thanks to arnold robbins for advice here. + diff --git a/usr.bin/awk/README b/usr.bin/awk/README new file mode 100644 index 0000000..2f986d0 --- /dev/null +++ b/usr.bin/awk/README @@ -0,0 +1,78 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +This is the version of awk described in "The AWK Programming Language", +by Al Aho, Brian Kernighan, and Peter Weinberger +(Addison-Wesley, 1988, ISBN 0-201-07981-X). + +Changes, mostly bug fixes and occasional enhancements, are listed +in FIXES. If you distribute this code further, please please please +distribute FIXES with it. If you find errors, please report them +to bwk@bell-labs.com. Thanks. + +The program itself is created by + make +which should produce a sequence of messages roughly like this: + + yacc -d awkgram.y + +conflicts: 42 shift/reduce, 83 reduce/reduce + mv y.tab.c ytab.c + mv y.tab.h ytab.h + cc -O -c ytab.c + cc -O -c b.c + cc -O -c main.c + cc -O -c parse.c + cc -O maketab.c -o maketab + ./maketab >proctab.c + cc -O -c proctab.c + cc -O -c tran.c + cc -O -c lib.c + cc -O -c run.c + cc -O -c lex.c + cc -O ytab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm + +This produces an executable a.out; you will eventually +want to move this to some place like /usr/bin/awk. + +If your system is does not have yacc or bison (the GNU +equivalent), you must compile the pieces manually. We have +included yacc output in ytab.c and ytab.h, and backup copies in +case you overwrite them. + +NOTE: This version uses ANSI C, as you should also. We have +compiled this without any changes using gcc -Wall and/or local C +compilers on a variety of systems, but new systems or compilers +may raise some new complaint; reports of difficulties are +welcome. + +This also compiles with Visual C++ 4.1 on Windows 95 and +presumably Windows NT, *if* you provide versions of popen and +pclose. The file missing95.c contains do-nothing versions that +can be used to get started with. It is too much trouble to +figure out how to make these work for real. + +The version of malloc that comes with some systems is sometimes +astonishly slow. If awk seems slow, you might try fixing that. + diff --git a/usr.bin/awk/awk.1 b/usr.bin/awk/awk.1 new file mode 100644 index 0000000..b54d27c --- /dev/null +++ b/usr.bin/awk/awk.1 @@ -0,0 +1,543 @@ +.de EX +.nf +.ft CW +.. +.de EE +.br +.fi +.ft 1 +.. +awk +.TH AWK 1 +.CT 1 files prog_other +.SH NAME +awk \- pattern-directed scanning and processing language +.SH SYNOPSIS +.B awk +[ +.BI \-F +.I fs +] +[ +.BI \-v +.I var=value +] +[ +.BI \-mr n +] +[ +.BI \-mf n +] +[ +.I 'prog' +| +.BI \-f +.I progfile +] +[ +.I file ... +] +.SH DESCRIPTION +.I Awk +scans each input +.I file +for lines that match any of a set of patterns specified literally in +.IR prog +or in one or more files +specified as +.B \-f +.IR progfile . +With each pattern +there can be an associated action that will be performed +when a line of a +.I file +matches the pattern. +Each line is matched against the +pattern portion of every pattern-action statement; +the associated action is performed for each matched pattern. +The file name +.B \- +means the standard input. +Any +.IR file +of the form +.I var=value +is treated as an assignment, not a filename, +and is executed at the time it would have been opened if it were a filename. +The option +.B \-v +followed by +.I var=value +is an assignment to be done before +.I prog +is executed; +any number of +.B \-v +options may be present. +The +.B \-F +.IR fs +option defines the input field separator to be the regular expression +.IR fs. +.PP +An input line is normally made up of fields separated by white space, +or by regular expression +.BR FS . +The fields are denoted +.BR $1 , +.BR $2 , +\&..., while +.B $0 +refers to the entire line. +If +.BR FS +is null, the input line is split into one field per character. +.PP +To compensate for inadequate implementation of storage management, +the +.B \-mr +option can be used to set the maximum size of the input record, +and the +.B \-mf +option to set the maximum number of fields. +.PP +A pattern-action statement has the form +.IP +.IB pattern " { " action " } +.PP +A missing +.BI { " action " } +means print the line; +a missing pattern always matches. +Pattern-action statements are separated by newlines or semicolons. +.PP +An action is a sequence of statements. +A statement can be one of the following: +.PP +.EX +.ta \w'\f(CWdelete array[expression]'u +.RS +.nf +.ft CW +if(\fI expression \fP)\fI statement \fP\fR[ \fPelse\fI statement \fP\fR]\fP +while(\fI expression \fP)\fI statement\fP +for(\fI expression \fP;\fI expression \fP;\fI expression \fP)\fI statement\fP +for(\fI var \fPin\fI array \fP)\fI statement\fP +do\fI statement \fPwhile(\fI expression \fP) +break +continue +{\fR [\fP\fI statement ... \fP\fR] \fP} +\fIexpression\fP #\fR commonly\fP\fI var = expression\fP +print\fR [ \fP\fIexpression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP +printf\fI format \fP\fR[ \fP,\fI expression-list \fP\fR] \fP\fR[ \fP>\fI expression \fP\fR]\fP +return\fR [ \fP\fIexpression \fP\fR]\fP +next #\fR skip remaining patterns on this input line\fP +nextfile #\fR skip rest of this file, open next, start at top\fP +delete\fI array\fP[\fI expression \fP] #\fR delete an array element\fP +delete\fI array\fP #\fR delete all elements of array\fP +exit\fR [ \fP\fIexpression \fP\fR]\fP #\fR exit immediately; status is \fP\fIexpression\fP +.fi +.RE +.EE +.DT +.PP +Statements are terminated by +semicolons, newlines or right braces. +An empty +.I expression-list +stands for +.BR $0 . +String constants are quoted \&\f(CW"\ "\fR, +with the usual C escapes recognized within. +Expressions take on string or numeric values as appropriate, +and are built using the operators +.B + \- * / % ^ +(exponentiation), and concatenation (indicated by white space). +The operators +.B +! ++ \-\- += \-= *= /= %= ^= > >= < <= == != ?: +are also available in expressions. +Variables may be scalars, array elements +(denoted +.IB x [ i ] ) +or fields. +Variables are initialized to the null string. +Array subscripts may be any string, +not necessarily numeric; +this allows for a form of associative memory. +Multiple subscripts such as +.B [i,j,k] +are permitted; the constituents are concatenated, +separated by the value of +.BR SUBSEP . +.PP +The +.B print +statement prints its arguments on the standard output +(or on a file if +.BI > file +or +.BI >> file +is present or on a pipe if +.BI | cmd +is present), separated by the current output field separator, +and terminated by the output record separator. +.I file +and +.I cmd +may be literal names or parenthesized expressions; +identical string values in different statements denote +the same open file. +The +.B printf +statement formats its expression list according to the format +(see +.IR printf (3)) . +The built-in function +.BI close( expr ) +closes the file or pipe +.IR expr . +The built-in function +.BI fflush( expr ) +flushes any buffered output for the file or pipe +.IR expr . +.PP +The mathematical functions +.BR exp , +.BR log , +.BR sqrt , +.BR sin , +.BR cos , +and +.BR atan2 +are built in. +Other built-in functions: +.TF length +.TP +.B length +the length of its argument +taken as a string, +or of +.B $0 +if no argument. +.TP +.B rand +random number on (0,1) +.TP +.B srand +sets seed for +.B rand +and returns the previous seed. +.TP +.B int +truncates to an integer value +.TP +.BI substr( s , " m" , " n\fB) +the +.IR n -character +substring of +.I s +that begins at position +.IR m +counted from 1. +.TP +.BI index( s , " t" ) +the position in +.I s +where the string +.I t +occurs, or 0 if it does not. +.TP +.BI match( s , " r" ) +the position in +.I s +where the regular expression +.I r +occurs, or 0 if it does not. +The variables +.B RSTART +and +.B RLENGTH +are set to the position and length of the matched string. +.TP +.BI split( s , " a" , " fs\fB) +splits the string +.I s +into array elements +.IB a [1] , +.IB a [2] , +\&..., +.IB a [ n ] , +and returns +.IR n . +The separation is done with the regular expression +.I fs +or with the field separator +.B FS +if +.I fs +is not given. +An empty string as field separator splits the string +into one array element per character. +.TP +.BI sub( r , " t" , " s\fB) +substitutes +.I t +for the first occurrence of the regular expression +.I r +in the string +.IR s . +If +.I s +is not given, +.B $0 +is used. +.TP +.B gsub +same as +.B sub +except that all occurrences of the regular expression +are replaced; +.B sub +and +.B gsub +return the number of replacements. +.TP +.BI sprintf( fmt , " expr" , " ...\fB ) +the string resulting from formatting +.I expr ... +according to the +.IR printf (3) +format +.I fmt +.TP +.BI system( cmd ) +executes +.I cmd +and returns its exit status +.TP +.BI tolower( str ) +returns a copy of +.I str +with all upper-case characters translated to their +corresponding lower-case equivalents. +.TP +.BI toupper( str ) +returns a copy of +.I str +with all lower-case characters translated to their +corresponding upper-case equivalents. +.PD +.PP +The ``function'' +.B getline +sets +.B $0 +to the next input record from the current input file; +.B getline +.BI < file +sets +.B $0 +to the next record from +.IR file . +.B getline +.I x +sets variable +.I x +instead. +Finally, +.IB cmd " | getline +pipes the output of +.I cmd +into +.BR getline ; +each call of +.B getline +returns the next line of output from +.IR cmd . +In all cases, +.B getline +returns 1 for a successful input, +0 for end of file, and \-1 for an error. +.PP +Patterns are arbitrary Boolean combinations +(with +.BR "! || &&" ) +of regular expressions and +relational expressions. +Regular expressions are as in +.IR egrep ; +see +.IR grep (1). +Isolated regular expressions +in a pattern apply to the entire line. +Regular expressions may also occur in +relational expressions, using the operators +.BR ~ +and +.BR !~ . +.BI / re / +is a constant regular expression; +any string (constant or variable) may be used +as a regular expression, except in the position of an isolated regular expression +in a pattern. +.PP +A pattern may consist of two patterns separated by a comma; +in this case, the action is performed for all lines +from an occurrence of the first pattern +though an occurrence of the second. +.PP +A relational expression is one of the following: +.IP +.I expression matchop regular-expression +.br +.I expression relop expression +.br +.IB expression " in " array-name +.br +.BI ( expr , expr,... ") in " array-name +.PP +where a relop is any of the six relational operators in C, +and a matchop is either +.B ~ +(matches) +or +.B !~ +(does not match). +A conditional is an arithmetic expression, +a relational expression, +or a Boolean combination +of these. +.PP +The special patterns +.B BEGIN +and +.B END +may be used to capture control before the first input line is read +and after the last. +.B BEGIN +and +.B END +do not combine with other patterns. +.PP +Variable names with special meanings: +.TF FILENAME +.TP +.B CONVFMT +conversion format used when converting numbers +(default +.BR "%.6g" ) +.TP +.B FS +regular expression used to separate fields; also settable +by option +.BI \-F fs. +.TP +.BR NF +number of fields in the current record +.TP +.B NR +ordinal number of the current record +.TP +.B FNR +ordinal number of the current record in the current file +.TP +.B FILENAME +the name of the current input file +.TP +.B RS +input record separator (default newline) +.TP +.B OFS +output field separator (default blank) +.TP +.B ORS +output record separator (default newline) +.TP +.B OFMT +output format for numbers (default +.BR "%.6g" ) +.TP +.B SUBSEP +separates multiple subscripts (default 034) +.TP +.B ARGC +argument count, assignable +.TP +.B ARGV +argument array, assignable; +non-null members are taken as filenames +.TP +.B ENVIRON +array of environment variables; subscripts are names. +.PD +.PP +Functions may be defined (at the position of a pattern-action statement) thus: +.IP +.B +function foo(a, b, c) { ...; return x } +.PP +Parameters are passed by value if scalar and by reference if array name; +functions may be called recursively. +Parameters are local to the function; all other variables are global. +Thus local variables may be created by providing excess parameters in +the function definition. +.SH EXAMPLES +.TP +.EX +length($0) > 72 +.EE +Print lines longer than 72 characters. +.TP +.EX +{ print $2, $1 } +.EE +Print first two fields in opposite order. +.PP +.EX +BEGIN { FS = ",[ \et]*|[ \et]+" } + { print $2, $1 } +.EE +.ns +.IP +Same, with input fields separated by comma and/or blanks and tabs. +.PP +.EX +.nf + { s += $1 } +END { print "sum is", s, " average is", s/NR } +.fi +.EE +.ns +.IP +Add up first column, print sum and average. +.TP +.EX +/start/, /stop/ +.EE +Print all lines between start/stop pairs. +.PP +.EX +.nf +BEGIN { # Simulate echo(1) + for (i = 1; i < ARGC; i++) printf "%s ", ARGV[i] + printf "\en" + exit } +.fi +.EE +.SH SEE ALSO +.IR lex (1), +.IR sed (1) +.br +A. V. Aho, B. W. Kernighan, P. J. Weinberger, +.I +The AWK Programming Language, +Addison-Wesley, 1988. ISBN 0-201-07981-X +.SH BUGS +There are no explicit conversions between numbers and strings. +To force an expression to be treated as a number add 0 to it; +to force it to be treated as a string concatenate +\&\f(CW""\fP to it. +.br +The scope rules for variables in functions are a botch; +the syntax is worse. diff --git a/usr.bin/awk/awk.h b/usr.bin/awk/awk.h new file mode 100644 index 0000000..97c5ad3 --- /dev/null +++ b/usr.bin/awk/awk.h @@ -0,0 +1,236 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +typedef double Awkfloat; + +/* unsigned char is more trouble than it's worth */ + +typedef unsigned char uschar; + +#define xfree(a) { if ((a) != NULL) { free((char *) a); a = NULL; } } + +#define DEBUG +#ifdef DEBUG + /* uses have to be doubly parenthesized */ +# define dprintf(x) if (dbg) printf x +#else +# define dprintf(x) +#endif + +extern char errbuf[]; +#define ERROR sprintf(errbuf, +#define FATAL ), error(1, errbuf) +#define WARNING ), error(0, errbuf) +#define SYNTAX ), yyerror(errbuf) + +extern int compile_time; /* 1 if compiling, 0 if running */ +extern int safe; /* 0 => unsafe, 1 => safe */ + +#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */ +extern int recsize; /* size of current record, orig RECSIZE */ + +extern char **FS; +extern char **RS; +extern char **ORS; +extern char **OFS; +extern char **OFMT; +extern Awkfloat *NR; +extern Awkfloat *FNR; +extern Awkfloat *NF; +extern char **FILENAME; +extern char **SUBSEP; +extern Awkfloat *RSTART; +extern Awkfloat *RLENGTH; + +extern char *record; /* points to $0 */ +extern int lineno; /* line number in awk program */ +extern int errorflag; /* 1 if error has occurred */ +extern int donefld; /* 1 if record broken into fields */ +extern int donerec; /* 1 if record is valid (no fld has changed */ +extern char inputFS[]; /* FS at time of input, for field splitting */ + +extern int dbg; + +extern char *patbeg; /* beginning of pattern matched */ +extern int patlen; /* length of pattern matched. set in b.c */ + +/* Cell: all information about a variable or constant */ + +typedef struct Cell { + uschar ctype; /* OCELL, OBOOL, OJUMP, etc. */ + uschar csub; /* CCON, CTEMP, CFLD, etc. */ + char *nval; /* name, for variables only */ + char *sval; /* string value */ + Awkfloat fval; /* value as number */ + unsigned tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE */ + struct Cell *cnext; /* ptr to next if chained */ +} Cell; + +typedef struct Array { /* symbol table array */ + int nelem; /* elements in table right now */ + int size; /* size of tab */ + Cell **tab; /* hash table pointers */ +} Array; + +#define NSYMTAB 50 /* initial size of a symbol table */ +extern Array *symtab; + +extern Cell *nrloc; /* NR */ +extern Cell *fnrloc; /* FNR */ +extern Cell *nfloc; /* NF */ +extern Cell *rstartloc; /* RSTART */ +extern Cell *rlengthloc; /* RLENGTH */ + +/* Cell.tval values: */ +#define NUM 01 /* number value is valid */ +#define STR 02 /* string value is valid */ +#define DONTFREE 04 /* string space is not freeable */ +#define CON 010 /* this is a constant */ +#define ARR 020 /* this is an array */ +#define FCN 040 /* this is a function name */ +#define FLD 0100 /* this is a field $1, $2, ... */ +#define REC 0200 /* this is $0 */ + + +/* function types */ +#define FLENGTH 1 +#define FSQRT 2 +#define FEXP 3 +#define FLOG 4 +#define FINT 5 +#define FSYSTEM 6 +#define FRAND 7 +#define FSRAND 8 +#define FSIN 9 +#define FCOS 10 +#define FATAN 11 +#define FTOUPPER 12 +#define FTOLOWER 13 +#define FFLUSH 14 + +/* Node: parse tree is made of nodes, with Cell's at bottom */ + +typedef struct Node { + int ntype; + struct Node *nnext; + int lineno; + int nobj; + struct Node *narg[1]; /* variable: actual size set by calling malloc */ +} Node; + +#define NIL ((Node *) 0) + +extern Node *winner; +extern Node *nullstat; +extern Node *nullnode; + +/* ctypes */ +#define OCELL 1 +#define OBOOL 2 +#define OJUMP 3 + +/* Cell subtypes: csub */ +#define CFREE 7 +#define CCOPY 6 +#define CCON 5 +#define CTEMP 4 +#define CNAME 3 +#define CVAR 2 +#define CFLD 1 +#define CUNK 0 + +/* bool subtypes */ +#define BTRUE 11 +#define BFALSE 12 + +/* jump subtypes */ +#define JEXIT 21 +#define JNEXT 22 +#define JBREAK 23 +#define JCONT 24 +#define JRET 25 +#define JNEXTFILE 26 + +/* node types */ +#define NVALUE 1 +#define NSTAT 2 +#define NEXPR 3 + + +extern int pairstack[], paircnt; + +#define notlegal(n) (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN] == nullproc) +#define isvalue(n) ((n)->ntype == NVALUE) +#define isexpr(n) ((n)->ntype == NEXPR) +#define isjump(n) ((n)->ctype == OJUMP) +#define isexit(n) ((n)->csub == JEXIT) +#define isbreak(n) ((n)->csub == JBREAK) +#define iscont(n) ((n)->csub == JCONT) +#define isnext(n) ((n)->csub == JNEXT) +#define isnextfile(n) ((n)->csub == JNEXTFILE) +#define isret(n) ((n)->csub == JRET) +#define isrec(n) ((n)->tval & REC) +#define isfld(n) ((n)->tval & FLD) +#define isstr(n) ((n)->tval & STR) +#define isnum(n) ((n)->tval & NUM) +#define isarr(n) ((n)->tval & ARR) +#define isfcn(n) ((n)->tval & FCN) +#define istrue(n) ((n)->csub == BTRUE) +#define istemp(n) ((n)->csub == CTEMP) +#define isargument(n) ((n)->nobj == ARG) +/* #define freeable(p) (!((p)->tval & DONTFREE)) */ +#define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR ) + +/* structures used by regular expression matching machinery, mostly b.c: */ + +#define NCHARS (256+1) /* 256 handles 8-bit chars; 128 does 7-bit */ + /* watch out in match(), etc. */ +#define NSTATES 32 + +typedef struct rrow { + int ltype; + union { + int i; + Node *np; + char *up; + } lval; /* because Al stores a pointer in it! */ + int *lfollow; +} rrow; + +typedef struct fa { + char *restr; + int anchor; + int use; + uschar gototab[NSTATES][NCHARS]; + int *posns[NSTATES]; + uschar out[NSTATES]; + int initstat; + int curstat; + int accept; + int reset; + struct rrow re[1]; +} fa; + + +#include "proto.h" diff --git a/usr.bin/awk/awkgram.y b/usr.bin/awk/awkgram.y new file mode 100644 index 0000000..158a25d --- /dev/null +++ b/usr.bin/awk/awkgram.y @@ -0,0 +1,485 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +%{ +#include +#include +#include "awk.h" + +void checkdup(Node *list, Cell *item); +int yywrap(void) { return(1); } + +Node *beginloc = 0; +Node *endloc = 0; +int infunc = 0; /* = 1 if in arglist or body of func */ +int inloop = 0; /* = 1 if in while, for, do */ +char *curfname = 0; /* current function name */ +Node *arglist = 0; /* list of args for current function */ +%} + +%union { + Node *p; + Cell *cp; + int i; + char *s; +} + +%token FIRSTTOKEN /* must be first */ +%token

PROGRAM PASTAT PASTAT2 XBEGIN XEND +%token NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']' +%token ARRAY +%token MATCH NOTMATCH MATCHOP +%token FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS +%token AND BOR APPEND EQ GE GT LE LT NE IN +%token ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC +%token SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE +%token ADD MINUS MULT DIVIDE MOD +%token ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ +%token PRINT PRINTF SPRINTF +%token

ELSE INTEST CONDEXPR +%token POSTINCR PREINCR POSTDECR PREDECR +%token VAR IVAR VARNF CALL NUMBER STRING +%token REGEXPR + +%type

pas pattern ppattern plist pplist patlist prarg term re +%type

pa_pat pa_stat pa_stats +%type reg_expr +%type

simple_stmt opt_simple_stmt stmt stmtlist +%type

var varname funcname varlist +%type

for if else while +%type do st +%type pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor +%type subop print + +%right ASGNOP +%right '?' +%right ':' +%left BOR +%left AND +%left GETLINE +%nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|' +%left ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC +%left GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER +%left PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR +%left REGEXPR VAR VARNF IVAR WHILE '(' +%left CAT +%left '+' '-' +%left '*' '/' '%' +%left NOT UMINUS +%right POWER +%right DECR INCR +%left INDIRECT +%token LASTTOKEN /* must be last */ + +%% + +program: + pas { if (errorflag==0) + winner = (Node *)stat3(PROGRAM, beginloc, $1, endloc); } + | error { yyclearin; bracecheck(); ERROR "bailing out" SYNTAX; } + ; + +and: + AND | and NL + ; + +bor: + BOR | bor NL + ; + +comma: + ',' | comma NL + ; + +do: + DO | do NL + ; + +else: + ELSE | else NL + ; + +for: + FOR '(' opt_simple_stmt ';' opt_nl pattern ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt + { --inloop; $$ = stat4(FOR, $3, notnull($6), $9, $12); } + | FOR '(' opt_simple_stmt ';' ';' opt_nl opt_simple_stmt rparen {inloop++;} stmt + { --inloop; $$ = stat4(FOR, $3, NIL, $7, $10); } + | FOR '(' varname IN varname rparen {inloop++;} stmt + { --inloop; $$ = stat3(IN, $3, makearr($5), $8); } + ; + +funcname: + VAR { setfname($1); } + | CALL { setfname($1); } + ; + +if: + IF '(' pattern rparen { $$ = notnull($3); } + ; + +lbrace: + '{' | lbrace NL + ; + +nl: + NL | nl NL + ; + +opt_nl: + /* empty */ { $$ = 0; } + | nl + ; + +opt_pst: + /* empty */ { $$ = 0; } + | pst + ; + + +opt_simple_stmt: + /* empty */ { $$ = 0; } + | simple_stmt + ; + +pas: + opt_pst { $$ = 0; } + | opt_pst pa_stats opt_pst { $$ = $2; } + ; + +pa_pat: + pattern { $$ = notnull($1); } + ; + +pa_stat: + pa_pat { $$ = stat2(PASTAT, $1, stat2(PRINT, rectonode(), NIL)); } + | pa_pat lbrace stmtlist '}' { $$ = stat2(PASTAT, $1, $3); } + | pa_pat ',' pa_pat { $$ = pa2stat($1, $3, stat2(PRINT, rectonode(), NIL)); } + | pa_pat ',' pa_pat lbrace stmtlist '}' { $$ = pa2stat($1, $3, $5); } + | lbrace stmtlist '}' { $$ = stat2(PASTAT, NIL, $2); } + | XBEGIN lbrace stmtlist '}' + { beginloc = linkum(beginloc, $3); $$ = 0; } + | XEND lbrace stmtlist '}' + { endloc = linkum(endloc, $3); $$ = 0; } + | FUNC funcname '(' varlist rparen {infunc++;} lbrace stmtlist '}' + { infunc--; curfname=0; defn((Cell *)$2, $4, $8); $$ = 0; } + ; + +pa_stats: + pa_stat + | pa_stats opt_pst pa_stat { $$ = linkum($1, $3); } + ; + +patlist: + pattern + | patlist comma pattern { $$ = linkum($1, $3); } + ; + +ppattern: + var ASGNOP ppattern { $$ = op2($2, $1, $3); } + | ppattern '?' ppattern ':' ppattern %prec '?' + { $$ = op3(CONDEXPR, notnull($1), $3, $5); } + | ppattern bor ppattern %prec BOR + { $$ = op2(BOR, notnull($1), notnull($3)); } + | ppattern and ppattern %prec AND + { $$ = op2(AND, notnull($1), notnull($3)); } + | ppattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); } + | ppattern MATCHOP ppattern + { if (constnode($3)) + $$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0)); + else + $$ = op3($2, (Node *)1, $1, $3); } + | ppattern IN varname { $$ = op2(INTEST, $1, makearr($3)); } + | '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); } + | ppattern term %prec CAT { $$ = op2(CAT, $1, $2); } + | re + | term + ; + +pattern: + var ASGNOP pattern { $$ = op2($2, $1, $3); } + | pattern '?' pattern ':' pattern %prec '?' + { $$ = op3(CONDEXPR, notnull($1), $3, $5); } + | pattern bor pattern %prec BOR + { $$ = op2(BOR, notnull($1), notnull($3)); } + | pattern and pattern %prec AND + { $$ = op2(AND, notnull($1), notnull($3)); } + | pattern EQ pattern { $$ = op2($2, $1, $3); } + | pattern GE pattern { $$ = op2($2, $1, $3); } + | pattern GT pattern { $$ = op2($2, $1, $3); } + | pattern LE pattern { $$ = op2($2, $1, $3); } + | pattern LT pattern { $$ = op2($2, $1, $3); } + | pattern NE pattern { $$ = op2($2, $1, $3); } + | pattern MATCHOP reg_expr { $$ = op3($2, NIL, $1, (Node*)makedfa($3, 0)); } + | pattern MATCHOP pattern + { if (constnode($3)) + $$ = op3($2, NIL, $1, (Node*)makedfa(strnode($3), 0)); + else + $$ = op3($2, (Node *)1, $1, $3); } + | pattern IN varname { $$ = op2(INTEST, $1, makearr($3)); } + | '(' plist ')' IN varname { $$ = op2(INTEST, $2, makearr($5)); } + | pattern '|' GETLINE var { + if (safe) ERROR "cmd | getline is unsafe" SYNTAX; + else $$ = op3(GETLINE, $4, (Node*)$2, $1); } + | pattern '|' GETLINE { + if (safe) ERROR "cmd | getline is unsafe" SYNTAX; + else $$ = op3(GETLINE, (Node*)0, (Node*)$2, $1); } + | pattern term %prec CAT { $$ = op2(CAT, $1, $2); } + | re + | term + ; + +plist: + pattern comma pattern { $$ = linkum($1, $3); } + | plist comma pattern { $$ = linkum($1, $3); } + ; + +pplist: + ppattern + | pplist comma ppattern { $$ = linkum($1, $3); } + ; + +prarg: + /* empty */ { $$ = rectonode(); } + | pplist + | '(' plist ')' { $$ = $2; } + ; + +print: + PRINT | PRINTF + ; + +pst: + NL | ';' | pst NL | pst ';' + ; + +rbrace: + '}' | rbrace NL + ; + +re: + reg_expr + { $$ = op3(MATCH, NIL, rectonode(), (Node*)makedfa($1, 0)); } + | NOT re { $$ = op1(NOT, notnull($2)); } + ; + +reg_expr: + '/' {startreg();} REGEXPR '/' { $$ = $3; } + ; + +rparen: + ')' | rparen NL + ; + +simple_stmt: + print prarg '|' term { + if (safe) ERROR "print | is unsafe" SYNTAX; + else $$ = stat3($1, $2, (Node *) $3, $4); } + | print prarg APPEND term { + if (safe) ERROR "print >> is unsafe" SYNTAX; + else $$ = stat3($1, $2, (Node *) $3, $4); } + | print prarg GT term { + if (safe) ERROR "print > is unsafe" SYNTAX; + else $$ = stat3($1, $2, (Node *) $3, $4); } + | print prarg { $$ = stat3($1, $2, NIL, NIL); } + | DELETE varname '[' patlist ']' { $$ = stat2(DELETE, makearr($2), $4); } + | DELETE varname { $$ = stat2(DELETE, makearr($2), 0); } + | pattern { $$ = exptostat($1); } + | error { yyclearin; ERROR "illegal statement" SYNTAX; } + ; + +st: + nl + | ';' opt_nl + ; + +stmt: + BREAK st { if (!inloop) ERROR "break illegal outside of loops" SYNTAX; + $$ = stat1(BREAK, NIL); } + | CLOSE pattern st { $$ = stat1(CLOSE, $2); } + | CONTINUE st { if (!inloop) ERROR "continue illegal outside of loops" SYNTAX; + $$ = stat1(CONTINUE, NIL); } + | do {inloop++;} stmt {--inloop;} WHILE '(' pattern ')' st + { $$ = stat2(DO, $3, notnull($7)); } + | EXIT pattern st { $$ = stat1(EXIT, $2); } + | EXIT st { $$ = stat1(EXIT, NIL); } + | for + | if stmt else stmt { $$ = stat3(IF, $1, $2, $4); } + | if stmt { $$ = stat3(IF, $1, $2, NIL); } + | lbrace stmtlist rbrace { $$ = $2; } + | NEXT st { if (infunc) + ERROR "next is illegal inside a function" SYNTAX; + $$ = stat1(NEXT, NIL); } + | NEXTFILE st { if (infunc) + ERROR "nextfile is illegal inside a function" SYNTAX; + $$ = stat1(NEXTFILE, NIL); } + | RETURN pattern st { $$ = stat1(RETURN, $2); } + | RETURN st { $$ = stat1(RETURN, NIL); } + | simple_stmt st + | while {inloop++;} stmt { --inloop; $$ = stat2(WHILE, $1, $3); } + | ';' opt_nl { $$ = 0; } + ; + +stmtlist: + stmt + | stmtlist stmt { $$ = linkum($1, $2); } + ; + +subop: + SUB | GSUB + ; + +term: + term '+' term { $$ = op2(ADD, $1, $3); } + | term '-' term { $$ = op2(MINUS, $1, $3); } + | term '*' term { $$ = op2(MULT, $1, $3); } + | term '/' term { $$ = op2(DIVIDE, $1, $3); } + | term '%' term { $$ = op2(MOD, $1, $3); } + | term POWER term { $$ = op2(POWER, $1, $3); } + | '-' term %prec UMINUS { $$ = op1(UMINUS, $2); } + | '+' term %prec UMINUS { $$ = $2; } + | NOT term %prec UMINUS { $$ = op1(NOT, notnull($2)); } + | BLTIN '(' ')' { $$ = op2(BLTIN, (Node *) $1, rectonode()); } + | BLTIN '(' patlist ')' { $$ = op2(BLTIN, (Node *) $1, $3); } + | BLTIN { $$ = op2(BLTIN, (Node *) $1, rectonode()); } + | CALL '(' ')' { $$ = op2(CALL, celltonode($1,CVAR), NIL); } + | CALL '(' patlist ')' { $$ = op2(CALL, celltonode($1,CVAR), $3); } + | DECR var { $$ = op1(PREDECR, $2); } + | INCR var { $$ = op1(PREINCR, $2); } + | var DECR { $$ = op1(POSTDECR, $1); } + | var INCR { $$ = op1(POSTINCR, $1); } + | GETLINE var LT term { $$ = op3(GETLINE, $2, (Node *)$3, $4); } + | GETLINE LT term { $$ = op3(GETLINE, NIL, (Node *)$2, $3); } + | GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); } + | GETLINE { $$ = op3(GETLINE, NIL, NIL, NIL); } + | INDEX '(' pattern comma pattern ')' + { $$ = op2(INDEX, $3, $5); } + | INDEX '(' pattern comma reg_expr ')' + { ERROR "index() doesn't permit regular expressions" SYNTAX; + $$ = op2(INDEX, $3, (Node*)$5); } + | '(' pattern ')' { $$ = $2; } + | MATCHFCN '(' pattern comma reg_expr ')' + { $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa($5, 1)); } + | MATCHFCN '(' pattern comma pattern ')' + { if (constnode($5)) + $$ = op3(MATCHFCN, NIL, $3, (Node*)makedfa(strnode($5), 1)); + else + $$ = op3(MATCHFCN, (Node *)1, $3, $5); } + | NUMBER { $$ = celltonode($1, CCON); } + | SPLIT '(' pattern comma varname comma pattern ')' /* string */ + { $$ = op4(SPLIT, $3, makearr($5), $7, (Node*)STRING); } + | SPLIT '(' pattern comma varname comma reg_expr ')' /* const /regexp/ */ + { $$ = op4(SPLIT, $3, makearr($5), (Node*)makedfa($7, 1), (Node *)REGEXPR); } + | SPLIT '(' pattern comma varname ')' + { $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */ + | SPRINTF '(' patlist ')' { $$ = op1($1, $3); } + | STRING { $$ = celltonode($1, CCON); } + | subop '(' reg_expr comma pattern ')' + { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); } + | subop '(' pattern comma pattern ')' + { if (constnode($3)) + $$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, rectonode()); + else + $$ = op4($1, (Node *)1, $3, $5, rectonode()); } + | subop '(' reg_expr comma pattern comma var ')' + { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, $7); } + | subop '(' pattern comma pattern comma var ')' + { if (constnode($3)) + $$ = op4($1, NIL, (Node*)makedfa(strnode($3), 1), $5, $7); + else + $$ = op4($1, (Node *)1, $3, $5, $7); } + | SUBSTR '(' pattern comma pattern comma pattern ')' + { $$ = op3(SUBSTR, $3, $5, $7); } + | SUBSTR '(' pattern comma pattern ')' + { $$ = op3(SUBSTR, $3, $5, NIL); } + | var + ; + +var: + varname + | varname '[' patlist ']' { $$ = op2(ARRAY, makearr($1), $3); } + | IVAR { $$ = op1(INDIRECT, celltonode($1, CVAR)); } + | INDIRECT term { $$ = op1(INDIRECT, $2); } + ; + +varlist: + /* nothing */ { arglist = $$ = 0; } + | VAR { arglist = $$ = celltonode($1,CVAR); } + | varlist comma VAR { + checkdup($1, $3); + arglist = $$ = linkum($1,celltonode($3,CVAR)); } + ; + +varname: + VAR { $$ = celltonode($1, CVAR); } + | ARG { $$ = op1(ARG, (Node *) $1); } + | VARNF { $$ = op1(VARNF, (Node *) $1); } + ; + + +while: + WHILE '(' pattern rparen { $$ = notnull($3); } + ; + +%% + +void setfname(Cell *p) +{ + if (isarr(p)) + ERROR "%s is an array, not a function", p->nval SYNTAX; + else if (isfcn(p)) + ERROR "you can't define function %s more than once", p->nval SYNTAX; + curfname = p->nval; +} + +int constnode(Node *p) +{ + return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON; +} + +char *strnode(Node *p) +{ + return ((Cell *)(p->narg[0]))->sval; +} + +Node *notnull(Node *n) +{ + switch (n->nobj) { + case LE: case LT: case EQ: case NE: case GT: case GE: + case BOR: case AND: case NOT: + return n; + default: + return op2(NE, n, nullnode); + } +} + +void checkdup(Node *vl, Cell *cp) /* check if name already in list */ +{ + char *s = cp->nval; + for ( ; vl; vl = vl->nnext) { + if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) { + ERROR "duplicate argument %s", s SYNTAX; + break; + } + } +} diff --git a/usr.bin/awk/b.c b/usr.bin/awk/b.c new file mode 100644 index 0000000..e4e2152 --- /dev/null +++ b/usr.bin/awk/b.c @@ -0,0 +1,850 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +/* lasciate ogne speranza, voi ch'entrate. */ + +#define DEBUG + +#include +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +#define HAT (NCHARS-1) /* matches ^ in regular expr */ + /* NCHARS is 2**n */ +#define MAXLIN 22 + +#define type(v) (v)->nobj +#define left(v) (v)->narg[0] +#define right(v) (v)->narg[1] +#define parent(v) (v)->nnext + +#define LEAF case CCL: case NCCL: case CHAR: case DOT: case FINAL: case ALL: +#define UNARY case STAR: case PLUS: case QUEST: + +/* encoding in tree Nodes: + leaf (CCL, NCCL, CHAR, DOT, FINAL, ALL): + left is index, right contains value or pointer to value + unary (STAR, PLUS, QUEST): left is child, right is null + binary (CAT, OR): left and right are children + parent contains pointer to parent +*/ + + +int *setvec; +int *tmpset; +int maxsetvec = 0; + +int rtok; /* next token in current re */ +int rlxval; +char *rlxstr; +char *prestr; /* current position in current re */ +char *lastre; /* origin of last re */ + +static int setcnt; +static int poscnt; + +char *patbeg; +int patlen; + +#define NFA 20 /* cache this many dynamic fa's */ +fa *fatab[NFA]; +int nfatab = 0; /* entries in fatab */ + +fa *makedfa(char *s, int anchor) /* returns dfa for reg expr s */ +{ + int i, use, nuse; + fa *pfa; + + if (setvec == 0) { /* first time through any RE */ + maxsetvec = MAXLIN; + setvec = (int *) malloc(maxsetvec * sizeof(int)); + tmpset = (int *) malloc(maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("out of space initializing makedfa"); + } + + if (compile_time) /* a constant for sure */ + return mkdfa(s, anchor); + for (i = 0; i < nfatab; i++) /* is it there already? */ + if (fatab[i]->anchor == anchor + && strcmp(fatab[i]->restr, s) == 0) { + fatab[i]->use++; + return fatab[i]; + } + pfa = mkdfa(s, anchor); + if (nfatab < NFA) { /* room for another */ + fatab[nfatab] = pfa; + fatab[nfatab]->use = 1; + nfatab++; + return pfa; + } + use = fatab[0]->use; /* replace least-recently used */ + nuse = 0; + for (i = 1; i < nfatab; i++) + if (fatab[i]->use < use) { + use = fatab[i]->use; + nuse = i; + } + freefa(fatab[nuse]); + fatab[nuse] = pfa; + pfa->use = 1; + return pfa; +} + +fa *mkdfa(char *s, int anchor) /* does the real work of making a dfa */ + /* anchor = 1 for anchored matches, else 0 */ +{ + Node *p, *p1; + fa *f; + + p = reparse(s); + p1 = op2(CAT, op2(STAR, op2(ALL, NIL, NIL), NIL), p); + /* put ALL STAR in front of reg. exp. */ + p1 = op2(CAT, p1, op2(FINAL, NIL, NIL)); + /* put FINAL after reg. exp. */ + + poscnt = 0; + penter(p1); /* enter parent pointers and leaf indices */ + if ((f = (fa *) calloc(1, sizeof(fa) + poscnt*sizeof(rrow))) == NULL) + overflo("out of space for fa"); + f->accept = poscnt-1; /* penter has computed number of positions in re */ + cfoll(f, p1); /* set up follow sets */ + freetr(p1); + if ((f->posns[0] = (int *) calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL) + overflo("out of space in makedfa"); + if ((f->posns[1] = (int *) calloc(1, sizeof(int))) == NULL) + overflo("out of space in makedfa"); + *f->posns[1] = 0; + f->initstat = makeinit(f, anchor); + f->anchor = anchor; + f->restr = tostring(s); + return f; +} + +int makeinit(fa *f, int anchor) +{ + int i, k; + + f->curstat = 2; + f->out[2] = 0; + f->reset = 0; + k = *(f->re[0].lfollow); + xfree(f->posns[2]); + if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + overflo("out of space in makeinit"); + for (i=0; i <= k; i++) { + (f->posns[2])[i] = (f->re[0].lfollow)[i]; + } + if ((f->posns[2])[1] == f->accept) + f->out[2] = 1; + for (i=0; i < NCHARS; i++) + f->gototab[2][i] = 0; + f->curstat = cgoto(f, 2, HAT); + if (anchor) { + *f->posns[2] = k-1; /* leave out position 0 */ + for (i=0; i < k; i++) { + (f->posns[0])[i] = (f->posns[2])[i]; + } + + f->out[0] = f->out[2]; + if (f->curstat != 2) + --(*f->posns[f->curstat]); + } + return f->curstat; +} + +void penter(Node *p) /* set up parent pointers and leaf indices */ +{ + switch (type(p)) { + LEAF + left(p) = (Node *) poscnt; + poscnt++; + break; + UNARY + penter(left(p)); + parent(left(p)) = p; + break; + case CAT: + case OR: + penter(left(p)); + penter(right(p)); + parent(left(p)) = p; + parent(right(p)) = p; + break; + default: /* can't happen */ + ERROR "can't happen: unknown type %d in penter", type(p) FATAL; + break; + } +} + +void freetr(Node *p) /* free parse tree */ +{ + switch (type(p)) { + LEAF + xfree(p); + break; + UNARY + freetr(left(p)); + xfree(p); + break; + case CAT: + case OR: + freetr(left(p)); + freetr(right(p)); + xfree(p); + break; + default: /* can't happen */ + ERROR "can't happen: unknown type %d in freetr", type(p) FATAL; + break; + } +} + +/* in the parsing of regular expressions, metacharacters like . have */ +/* to be seen literally; \056 is not a metacharacter. */ + +int hexstr(char **pp) /* find and eval hex string at pp, return new p */ +{ /* only pick up one 8-bit byte (2 chars) */ + char *p; + int n = 0; + int i; + + for (i = 0, p = *pp; i < 2 && isxdigit(*p); i++, p++) { + if (isdigit(*p)) + n = 16 * n + *p - '0'; + else if (*p >= 'a' && *p <= 'f') + n = 16 * n + *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + n = 16 * n + *p - 'A' + 10; + } + *pp = p; + return n; +} + +#define isoctdigit(c) ((c) >= '0' && (c) <= '7') /* multiple use of arg */ + +int quoted(char **pp) /* pick up next thing after a \\ */ + /* and increment *pp */ +{ + char *p = *pp; + int c; + + if ((c = *p++) == 't') + c = '\t'; + else if (c == 'n') + c = '\n'; + else if (c == 'f') + c = '\f'; + else if (c == 'r') + c = '\r'; + else if (c == 'b') + c = '\b'; + else if (c == '\\') + c = '\\'; + else if (c == 'x') { /* hexadecimal goo follows */ + c = hexstr(&p); /* this adds a null if number is invalid */ + } else if (isoctdigit(c)) { /* \d \dd \ddd */ + int n = c - '0'; + if (isoctdigit(*p)) { + n = 8 * n + *p++ - '0'; + if (isoctdigit(*p)) + n = 8 * n + *p++ - '0'; + } + c = n; + } /* else */ + /* c = c; */ + *pp = p; + return c; +} + +char *cclenter(char *p) /* add a character class */ +{ + int i, c, c2; + char *op, *bp; + static char *buf = 0; + static int bufsz = 100; + + op = p; + if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + ERROR "out of space for character class [%.10s...] 1", p FATAL; + bp = buf; + for (i = 0; (c = *p++) != 0; ) { + if (c == '\\') { + c = quoted(&p); + } else if (c == '-' && i > 0 && bp[-1] != 0) { + if (*p != 0) { + c = bp[-1]; + c2 = *p++; + if (c2 == '\\') + c2 = quoted(&p); + if (c > c2) { /* empty; ignore */ + bp--; + i--; + continue; + } + while (c < c2) { + if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, 0)) + ERROR "out of space for character class [%.10s...] 2", p FATAL; + *bp++ = ++c; + i++; + } + continue; + } + } + if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, 0)) + ERROR "out of space for character class [%.10s...] 3", p FATAL; + *bp++ = c; + i++; + } + *bp = 0; + dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) ); + xfree(op); + return(tostring(buf)); +} + +void overflo(char *s) +{ + ERROR "regular expression too big: %.30s...", s FATAL; +} + +void cfoll(fa *f, Node *v) /* enter follow set of each leaf of vertex v into lfollow[leaf] */ +{ + int i; + int *p; + + switch (type(v)) { + LEAF + f->re[(int) left(v)].ltype = type(v); + f->re[(int) left(v)].lval.np = right(v); + while (f->accept >= maxsetvec) { /* guessing here! */ + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("out of space in cfoll()"); + } + for (i = 0; i <= f->accept; i++) + setvec[i] = 0; + setcnt = 0; + follow(v); /* computes setvec and setcnt */ + if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL) + overflo("out of space building follow set"); + f->re[(int) left(v)].lfollow = p; + *p = setcnt; + for (i = f->accept; i >= 0; i--) + if (setvec[i] == 1) + *++p = i; + break; + UNARY + cfoll(f,left(v)); + break; + case CAT: + case OR: + cfoll(f,left(v)); + cfoll(f,right(v)); + break; + default: /* can't happen */ + ERROR "can't happen: unknown type %d in cfoll", type(v) FATAL; + } +} + +int first(Node *p) /* collects initially active leaves of p into setvec */ + /* returns 1 if p matches empty string */ +{ + int b, lp; + + switch (type(p)) { + LEAF + lp = (int) left(p); /* look for high-water mark of subscripts */ + while (setcnt >= maxsetvec || lp >= maxsetvec) { /* guessing here! */ + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) { abort(); + overflo("out of space in first()"); +} + } + if (setvec[lp] != 1) { + setvec[lp] = 1; + setcnt++; + } + if (type(p) == CCL && (*(char *) right(p)) == '\0') + return(0); /* empty CCL */ + else return(1); + case PLUS: + if (first(left(p)) == 0) return(0); + return(1); + case STAR: + case QUEST: + first(left(p)); + return(0); + case CAT: + if (first(left(p)) == 0 && first(right(p)) == 0) return(0); + return(1); + case OR: + b = first(right(p)); + if (first(left(p)) == 0 || b == 0) return(0); + return(1); + } + ERROR "can't happen: unknown type %d in first", type(p) FATAL; /* can't happen */ + return(-1); +} + +void follow(Node *v) /* collects leaves that can follow v into setvec */ +{ + Node *p; + + if (type(v) == FINAL) + return; + p = parent(v); + switch (type(p)) { + case STAR: + case PLUS: + first(v); + follow(p); + return; + + case OR: + case QUEST: + follow(p); + return; + + case CAT: + if (v == left(p)) { /* v is left child of p */ + if (first(right(p)) == 0) { + follow(p); + return; + } + } else /* v is right child */ + follow(p); + return; + } +} + +int member(int c, char *s) /* is c in s? */ +{ + while (*s) + if (c == *s++) + return(1); + return(0); +} + +int match(fa *f, char *p0) /* shortest match ? */ +{ + int s, ns; + uschar *p = (uschar *) p0; + + s = f->reset ? makeinit(f,0) : f->initstat; + if (f->out[s]) + return(1); + do { + if ((ns = f->gototab[s][*p]) != 0) + s = ns; + else + s = cgoto(f, s, *p); + if (f->out[s]) + return(1); + } while (*p++ != 0); + return(0); +} + +int pmatch(fa *f, char *p0) /* longest match, for sub */ +{ + int s, ns; + uschar *p = (uschar *) p0; + uschar *q; + int i, k; + + s = f->reset ? makeinit(f,1) : f->initstat; + patbeg = (char *) p; + patlen = -1; + do { + q = p; + do { + if (f->out[s]) /* final state */ + patlen = q-p; + if ((ns = f->gototab[s][*q]) != 0) + s = ns; + else + s = cgoto(f, s, *q); + if (s == 1) /* no transition */ + if (patlen >= 0) { + patbeg = (char *) p; + return(1); + } + else + goto nextin; /* no match */ + } while (*q++ != 0); + if (f->out[s]) + patlen = q-p-1; /* don't count $ */ + if (patlen >= 0) { + patbeg = (char *) p; + return(1); + } + nextin: + s = 2; + if (f->reset) { + for (i = 2; i <= f->curstat; i++) + xfree(f->posns[i]); + k = *f->posns[0]; + if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + overflo("out of space in pmatch"); + for (i = 0; i <= k; i++) + (f->posns[2])[i] = (f->posns[0])[i]; + f->initstat = f->curstat = 2; + f->out[2] = f->out[0]; + for (i = 0; i < NCHARS; i++) + f->gototab[2][i] = 0; + } + } while (*p++ != 0); + return (0); +} + +int nematch(fa *f, char *p0) /* non-empty match, for sub */ +{ + int s, ns; + uschar *p = (uschar *) p0; + uschar *q; + int i, k; + + s = f->reset ? makeinit(f,1) : f->initstat; + patlen = -1; + while (*p) { + q = p; + do { + if (f->out[s]) /* final state */ + patlen = q-p; + if ((ns = f->gototab[s][*q]) != 0) + s = ns; + else + s = cgoto(f, s, *q); + if (s == 1) /* no transition */ + if (patlen > 0) { + patbeg = (char *) p; + return(1); + } else + goto nnextin; /* no nonempty match */ + } while (*q++ != 0); + if (f->out[s]) + patlen = q-p-1; /* don't count $ */ + if (patlen > 0 ) { + patbeg = (char *) p; + return(1); + } + nnextin: + s = 2; + if (f->reset) { + for (i = 2; i <= f->curstat; i++) + xfree(f->posns[i]); + k = *f->posns[0]; + if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + overflo("out of state space"); + for (i = 0; i <= k; i++) + (f->posns[2])[i] = (f->posns[0])[i]; + f->initstat = f->curstat = 2; + f->out[2] = f->out[0]; + for (i = 0; i < NCHARS; i++) + f->gototab[2][i] = 0; + } + p++; + } + return (0); +} + +Node *reparse(char *p) /* parses regular expression pointed to by p */ +{ /* uses relex() to scan regular expression */ + Node *np; + + dprintf( ("reparse <%s>\n", p) ); + lastre = prestr = p; /* prestr points to string to be parsed */ + rtok = relex(); + if (rtok == '\0') + ERROR "empty regular expression" FATAL; + np = regexp(); + if (rtok != '\0') + ERROR "syntax error in regular expression %s at %s", lastre, prestr FATAL; + return(np); +} + +Node *regexp(void) /* top-level parse of reg expr */ +{ + return (alt(concat(primary()))); +} + +Node *primary(void) +{ + Node *np; + + switch (rtok) { + case CHAR: + np = op2(CHAR, NIL, (Node *) rlxval); + rtok = relex(); + return (unary(np)); + case ALL: + rtok = relex(); + return (unary(op2(ALL, NIL, NIL))); + case DOT: + rtok = relex(); + return (unary(op2(DOT, NIL, NIL))); + case CCL: + np = op2(CCL, NIL, (Node*) cclenter(rlxstr)); + rtok = relex(); + return (unary(np)); + case NCCL: + np = op2(NCCL, NIL, (Node *) cclenter(rlxstr)); + rtok = relex(); + return (unary(np)); + case '^': + rtok = relex(); + return (unary(op2(CHAR, NIL, (Node *) HAT))); + case '$': + rtok = relex(); + return (unary(op2(CHAR, NIL, NIL))); + case '(': + rtok = relex(); + if (rtok == ')') { /* special pleading for () */ + rtok = relex(); + return unary(op2(CCL, NIL, (Node *) tostring(""))); + } + np = regexp(); + if (rtok == ')') { + rtok = relex(); + return (unary(np)); + } + else + ERROR "syntax error in regular expression %s at %s", lastre, prestr FATAL; + default: + ERROR "illegal primary in regular expression %s at %s", lastre, prestr FATAL; + } + return 0; /*NOTREACHED*/ +} + +Node *concat(Node *np) +{ + switch (rtok) { + case CHAR: case DOT: case ALL: case CCL: case NCCL: case '$': case '(': + return (concat(op2(CAT, np, primary()))); + } + return (np); +} + +Node *alt(Node *np) +{ + if (rtok == OR) { + rtok = relex(); + return (alt(op2(OR, np, concat(primary())))); + } + return (np); +} + +Node *unary(Node *np) +{ + switch (rtok) { + case STAR: + rtok = relex(); + return (unary(op2(STAR, np, NIL))); + case PLUS: + rtok = relex(); + return (unary(op2(PLUS, np, NIL))); + case QUEST: + rtok = relex(); + return (unary(op2(QUEST, np, NIL))); + default: + return (np); + } +} + +int relex(void) /* lexical analyzer for reparse */ +{ + int c, n; + int cflag; + static char *buf = 0; + static int bufsz = 100; + char *bp; + + switch (c = *prestr++) { + case '|': return OR; + case '*': return STAR; + case '+': return PLUS; + case '?': return QUEST; + case '.': return DOT; + case '\0': prestr--; return '\0'; + case '^': + case '$': + case '(': + case ')': + return c; + case '\\': + rlxval = quoted(&prestr); + return CHAR; + default: + rlxval = c; + return CHAR; + case '[': + if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + ERROR "out of space in reg expr %.10s..", lastre FATAL; + bp = buf; + if (*prestr == '^') { + cflag = 1; + prestr++; + } + else + cflag = 0; + n = 2 * strlen(prestr)+1; + if (!adjbuf(&buf, &bufsz, n, n, &bp, 0)) + ERROR "out of space for reg expr %.10s...", lastre FATAL; + for (; ; ) { + if ((c = *prestr++) == '\\') { + *bp++ = '\\'; + if ((c = *prestr++) == '\0') + ERROR "nonterminated character class %.20s...", lastre FATAL; + *bp++ = c; + } else if (c == '\n') { + ERROR "newline in character class %.20s...", lastre FATAL; + } else if (c == '\0') { + ERROR "nonterminated character class %.20s", lastre FATAL; + } else if (bp == buf) { /* 1st char is special */ + *bp++ = c; + } else if (c == ']') { + *bp++ = 0; + rlxstr = tostring(buf); + if (cflag == 0) + return CCL; + else + return NCCL; + } else + *bp++ = c; + } + } +} + +int cgoto(fa *f, int s, int c) +{ + int i, j, k; + int *p, *q; + + if (c < 0) + ERROR "can't happen: neg char %d in cgoto", c FATAL; + while (f->accept >= maxsetvec) { /* guessing here! */ + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) { abort(); + overflo("out of space in cgoto()"); +} + } + for (i = 0; i <= f->accept; i++) + setvec[i] = 0; + setcnt = 0; + /* compute positions of gototab[s,c] into setvec */ + p = f->posns[s]; + for (i = 1; i <= *p; i++) { + if ((k = f->re[p[i]].ltype) != FINAL) { + if ((k == CHAR && c == f->re[p[i]].lval.i) + || (k == DOT && c != 0 && c != HAT) + || (k == ALL && c != 0) + || (k == CCL && member(c, f->re[p[i]].lval.up)) + || (k == NCCL && !member(c, f->re[p[i]].lval.up) && c != 0 && c != HAT)) { + q = f->re[p[i]].lfollow; + for (j = 1; j <= *q; j++) { + if (q[j] >= maxsetvec) { + maxsetvec *= 4; + setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); + tmpset = (int *) realloc(setvec, maxsetvec * sizeof(int)); + if (setvec == 0 || tmpset == 0) + overflo("cgoto overflow"); + } + if (setvec[q[j]] == 0) { + setcnt++; + setvec[q[j]] = 1; + } + } + } + } + } + /* determine if setvec is a previous state */ + tmpset[0] = setcnt; + j = 1; + for (i = f->accept; i >= 0; i--) + if (setvec[i]) { + tmpset[j++] = i; + } + /* tmpset == previous state? */ + for (i = 1; i <= f->curstat; i++) { + p = f->posns[i]; + if ((k = tmpset[0]) != p[0]) + goto different; + for (j = 1; j <= k; j++) + if (tmpset[j] != p[j]) + goto different; + /* setvec is state i */ + f->gototab[s][c] = i; + return i; + different:; + } + + /* add tmpset to current set of states */ + if (f->curstat >= NSTATES-1) { + f->curstat = 2; + f->reset = 1; + for (i = 2; i < NSTATES; i++) + xfree(f->posns[i]); + } else + ++(f->curstat); + for (i = 0; i < NCHARS; i++) + f->gototab[f->curstat][i] = 0; + xfree(f->posns[f->curstat]); + if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL) + overflo("out of space in cgoto"); + + f->posns[f->curstat] = p; + f->gototab[s][c] = f->curstat; + for (i = 0; i <= setcnt; i++) + p[i] = tmpset[i]; + if (setvec[f->accept]) + f->out[f->curstat] = 1; + else + f->out[f->curstat] = 0; + return f->curstat; +} + + +void freefa(fa *f) /* free a finite automaton */ +{ + int i; + + if (f == NULL) + return; + for (i = 0; i <= f->curstat; i++) + xfree(f->posns[i]); + for (i = 0; i <= f->accept; i++) { + xfree(f->re[i].lfollow); + if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL) + xfree((f->re[i].lval.np)); + } + xfree(f->restr); + xfree(f); +} diff --git a/usr.bin/awk/lex.c b/usr.bin/awk/lex.c new file mode 100644 index 0000000..e6e3a95 --- /dev/null +++ b/usr.bin/awk/lex.c @@ -0,0 +1,571 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#include +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +extern YYSTYPE yylval; +extern int infunc; + +int lineno = 1; +int bracecnt = 0; +int brackcnt = 0; +int parencnt = 0; + +typedef struct Keyword { + char *word; + int sub; + int type; +} Keyword; + +Keyword keywords[] ={ /* keep sorted: binary searched */ + { "BEGIN", XBEGIN, XBEGIN }, + { "END", XEND, XEND }, + { "NF", VARNF, VARNF }, + { "atan2", FATAN, BLTIN }, + { "break", BREAK, BREAK }, + { "close", CLOSE, CLOSE }, + { "continue", CONTINUE, CONTINUE }, + { "cos", FCOS, BLTIN }, + { "delete", DELETE, DELETE }, + { "do", DO, DO }, + { "else", ELSE, ELSE }, + { "exit", EXIT, EXIT }, + { "exp", FEXP, BLTIN }, + { "fflush", FFLUSH, BLTIN }, + { "for", FOR, FOR }, + { "func", FUNC, FUNC }, + { "function", FUNC, FUNC }, + { "getline", GETLINE, GETLINE }, + { "gsub", GSUB, GSUB }, + { "if", IF, IF }, + { "in", IN, IN }, + { "index", INDEX, INDEX }, + { "int", FINT, BLTIN }, + { "length", FLENGTH, BLTIN }, + { "log", FLOG, BLTIN }, + { "match", MATCHFCN, MATCHFCN }, + { "next", NEXT, NEXT }, + { "nextfile", NEXTFILE, NEXTFILE }, + { "print", PRINT, PRINT }, + { "printf", PRINTF, PRINTF }, + { "rand", FRAND, BLTIN }, + { "return", RETURN, RETURN }, + { "sin", FSIN, BLTIN }, + { "split", SPLIT, SPLIT }, + { "sprintf", SPRINTF, SPRINTF }, + { "sqrt", FSQRT, BLTIN }, + { "srand", FSRAND, BLTIN }, + { "sub", SUB, SUB }, + { "substr", SUBSTR, SUBSTR }, + { "system", FSYSTEM, BLTIN }, + { "tolower", FTOLOWER, BLTIN }, + { "toupper", FTOUPPER, BLTIN }, + { "while", WHILE, WHILE }, +}; + +#define DEBUG +#ifdef DEBUG +#define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); } +#else +#define RET(x) return(x) +#endif + +int peek() +{ + int c = input(); + unput(c); + return c; +} + +int gettok(char **pbuf, int *psz) /* get next input token */ +{ + int c; + char *buf = *pbuf; + int sz = *psz; + char *bp = buf; + + c = input(); + if (c == 0) + return 0; + buf[0] = c; + buf[1] = 0; + if (!isalnum(c) && c != '.' && c != '_') + return c; + + *bp++ = c; + if (isalpha(c) || c == '_') { /* it's a varname */ + for ( ; (c = input()) != 0; ) { + if (bp-buf >= sz) + if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) + ERROR "out of space for name %.10s...", buf FATAL; + if (isalnum(c) || c == '_') + *bp++ = c; + else { + *bp = 0; + unput(c); + break; + } + } + } else { /* it's a number */ + char *rem; + /* read input until can't be a number */ + for ( ; (c = input()) != 0; ) { + if (bp-buf >= sz) + if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) + ERROR "out of space for number %.10s...", buf FATAL; + if (isdigit(c) || c == 'e' || c == 'E' + || c == '.' || c == '+' || c == '-') + *bp++ = c; + else { + *bp = 0; + unput(c); + break; + } + } + strtod(buf, &rem); /* parse the number */ + unputstr(rem); /* put rest back for later */ + rem[0] = 0; + } + *pbuf = buf; + *psz = sz; + return buf[0]; +} + +int word(char *); +int string(void); +int regexpr(void); +int sc = 0; /* 1 => return a } right now */ +int reg = 0; /* 1 => return a REGEXPR now */ + +int yylex() +{ + int c, n; + static char *buf = 0; + static int bufsize = 500; + + if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL) + ERROR "out of space in yylex" FATAL; + if (sc) { + sc = 0; + RET('}'); + } + if (reg) { + reg = 0; + return regexpr(); + } + for (;;) { + c = gettok(&buf, &bufsize); + if (c == 0) + return 0; + if (isalpha(c) || c == '_') + return word(buf); + if (isdigit(c) || c == '.') { + yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab); + /* should this also have STR set? */ + RET(NUMBER); + } + + yylval.i = c; + switch (c) { + case '\n': /* {EOL} */ + RET(NL); + case '\r': /* assume \n is coming */ + case ' ': /* {WS}+ */ + case '\t': + break; + case '#': /* #.* strip comments */ + while ((c = input()) != '\n' && c != 0) + ; + unput(c); + break; + case ';': + RET(';'); + case '\\': + if (peek() == '\n') { + input(); lineno++; + } else if (peek() == '\r') { + input(); input(); /* \n */ + lineno++; + } else { + RET(c); + } + break; + case '&': + if (peek() == '&') { + input(); RET(AND); + } else + RET('&'); + case '|': + if (peek() == '|') { + input(); RET(BOR); + } else + RET('|'); + case '!': + if (peek() == '=') { + input(); yylval.i = NE; RET(NE); + } else if (peek() == '~') { + input(); yylval.i = NOTMATCH; RET(MATCHOP); + } else + RET(NOT); + case '~': + yylval.i = MATCH; + RET(MATCHOP); + case '<': + if (peek() == '=') { + input(); yylval.i = LE; RET(LE); + } else { + yylval.i = LT; RET(LT); + } + case '=': + if (peek() == '=') { + input(); yylval.i = EQ; RET(EQ); + } else { + yylval.i = ASSIGN; RET(ASGNOP); + } + case '>': + if (peek() == '=') { + input(); yylval.i = GE; RET(GE); + } else if (peek() == '>') { + input(); yylval.i = APPEND; RET(APPEND); + } else { + yylval.i = GT; RET(GT); + } + case '+': + if (peek() == '+') { + input(); yylval.i = INCR; RET(INCR); + } else if (peek() == '=') { + input(); yylval.i = ADDEQ; RET(ASGNOP); + } else + RET('+'); + case '-': + if (peek() == '-') { + input(); yylval.i = DECR; RET(DECR); + } else if (peek() == '=') { + input(); yylval.i = SUBEQ; RET(ASGNOP); + } else + RET('-'); + case '*': + if (peek() == '=') { /* *= */ + input(); yylval.i = MULTEQ; RET(ASGNOP); + } else if (peek() == '*') { /* ** or **= */ + input(); /* eat 2nd * */ + if (peek() == '=') { + input(); yylval.i = POWEQ; RET(ASGNOP); + } else { + RET(POWER); + } + } else + RET('*'); + case '/': + if (peek() == '=') { + input(); yylval.i = DIVEQ; RET(ASGNOP); + } else + RET('/'); + case '%': + if (peek() == '=') { + input(); yylval.i = MODEQ; RET(ASGNOP); + } else + RET('%'); + case '^': + if (peek() == '=') { + input(); yylval.i = POWEQ; RET(ASGNOP); + } else + RET(POWER); + + case '$': + /* BUG: awkward, if not wrong */ + c = gettok(&buf, &bufsize); + if (c == '(' || c == '[' || (infunc && (n=isarg(buf)) >= 0)) { + unputstr(buf); + RET(INDIRECT); + } else if (isalpha(c)) { + if (strcmp(buf, "NF") == 0) { /* very special */ + unputstr("(NF)"); + RET(INDIRECT); + } + yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab); + RET(IVAR); + } else { + unputstr(buf); + RET(INDIRECT); + } + + case '}': + if (--bracecnt < 0) + ERROR "extra }" SYNTAX; + sc = 1; + RET(';'); + case ']': + if (--brackcnt < 0) + ERROR "extra ]" SYNTAX; + RET(']'); + case ')': + if (--parencnt < 0) + ERROR "extra )" SYNTAX; + RET(')'); + case '{': + bracecnt++; + RET('{'); + case '[': + brackcnt++; + RET('['); + case '(': + parencnt++; + RET('('); + + case '"': + return string(); /* BUG: should be like tran.c ? */ + + default: + RET(c); + } + } +} + +int string() +{ + int c, n; + char *s, *bp; + static char *buf = 0; + static int bufsz = 500; + + if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + ERROR "out of space for strings" FATAL; + for (bp = buf; (c = input()) != '"'; ) { + if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0)) + ERROR "out of space for string %.10s...", buf FATAL; + switch (c) { + case '\n': + case '\r': + case 0: + ERROR "non-terminated string %.10s...", buf SYNTAX; + lineno++; + break; + case '\\': + c = input(); + switch (c) { + case '"': *bp++ = '"'; break; + case 'n': *bp++ = '\n'; break; + case 't': *bp++ = '\t'; break; + case 'f': *bp++ = '\f'; break; + case 'r': *bp++ = '\r'; break; + case 'b': *bp++ = '\b'; break; + case 'v': *bp++ = '\v'; break; + case 'a': *bp++ = '\a'; break; + case '\\': *bp++ = '\\'; break; + + case '0': case '1': case '2': /* octal: \d \dd \ddd */ + case '3': case '4': case '5': case '6': case '7': + n = c - '0'; + if ((c = peek()) >= '0' && c < '8') { + n = 8 * n + input() - '0'; + if ((c = peek()) >= '0' && c < '8') + n = 8 * n + input() - '0'; + } + *bp++ = n; + break; + + case 'x': /* hex \x0-9a-fA-F + */ + { char xbuf[100], *px; + for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) { + if (isdigit(c) + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')) + *px++ = c; + else + break; + } + *px = 0; + unput(c); + sscanf(xbuf, "%x", &n); + *bp++ = n; + break; + } + + default: + *bp++ = c; + break; + } + break; + default: + *bp++ = c; + break; + } + } + *bp = 0; + s = tostring(buf); + *bp++ = ' '; *bp++ = 0; + yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab); + RET(STRING); +} + + +int binsearch(char *w, Keyword *kp, int n) +{ + int cond, low, mid, high; + + low = 0; + high = n - 1; + while (low <= high) { + mid = (low + high) / 2; + if ((cond = strcmp(w, kp[mid].word)) < 0) + high = mid - 1; + else if (cond > 0) + low = mid + 1; + else + return mid; + } + return -1; +} + +int word(char *w) +{ + Keyword *kp; + int c, n; + + n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0])); + kp = keywords + n; + if (n != -1) { /* found in table */ + yylval.i = kp->sub; + switch (kp->type) { /* special handling */ + case FSYSTEM: + if (safe) + ERROR "system is unsafe" SYNTAX; + RET(kp->type); + case FUNC: + if (infunc) + ERROR "illegal nested function" SYNTAX; + RET(kp->type); + case RETURN: + if (!infunc) + ERROR "return not in function" SYNTAX; + RET(kp->type); + case VARNF: + yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab); + RET(VARNF); + default: + RET(kp->type); + } + } + c = peek(); /* look for '(' */ + if (c != '(' && infunc && (n=isarg(w)) >= 0) { + yylval.i = n; + RET(ARG); + } else { + yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab); + if (c == '(') { + RET(CALL); + } else { + RET(VAR); + } + } +} + +void startreg(void) /* next call to yyles will return a regular expression */ +{ + reg = 1; +} + +int regexpr() +{ + int c; + static char *buf = 0; + static int bufsz = 500; + char *bp; + + if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + ERROR "out of space for rex expr" FATAL; + bp = buf; + for ( ; (c = input()) != '/' && c != 0; ) { + if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0)) + ERROR "out of space for reg expr %.10s...", buf FATAL; + if (c == '\n') { + ERROR "newline in regular expression %.10s...", buf SYNTAX; + unput('\n'); + break; + } else if (c == '\\') { + *bp++ = '\\'; + *bp++ = input(); + } else { + *bp++ = c; + } + } + *bp = 0; + yylval.s = tostring(buf); + unput('/'); + RET(REGEXPR); +} + +/* low-level lexical stuff, sort of inherited from lex */ + +char ebuf[300]; +char *ep = ebuf; +char yysbuf[100]; /* pushback buffer */ +char *yysptr = yysbuf; +FILE *yyin = 0; + +int input(void) /* get next lexical input character */ +{ + int c; + extern char *lexprog; + + if (yysptr > yysbuf) + c = *--yysptr; + else if (lexprog != NULL) { /* awk '...' */ + if ((c = *lexprog) != 0) + lexprog++; + } else /* awk -f ... */ + c = pgetc(); + if (c == '\n') + lineno++; + else if (c == EOF) + c = 0; + if (ep >= ebuf + sizeof ebuf) + ep = ebuf; + return *ep++ = c; +} + +void unput(int c) /* put lexical character back on input */ +{ + if (c == '\n') + lineno--; + if (yysptr >= yysbuf + sizeof(yysbuf)) + ERROR "pushed back too much: %.20s...", yysbuf FATAL; + *yysptr++ = c; + if (--ep < ebuf) + ep = ebuf + sizeof(ebuf) - 1; +} + +void unputstr(char *s) /* put a string back on input */ +{ + int i; + + for (i = strlen(s)-1; i >= 0; i--) + unput(s[i]); +} diff --git a/usr.bin/awk/lib.c b/usr.bin/awk/lib.c new file mode 100644 index 0000000..42c450f --- /dev/null +++ b/usr.bin/awk/lib.c @@ -0,0 +1,651 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include +#include +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +FILE *infile = NULL; +char *file = ""; +char *record; +int recsize = RECSIZE; +char *fields; +int fieldssize = RECSIZE; + +Cell **fldtab; /* pointers to Cells */ +char inputFS[100]; + +#define MAXFLD 200 +int nfields = MAXFLD; /* last allocated slot for $i */ + +int donefld; /* 1 = implies rec broken into fields */ +int donerec; /* 1 = record is valid (no flds have changed) */ + +int lastfld = 0; /* last used field */ +int argno = 1; /* current input argument number */ +extern Awkfloat *ARGC; + +static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; +static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; + +void recinit(unsigned int n) +{ + record = (char *) malloc(n); + fields = (char *) malloc(n); + fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *)); + if (record == NULL || fields == NULL || fldtab == NULL) + ERROR "out of space for $0 and fields" FATAL; + + fldtab[0] = (Cell *) malloc(sizeof (Cell)); + *fldtab[0] = dollar0; + fldtab[0]->sval = record; + fldtab[0]->nval = tostring("0"); + makefields(1, nfields); +} + +void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ +{ + char temp[50]; + int i; + + for (i = n1; i <= n2; i++) { + fldtab[i] = (Cell *) malloc(sizeof (struct Cell)); + if (fldtab[i] == NULL) + ERROR "out of space in makefields %d", i FATAL; + *fldtab[i] = dollar1; + sprintf(temp, "%d", i); + fldtab[i]->nval = tostring(temp); + } +} + +void initgetrec(void) +{ + int i; + char *p; + + for (i = 1; i < *ARGC; i++) { + if (!isclvar(p = getargv(i))) { /* find 1st real filename */ + setsval(lookup("FILENAME", symtab), getargv(i)); + return; + } + setclvar(p); /* a commandline assignment before filename */ + argno++; + } + infile = stdin; /* no filenames, so use stdin */ +} + +int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */ +{ /* note: cares whether buf == record */ + int c; + static int firsttime = 1; + char *buf = *pbuf; + int bufsize = *pbufsize; + + if (firsttime) { + firsttime = 0; + initgetrec(); + } + dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", + *RS, *FS, *ARGC, *FILENAME) ); + donefld = 0; + donerec = 1; + buf[0] = 0; + while (argno < *ARGC || infile == stdin) { + dprintf( ("argno=%d, file=|%s|\n", argno, file) ); + if (infile == NULL) { /* have to open a new file */ + file = getargv(argno); + if (*file == '\0') { /* it's been zapped */ + argno++; + continue; + } + if (isclvar(file)) { /* a var=value arg */ + setclvar(file); + argno++; + continue; + } + *FILENAME = file; + dprintf( ("opening file %s\n", file) ); + if (*file == '-' && *(file+1) == '\0') + infile = stdin; + else if ((infile = fopen(file, "r")) == NULL) + ERROR "can't open file %s", file FATAL; + setfval(fnrloc, 0.0); + } + c = readrec(&buf, &bufsize, infile); + if (c != 0 || buf[0] != '\0') { /* normal record */ + if (isrecord) { + if (freeable(fldtab[0])) + xfree(fldtab[0]->sval); + fldtab[0]->sval = buf; /* buf == record */ + fldtab[0]->tval = REC | STR | DONTFREE; + if (isnumber(fldtab[0]->sval)) { + fldtab[0]->fval = atof(fldtab[0]->sval); + fldtab[0]->tval |= NUM; + } + } + setfval(nrloc, nrloc->fval+1); + setfval(fnrloc, fnrloc->fval+1); + *pbuf = buf; + *pbufsize = bufsize; + return 1; + } + /* EOF arrived on this file; set up next */ + if (infile != stdin) + fclose(infile); + infile = NULL; + argno++; + } + *pbuf = buf; + *pbufsize = bufsize; + return 0; /* true end of file */ +} + +void nextfile(void) +{ + if (infile != stdin) + fclose(infile); + infile = NULL; + argno++; +} + +int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */ +{ + int sep, c; + char *rr, *buf = *pbuf; + int bufsize = *pbufsize; + + if (strlen(*FS) >= sizeof(inputFS)) + ERROR "field separator %.10s... is too long", *FS FATAL; + strcpy(inputFS, *FS); /* for subsequent field splitting */ + if ((sep = **RS) == 0) { + sep = '\n'; + while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ + ; + if (c != EOF) + ungetc(c, inf); + } + for (rr = buf; ; ) { + for (; (c=getc(inf)) != sep && c != EOF; ) { + if (rr-buf+1 > bufsize) + if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1")) + ERROR "input record `%.30s...' too long", buf FATAL; + *rr++ = c; + } + if (**RS == sep || c == EOF) + break; + if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ + break; + if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2")) + ERROR "input record `%.30s...' too long", buf FATAL; + *rr++ = '\n'; + *rr++ = c; + } + if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) + ERROR "input record `%.30s...' too long", buf FATAL; + *rr = 0; + dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) ); + *pbuf = buf; + *pbufsize = bufsize; + return c == EOF && rr == buf ? 0 : 1; +} + +char *getargv(int n) /* get ARGV[n] */ +{ + Cell *x; + char *s, temp[50]; + extern Array *ARGVtab; + + sprintf(temp, "%d", n); + x = setsymtab(temp, "", 0.0, STR, ARGVtab); + s = getsval(x); + dprintf( ("getargv(%d) returns |%s|\n", n, s) ); + return s; +} + +void setclvar(char *s) /* set var=value from s */ +{ + char *p; + Cell *q; + + for (p=s; *p != '='; p++) + ; + *p++ = 0; + p = qstring(p, '\0'); + q = setsymtab(s, p, 0.0, STR, symtab); + setsval(q, p); + if (isnumber(q->sval)) { + q->fval = atof(q->sval); + q->tval |= NUM; + } + dprintf( ("command line set %s to |%s|\n", s, p) ); +} + + +void fldbld(void) /* create fields from current record */ +{ + /* this relies on having fields[] the same length as $0 */ + /* the fields are all stored in this one array with \0's */ + char *r, *fr, sep; + Cell *p; + int i, j, n; + + if (donefld) + return; + if (!isstr(fldtab[0])) + getsval(fldtab[0]); + r = fldtab[0]->sval; + n = strlen(r); + if (n > fieldssize) { + xfree(fields); + if ((fields = (char *) malloc(n+1)) == NULL) + ERROR "out of space for fields in fldbld %d", n FATAL; + fieldssize = n; + } + fr = fields; + i = 0; /* number of fields accumulated here */ + if (strlen(inputFS) > 1) { /* it's a regular expression */ + i = refldbld(r, inputFS); + } else if ((sep = *inputFS) == ' ') { /* default whitespace */ + for (i = 0; ; ) { + while (*r == ' ' || *r == '\t' || *r == '\n') + r++; + if (*r == 0) + break; + i++; + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + fldtab[i]->sval = fr; + fldtab[i]->tval = FLD | STR | DONTFREE; + do + *fr++ = *r++; + while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); + *fr++ = 0; + } + *fr = 0; + } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */ + for (i = 0; *r != 0; r++) { + char buf[2]; + i++; + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + buf[0] = *r; + buf[1] = 0; + fldtab[i]->sval = tostring(buf); + fldtab[i]->tval = FLD | STR; + } + *fr = 0; + } else if (*r != 0) { /* if 0, it's a null field */ + for (;;) { + i++; + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + fldtab[i]->sval = fr; + fldtab[i]->tval = FLD | STR | DONTFREE; + while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */ + *fr++ = *r++; + *fr++ = 0; + if (*r++ == 0) + break; + } + *fr = 0; + } + if (i > nfields) + ERROR "record `%.30s...' has too many fields; can't happen", r FATAL; + cleanfld(i+1, lastfld); /* clean out junk from previous record */ + lastfld = i; + donefld = 1; + for (j = 1; j <= lastfld; j++) { + p = fldtab[j]; + if(isnumber(p->sval)) { + p->fval = atof(p->sval); + p->tval |= NUM; + } + } + setfval(nfloc, (Awkfloat) lastfld); + if (dbg) { + for (j = 0; j <= lastfld; j++) { + p = fldtab[j]; + printf("field %d (%s): |%s|\n", j, p->nval, p->sval); + } + } +} + +void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ +{ /* nvals remain intact */ + Cell *p; + int i; + + for (i = n1; i <= n2; i++) { + p = fldtab[i]; + if (freeable(p)) + xfree(p->sval); + p->sval = ""; + p->tval = FLD | STR | DONTFREE; + } +} + +void newfld(int n) /* add field n after end of existing lastfld */ +{ + if (n > nfields) + growfldtab(n); + cleanfld(lastfld+1, n); + lastfld = n; + setfval(nfloc, (Awkfloat) n); +} + +Cell *fieldadr(int n) /* get nth field */ +{ + if (n < 0) + ERROR "trying to access field %d", n FATAL; + if (n > nfields) /* fields after NF are empty */ + growfldtab(n); /* but does not increase NF */ + return(fldtab[n]); +} + +void growfldtab(int n) /* make new fields up to at least $n */ +{ + int nf = 2 * nfields; + + if (n > nf) + nf = n; + fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *))); + if (fldtab == NULL) + ERROR "out of space creating %d fields", nf FATAL; + makefields(nfields+1, nf); + nfields = nf; +} + +int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */ +{ + /* this relies on having fields[] the same length as $0 */ + /* the fields are all stored in this one array with \0's */ + char *fr; + int i, tempstat, n; + fa *pfa; + + n = strlen(rec); + if (n > fieldssize) { + xfree(fields); + if ((fields = (char *) malloc(n+1)) == NULL) + ERROR "out of space for fields in refldbld %d", n FATAL; + fieldssize = n; + } + fr = fields; + *fr = '\0'; + if (*rec == '\0') + return 0; + pfa = makedfa(fs, 1); + dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); + tempstat = pfa->initstat; + for (i = 1; ; i++) { + if (i > nfields) + growfldtab(i); + if (freeable(fldtab[i])) + xfree(fldtab[i]->sval); + fldtab[i]->tval = FLD | STR | DONTFREE; + fldtab[i]->sval = fr; + dprintf( ("refldbld: i=%d\n", i) ); + if (nematch(pfa, rec)) { + pfa->initstat = 2; /* horrible coupling to b.c */ + dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); + strncpy(fr, rec, patbeg-rec); + fr += patbeg - rec + 1; + *(fr-1) = '\0'; + rec = patbeg + patlen; + } else { + dprintf( ("no match %s\n", rec) ); + strcpy(fr, rec); + pfa->initstat = tempstat; + break; + } + } + return i; +} + +void recbld(void) /* create $0 from $1..$NF if necessary */ +{ + int i; + char *r, *p; + char *buf = record; + int bufsize = recsize; + + if (donerec == 1) + return; + r = buf; + for (i = 1; i <= *NF; i++) { + p = getsval(fldtab[i]); + if (!adjbuf(&buf, &bufsize, 1+strlen(p)+r-buf, recsize, &r, "recbld 1")) + ERROR "created $0 `%.30s...' too long", buf FATAL; + while ((*r = *p++) != 0) + r++; + if (i < *NF) { + if (!adjbuf(&buf, &bufsize, 2+strlen(*OFS)+r-buf, recsize, &r, "recbld 2")) + ERROR "created $0 `%.30s...' too long", buf FATAL; + for (p = *OFS; (*r = *p++) != 0; ) + r++; + } + } + if (!adjbuf(&buf, &bufsize, 2+r-buf, recsize, &r, "recbld 3")) + ERROR "built giant record `%.30s...'", buf FATAL; + *r = '\0'; + dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) ); + + if (buf != record) { /* increased size of record */ + record = buf; /* BUG? memory leak? */ + recsize = bufsize; + } + if (freeable(fldtab[0])) + xfree(fldtab[0]->sval); + fldtab[0]->tval = REC | STR | DONTFREE; + fldtab[0]->sval = record; + + dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) ); + dprintf( ("recbld = |%s|\n", record) ); + donerec = 1; +} + +int errorflag = 0; +char errbuf[300]; /* used by ERROR macro */ + +void yyerror(char *s) +{ + extern char *cmdname, *curfname; + static int been_here = 0; + + if (been_here++ > 2) + return; + fprintf(stderr, "%s: %s", cmdname, s); + fprintf(stderr, " at source line %d", lineno); + if (curfname != NULL) + fprintf(stderr, " in function %s", curfname); + fprintf(stderr, "\n"); + errorflag = 2; + eprint(); +} + +void fpecatch(int n) +{ + ERROR "floating point exception %d", n FATAL; +} + +extern int bracecnt, brackcnt, parencnt; + +void bracecheck(void) +{ + int c; + static int beenhere = 0; + + if (beenhere++) + return; + while ((c = input()) != EOF && c != '\0') + bclass(c); + bcheck2(bracecnt, '{', '}'); + bcheck2(brackcnt, '[', ']'); + bcheck2(parencnt, '(', ')'); +} + +void bcheck2(int n, int c1, int c2) +{ + if (n == 1) + fprintf(stderr, "\tmissing %c\n", c2); + else if (n > 1) + fprintf(stderr, "\t%d missing %c's\n", n, c2); + else if (n == -1) + fprintf(stderr, "\textra %c\n", c2); + else if (n < -1) + fprintf(stderr, "\t%d extra %c's\n", -n, c2); +} + +void error(int f, char *s) +{ + extern Node *curnode; + extern char *cmdname; + + fflush(stdout); + fprintf(stderr, "%s: ", cmdname); + fprintf(stderr, "%s", s); + fprintf(stderr, "\n"); + if (compile_time != 2 && NR && *NR > 0) { + fprintf(stderr, " input record number %d", (int) (*FNR)); + if (strcmp(*FILENAME, "-") != 0) + fprintf(stderr, ", file %s", *FILENAME); + fprintf(stderr, "\n"); + } + if (compile_time != 2 && curnode) + fprintf(stderr, " source line number %d\n", curnode->lineno); + else if (compile_time != 2 && lineno) + fprintf(stderr, " source line number %d\n", lineno); + eprint(); + if (f) { + if (dbg > 1) /* core dump if serious debugging on */ + abort(); + exit(2); + } +} + +void eprint(void) /* try to print context around error */ +{ + char *p, *q; + int c; + static int been_here = 0; + extern char ebuf[], *ep; + + if (compile_time == 2 || compile_time == 0 || been_here++ > 0) + return; + p = ep - 1; + if (p > ebuf && *p == '\n') + p--; + for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) + ; + while (*p == '\n') + p++; + fprintf(stderr, " context is\n\t"); + for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) + ; + for ( ; p < q; p++) + if (*p) + putc(*p, stderr); + fprintf(stderr, " >>> "); + for ( ; p < ep; p++) + if (*p) + putc(*p, stderr); + fprintf(stderr, " <<< "); + if (*ep) + while ((c = input()) != '\n' && c != '\0' && c != EOF) { + putc(c, stderr); + bclass(c); + } + putc('\n', stderr); + ep = ebuf; +} + +void bclass(int c) +{ + switch (c) { + case '{': bracecnt++; break; + case '}': bracecnt--; break; + case '[': brackcnt++; break; + case ']': brackcnt--; break; + case '(': parencnt++; break; + case ')': parencnt--; break; + } +} + +double errcheck(double x, char *s) +{ + extern int errno; + + if (errno == EDOM) { + errno = 0; + ERROR "%s argument out of domain", s WARNING; + x = 1; + } else if (errno == ERANGE) { + errno = 0; + ERROR "%s result out of range", s WARNING; + x = 1; + } + return x; +} + +int isclvar(char *s) /* is s of form var=something ? */ +{ + char *os = s; + + if (!isalpha(*s) && *s != '_') + return 0; + for ( ; *s; s++) + if (!(isalnum(*s) || *s == '_')) + break; + return *s == '=' && s > os && *(s+1) != '='; +} + +/* strtod is supposed to be a proper test of what's a valid number */ + +#include +int isnumber(char *s) +{ + double r; + char *ep; + errno = 0; + r = strtod(s, &ep); + if (ep == s || r == HUGE_VAL || errno == ERANGE) + return 0; + while (*ep == ' ' || *ep == '\t' || *ep == '\n') + ep++; + if (*ep == '\0') + return 1; + else + return 0; +} diff --git a/usr.bin/awk/main.c b/usr.bin/awk/main.c new file mode 100644 index 0000000..2a44d38 --- /dev/null +++ b/usr.bin/awk/main.c @@ -0,0 +1,184 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +char *version = "version 970821"; + +#define DEBUG +#include +#include +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +extern char **environ; +extern int nfields; + +int dbg = 0; +char *cmdname; /* gets argv[0] for error messages */ +extern FILE *yyin; /* lex input file */ +char *lexprog; /* points to program argument if it exists */ +extern int errorflag; /* non-zero if any syntax errors; set by yyerror */ +int compile_time = 2; /* for error printing: */ + /* 2 = cmdline, 1 = compile, 0 = running */ + +char *pfile[20]; /* program filenames from -f's */ +int npfile = 0; /* number of filenames */ +int curpfile = 0; /* current filename */ + +int safe = 0; /* 1 => "safe" mode */ + +int main(int argc, char *argv[]) +{ + char *fs = NULL, *marg; + int temp; + + cmdname = argv[0]; + if (argc == 1) { + fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname); + exit(1); + } + signal(SIGFPE, fpecatch); + yyin = NULL; + symtab = makesymtab(NSYMTAB); + while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') { + if (strcmp(argv[1], "--") == 0) { /* explicit end of args */ + argc--; + argv++; + break; + } + switch (argv[1][1]) { + case 's': + if (strcmp(argv[1], "-safe") == 0) + safe = 1; + break; + case 'f': /* next argument is program filename */ + argc--; + argv++; + if (argc <= 1) + ERROR "no program filename" FATAL; + pfile[npfile++] = argv[1]; + break; + case 'F': /* set field separator */ + if (argv[1][2] != 0) { /* arg is -Fsomething */ + if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */ + fs = "\t"; + else if (argv[1][2] != 0) + fs = &argv[1][2]; + } else { /* arg is -F something */ + argc--; argv++; + if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */ + fs = "\t"; + else if (argc > 1 && argv[1][0] != 0) + fs = &argv[1][0]; + } + if (fs == NULL || *fs == '\0') + ERROR "field separator FS is empty" WARNING; + break; + case 'v': /* -v a=1 to be done NOW. one -v for each */ + if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1])) + setclvar(argv[1]); + break; + case 'm': /* more memory: -mr=record, -mf=fields */ + /* no longer needed */ + marg = argv[1]; + if (argv[1][3]) + temp = atoi(&argv[1][3]); + else { + argv++; argc--; + temp = atoi(&argv[1][0]); + } + switch (marg[2]) { + case 'r': recsize = temp; break; + case 'f': nfields = temp; break; + default: ERROR "unknown option %s\n", marg FATAL; + } + break; + case 'd': + dbg = atoi(&argv[1][2]); + if (dbg == 0) + dbg = 1; + printf("awk %s\n", version); + break; + default: + ERROR "unknown option %s ignored", argv[1] WARNING; + break; + } + argc--; + argv++; + } + /* argv[1] is now the first argument */ + if (npfile == 0) { /* no -f; first argument is program */ + if (argc <= 1) { + if (dbg) + exit(0); + ERROR "no program given" FATAL; + } + dprintf( ("program = |%s|\n", argv[1]) ); + lexprog = argv[1]; + argc--; + argv++; + } + recinit(recsize); + syminit(); + compile_time = 1; + argv[0] = cmdname; /* put prog name at front of arglist */ + dprintf( ("argc=%d, argv[0]=%s\n", argc, argv[0]) ); + arginit(argc, argv); + if (!safe) + envinit(environ); + yyparse(); + if (fs) + *FS = qstring(fs, '\0'); + dprintf( ("errorflag=%d\n", errorflag) ); + if (errorflag == 0) { + compile_time = 0; + run(winner); + } else + bracecheck(); + return(errorflag); +} + +int pgetc(void) /* get 1 character from awk program */ +{ + int c; + + for (;;) { + if (yyin == NULL) { + if (curpfile >= npfile) + return EOF; + if (strcmp(pfile[curpfile], "-") == 0) + yyin = stdin; + else if ((yyin = fopen(pfile[curpfile], "r")) == NULL) + ERROR "can't open file %s", pfile[curpfile] FATAL; + } + if ((c = getc(yyin)) != EOF) + return c; + if (yyin != stdin) + fclose(yyin); + yyin = NULL; + curpfile++; + } +} diff --git a/usr.bin/awk/makefile b/usr.bin/awk/makefile new file mode 100644 index 0000000..8d14989 --- /dev/null +++ b/usr.bin/awk/makefile @@ -0,0 +1,76 @@ +# /**************************************************************** +# Copyright (C) Lucent Technologies 1997 +# All Rights Reserved +# +# Permission to use, copy, modify, and distribute this software and +# its documentation for any purpose and without fee is hereby +# granted, provided that the above copyright notice appear in all +# copies and that both that the copyright notice and this +# permission notice and warranty disclaimer appear in supporting +# documentation, and that the name Lucent Technologies or any of +# its entities not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. +# +# LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +# IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +# SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +# THIS SOFTWARE. +# ****************************************************************/ + +CFLAGS = -g +CFLAGS = -O +CC = purify cc +CC = gcc -Wall -g +CC = cc + +YACC = bison -y +YACC = yacc +YFLAGS = -d + +OFILES = b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o + +SOURCE = awk.h ytab.c ytab.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c lib.c run.c tran.c missing95.c + +LISTING = awk.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c lib.c run.c tran.c missing.c + +a.out: ytab.o $(OFILES) + $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC) -lm + +$(OFILES): awk.h ytab.h proto.h + +ytab.o: awk.h proto.h awkgram.y + $(YACC) $(YFLAGS) awkgram.y + mv y.tab.c ytab.c + mv y.tab.h ytab.h + $(CC) $(CFLAGS) -c ytab.c + +proctab.c: maketab + ./maketab >proctab.c + +maketab: ytab.h maketab.c + $(CC) $(CFLAGS) maketab.c -o maketab + +bundle: + @cp ytab.h ytabh.bak + @cp ytab.c ytabc.bak + @bundle README FIXES $(SOURCE) ytab[ch].bak makefile awk.1 + +tar: + @cp ytab.h ytabh.bak + @cp ytab.c ytabc.bak + @tar cf awk.tar README FIXES $(SOURCE) ytab[ch].bak makefile awk.1 + gzip awk.tar + ls -l awk.tar.gz + @zip awk.zip README FIXES $(SOURCE) ytab[ch].bak makefile awk.1 + ls -l awk.zip + +names: + @echo $(LISTING) + +clean: + rm -f a.out *.o maketab proctab.c diff --git a/usr.bin/awk/maketab.c b/usr.bin/awk/maketab.c new file mode 100644 index 0000000..d3fc37e --- /dev/null +++ b/usr.bin/awk/maketab.c @@ -0,0 +1,168 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +/* + * this program makes the table to link function names + * and type indices that is used by execute() in run.c. + * it finds the indices in ytab.h, produced by yacc. + */ + +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +struct xx +{ int token; + char *name; + char *pname; +} proc[] = { + { PROGRAM, "program", NULL }, + { BOR, "boolop", " || " }, + { AND, "boolop", " && " }, + { NOT, "boolop", " !" }, + { NE, "relop", " != " }, + { EQ, "relop", " == " }, + { LE, "relop", " <= " }, + { LT, "relop", " < " }, + { GE, "relop", " >= " }, + { GT, "relop", " > " }, + { ARRAY, "array", NULL }, + { INDIRECT, "indirect", "$(" }, + { SUBSTR, "substr", "substr" }, + { SUB, "sub", "sub" }, + { GSUB, "gsub", "gsub" }, + { INDEX, "sindex", "sindex" }, + { SPRINTF, "awksprintf", "sprintf " }, + { ADD, "arith", " + " }, + { MINUS, "arith", " - " }, + { MULT, "arith", " * " }, + { DIVIDE, "arith", " / " }, + { MOD, "arith", " % " }, + { UMINUS, "arith", " -" }, + { POWER, "arith", " **" }, + { PREINCR, "incrdecr", "++" }, + { POSTINCR, "incrdecr", "++" }, + { PREDECR, "incrdecr", "--" }, + { POSTDECR, "incrdecr", "--" }, + { CAT, "cat", " " }, + { PASTAT, "pastat", NULL }, + { PASTAT2, "dopa2", NULL }, + { MATCH, "matchop", " ~ " }, + { NOTMATCH, "matchop", " !~ " }, + { MATCHFCN, "matchop", "matchop" }, + { INTEST, "intest", "intest" }, + { PRINTF, "awkprintf", "printf" }, + { PRINT, "printstat", "print" }, + { CLOSE, "closefile", "closefile" }, + { DELETE, "adelete", "adelete" }, + { SPLIT, "split", "split" }, + { ASSIGN, "assign", " = " }, + { ADDEQ, "assign", " += " }, + { SUBEQ, "assign", " -= " }, + { MULTEQ, "assign", " *= " }, + { DIVEQ, "assign", " /= " }, + { MODEQ, "assign", " %= " }, + { POWEQ, "assign", " ^= " }, + { CONDEXPR, "condexpr", " ?: " }, + { IF, "ifstat", "if(" }, + { WHILE, "whilestat", "while(" }, + { FOR, "forstat", "for(" }, + { DO, "dostat", "do" }, + { IN, "instat", "instat" }, + { NEXT, "jump", "next" }, + { NEXTFILE, "jump", "nextfile" }, + { EXIT, "jump", "exit" }, + { BREAK, "jump", "break" }, + { CONTINUE, "jump", "continue" }, + { RETURN, "jump", "ret" }, + { BLTIN, "bltin", "bltin" }, + { CALL, "call", "call" }, + { ARG, "arg", "arg" }, + { VARNF, "getnf", "NF" }, + { GETLINE, "getline", "getline" }, + { 0, "", "" }, +}; + +#define SIZE (LASTTOKEN - FIRSTTOKEN + 1) +char *table[SIZE]; +char *names[SIZE]; + +int main(int argc, char *argv[]) +{ + struct xx *p; + int i, n, tok; + char c; + FILE *fp; + char buf[200], name[200], def[200]; + + printf("#include \n"); + printf("#include \"awk.h\"\n"); + printf("#include \"ytab.h\"\n\n"); + for (i = SIZE; --i >= 0; ) + names[i] = ""; + + if ((fp = fopen("ytab.h", "r")) == NULL) { + fprintf(stderr, "maketab can't open ytab.h!\n"); + exit(1); + } + printf("static char *printname[%d] = {\n", SIZE); + i = 0; + while (fgets(buf, sizeof buf, fp) != NULL) { + n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok); + if (c != '#' || (n != 4 && strcmp(def,"define") != 0)) /* not a valid #define */ + continue; + if (tok < FIRSTTOKEN || tok > LASTTOKEN) { + fprintf(stderr, "maketab funny token %d %s\n", tok, buf); + exit(1); + } + names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1); + strcpy(names[tok-FIRSTTOKEN], name); + printf("\t(char *) \"%s\",\t/* %d */\n", name, tok); + i++; + } + printf("};\n\n"); + + for (p=proc; p->token!=0; p++) + table[p->token-FIRSTTOKEN] = p->name; + printf("\nCell *(*proctab[%d])(Node **, int) = {\n", SIZE); + for (i=0; i LASTTOKEN) {\n"); + printf(" sprintf(buf, \"token %%d\", n);\n"); + printf(" return buf;\n"); + printf(" }\n"); + printf(" return printname[n-FIRSTTOKEN];\n"); + printf("}\n"); + return 0; +} diff --git a/usr.bin/awk/missing95.c b/usr.bin/awk/missing95.c new file mode 100644 index 0000000..1bfb493 --- /dev/null +++ b/usr.bin/awk/missing95.c @@ -0,0 +1,6 @@ +/* these routines are not part of win 95 and nt; + they are included here so you can compile. */ + +#include +FILE *popen(char *s, char *m) { return NULL; } +int pclose(FILE *f) { return 0; } diff --git a/usr.bin/awk/parse.c b/usr.bin/awk/parse.c new file mode 100644 index 0000000..66a94cc --- /dev/null +++ b/usr.bin/awk/parse.c @@ -0,0 +1,261 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +Node *nodealloc(int n) +{ + Node *x; + + x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *)); + if (x == NULL) + ERROR "out of space in nodealloc" FATAL; + x->nnext = NULL; + x->lineno = lineno; + return(x); +} + +Node *exptostat(Node *a) +{ + a->ntype = NSTAT; + return(a); +} + +Node *node1(int a, Node *b) +{ + Node *x; + + x = nodealloc(1); + x->nobj = a; + x->narg[0]=b; + return(x); +} + +Node *node2(int a, Node *b, Node *c) +{ + Node *x; + + x = nodealloc(2); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + return(x); +} + +Node *node3(int a, Node *b, Node *c, Node *d) +{ + Node *x; + + x = nodealloc(3); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + return(x); +} + +Node *node4(int a, Node *b, Node *c, Node *d, Node *e) +{ + Node *x; + + x = nodealloc(4); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + x->narg[3] = e; + return(x); +} + +Node *stat1(int a, Node *b) +{ + Node *x; + + x = node1(a,b); + x->ntype = NSTAT; + return(x); +} + +Node *stat2(int a, Node *b, Node *c) +{ + Node *x; + + x = node2(a,b,c); + x->ntype = NSTAT; + return(x); +} + +Node *stat3(int a, Node *b, Node *c, Node *d) +{ + Node *x; + + x = node3(a,b,c,d); + x->ntype = NSTAT; + return(x); +} + +Node *stat4(int a, Node *b, Node *c, Node *d, Node *e) +{ + Node *x; + + x = node4(a,b,c,d,e); + x->ntype = NSTAT; + return(x); +} + +Node *op1(int a, Node *b) +{ + Node *x; + + x = node1(a,b); + x->ntype = NEXPR; + return(x); +} + +Node *op2(int a, Node *b, Node *c) +{ + Node *x; + + x = node2(a,b,c); + x->ntype = NEXPR; + return(x); +} + +Node *op3(int a, Node *b, Node *c, Node *d) +{ + Node *x; + + x = node3(a,b,c,d); + x->ntype = NEXPR; + return(x); +} + +Node *op4(int a, Node *b, Node *c, Node *d, Node *e) +{ + Node *x; + + x = node4(a,b,c,d,e); + x->ntype = NEXPR; + return(x); +} + +Node *celltonode(Cell *a, int b) +{ + Node *x; + + a->ctype = OCELL; + a->csub = b; + x = node1(0, (Node *) a); + x->ntype = NVALUE; + return(x); +} + +Node *rectonode(void) /* make $0 into a Node */ +{ + extern Cell *literal0; + return op1(INDIRECT, celltonode(literal0, CUNK)); +} + +Node *makearr(Node *p) +{ + Cell *cp; + + if (isvalue(p)) { + cp = (Cell *) (p->narg[0]); + if (isfcn(cp)) + ERROR "%s is a function, not an array", cp->nval SYNTAX; + else if (!isarr(cp)) { + xfree(cp->sval); + cp->sval = (char *) makesymtab(NSYMTAB); + cp->tval = ARR; + } + } + return p; +} + +#define PA2NUM 50 /* max number of pat,pat patterns allowed */ +int paircnt; /* number of them in use */ +int pairstack[PA2NUM]; /* state of each pat,pat */ + +Node *pa2stat(Node *a, Node *b, Node *c) /* pat, pat {...} */ +{ + Node *x; + + x = node4(PASTAT2, a, b, c, (Node *) paircnt); + if (paircnt++ >= PA2NUM) + ERROR "limited to %d pat,pat statements", PA2NUM SYNTAX; + x->ntype = NSTAT; + return(x); +} + +Node *linkum(Node *a, Node *b) +{ + Node *c; + + if (errorflag) /* don't link things that are wrong */ + return a; + if (a == NULL) + return(b); + else if (b == NULL) + return(a); + for (c = a; c->nnext != NULL; c = c->nnext) + ; + c->nnext = b; + return(a); +} + +void defn(Cell *v, Node *vl, Node *st) /* turn on FCN bit in definition, */ +{ /* body of function, arglist */ + Node *p; + int n; + + if (isarr(v)) { + ERROR "`%s' is an array name and a function name", v->nval SYNTAX; + return; + } + v->tval = FCN; + v->sval = (char *) st; + n = 0; /* count arguments */ + for (p = vl; p; p = p->nnext) + n++; + v->fval = n; + dprintf( ("defining func %s (%d args)\n", v->nval, n) ); +} + +int isarg(char *s) /* is s in argument list for current function? */ +{ /* return -1 if not, otherwise arg # */ + extern Node *arglist; + Node *p = arglist; + int n; + + for (n = 0; p != 0; p = p->nnext, n++) + if (strcmp(((Cell *)(p->narg[0]))->nval, s) == 0) + return n; + return -1; +} diff --git a/usr.bin/awk/proto.h b/usr.bin/awk/proto.h new file mode 100644 index 0000000..3f9e5d9 --- /dev/null +++ b/usr.bin/awk/proto.h @@ -0,0 +1,188 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +extern int yywrap(void); +extern void setfname(Cell *); +extern int constnode(Node *); +extern char *strnode(Node *); +extern Node *notnull(Node *); +extern int yyparse(void); + +extern int yylex(void); +extern void startreg(void); +extern int input(void); +extern void unput(int); +extern void unputstr(char *); +extern int yylook(void); +extern int yyback(int *, int); +extern int yyinput(void); + +extern fa *makedfa(char *, int); +extern fa *mkdfa(char *, int); +extern int makeinit(fa *, int); +extern void penter(Node *); +extern void freetr(Node *); +extern int hexstr(char **); +extern int quoted(char **); +extern char *cclenter(char *); +extern void overflo(char *); +extern void cfoll(fa *, Node *); +extern int first(Node *); +extern void follow(Node *); +extern int member(int, char *); +extern int match(fa *, char *); +extern int pmatch(fa *, char *); +extern int nematch(fa *, char *); +extern Node *reparse(char *); +extern Node *regexp(void); +extern Node *primary(void); +extern Node *concat(Node *); +extern Node *alt(Node *); +extern Node *unary(Node *); +extern int relex(void); +extern int cgoto(fa *, int, int); +extern void freefa(fa *); + +extern int pgetc(void); + +extern Node *nodealloc(int); +extern Node *exptostat(Node *); +extern Node *node1(int, Node *); +extern Node *node2(int, Node *, Node *); +extern Node *node3(int, Node *, Node *, Node *); +extern Node *node4(int, Node *, Node *, Node *, Node *); +extern Node *stat3(int, Node *, Node *, Node *); +extern Node *op2(int, Node *, Node *); +extern Node *op1(int, Node *); +extern Node *stat1(int, Node *); +extern Node *op3(int, Node *, Node *, Node *); +extern Node *op4(int, Node *, Node *, Node *, Node *); +extern Node *stat2(int, Node *, Node *); +extern Node *stat4(int, Node *, Node *, Node *, Node *); +extern Node *celltonode(Cell *, int); +extern Node *rectonode(void); +extern Node *makearr(Node *); +extern Node *pa2stat(Node *, Node *, Node *); +extern Node *linkum(Node *, Node *); +extern void defn(Cell *, Node *, Node *); +extern int isarg(char *); +extern char *tokname(int); +extern Cell *(*proctab[])(Node **, int); + +extern void syminit(void); +extern void arginit(int, char **); +extern void envinit(char **); +extern Array *makesymtab(int); +extern void freesymtab(Cell *); +extern void freeelem(Cell *, char *); +extern Cell *setsymtab(char *, char *, double, unsigned int, Array *); +extern int hash(char *, int); +extern void rehash(Array *); +extern Cell *lookup(char *, Array *); +extern double setfval(Cell *, double); +extern void funnyvar(Cell *, char *); +extern char *setsval(Cell *, char *); +extern double getfval(Cell *); +extern char *getsval(Cell *); +extern char *tostring(char *); +extern char *qstring(char *, int); + +extern void recinit(unsigned int); +extern void initgetrec(void); +extern void makefields(int, int); +extern void growfldtab(int n); +extern int getrec(char **, int *, int); +extern void nextfile(void); +extern int readrec(char **buf, int *bufsize, FILE *inf); +extern char *getargv(int); +extern void setclvar(char *); +extern void fldbld(void); +extern void cleanfld(int, int); +extern void newfld(int); +extern int refldbld(char *, char *); +extern void recbld(void); +extern Cell *fieldadr(int); +extern void yyerror(char *); +extern void fpecatch(int); +extern void bracecheck(void); +extern void bcheck2(int, int, int); +extern void error(int, char *); +extern void eprint(void); +extern void bclass(int); +extern double errcheck(double, char *); +extern int isclvar(char *); +extern int isnumber(char *); + +extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, char *what); +extern void run(Node *); +extern Cell *execute(Node *); +extern Cell *program(Node **, int); +extern Cell *call(Node **, int); +extern Cell *copycell(Cell *); +extern Cell *arg(Node **, int); +extern Cell *jump(Node **, int); +extern Cell *getline(Node **, int); +extern Cell *getnf(Node **, int); +extern Cell *array(Node **, int); +extern Cell *adelete(Node **, int); +extern Cell *intest(Node **, int); +extern Cell *matchop(Node **, int); +extern Cell *boolop(Node **, int); +extern Cell *relop(Node **, int); +extern void tfree(Cell *); +extern Cell *gettemp(void); +extern Cell *field(Node **, int); +extern Cell *indirect(Node **, int); +extern Cell *substr(Node **, int); +extern Cell *sindex(Node **, int); +extern int format(char **, int *, char *, Node *); +extern Cell *awksprintf(Node **, int); +extern Cell *awkprintf(Node **, int); +extern Cell *arith(Node **, int); +extern double ipow(double, int); +extern Cell *incrdecr(Node **, int); +extern Cell *assign(Node **, int); +extern Cell *cat(Node **, int); +extern Cell *pastat(Node **, int); +extern Cell *dopa2(Node **, int); +extern Cell *split(Node **, int); +extern Cell *condexpr(Node **, int); +extern Cell *ifstat(Node **, int); +extern Cell *whilestat(Node **, int); +extern Cell *dostat(Node **, int); +extern Cell *forstat(Node **, int); +extern Cell *instat(Node **, int); +extern Cell *bltin(Node **, int); +extern Cell *printstat(Node **, int); +extern Cell *nullproc(Node **, int); +extern FILE *redirect(int, Node *); +extern FILE *openfile(int, char *); +extern char *filename(FILE *); +extern Cell *closefile(Node **, int); +extern void closeall(void); +extern Cell *sub(Node **, int); +extern Cell *gsub(Node **, int); + +extern FILE *popen(const char *, const char *); +extern int pclose(FILE *); diff --git a/usr.bin/awk/run.c b/usr.bin/awk/run.c new file mode 100644 index 0000000..aa4a818 --- /dev/null +++ b/usr.bin/awk/run.c @@ -0,0 +1,1869 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +#define tempfree(x) if (istemp(x)) tfree(x); else + +/* +#undef tempfree + +void tempfree(Cell *p) { + if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) { + ERROR "bad csub %d in Cell %d %s", + p->csub, p->ctype, p->sval WARNING; + } + if (istemp(p)) + tfree(p); +} +*/ + +#ifdef _NFILE +#ifndef FOPEN_MAX +#define FOPEN_MAX _NFILE +#endif +#endif + +#ifndef FOPEN_MAX +#define FOPEN_MAX 40 /* max number of open files */ +#endif + +#ifndef RAND_MAX +#define RAND_MAX 32767 /* all that ansi guarantees */ +#endif + +jmp_buf env; +extern int pairstack[]; + +Node *winner = NULL; /* root of parse tree */ +Cell *tmps; /* free temporary cells for execution */ + +static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; +Cell *true = &truecell; +static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; +Cell *false = &falsecell; +static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; +Cell *jbreak = &breakcell; +static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; +Cell *jcont = &contcell; +static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; +Cell *jnext = &nextcell; +static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM }; +Cell *jnextfile = &nextfilecell; +static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; +Cell *jexit = &exitcell; +static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; +Cell *jret = &retcell; +static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE }; + +Node *curnode = NULL; /* the node being executed, for debugging */ + +/* buffer memory management */ +int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, + char *whatrtn) +/* pbuf: address of pointer to buffer being managed + * psiz: address of buffer size variable + * minlen: minimum length of buffer needed + * quantum: buffer size quantum + * pbptr: address of movable pointer into buffer, or 0 if none + * whatrtn: name of the calling routine if failure should cause fatal error + * + * return 0 for realloc failure, !=0 for success + */ +{ + if (minlen > *psiz) { + char *tbuf; + int rminlen = quantum ? minlen % quantum : 0; + int boff = pbptr ? *pbptr - *pbuf : 0; + /* round up to next multiple of quantum */ + if (rminlen) + minlen += quantum - rminlen; + tbuf = realloc(*pbuf, minlen); + if (tbuf == NULL) { + if (whatrtn) + ERROR "out of memory in %s", whatrtn FATAL; + return 0; + } + *pbuf = tbuf; + *psiz = minlen; + if (pbptr) + *pbptr = tbuf + boff; + } + return 1; +} + +void run(Node *a) /* execution of parse tree starts here */ +{ + execute(a); + closeall(); +} + +Cell *execute(Node *u) /* execute a node of the parse tree */ +{ + Cell *(*proc)(Node **, int); + Cell *x; + Node *a; + + if (u == NULL) + return(true); + for (a = u; ; a = a->nnext) { + curnode = a; + if (isvalue(a)) { + x = (Cell *) (a->narg[0]); + if (isfld(x) && !donefld) + fldbld(); + else if (isrec(x) && !donerec) + recbld(); + return(x); + } + if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ + ERROR "illegal statement" FATAL; + proc = proctab[a->nobj-FIRSTTOKEN]; + x = (*proc)(a->narg, a->nobj); + if (isfld(x) && !donefld) + fldbld(); + else if (isrec(x) && !donerec) + recbld(); + if (isexpr(a)) + return(x); + if (isjump(x)) + return(x); + if (a->nnext == NULL) + return(x); + tempfree(x); + } +} + + +Cell *program(Node **a, int n) /* execute an awk program */ +{ /* a[0] = BEGIN, a[1] = body, a[2] = END */ + Cell *x; + + if (setjmp(env) != 0) + goto ex; + if (a[0]) { /* BEGIN */ + x = execute(a[0]); + if (isexit(x)) + return(true); + if (isjump(x)) + ERROR "illegal break, continue, next or nextfile from BEGIN" FATAL; + tempfree(x); + } + if (a[1] || a[2]) + while (getrec(&record, &recsize, 1) > 0) { + x = execute(a[1]); + if (isexit(x)) + break; + tempfree(x); + } + ex: + if (setjmp(env) != 0) /* handles exit within END */ + goto ex1; + if (a[2]) { /* END */ + x = execute(a[2]); + if (isbreak(x) || isnext(x) || iscont(x)) + ERROR "illegal break, continue, next or nextfile from END" FATAL; + tempfree(x); + } + ex1: + return(true); +} + +struct Frame { /* stack frame for awk function calls */ + int nargs; /* number of arguments in this call */ + Cell *fcncell; /* pointer to Cell for function */ + Cell **args; /* pointer to array of arguments after execute */ + Cell *retval; /* return value */ +}; + +#define NARGS 50 /* max args in a call */ + +struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ +int nframe = 0; /* number of frames allocated */ +struct Frame *fp = NULL; /* frame pointer. bottom level unused */ + +Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ +{ + static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; + int i, ncall, ndef; + Node *x; + Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ + Cell *y, *z, *fcn; + char *s; + + fcn = execute(a[0]); /* the function itself */ + s = fcn->nval; + if (!isfcn(fcn)) + ERROR "calling undefined function %s", s FATAL; + if (frame == NULL) { + fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); + if (frame == NULL) + ERROR "out of space for stack frames calling %s", s FATAL; + } + for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ + ncall++; + ndef = (int) fcn->fval; /* args in defn */ + dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) ); + if (ncall > ndef) + ERROR "function %s called with %d args, uses only %d", + s, ncall, ndef WARNING; + if (ncall + ndef > NARGS) + ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL; + for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ + dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) ); + y = execute(x); + oargs[i] = y; + dprintf( ("args[%d]: %s %f <%s>, t=%o\n", + i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) ); + if (isfcn(y)) + ERROR "can't use function %s as argument in %s", y->nval, s FATAL; + if (isarr(y)) + args[i] = y; /* arrays by ref */ + else + args[i] = copycell(y); + tempfree(y); + } + for ( ; i < ndef; i++) { /* add null args for ones not provided */ + args[i] = gettemp(); + *args[i] = newcopycell; + } + fp++; /* now ok to up frame */ + if (fp >= frame + nframe) { + int dfp = fp - frame; /* old index */ + frame = (struct Frame *) + realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); + if (frame == NULL) + ERROR "out of space for stack frames in %s", s FATAL; + fp = frame + dfp; + } + fp->fcncell = fcn; + fp->args = args; + fp->nargs = ndef; /* number defined with (excess are locals) */ + fp->retval = gettemp(); + + dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) ); + y = execute((Node *)(fcn->sval)); /* execute body */ + dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) ); + + for (i = 0; i < ndef; i++) { + Cell *t = fp->args[i]; + if (isarr(t)) { + if (t->csub == CCOPY) { + if (i >= ncall) { + freesymtab(t); + t->csub = CTEMP; + } else { + oargs[i]->tval = t->tval; + oargs[i]->tval &= ~(STR|NUM|DONTFREE); + oargs[i]->sval = t->sval; + tempfree(t); + } + } + } else if (t != y) { /* kludge to prevent freeing twice */ + t->csub = CTEMP; + tempfree(t); + } + } + tempfree(fcn); + if (isexit(y) || isnext(y) || isnextfile(y)) + return y; + tempfree(y); /* this can free twice! */ + z = fp->retval; /* return value */ + dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); + fp--; + return(z); +} + +Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ +{ + Cell *y; + + y = gettemp(); + y->csub = CCOPY; /* prevents freeing until call is over */ + y->nval = x->nval; /* BUG? */ + y->sval = x->sval ? tostring(x->sval) : NULL; + y->fval = x->fval; + y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ + /* is DONTFREE right? */ + return y; +} + +Cell *arg(Node **a, int n) /* nth argument of a function */ +{ + + n = (int) a[0]; /* argument number, counting from 0 */ + dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); + if (n+1 > fp->nargs) + ERROR "argument #%d of function %s was not supplied", + n+1, fp->fcncell->nval FATAL; + return fp->args[n]; +} + +Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ +{ + Cell *y; + + switch (n) { + case EXIT: + if (a[0] != NULL) { + y = execute(a[0]); + errorflag = getfval(y); + tempfree(y); + } + longjmp(env, 1); + case RETURN: + if (a[0] != NULL) { + y = execute(a[0]); + if ((y->tval & (STR|NUM)) == (STR|NUM)) { + setsval(fp->retval, getsval(y)); + fp->retval->fval = getfval(y); + fp->retval->tval |= NUM; + } + else if (y->tval & STR) + setsval(fp->retval, getsval(y)); + else if (y->tval & NUM) + setfval(fp->retval, getfval(y)); + else /* can't happen */ + ERROR "bad type variable %d", y->tval FATAL; + tempfree(y); + } + return(jret); + case NEXT: + return(jnext); + case NEXTFILE: + nextfile(); + return(jnextfile); + case BREAK: + return(jbreak); + case CONTINUE: + return(jcont); + default: /* can't happen */ + ERROR "illegal jump type %d", n FATAL; + } + return 0; /* not reached */ +} + +Cell *getline(Node **a, int n) /* get next line from specific input */ +{ /* a[0] is variable, a[1] is operator, a[2] is filename */ + Cell *r, *x; + extern Cell **fldtab; + FILE *fp; + char *buf; + int bufsize = recsize; + + if ((buf = (char *) malloc(bufsize)) == NULL) + ERROR "out of memory in getline" FATAL; + + fflush(stdout); /* in case someone is waiting for a prompt */ + r = gettemp(); + if (a[1] != NULL) { /* getline < file */ + x = execute(a[2]); /* filename */ + if ((int) a[1] == '|') /* input pipe */ + a[1] = (Node *) LE; /* arbitrary flag */ + fp = openfile((int) a[1], getsval(x)); + tempfree(x); + if (fp == NULL) + n = -1; + else + n = readrec(&buf, &bufsize, fp); + if (n <= 0) { + ; + } else if (a[0] != NULL) { /* getline var sval)) { + fldtab[0]->fval = atof(fldtab[0]->sval); + fldtab[0]->tval |= NUM; + } + } + } else { /* bare getline; use current input */ + if (a[0] == NULL) /* getline */ + n = getrec(&record, &recsize, 1); + else { /* getline var */ + n = getrec(&buf, &bufsize, 0); + x = execute(a[0]); + setsval(x, buf); + tempfree(x); + } + } + setfval(r, (Awkfloat) n); + free(buf); + return r; +} + +Cell *getnf(Node **a, int n) /* get NF */ +{ + if (donefld == 0) + fldbld(); + return (Cell *) a[0]; +} + +Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ +{ + Cell *x, *y, *z; + char *s; + Node *np; + char *buf; + int bufsz = recsize; + int nsub = strlen(*SUBSEP); + + if ((buf = malloc(bufsz)) == NULL) + ERROR "out of memory in array" FATAL; + + x = execute(a[0]); /* Cell* for symbol table */ + buf[0] = 0; + for (np = a[1]; np; np = np->nnext) { + y = execute(np); /* subscript */ + s = getsval(y); + if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) + ERROR "out of memory for %s[%s...]", x->nval, buf FATAL; + strcat(buf, s); + if (np->nnext) + strcat(buf, *SUBSEP); + tempfree(y); + } + if (!isarr(x)) { + dprintf( ("making %s into an array\n", x->nval) ); + if (freeable(x)) + xfree(x->sval); + x->tval &= ~(STR|NUM|DONTFREE); + x->tval |= ARR; + x->sval = (char *) makesymtab(NSYMTAB); + } + z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); + z->ctype = OCELL; + z->csub = CVAR; + tempfree(x); + free(buf); + return(z); +} + +Cell *adelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ +{ + Cell *x, *y; + Node *np; + char *s; + int nsub = strlen(*SUBSEP); + + x = execute(a[0]); /* Cell* for symbol table */ + if (!isarr(x)) + return true; + if (a[1] == 0) { /* delete the elements, not the table */ + freesymtab(x); + x->tval &= ~STR; + x->tval |= ARR; + x->sval = (char *) makesymtab(NSYMTAB); + } else { + int bufsz = recsize; + char *buf; + if ((buf = malloc(bufsz)) == NULL) + ERROR "out of memory in adelete" FATAL; + buf[0] = 0; + for (np = a[1]; np; np = np->nnext) { + y = execute(np); /* subscript */ + s = getsval(y); + if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) + ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL; + strcat(buf, s); + if (np->nnext) + strcat(buf, *SUBSEP); + tempfree(y); + } + freeelem(x, buf); + free(buf); + } + tempfree(x); + return true; +} + +Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ +{ + Cell *x, *ap, *k; + Node *p; + char *buf; + char *s; + int bufsz = recsize; + int nsub = strlen(*SUBSEP); + + ap = execute(a[1]); /* array name */ + if (!isarr(ap)) { + dprintf( ("making %s into an array\n", ap->nval) ); + if (freeable(ap)) + xfree(ap->sval); + ap->tval &= ~(STR|NUM|DONTFREE); + ap->tval |= ARR; + ap->sval = (char *) makesymtab(NSYMTAB); + } + if ((buf = malloc(bufsz)) == NULL) { + ERROR "out of memory in intest" FATAL; + } + buf[0] = 0; + for (p = a[0]; p; p = p->nnext) { + x = execute(p); /* expr */ + s = getsval(x); + if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0)) + ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL; + strcat(buf, s); + tempfree(x); + if (p->nnext) + strcat(buf, *SUBSEP); + } + k = lookup(buf, (Array *) ap->sval); + tempfree(ap); + free(buf); + if (k == NULL) + return(false); + else + return(true); +} + + +Cell *matchop(Node **a, int n) /* ~ and match() */ +{ + Cell *x, *y; + char *s, *t; + int i; + fa *pfa; + int (*mf)(fa *, char *) = match, mode = 0; + + if (n == MATCHFCN) { + mf = pmatch; + mode = 1; + } + x = execute(a[1]); /* a[1] = target text */ + s = getsval(x); + if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ + i = (*mf)((fa *) a[2], s); + else { + y = execute(a[2]); /* a[2] = regular expr */ + t = getsval(y); + pfa = makedfa(t, mode); + i = (*mf)(pfa, s); + tempfree(y); + } + tempfree(x); + if (n == MATCHFCN) { + int start = patbeg - s + 1; + if (patlen < 0) + start = 0; + setfval(rstartloc, (Awkfloat) start); + setfval(rlengthloc, (Awkfloat) patlen); + x = gettemp(); + x->tval = NUM; + x->fval = start; + return x; + } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) + return(true); + else + return(false); +} + + +Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ +{ + Cell *x, *y; + int i; + + x = execute(a[0]); + i = istrue(x); + tempfree(x); + switch (n) { + case BOR: + if (i) return(true); + y = execute(a[1]); + i = istrue(y); + tempfree(y); + if (i) return(true); + else return(false); + case AND: + if ( !i ) return(false); + y = execute(a[1]); + i = istrue(y); + tempfree(y); + if (i) return(true); + else return(false); + case NOT: + if (i) return(false); + else return(true); + default: /* can't happen */ + ERROR "unknown boolean operator %d", n FATAL; + } + return 0; /*NOTREACHED*/ +} + +Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */ +{ + int i; + Cell *x, *y; + Awkfloat j; + + x = execute(a[0]); + y = execute(a[1]); + if (x->tval&NUM && y->tval&NUM) { + j = x->fval - y->fval; + i = j<0? -1: (j>0? 1: 0); + } else { + i = strcmp(getsval(x), getsval(y)); + } + tempfree(x); + tempfree(y); + switch (n) { + case LT: if (i<0) return(true); + else return(false); + case LE: if (i<=0) return(true); + else return(false); + case NE: if (i!=0) return(true); + else return(false); + case EQ: if (i == 0) return(true); + else return(false); + case GE: if (i>=0) return(true); + else return(false); + case GT: if (i>0) return(true); + else return(false); + default: /* can't happen */ + ERROR "unknown relational operator %d", n FATAL; + } + return 0; /*NOTREACHED*/ +} + +void tfree(Cell *a) /* free a tempcell */ +{ + if (freeable(a)) { + dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) ); + xfree(a->sval); + } + if (a == tmps) + ERROR "tempcell list is curdled" FATAL; + a->cnext = tmps; + tmps = a; +} + +Cell *gettemp(void) /* get a tempcell */ +{ int i; + Cell *x; + + if (!tmps) { + tmps = (Cell *) calloc(100, sizeof(Cell)); + if (!tmps) + ERROR "out of space for temporaries" FATAL; + for(i = 1; i < 100; i++) + tmps[i-1].cnext = &tmps[i]; + tmps[i-1].cnext = 0; + } + x = tmps; + tmps = x->cnext; + *x = tempcell; + return(x); +} + +Cell *indirect(Node **a, int n) /* $( a[0] ) */ +{ + Cell *x; + int m; + char *s; + + x = execute(a[0]); + m = getfval(x); + if (m == 0 && !isnumber(s = getsval(x))) /* suspicion! */ + ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL; + /* BUG: can x->nval ever be null??? */ + tempfree(x); + x = fieldadr(m); + x->ctype = OCELL; /* BUG? why are these needed? */ + x->csub = CFLD; + return(x); +} + +Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ +{ + int k, m, n; + char *s; + int temp; + Cell *x, *y, *z = 0; + + x = execute(a[0]); + y = execute(a[1]); + if (a[2] != 0) + z = execute(a[2]); + s = getsval(x); + k = strlen(s) + 1; + if (k <= 1) { + tempfree(x); + tempfree(y); + if (a[2] != 0) + tempfree(z); + x = gettemp(); + setsval(x, ""); + return(x); + } + m = getfval(y); + if (m <= 0) + m = 1; + else if (m > k) + m = k; + tempfree(y); + if (a[2] != 0) { + n = getfval(z); + tempfree(z); + } else + n = k - 1; + if (n < 0) + n = 0; + else if (n > k - m) + n = k - m; + dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); + y = gettemp(); + temp = s[n+m-1]; /* with thanks to John Linderman */ + s[n+m-1] = '\0'; + setsval(y, s + m - 1); + s[n+m-1] = temp; + tempfree(x); + return(y); +} + +Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ +{ + Cell *x, *y, *z; + char *s1, *s2, *p1, *p2, *q; + Awkfloat v = 0.0; + + x = execute(a[0]); + s1 = getsval(x); + y = execute(a[1]); + s2 = getsval(y); + + z = gettemp(); + for (p1 = s1; *p1 != '\0'; p1++) { + for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) + ; + if (*p2 == '\0') { + v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */ + break; + } + } + tempfree(x); + tempfree(y); + setfval(z, v); + return(z); +} + +#define MAXNUMSIZE 50 + +int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */ +{ + char *fmt; + char *p, *t, *os; + Cell *x; + int flag = 0, n; + int fmtwd; /* format width */ + int fmtsz = recsize; + char *buf = *pbuf; + int bufsize = *pbufsize; + + os = s; + p = buf; + if ((fmt = malloc(fmtsz)) == NULL) + ERROR "out of memory in format()" FATAL; + while (*s) { + adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format"); + if (*s != '%') { + *p++ = *s++; + continue; + } + if (*(s+1) == '%') { + *p++ = '%'; + s += 2; + continue; + } + /* have to be real careful in case this is a huge number, eg, %100000d */ + fmtwd = atoi(s+1); + if (fmtwd < 0) + fmtwd = -fmtwd; + adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); + for (t = fmt; (*t++ = *s) != '\0'; s++) { + if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0)) + ERROR "format item %.30s... ran format() out of memory", os FATAL; + if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L') + break; /* the ansi panoply */ + if (*s == '*') { + x = execute(a); + a = a->nnext; + sprintf(t-1, "%d", fmtwd=(int) getfval(x)); + if (fmtwd < 0) + fmtwd = -fmtwd; + adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); + t = fmt + strlen(fmt); + tempfree(x); + } + } + *t = '\0'; + if (fmtwd < 0) + fmtwd = -fmtwd; + adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); + + switch (*s) { + case 'f': case 'e': case 'g': case 'E': case 'G': + flag = 1; + break; + case 'd': case 'i': + flag = 2; + if(*(s-1) == 'l') break; + *(t-1) = 'l'; + *t = 'd'; + *++t = '\0'; + break; + case 'o': case 'x': case 'X': case 'u': + flag = *(s-1) == 'l' ? 2 : 3; + break; + case 's': + flag = 4; + break; + case 'c': + flag = 5; + break; + default: + ERROR "weird printf conversion %s", fmt WARNING; + flag = 0; + break; + } + if (a == NULL) + ERROR "not enough args in printf(%s)", os FATAL; + x = execute(a); + a = a->nnext; + n = MAXNUMSIZE; + if (fmtwd > n) + n = fmtwd; + adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format"); + switch (flag) { + case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */ + t = getsval(x); + n = strlen(t); + if (fmtwd > n) + n = fmtwd; + adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format"); + p += strlen(p); + sprintf(p, "%s", t); + break; + case 1: sprintf(p, fmt, getfval(x)); break; + case 2: sprintf(p, fmt, (long) getfval(x)); break; + case 3: sprintf(p, fmt, (int) getfval(x)); break; + case 4: + t = getsval(x); + n = strlen(t); + if (fmtwd > n) + n = fmtwd; + if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0)) + ERROR "huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t FATAL; + sprintf(p, fmt, t); + break; + case 5: + if (isnum(x)) { + if (getfval(x)) + sprintf(p, fmt, (int) getfval(x)); + else + *p++ = '\0'; + } else + sprintf(p, fmt, getsval(x)[0]); + break; + } + tempfree(x); + p += strlen(p); + s++; + } + *p = '\0'; + free(fmt); + for ( ; a; a = a->nnext) /* evaluate any remaining args */ + execute(a); + *pbuf = buf; + *pbufsize = bufsize; + return p - buf; +} + +Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ +{ + Cell *x; + Node *y; + char *buf; + int bufsz=3*recsize; + + if ((buf=malloc(bufsz)) == NULL) + ERROR "out of memory in awksprintf" FATAL; + y = a[0]->nnext; + x = execute(a[0]); + if (format(&buf, &bufsz, getsval(x), y) == -1) + ERROR "sprintf string %.30s... too long. can't happen.", buf FATAL; + tempfree(x); + x = gettemp(); + x->sval = buf; + x->tval = STR; + return(x); +} + +Cell *awkprintf(Node **a, int n) /* printf */ +{ /* a[0] is list of args, starting with format string */ + /* a[1] is redirection operator, a[2] is redirection file */ + FILE *fp; + Cell *x; + Node *y; + char *buf; + int len; + int bufsz=3*recsize; + + if ((buf=malloc(bufsz)) == NULL) + ERROR "out of memory in awkprintf" FATAL; + y = a[0]->nnext; + x = execute(a[0]); + if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) + ERROR "printf string %.30s... too long. can't happen.", buf FATAL; + tempfree(x); + if (a[1] == NULL) { + /* fputs(buf, stdout); */ + fwrite(buf, len, 1, stdout); + if (ferror(stdout)) + ERROR "write error on stdout" FATAL; + } else { + fp = redirect((int)a[1], a[2]); + /* fputs(buf, fp); */ + fwrite(buf, len, 1, fp); + fflush(fp); + if (ferror(fp)) + ERROR "write error on %s", filename(fp) FATAL; + } + free(buf); + return(true); +} + +Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ +{ + Awkfloat i, j = 0; + double v; + Cell *x, *y, *z; + + x = execute(a[0]); + i = getfval(x); + tempfree(x); + if (n != UMINUS) { + y = execute(a[1]); + j = getfval(y); + tempfree(y); + } + z = gettemp(); + switch (n) { + case ADD: + i += j; + break; + case MINUS: + i -= j; + break; + case MULT: + i *= j; + break; + case DIVIDE: + if (j == 0) + ERROR "division by zero" FATAL; + i /= j; + break; + case MOD: + if (j == 0) + ERROR "division by zero in mod" FATAL; + modf(i/j, &v); + i = i - j * v; + break; + case UMINUS: + i = -i; + break; + case POWER: + if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ + i = ipow(i, (int) j); + else + i = errcheck(pow(i, j), "pow"); + break; + default: /* can't happen */ + ERROR "illegal arithmetic operator %d", n FATAL; + } + setfval(z, i); + return(z); +} + +double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */ +{ + double v; + + if (n <= 0) + return 1; + v = ipow(x, n/2); + if (n % 2 == 0) + return v * v; + else + return x * v * v; +} + +Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */ +{ + Cell *x, *z; + int k; + Awkfloat xf; + + x = execute(a[0]); + xf = getfval(x); + k = (n == PREINCR || n == POSTINCR) ? 1 : -1; + if (n == PREINCR || n == PREDECR) { + setfval(x, xf + k); + return(x); + } + z = gettemp(); + setfval(z, xf); + setfval(x, xf + k); + tempfree(x); + return(z); +} + +Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ +{ /* this is subtle; don't muck with it. */ + Cell *x, *y; + Awkfloat xf, yf; + double v; + + y = execute(a[1]); + x = execute(a[0]); + if (n == ASSIGN) { /* ordinary assignment */ + if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */ + ; /* leave alone unless it's a field */ + else if ((y->tval & (STR|NUM)) == (STR|NUM)) { + setsval(x, getsval(y)); + x->fval = getfval(y); + x->tval |= NUM; + } + else if (isstr(y)) + setsval(x, getsval(y)); + else if (isnum(y)) + setfval(x, getfval(y)); + else + funnyvar(y, "read value of"); + tempfree(y); + return(x); + } + xf = getfval(x); + yf = getfval(y); + switch (n) { + case ADDEQ: + xf += yf; + break; + case SUBEQ: + xf -= yf; + break; + case MULTEQ: + xf *= yf; + break; + case DIVEQ: + if (yf == 0) + ERROR "division by zero in /=" FATAL; + xf /= yf; + break; + case MODEQ: + if (yf == 0) + ERROR "division by zero in %%=" FATAL; + modf(xf/yf, &v); + xf = xf - yf * v; + break; + case POWEQ: + if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ + xf = ipow(xf, (int) yf); + else + xf = errcheck(pow(xf, yf), "pow"); + break; + default: + ERROR "illegal assignment operator %d", n FATAL; + break; + } + tempfree(y); + setfval(x, xf); + return(x); +} + +Cell *cat(Node **a, int q) /* a[0] cat a[1] */ +{ + Cell *x, *y, *z; + int n1, n2; + char *s; + + x = execute(a[0]); + y = execute(a[1]); + getsval(x); + getsval(y); + n1 = strlen(x->sval); + n2 = strlen(y->sval); + s = (char *) malloc(n1 + n2 + 1); + if (s == NULL) + ERROR "out of space concatenating %.15s... and %.15s...", + x->sval, y->sval FATAL; + strcpy(s, x->sval); + strcpy(s+n1, y->sval); + tempfree(y); + z = gettemp(); + z->sval = s; + z->tval = STR; + tempfree(x); + return(z); +} + +Cell *pastat(Node **a, int n) /* a[0] { a[1] } */ +{ + Cell *x; + + if (a[0] == 0) + x = execute(a[1]); + else { + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } + } + return x; +} + +Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ +{ + Cell *x; + int pair; + + pair = (int) a[3]; + if (pairstack[pair] == 0) { + x = execute(a[0]); + if (istrue(x)) + pairstack[pair] = 1; + tempfree(x); + } + if (pairstack[pair] == 1) { + x = execute(a[1]); + if (istrue(x)) + pairstack[pair] = 0; + tempfree(x); + x = execute(a[2]); + return(x); + } + return(false); +} + +Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ +{ + Cell *x = 0, *y, *ap; + char *s; + int sep; + char *t, temp, num[50], *fs = 0; + int n, tempstat; + + y = execute(a[0]); /* source string */ + s = getsval(y); + if (a[2] == 0) /* fs string */ + fs = *FS; + else if ((int) a[3] == STRING) { /* split(str,arr,"string") */ + x = execute(a[2]); + fs = getsval(x); + } else if ((int) a[3] == REGEXPR) + fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ + else + ERROR "illegal type of split" FATAL; + sep = *fs; + ap = execute(a[1]); /* array name */ + freesymtab(ap); + dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) ); + ap->tval &= ~STR; + ap->tval |= ARR; + ap->sval = (char *) makesymtab(NSYMTAB); + + n = 0; + if ((*s != '\0' && strlen(fs) > 1) || (int) a[3] == REGEXPR) { /* reg expr */ + fa *pfa; + if ((int) a[3] == REGEXPR) { /* it's ready already */ + pfa = (fa *) a[2]; + } else { + pfa = makedfa(fs, 1); + } + if (nematch(pfa,s)) { + tempstat = pfa->initstat; + pfa->initstat = 2; + do { + n++; + sprintf(num, "%d", n); + temp = *patbeg; + *patbeg = '\0'; + if (isnumber(s)) + setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, s, 0.0, STR, (Array *) ap->sval); + *patbeg = temp; + s = patbeg + patlen; + if (*(patbeg+patlen-1) == 0 || *s == 0) { + n++; + sprintf(num, "%d", n); + setsymtab(num, "", 0.0, STR, (Array *) ap->sval); + pfa->initstat = tempstat; + goto spdone; + } + } while (nematch(pfa,s)); + } + n++; + sprintf(num, "%d", n); + if (isnumber(s)) + setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, s, 0.0, STR, (Array *) ap->sval); + spdone: + pfa = NULL; + } else if (sep == ' ') { + for (n = 0; ; ) { + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + if (*s == 0) + break; + n++; + t = s; + do + s++; + while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); + temp = *s; + *s = '\0'; + sprintf(num, "%d", n); + if (isnumber(t)) + setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, t, 0.0, STR, (Array *) ap->sval); + *s = temp; + if (*s != 0) + s++; + } + } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */ + for (n = 0; *s != 0; s++) { + char buf[2]; + n++; + sprintf(num, "%d", n); + buf[0] = *s; + buf[1] = 0; + if (isdigit(buf[0])) + setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, buf, 0.0, STR, (Array *) ap->sval); + } + } else if (*s != 0) { + for (;;) { + n++; + t = s; + while (*s != sep && *s != '\n' && *s != '\0') + s++; + temp = *s; + *s = '\0'; + sprintf(num, "%d", n); + if (isnumber(t)) + setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); + else + setsymtab(num, t, 0.0, STR, (Array *) ap->sval); + *s = temp; + if (*s++ == 0) + break; + } + } + tempfree(ap); + tempfree(y); + if (a[2] != 0 && (int) a[3] == STRING) + tempfree(x); + x = gettemp(); + x->tval = NUM; + x->fval = n; + return(x); +} + +Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ +{ + Cell *x; + + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } else { + tempfree(x); + x = execute(a[2]); + } + return(x); +} + +Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ +{ + Cell *x; + + x = execute(a[0]); + if (istrue(x)) { + tempfree(x); + x = execute(a[1]); + } else if (a[2] != 0) { + tempfree(x); + x = execute(a[2]); + } + return(x); +} + +Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ +{ + Cell *x; + + for (;;) { + x = execute(a[0]); + if (!istrue(x)) + return(x); + tempfree(x); + x = execute(a[1]); + if (isbreak(x)) { + x = true; + return(x); + } + if (isnext(x) || isexit(x) || isret(x)) + return(x); + tempfree(x); + } +} + +Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ +{ + Cell *x; + + for (;;) { + x = execute(a[0]); + if (isbreak(x)) + return true; + if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) + return(x); + tempfree(x); + x = execute(a[1]); + if (!istrue(x)) + return(x); + tempfree(x); + } +} + +Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ +{ + Cell *x; + + x = execute(a[0]); + tempfree(x); + for (;;) { + if (a[1]!=0) { + x = execute(a[1]); + if (!istrue(x)) return(x); + else tempfree(x); + } + x = execute(a[3]); + if (isbreak(x)) /* turn off break */ + return true; + if (isnext(x) || isexit(x) || isret(x)) + return(x); + tempfree(x); + x = execute(a[2]); + tempfree(x); + } +} + +Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ +{ + Cell *x, *vp, *arrayp, *cp, *ncp; + Array *tp; + int i; + + vp = execute(a[0]); + arrayp = execute(a[1]); + if (!isarr(arrayp)) { + return true; + } + tp = (Array *) arrayp->sval; + tempfree(arrayp); + for (i = 0; i < tp->size; i++) { /* this routine knows too much */ + for (cp = tp->tab[i]; cp != NULL; cp = ncp) { + setsval(vp, cp->nval); + ncp = cp->cnext; + x = execute(a[2]); + if (isbreak(x)) { + tempfree(vp); + return true; + } + if (isnext(x) || isexit(x) || isret(x)) { + tempfree(vp); + return(x); + } + tempfree(x); + } + } + return true; +} + +Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ +{ + Cell *x, *y; + Awkfloat u; + int t; + char *p, *buf; + Node *nextarg; + FILE *fp; + + t = (int) a[0]; + x = execute(a[1]); + nextarg = a[1]->nnext; + switch (t) { + case FLENGTH: + u = strlen(getsval(x)); break; + case FLOG: + u = errcheck(log(getfval(x)), "log"); break; + case FINT: + modf(getfval(x), &u); break; + case FEXP: + u = errcheck(exp(getfval(x)), "exp"); break; + case FSQRT: + u = errcheck(sqrt(getfval(x)), "sqrt"); break; + case FSIN: + u = sin(getfval(x)); break; + case FCOS: + u = cos(getfval(x)); break; + case FATAN: + if (nextarg == 0) { + ERROR "atan2 requires two arguments; returning 1.0" WARNING; + u = 1.0; + } else { + y = execute(a[1]->nnext); + u = atan2(getfval(x), getfval(y)); + tempfree(y); + nextarg = nextarg->nnext; + } + break; + case FSYSTEM: + fflush(stdout); /* in case something is buffered already */ + u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ + break; + case FRAND: + /* in principle, rand() returns something in 0..RAND_MAX */ + u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; + break; + case FSRAND: + if (isrec(x)) /* no argument provided */ + u = time((time_t *)0); + else + u = getfval(x); + srand((int) u); u = (int) u; + break; + case FTOUPPER: + case FTOLOWER: + buf = tostring(getsval(x)); + if (t == FTOUPPER) { + for (p = buf; *p; p++) + if (islower(*p)) + *p = toupper(*p); + } else { + for (p = buf; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + } + tempfree(x); + x = gettemp(); + setsval(x, buf); + free(buf); + return x; + case FFLUSH: + if ((fp = openfile(FFLUSH, getsval(x))) == NULL) + u = EOF; + else + u = fflush(fp); + break; + default: /* can't happen */ + ERROR "illegal function type %d", t FATAL; + break; + } + tempfree(x); + x = gettemp(); + setfval(x, u); + if (nextarg != 0) { + ERROR "warning: function has too many arguments" WARNING; + for ( ; nextarg; nextarg = nextarg->nnext) + execute(nextarg); + } + return(x); +} + +Cell *printstat(Node **a, int n) /* print a[0] */ +{ + Node *x; + Cell *y; + FILE *fp; + + if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ + fp = stdout; + else + fp = redirect((int)a[1], a[2]); + for (x = a[0]; x != NULL; x = x->nnext) { + y = execute(x); + fputs(getsval(y), fp); + tempfree(y); + if (x->nnext == NULL) + fputs(*ORS, fp); + else + fputs(*OFS, fp); + } + if (a[1] != 0) + fflush(fp); + if (ferror(fp)) + ERROR "write error on %s", filename(fp) FATAL; + return(true); +} + +Cell *nullproc(Node **a, int n) +{ + n = 0; + a = 0; + return 0; +} + + +FILE *redirect(int a, Node *b) /* set up all i/o redirections */ +{ + FILE *fp; + Cell *x; + char *fname; + + x = execute(b); + fname = getsval(x); + fp = openfile(a, fname); + if (fp == NULL) + ERROR "can't open file %s", fname FATAL; + tempfree(x); + return fp; +} + +struct files { + FILE *fp; + char *fname; + int mode; /* '|', 'a', 'w' => LE/LT, GT */ +} files[FOPEN_MAX] ={ + { stdin, "/dev/stdin", LT }, /* watch out: don't free this! */ + { stdout, "/dev/stdout", GT }, + { stderr, "/dev/stderr", GT } +}; + +FILE *openfile(int a, char *us) +{ + char *s = us; + int i, m; + FILE *fp = 0; + + if (*s == '\0') + ERROR "null file name in print or getline" FATAL; + for (i=0; i < FOPEN_MAX; i++) + if (files[i].fname && strcmp(s, files[i].fname) == 0) { + if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) + return files[i].fp; + if (a == FFLUSH) + return files[i].fp; + } + if (a == FFLUSH) /* didn't find it, so don't create it! */ + return NULL; + + for (i=0; i < FOPEN_MAX; i++) + if (files[i].fp == 0) + break; + if (i >= FOPEN_MAX) + ERROR "%s makes too many open files", s FATAL; + fflush(stdout); /* force a semblance of order */ + m = a; + if (a == GT) { + fp = fopen(s, "w"); + } else if (a == APPEND) { + fp = fopen(s, "a"); + m = GT; /* so can mix > and >> */ + } else if (a == '|') { /* output pipe */ + fp = popen(s, "w"); + } else if (a == LE) { /* input pipe */ + fp = popen(s, "r"); + } else if (a == LT) { /* getline sval, files[i].fname) == 0) { + if (ferror(files[i].fp)) + ERROR "i/o error occurred on %s", files[i].fname WARNING; + if (files[i].mode == '|' || files[i].mode == LE) + stat = pclose(files[i].fp); + else + stat = fclose(files[i].fp); + if (stat == EOF) + ERROR "i/o error occurred closing %s", files[i].fname WARNING; + if (i > 2) /* don't do /dev/std... */ + xfree(files[i].fname); + files[i].fname = NULL; /* watch out for ref thru this */ + files[i].fp = NULL; + } + tempfree(x); + return(true); +} + +void closeall(void) +{ + int i, stat; + + for (i = 0; i < FOPEN_MAX; i++) + if (files[i].fp) { + if (ferror(files[i].fp)) + ERROR "i/o error occurred on %s", files[i].fname WARNING; + if (files[i].mode == '|' || files[i].mode == LE) + stat = pclose(files[i].fp); + else + stat = fclose(files[i].fp); + if (stat == EOF) + ERROR "i/o error occurred while closing %s", files[i].fname WARNING; + } +} + +void backsub(char **pb_ptr, char **sptr_ptr); + +Cell *sub(Node **a, int nnn) /* substitute command */ +{ + char *sptr, *pb, *q; + Cell *x, *y, *result; + char *t, *buf; + fa *pfa; + int bufsz = recsize; + + if ((buf=malloc(bufsz)) == NULL) + ERROR "out of memory in sub" FATAL; + x = execute(a[3]); /* target string */ + t = getsval(x); + if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ + pfa = (fa *) a[1]; /* regular expression */ + else { + y = execute(a[1]); + pfa = makedfa(getsval(y), 1); + tempfree(y); + } + y = execute(a[2]); /* replacement string */ + result = false; + if (pmatch(pfa, t)) { + sptr = t; + adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); + pb = buf; + while (sptr < patbeg) + *pb++ = *sptr++; + sptr = getsval(y); + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + *pb = '\0'; + if (pb > buf + bufsz) + ERROR "sub result1 %.30s too big; can't happen", buf FATAL; + sptr = patbeg + patlen; + if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { + adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); + while ((*pb++ = *sptr++) != 0) + ; + } + if (pb > buf + bufsz) + ERROR "sub result2 %.30s too big; can't happen", buf FATAL; + setsval(x, buf); /* BUG: should be able to avoid copy */ + result = true;; + } + tempfree(x); + tempfree(y); + free(buf); + return result; +} + +Cell *gsub(Node **a, int nnn) /* global substitute */ +{ + Cell *x, *y; + char *rptr, *sptr, *t, *pb, *q; + char *buf; + fa *pfa; + int mflag, tempstat, num; + int bufsz = recsize; + + if ((buf=malloc(bufsz)) == NULL) + ERROR "out of memory in gsub" FATAL; + mflag = 0; /* if mflag == 0, can replace empty string */ + num = 0; + x = execute(a[3]); /* target string */ + t = getsval(x); + if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ + pfa = (fa *) a[1]; /* regular expression */ + else { + y = execute(a[1]); + pfa = makedfa(getsval(y), 1); + tempfree(y); + } + y = execute(a[2]); /* replacement string */ + if (pmatch(pfa, t)) { + tempstat = pfa->initstat; + pfa->initstat = 2; + pb = buf; + rptr = getsval(y); + do { + if (patlen == 0 && *patbeg != 0) { /* matched empty string */ + if (mflag == 0) { /* can replace empty */ + num++; + sptr = rptr; + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + } + if (*t == 0) /* at end */ + goto done; + adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub"); + *pb++ = *t++; + if (pb > buf + bufsz) /* BUG: not sure of this test */ + ERROR "gsub result0 %.30s too big; can't happen", buf FATAL; + mflag = 0; + } + else { /* matched nonempty string */ + num++; + sptr = t; + adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub"); + while (sptr < patbeg) + *pb++ = *sptr++; + sptr = rptr; + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + t = patbeg + patlen; + if (patlen == 0 || *t == 0 || *(t-1) == 0) + goto done; + if (pb > buf + bufsz) + ERROR "gsub result1 %.30s too big; can't happen", buf FATAL; + mflag = 1; + } + } while (pmatch(pfa,t)); + sptr = t; + adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); + while ((*pb++ = *sptr++) != 0) + ; + done: if (pb > buf + bufsz) + ERROR "gsub result2 %.30s too big; can't happen", buf FATAL; + *pb = '\0'; + setsval(x, buf); /* BUG: should be able to avoid copy + free */ + pfa->initstat = tempstat; + } + tempfree(x); + tempfree(y); + x = gettemp(); + x->tval = NUM; + x->fval = num; + free(buf); + return(x); +} + +void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ +{ /* sptr[0] == '\\' */ + char *pb = *pb_ptr, *sptr = *sptr_ptr; + + if (sptr[1] == '\\') { + if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ + *pb++ = '\\'; + *pb++ = '&'; + sptr += 4; + } else if (sptr[2] == '&') { /* \\& -> \ + matched */ + *pb++ = '\\'; + sptr += 2; + } else { /* \\x -> \\x */ + *pb++ = *sptr++; + *pb++ = *sptr++; + } + } else if (sptr[1] == '&') { /* literal & */ + sptr++; + *pb++ = *sptr++; + } else /* literal \ */ + *pb++ = *sptr++; + + *pb_ptr = pb; + *sptr_ptr = sptr; +} diff --git a/usr.bin/awk/tran.c b/usr.bin/awk/tran.c new file mode 100644 index 0000000..56db23b --- /dev/null +++ b/usr.bin/awk/tran.c @@ -0,0 +1,426 @@ +/**************************************************************** +Copyright (C) Lucent Technologies 1997 +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. +****************************************************************/ + +#define DEBUG +#include +#include +#include +#include +#include +#include "awk.h" +#include "ytab.h" + +#define FULLTAB 2 /* rehash when table gets this x full */ +#define GROWTAB 4 /* grow table by this factor */ + +Array *symtab; /* main symbol table */ + +char **FS; /* initial field sep */ +char **RS; /* initial record sep */ +char **OFS; /* output field sep */ +char **ORS; /* output record sep */ +char **OFMT; /* output format for numbers */ +char **CONVFMT; /* format for conversions in getsval */ +Awkfloat *NF; /* number of fields in current record */ +Awkfloat *NR; /* number of current record */ +Awkfloat *FNR; /* number of current record in current file */ +char **FILENAME; /* current filename argument */ +Awkfloat *ARGC; /* number of arguments from command line */ +char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ +Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ +Awkfloat *RLENGTH; /* length of same */ + +Cell *nrloc; /* NR */ +Cell *nfloc; /* NF */ +Cell *fnrloc; /* FNR */ +Array *ARGVtab; /* symbol table containing ARGV[...] */ +Array *ENVtab; /* symbol table containing ENVIRON[...] */ +Cell *rstartloc; /* RSTART */ +Cell *rlengthloc; /* RLENGTH */ +Cell *symtabloc; /* SYMTAB */ + +Cell *nullloc; /* a guaranteed empty cell */ +Node *nullnode; /* zero&null, converted into a node for comparisons */ +Cell *literal0; + +extern Cell **fldtab; + +void syminit(void) /* initialize symbol table with builtin vars */ +{ + literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); + /* this is used for if(x)... tests: */ + nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); + nullnode = celltonode(nullloc, CCON); + + FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; + RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; + OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; + ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; + OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; + CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; + FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; + nfloc = setsymtab("NF", "", 0.0, NUM, symtab); + NF = &nfloc->fval; + nrloc = setsymtab("NR", "", 0.0, NUM, symtab); + NR = &nrloc->fval; + fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); + FNR = &fnrloc->fval; + SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; + rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); + RSTART = &rstartloc->fval; + rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); + RLENGTH = &rlengthloc->fval; + symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); + symtabloc->sval = (char *) symtab; +} + +void arginit(int ac, char **av) /* set up ARGV and ARGC */ +{ + Cell *cp; + int i; + char temp[50]; + + ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; + cp = setsymtab("ARGV", "", 0.0, ARR, symtab); + ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ + cp->sval = (char *) ARGVtab; + for (i = 0; i < ac; i++) { + sprintf(temp, "%d", i); + if (isnumber(*av)) + setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); + else + setsymtab(temp, *av, 0.0, STR, ARGVtab); + av++; + } +} + +void envinit(char **envp) /* set up ENVIRON variable */ +{ + Cell *cp; + char *p; + + cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); + ENVtab = makesymtab(NSYMTAB); + cp->sval = (char *) ENVtab; + for ( ; *envp; envp++) { + if ((p = strchr(*envp, '=')) == NULL) + continue; + *p++ = 0; /* split into two strings at = */ + if (isnumber(p)) + setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); + else + setsymtab(*envp, p, 0.0, STR, ENVtab); + p[-1] = '='; /* restore in case env is passed down to a shell */ + } +} + +Array *makesymtab(int n) /* make a new symbol table */ +{ + Array *ap; + Cell **tp; + + ap = (Array *) malloc(sizeof(Array)); + tp = (Cell **) calloc(n, sizeof(Cell *)); + if (ap == NULL || tp == NULL) + ERROR "out of space in makesymtab" FATAL; + ap->nelem = 0; + ap->size = n; + ap->tab = tp; + return(ap); +} + +void freesymtab(Cell *ap) /* free a symbol table */ +{ + Cell *cp, *temp; + Array *tp; + int i; + + if (!isarr(ap)) + return; + tp = (Array *) ap->sval; + if (tp == NULL) + return; + for (i = 0; i < tp->size; i++) { + for (cp = tp->tab[i]; cp != NULL; cp = temp) { + xfree(cp->nval); + if (freeable(cp)) + xfree(cp->sval); + temp = cp->cnext; /* avoids freeing then using */ + free(cp); + } + tp->tab[i] = 0; + } + free(tp->tab); + free(tp); +} + +void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */ +{ + Array *tp; + Cell *p, *prev = NULL; + int h; + + tp = (Array *) ap->sval; + h = hash(s, tp->size); + for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) + if (strcmp(s, p->nval) == 0) { + if (prev == NULL) /* 1st one */ + tp->tab[h] = p->cnext; + else /* middle somewhere */ + prev->cnext = p->cnext; + if (freeable(p)) + xfree(p->sval); + free(p->nval); + free(p); + tp->nelem--; + return; + } +} + +Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp) +{ + int h; + Cell *p; + + if (n != NULL && (p = lookup(n, tp)) != NULL) { + dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", + p, p->nval, p->sval, p->fval, p->tval) ); + return(p); + } + p = (Cell *) malloc(sizeof(Cell)); + if (p == NULL) + ERROR "out of space for symbol table at %s", n FATAL; + p->nval = tostring(n); + p->sval = s ? tostring(s) : tostring(""); + p->fval = f; + p->tval = t; + p->csub = CUNK; + p->ctype = OCELL; + tp->nelem++; + if (tp->nelem > FULLTAB * tp->size) + rehash(tp); + h = hash(n, tp->size); + p->cnext = tp->tab[h]; + tp->tab[h] = p; + dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", + p, p->nval, p->sval, p->fval, p->tval) ); + return(p); +} + +int hash(char *s, int n) /* form hash value for string s */ +{ + unsigned hashval; + + for (hashval = 0; *s != '\0'; s++) + hashval = (*s + 31 * hashval); + return hashval % n; +} + +void rehash(Array *tp) /* rehash items in small table into big one */ +{ + int i, nh, nsz; + Cell *cp, *op, **np; + + nsz = GROWTAB * tp->size; + np = (Cell **) calloc(nsz, sizeof(Cell *)); + if (np == NULL) /* can't do it, but can keep running. */ + return; /* someone else will run out later. */ + for (i = 0; i < tp->size; i++) { + for (cp = tp->tab[i]; cp; cp = op) { + op = cp->cnext; + nh = hash(cp->nval, nsz); + cp->cnext = np[nh]; + np[nh] = cp; + } + } + free(tp->tab); + tp->tab = np; + tp->size = nsz; +} + +Cell *lookup(char *s, Array *tp) /* look for s in tp */ +{ + Cell *p, *prev = NULL; + int h; + + h = hash(s, tp->size); + for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) + if (strcmp(s, p->nval) == 0) + return(p); /* found it */ + return(NULL); /* not found */ +} + +Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ +{ + int fldno; + + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "assign to"); + if (isfld(vp)) { + donerec = 0; /* mark $0 invalid */ + fldno = atoi(vp->nval); + if (fldno > *NF) + newfld(fldno); + dprintf( ("setting field %d to %g\n", fldno, f) ); + } else if (isrec(vp)) { + donefld = 0; /* mark $1... invalid */ + donerec = 1; + } + vp->tval &= ~STR; /* mark string invalid */ + vp->tval |= NUM; /* mark number ok */ + dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); + return vp->fval = f; +} + +void funnyvar(Cell *vp, char *rw) +{ + if (isarr(vp)) + ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL; + if (vp->tval & FCN) + ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL; + ERROR "funny variable %p: n=%s s=\"%s\" f=%g t=%o", + vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING; +} + +char *setsval(Cell *vp, char *s) /* set string val of a Cell */ +{ + char *t; + int fldno; + + dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) ); + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "assign to"); + if (isfld(vp)) { + donerec = 0; /* mark $0 invalid */ + fldno = atoi(vp->nval); + if (fldno > *NF) + newfld(fldno); + dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); + } else if (isrec(vp)) { + donefld = 0; /* mark $1... invalid */ + donerec = 1; + } + t = tostring(s); /* in case it's self-assign */ + vp->tval &= ~NUM; + vp->tval |= STR; + if (freeable(vp)) + xfree(vp->sval); + vp->tval &= ~DONTFREE; + dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) ); + return(vp->sval = t); +} + +Awkfloat getfval(Cell *vp) /* get float val of a Cell */ +{ + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "read value of"); + if (isfld(vp) && donefld == 0) + fldbld(); + else if (isrec(vp) && donerec == 0) + recbld(); + if (!isnum(vp)) { /* not a number */ + vp->fval = atof(vp->sval); /* best guess */ + if (isnumber(vp->sval) && !(vp->tval&CON)) + vp->tval |= NUM; /* make NUM only sparingly */ + } + dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); + return(vp->fval); +} + +char *getsval(Cell *vp) /* get string val of a Cell */ +{ + char s[100]; /* BUG: unchecked */ + double dtemp; + + if ((vp->tval & (NUM | STR)) == 0) + funnyvar(vp, "read value of"); + if (isfld(vp) && donefld == 0) + fldbld(); + else if (isrec(vp) && donerec == 0) + recbld(); + if (isstr(vp) == 0) { + if (freeable(vp)) + xfree(vp->sval); + if (modf(vp->fval, &dtemp) == 0) /* it's integral */ + sprintf(s, "%.30g", vp->fval); + else + sprintf(s, *CONVFMT, vp->fval); + vp->sval = tostring(s); + vp->tval &= ~DONTFREE; + vp->tval |= STR; + } + dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) ); + return(vp->sval); +} + +char *tostring(char *s) /* make a copy of string s */ +{ + char *p; + + p = (char *) malloc(strlen(s)+1); + if (p == NULL) + ERROR "out of space in tostring on %s", s FATAL; + strcpy(p, s); + return(p); +} + +char *qstring(char *s, int delim) /* collect string up to next delim */ +{ + int c, n; + char *buf = 0, *bp; + + if ((buf = (char *) malloc(strlen(s)+3)) == NULL) + ERROR "out of space in qstring(%s)", s); + for (bp = buf; (c = *s) != delim; s++) { + if (c == '\n') + ERROR "newline in string %.10s...", buf SYNTAX; + else if (c != '\\') + *bp++ = c; + else { /* \something */ + switch (c = *++s) { + case '\\': *bp++ = '\\'; break; + case 'n': *bp++ = '\n'; break; + case 't': *bp++ = '\t'; break; + case 'b': *bp++ = '\b'; break; + case 'f': *bp++ = '\f'; break; + case 'r': *bp++ = '\r'; break; + default: + if (!isdigit(c)) { + *bp++ = c; + break; + } + n = c - '0'; + if (isdigit(s[1])) { + n = 8 * n + *++s - '0'; + if (isdigit(s[1])) + n = 8 * n + *++s - '0'; + } + *bp++ = n; + break; + } + } + } + *bp++ = 0; + return buf; +} diff --git a/usr.bin/awk/ytab.c b/usr.bin/awk/ytab.c new file mode 100644 index 0000000..b1ce520 --- /dev/null +++ b/usr.bin/awk/ytab.c @@ -0,0 +1,1612 @@ + +#line 26 "awkgram.y" +#include +#include +#include "awk.h" + +void checkdup(Node *list, Cell *item); +int yywrap(void) { return(1); } + +Node *beginloc = 0; +Node *endloc = 0; +int infunc = 0; /* = 1 if in arglist or body of func */ +int inloop = 0; /* = 1 if in while, for, do */ +char *curfname = 0; /* current function name */ +Node *arglist = 0; /* list of args for current function */ + +#line 41 "awkgram.y" +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval; +YYSTYPE yyval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 +#define YYEOFCODE 1 +#define YYERRCODE 2 + +#line 444 "awkgram.y" + + +void setfname(Cell *p) +{ + if (isarr(p)) + ERROR "%s is an array, not a function", p->nval SYNTAX; + else if (isfcn(p)) + ERROR "you can't define function %s more than once", p->nval SYNTAX; + curfname = p->nval; +} + +int constnode(Node *p) +{ + return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON; +} + +char *strnode(Node *p) +{ + return ((Cell *)(p->narg[0]))->sval; +} + +Node *notnull(Node *n) +{ + switch (n->nobj) { + case LE: case LT: case EQ: case NE: case GT: case GE: + case BOR: case AND: case NOT: + return n; + default: + return op2(NE, n, nullnode); + } +} + +void checkdup(Node *vl, Cell *cp) /* check if name already in list */ +{ + char *s = cp->nval; + for ( ; vl; vl = vl->nnext) { + if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) { + ERROR "duplicate argument %s", s SYNTAX; + break; + } + } +} +short yyexca[] = +{-1, 0, + 1, 28, + 8, 28, + 9, 28, + 12, 28, + 13, 28, + 16, 28, + 45, 28, + 46, 28, + 54, 28, + 55, 28, + 56, 28, + 58, 28, + 60, 28, + 78, 28, + 86, 28, + 87, 28, + 88, 28, + 89, 28, + 90, 28, + 91, 28, + 95, 28, + 97, 28, + 98, 28, + 101, 28, + 102, 28, + 105, 28, + 108, 28, + 109, 28, + 110, 28, + -2, 0, +-1, 1, + 1, -1, + -2, 0, +-1, 157, + 15, 30, + -2, 0, +-1, 176, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 63, +-1, 177, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 64, +-1, 178, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 65, +-1, 179, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 66, +-1, 180, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 67, +-1, 181, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 68, +-1, 183, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 70, +-1, 288, + 24, 0, + 44, 0, + -2, 53, +-1, 332, + 17, 30, + -2, 0, +-1, 354, + 17, 30, + -2, 0, +}; +#define YYNPROD 184 +#define YYPRIVATE 57344 +#define YYLAST 4108 +short yyact[] = +{ + 17, 137, 112, 66, 155, 228, 199, 24, 276, 124, + 185, 105, 42, 53, 253, 110, 100, 138, 243, 103, + 104, 307, 214, 102, 100, 249, 100, 100, 100, 42, + 62, 121, 122, 123, 82, 11, 223, 83, 313, 9, + 42, 50, 253, 79, 80, 110, 10, 252, 232, 42, + 205, 268, 244, 41, 22, 43, 113, 103, 104, 142, + 113, 146, 103, 104, 133, 149, 150, 152, 153, 190, + 41, 233, 43, 163, 234, 100, 148, 23, 315, 277, + 11, 41, 22, 43, 85, 275, 156, 190, 253, 132, + 41, 22, 43, 168, 169, 16, 257, 351, 134, 350, + 100, 182, 109, 111, 349, 23, 112, 100, 100, 100, + 100, 100, 100, 100, 23, 190, 190, 320, 317, 319, + 330, 334, 323, 42, 140, 100, 202, 204, 190, 139, + 107, 108, 109, 111, 277, 210, 112, 211, 86, 190, + 274, 190, 100, 219, 218, 283, 100, 221, 190, 190, + 190, 311, 100, 226, 264, 259, 258, 156, 170, 167, + 158, 230, 190, 100, 41, 216, 43, 157, 188, 130, + 140, 129, 100, 236, 100, 309, 100, 100, 100, 100, + 100, 100, 100, 3, 100, 6, 251, 100, 100, 47, + 7, 6, 154, 128, 48, 127, 7, 126, 125, 120, + 20, 100, 119, 51, 16, 140, 100, 273, 100, 100, + 100, 217, 143, 100, 100, 270, 96, 144, 131, 316, + 4, 346, 360, 363, 114, 1, 116, 117, 118, 49, + 269, 72, 100, 100, 100, 100, 163, 39, 163, 163, + 163, 163, 224, 5, 163, 58, 100, 238, 287, 67, + 222, 291, 61, 60, 292, 100, 100, 293, 248, 81, + 8, 159, 160, 2, 0, 0, 0, 0, 0, 299, + 300, 0, 0, 165, 0, 96, 0, 0, 0, 308, + 0, 0, 100, 0, 0, 100, 100, 100, 0, 100, + 0, 100, 156, 0, 312, 0, 100, 0, 100, 100, + 116, 239, 100, 54, 100, 100, 100, 96, 193, 194, + 195, 196, 197, 198, 332, 163, 0, 0, 0, 333, + 0, 0, 19, 0, 0, 206, 340, 156, 341, 0, + 339, 0, 100, 0, 0, 0, 230, 100, 345, 100, + 0, 0, 96, 100, 100, 0, 96, 337, 115, 354, + 0, 347, 96, 0, 355, 358, 0, 136, 230, 0, + 359, 162, 156, 242, 0, 147, 238, 0, 361, 238, + 238, 238, 96, 238, 96, 238, 96, 96, 96, 96, + 96, 96, 96, 21, 96, 0, 0, 96, 96, 0, + 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, + 0, 96, 0, 0, 0, 0, 260, 0, 96, 96, + 96, 0, 0, 96, 96, 0, 0, 0, 0, 0, + 239, 238, 0, 239, 239, 239, 0, 239, 0, 239, + 0, 0, 96, 278, 279, 280, 165, 136, 165, 165, + 165, 165, 0, 0, 165, 0, 96, 0, 220, 0, + 0, 0, 136, 0, 0, 96, 96, 166, 227, 0, + 0, 256, 74, 0, 0, 0, 0, 15, 0, 0, + 0, 0, 136, 136, 0, 239, 0, 0, 184, 0, + 0, 106, 242, 0, 0, 242, 242, 242, 0, 242, + 0, 242, 0, 0, 0, 0, 96, 0, 96, 96, + 0, 0, 96, 0, 96, 96, 96, 0, 0, 0, + 0, 0, 15, 0, 15, 165, 0, 0, 0, 141, + 0, 0, 145, 0, 0, 0, 272, 0, 151, 0, + 0, 0, 96, 0, 0, 0, 0, 242, 0, 96, + 0, 229, 0, 96, 96, 0, 0, 171, 173, 175, + 176, 177, 178, 179, 180, 181, 183, 0, 164, 0, + 164, 164, 164, 164, 186, 187, 164, 189, 191, 0, + 0, 0, 0, 136, 0, 0, 200, 0, 0, 0, + 0, 0, 200, 200, 0, 0, 0, 0, 207, 208, + 209, 200, 212, 213, 0, 0, 0, 281, 0, 284, + 285, 286, 288, 0, 0, 290, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 231, 235, 0, 106, 289, 0, 0, 0, 0, + 245, 0, 0, 0, 0, 0, 296, 164, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, + 356, 136, 254, 0, 255, 140, 0, 0, 18, 310, + 139, 44, 0, 0, 362, 0, 0, 364, 0, 261, + 262, 263, 0, 265, 266, 267, 336, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 42, 28, 0, 0, 0, 0, 0, 335, 189, 0, + 45, 46, 0, 33, 0, 34, 0, 200, 0, 0, + 294, 0, 0, 295, 0, 0, 0, 0, 0, 297, + 0, 0, 0, 37, 298, 301, 0, 0, 303, 304, + 305, 41, 22, 43, 29, 35, 38, 0, 0, 0, + 32, 0, 36, 40, 0, 106, 27, 26, 0, 0, + 25, 0, 0, 30, 31, 23, 0, 0, 0, 75, + 0, 0, 0, 0, 322, 325, 327, 328, 0, 16, + 18, 331, 68, 44, 189, 357, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 338, 0, 0, 0, 0, + 0, 342, 0, 343, 0, 0, 0, 0, 0, 0, + 0, 0, 42, 28, 55, 56, 57, 73, 69, 59, + 70, 0, 45, 46, 71, 33, 0, 34, 63, 64, + 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 77, 78, 37, 52, 0, 16, 18, + 0, 68, 44, 41, 22, 43, 29, 35, 38, 0, + 0, 0, 32, 65, 36, 40, 76, 0, 27, 26, + 0, 0, 25, 0, 0, 30, 31, 23, 0, 0, + 0, 42, 28, 55, 56, 57, 73, 69, 59, 70, + 0, 45, 46, 71, 33, 0, 34, 63, 64, 0, + 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 77, 78, 37, 16, 18, 0, 68, 44, + 0, 306, 41, 22, 43, 29, 35, 38, 0, 0, + 0, 32, 65, 36, 40, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 30, 31, 23, 0, 42, 28, + 55, 56, 57, 73, 69, 59, 70, 0, 45, 46, + 71, 33, 0, 34, 63, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 0, 77, + 78, 37, 271, 0, 16, 18, 0, 68, 44, 41, + 22, 43, 29, 35, 38, 0, 0, 0, 32, 65, + 36, 40, 76, 0, 27, 26, 0, 0, 25, 0, + 0, 30, 31, 23, 0, 0, 0, 42, 28, 55, + 56, 57, 73, 69, 59, 70, 0, 45, 46, 71, + 33, 0, 34, 63, 64, 0, 0, 0, 0, 0, + 0, 75, 0, 0, 0, 0, 0, 0, 77, 78, + 37, 16, 18, 0, 68, 44, 0, 247, 41, 22, + 43, 29, 35, 38, 0, 0, 0, 32, 65, 36, + 40, 76, 0, 27, 26, 0, 0, 25, 0, 0, + 30, 31, 23, 0, 42, 28, 55, 56, 57, 73, + 69, 59, 70, 0, 45, 46, 71, 33, 0, 34, + 63, 64, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 77, 78, 37, 16, 18, + 0, 68, 44, 0, 246, 41, 22, 43, 29, 35, + 38, 0, 0, 0, 32, 65, 36, 40, 76, 0, + 27, 26, 0, 0, 25, 0, 0, 30, 31, 23, + 0, 42, 28, 55, 56, 57, 73, 69, 59, 70, + 0, 45, 46, 71, 33, 0, 34, 63, 64, 0, + 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 77, 78, 37, 16, 18, 0, 68, 44, + 0, 225, 41, 22, 43, 29, 35, 38, 0, 0, + 0, 32, 65, 36, 40, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 30, 31, 23, 0, 42, 28, + 55, 56, 57, 73, 69, 59, 70, 0, 45, 46, + 71, 33, 0, 34, 63, 64, 0, 0, 0, 0, + 0, 0, 75, 0, 0, 0, 0, 0, 0, 77, + 78, 37, 16, 18, 0, 68, 44, 0, 215, 41, + 22, 43, 29, 35, 38, 0, 0, 0, 32, 65, + 36, 40, 76, 0, 27, 26, 0, 0, 25, 0, + 0, 30, 31, 23, 0, 42, 28, 55, 56, 57, + 73, 69, 59, 70, 0, 45, 46, 71, 33, 0, + 34, 63, 64, 0, 0, 0, 0, 0, 0, 75, + 0, 0, 0, 0, 0, 0, 77, 78, 37, 16, + 18, 0, 68, 44, 0, 135, 41, 22, 43, 29, + 35, 38, 0, 0, 0, 32, 65, 36, 40, 76, + 0, 27, 26, 0, 0, 25, 0, 0, 30, 31, + 23, 0, 42, 28, 55, 56, 57, 73, 69, 59, + 70, 0, 45, 46, 71, 33, 0, 34, 63, 64, + 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 0, 0, 0, 77, 78, 37, 16, 18, 0, 68, + 44, 0, 0, 41, 22, 43, 29, 35, 38, 0, + 0, 0, 32, 65, 36, 40, 76, 0, 27, 26, + 0, 0, 25, 0, 0, 30, 31, 23, 0, 42, + 28, 55, 56, 57, 73, 69, 59, 70, 0, 45, + 46, 71, 33, 0, 34, 63, 64, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 77, 78, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 0, 0, 32, + 65, 36, 40, 76, 0, 27, 26, 0, 0, 25, + 0, 0, 30, 31, 23, 190, 0, 101, 95, 0, + 0, 329, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 42, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 84, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 30, 31, 23, 190, 0, 101, 95, 0, + 0, 326, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 42, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 84, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 30, 31, 23, 190, 0, 101, 95, 0, + 0, 324, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 42, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 84, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 30, 31, 23, 140, 0, 0, 101, 95, + 139, 0, 0, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 0, 0, + 99, 0, 0, 30, 31, 23, 190, 0, 101, 95, + 0, 0, 192, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 101, 95, + 99, 0, 353, 30, 31, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 101, 95, + 99, 0, 352, 30, 31, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 101, 95, + 99, 0, 348, 30, 31, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 0, 0, + 99, 0, 0, 30, 31, 23, 101, 95, 344, 0, + 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 101, 95, 99, 0, + 321, 30, 31, 23, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 101, 95, 99, 0, + 318, 30, 31, 23, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 101, 95, 99, 0, + 277, 30, 31, 23, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 0, 190, 99, 101, + 95, 30, 31, 23, 0, 0, 0, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 192, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 250, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 0, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 101, 95, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 93, + 0, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 0, 0, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 101, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 240, 0, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 98, 97, + 99, 0, 0, 30, 31, 23, 0, 241, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 75, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, + 44, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 237, 314, 32, 0, + 36, 40, 0, 0, 27, 26, 0, 0, 99, 42, + 28, 30, 31, 23, 73, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 77, 78, 37, 0, 0, 101, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 240, 0, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 98, 97, 25, + 0, 0, 30, 31, 23, 0, 241, 42, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 45, 46, 0, + 33, 0, 34, 0, 0, 0, 0, 0, 12, 13, + 0, 0, 16, 18, 0, 0, 44, 0, 0, 0, + 37, 0, 0, 0, 0, 0, 0, 0, 41, 22, + 43, 29, 35, 38, 0, 237, 0, 32, 0, 36, + 40, 0, 0, 27, 26, 42, 28, 99, 0, 0, + 30, 31, 23, 0, 14, 45, 46, 0, 33, 0, + 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, + 0, 101, 0, 0, 0, 0, 41, 22, 43, 29, + 35, 38, 240, 0, 0, 32, 0, 36, 40, 0, + 0, 27, 26, 98, 0, 25, 0, 0, 30, 31, + 23, 0, 241, 42, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 46, 0, 33, 0, 34, 0, + 0, 0, 0, 0, 0, 0, 253, 0, 0, 18, + 0, 0, 44, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 41, 22, 43, 29, 35, 38, + 0, 0, 0, 32, 101, 36, 40, 0, 0, 27, + 26, 42, 28, 99, 0, 240, 30, 31, 23, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 241, 42, 28, 0, 0, + 0, 0, 0, 0, 37, 0, 45, 46, 0, 33, + 0, 34, 41, 22, 43, 29, 35, 38, 0, 174, + 0, 32, 282, 36, 40, 44, 0, 27, 26, 37, + 0, 25, 0, 0, 30, 31, 23, 41, 22, 43, + 29, 35, 38, 0, 172, 0, 32, 282, 36, 40, + 44, 0, 27, 26, 42, 28, 99, 0, 0, 30, + 31, 23, 0, 0, 45, 46, 0, 33, 0, 34, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, + 28, 0, 0, 0, 0, 0, 0, 37, 0, 45, + 46, 0, 33, 0, 34, 41, 22, 43, 29, 35, + 38, 0, 253, 0, 32, 282, 36, 40, 44, 0, + 27, 26, 37, 0, 25, 0, 0, 30, 31, 23, + 41, 22, 43, 29, 35, 38, 0, 0, 0, 32, + 18, 36, 40, 44, 203, 27, 26, 42, 28, 25, + 0, 0, 30, 31, 23, 0, 0, 45, 46, 0, + 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 42, 28, 0, 0, 0, 0, 0, 0, + 37, 0, 45, 46, 0, 33, 0, 34, 41, 22, + 43, 29, 35, 38, 0, 0, 0, 32, 18, 36, + 40, 44, 201, 27, 26, 37, 0, 25, 0, 0, + 30, 31, 23, 41, 22, 43, 29, 35, 38, 0, + 174, 0, 32, 18, 36, 40, 44, 0, 27, 26, + 42, 28, 25, 0, 0, 30, 31, 23, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 42, 28, 0, 0, 0, + 0, 0, 0, 37, 0, 45, 46, 0, 33, 0, + 34, 41, 22, 43, 29, 35, 38, 0, 172, 0, + 32, 18, 36, 40, 44, 0, 27, 26, 37, 0, + 25, 0, 0, 30, 31, 23, 41, 22, 43, 29, + 35, 38, 0, 0, 0, 32, 18, 36, 40, 44, + 0, 27, 26, 42, 28, 25, 0, 0, 30, 31, + 23, 0, 0, 45, 46, 0, 33, 0, 34, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 28, + 0, 0, 0, 0, 0, 0, 37, 0, 45, 46, + 0, 33, 0, 34, 41, 22, 43, 29, 35, 38, + 0, 0, 0, 32, 282, 36, 40, 44, 0, 27, + 26, 37, 0, 25, 0, 0, 30, 31, 23, 41, + 22, 43, 29, 35, 38, 0, 0, 0, 32, 161, + 36, 40, 44, 0, 27, 26, 42, 28, 25, 0, + 0, 30, 31, 23, 0, 0, 45, 46, 0, 33, + 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 42, 28, 0, 0, 0, 0, 0, 0, 37, + 0, 45, 46, 0, 33, 0, 34, 41, 22, 43, + 29, 35, 38, 0, 0, 0, 32, 101, 36, 40, + 44, 0, 27, 26, 37, 0, 25, 0, 0, 30, + 31, 23, 41, 22, 43, 29, 35, 38, 0, 0, + 0, 32, 101, 36, 40, 0, 0, 27, 26, 42, + 28, 25, 0, 0, 30, 31, 23, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 28, 0, 0, 0, 0, + 0, 0, 37, 0, 45, 46, 0, 33, 0, 34, + 41, 22, 43, 29, 35, 38, 0, 0, 0, 32, + 101, 36, 40, 0, 0, 27, 26, 37, 0, 25, + 0, 0, 30, 31, 23, 41, 22, 43, 29, 35, + 38, 0, 0, 0, 32, 0, 36, 40, 0, 0, + 27, 26, 42, 28, 99, 0, 0, 30, 31, 23, + 0, 0, 45, 46, 0, 33, 0, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, + 0, 0, 0, 41, 22, 43, 29, 35, 38, 0, + 0, 0, 0, 0, 36, 40, 0, 0, 27, 26, + 0, 0, 99, 0, 0, 30, 31, 23 +}; +short yypact[] = +{ + 181,-1000,-1000,-1000,3290, 179,-1000,-1000, 175,-1000, + 192, 826, 83, 83, -52,2866,-1000, -46,3773,-1000, + 29, 37,-1000,3939,-1000,3914,3939,3939, 189, 186, + -5, -5, -33, 185, 184,-1000, 182, 180,-1000, 158, + 156,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,3290, + 826,3773,-1000,1297,-1000, 114,3773, 114, 202, 645, +-1000,1364, 826, 114, 114, 645, 114,-1000, 195,-1000, + 154, 147,3856, -16,2866,-1000, 146,-1000,-1000, 826, + 826, 145,-1000,-1000,3773,3748,3690,3773,3773,3773, +3773,3773,3773,3773, -16, -85, 29,-1000,-1000,3939, + -89,3773,3773,-1000,-1000, 151,1865,3939,3939,3939, +3939,3939,3939,3773,-1000,-1000,-105,-105,-105,3665, +3607,-1000,-1000, 8,3939,3773,3773,3773,3773,3773, +3773, -70,-1000,1230, 83,-1000,-1000,-1000, 201, 195, +-1000,1765,-1000,-1000,1364,1765,-1000, -43,1163,-1000, +-1000,1765,-1000,-1000,1364,-1000, 201,3164,3773, 34, + 130,3773,3232, -51,-1000, 29, 33,3773,1096,1029, + -61,2776,-1000,2956,-1000,3035,3997,3997,3997,3997, +3997,3997,-1000,3997,-1000, -5,2686,2866, 3,3416, +-1000,3416,-1000, -1, -1,-105,-105,-105,-105, 76, +2866,-1000, 139,-1000, 138,3939, 29,2596,2596,2596, + 137, 130,2596,2596, 35,-1000, 826,-1000,-1000,-1000, +-1000,-1000, 962,-1000, 197,-1000,-1000,-1000, 125, 41, +-1000,2503,3939,3939,3939,3582, 128,3831,3524,3499, +3831, -16, 29,3831,3773,2503,-1000,-1000, 117,-1000, +3773,-1000, -16,-1000,2866,2866,3416,-1000,-1000,-1000, + 29,3416,3416, 78,-1000,3416,3416,3416,-1000, 893, + -78,-1000,-1000,-1000, 160, -16, 141,-1000, 29, 29, + 29,3232,3773, -6,3103,3358,3441,-1000,3997,-1000, +3232, 58, 141, 141, 32,2866,-1000,2866,2413, 102, + 100,2323, 105,1664,1564,1464,-1000, 107,3773, 195, + 62,-1000, 104, -16,3831,-1000, 83,-1000,-1000,-1000, +-1000,-1000,3416,-1000,-1000, 4,-1000, 4,3416,-1000, +3773,2233,3164, 141, -6,-1000,3232, 826,2135, 87, + 82, 80,2045,1955, 195, 62,1364, 757,-1000,-1000, +-1000,-1000,-1000, 114,3164, 141,-1000,-1000,-1000, 62, +1364, 141,-1000,1364,-1000 +}; +short yypgo[] = +{ + 0, 263, 462, 361, 11, 262, 6, 261, 200, 322, + 46, 39, 260, 7, 3, 5, 303, 13, 0, 383, + 259, 258, 253, 252, 250, 249, 245, 1, 243, 220, + 30, 242, 8, 461, 17, 4, 138, 84, 237, 231, + 225, 223, 222, 221, 219, 218, 217, 215, 192 +}; +short yyr1[] = +{ + 0, 40, 40, 36, 36, 37, 37, 33, 33, 26, + 26, 24, 24, 41, 22, 42, 22, 43, 22, 20, + 20, 23, 30, 30, 34, 34, 35, 35, 29, 29, + 15, 15, 1, 1, 10, 11, 11, 11, 11, 11, + 11, 11, 44, 11, 12, 12, 6, 6, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 5, 5, 7, 7, 7, 39, 39, 28, 28, 28, + 28, 31, 31, 9, 9, 45, 13, 32, 32, 14, + 14, 14, 14, 14, 14, 14, 14, 27, 27, 16, + 16, 16, 46, 47, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 48, 16, 16, 17, + 17, 38, 38, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 18, 18, 18, 18, 21, 21, 21, + 19, 19, 19, 25 +}; +short yyr2[] = +{ + 0, 1, 1, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 0, 12, 0, 10, 0, 8, 1, + 1, 4, 1, 2, 1, 2, 0, 1, 0, 1, + 0, 1, 1, 3, 1, 1, 4, 3, 6, 3, + 4, 4, 0, 9, 1, 3, 1, 3, 3, 5, + 3, 3, 3, 3, 3, 5, 2, 1, 1, 3, + 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 4, 3, 2, 1, 1, 3, 3, + 1, 3, 0, 1, 3, 1, 1, 1, 1, 2, + 2, 1, 2, 1, 2, 0, 4, 1, 2, 4, + 4, 4, 2, 5, 2, 1, 1, 1, 2, 2, + 3, 2, 0, 0, 9, 3, 2, 1, 4, 2, + 3, 2, 2, 3, 2, 2, 0, 3, 2, 1, + 2, 1, 1, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 3, 4, 1, 3, 4, 2, 2, 2, + 2, 4, 3, 2, 1, 6, 6, 3, 6, 6, + 1, 8, 8, 6, 4, 1, 6, 6, 8, 8, + 8, 6, 1, 1, 4, 1, 2, 0, 1, 3, + 1, 1, 1, 4 +}; +short yychk[] = +{ +-1000, -40, -1, 2, -29, -28, 10, 15, -12, -11, + -10, -30, 8, 9, 54, -2, 12, -18, 13, -9, + -8, -19, 87, 110, -13, 105, 102, 101, 46, 89, + 108, 109, 95, 58, 60, 90, 97, 78, 91, -38, + 98, 86, 45, 88, 16, 55, 56, 10, 15, -29, + -30, 11, 10, -17, -16, 47, 48, 49, -26, 52, + -22, -23, -30, 61, 62, 96, -14, -25, 15, 51, + 53, 57, -39, 50, -2, 2, 99, 76, 77, -30, + -30, -20, 86, 89, 93, -37, -36, 38, 39, 40, + 41, 42, 43, 24, 44, 14, -8, 36, 35, 105, + -18, 13, 69, 108, 109, -4, -2, 101, 102, 103, + 16, 104, 107, 19, -8, -9, -8, -8, -8, 13, + 13, -18, -18, -18, 42, 13, 13, 13, 13, 13, + 13, -45, -11, -17, -10, 18, -16, -27, -34, 15, + 10, -2, -27, 10, -46, -2, -27, -16, -17, -27, + -27, -2, -27, -27, -48, -35, -34, 13, 13, -7, + -5, 13, -3, -18, -9, -8, -19, 13, -17, -17, + 13, -2, 10, -2, 10, -2, -2, -2, -2, -2, + -2, -2, -13, -2, -19, 95, -2, -2, 17, -33, + 11, -33, 17, -8, -8, -8, -8, -8, -8, -6, + -2, 17, -6, 17, -6, 42, -8, -2, -2, -2, + -6, -13, -2, -2, 92, 18, -30, 10, -35, -27, + -16, -27, -24, 79, -31, 18, -27, -16, -15, -19, + -14, -2, 14, 37, 40, -33, -4, 93, -37, -36, + 24, 44, -8, 69, 19, -2, 18, 18, -21, 86, + 94, -18, 44, 10, -2, -2, -33, 20, 17, 17, + -8, -33, -33, -33, 17, -33, -33, -33, 16, -17, + -47, 10, -16, 10, 15, 44, -32, 17, -8, -8, + -8, -3, 13, 17, -3, -3, -3, -13, -3, -19, + -3, -6, -32, -32, -33, -2, -19, -2, -2, -13, + -13, -2, -19, -2, -2, -2, 18, 99, -35, 15, + -19, 10, -4, 44, 94, 20, -44, 86, 17, 17, + 17, 17, -33, 17, 17, -33, 17, -33, -33, 17, + 13, -2, -35, -32, 17, -19, -3, -30, -2, -13, + -18, -18, -2, -2, 15, -15, -43, -17, 17, 17, + 17, 17, 17, 17, -35, -32, -16, 18, -27, -15, + -42, -32, -16, -41, -16 +}; +short yydef[] = +{ + -2, -2, 1, 2, 32, 29, 87, 88, 28, 44, + 35, 0, 0, 0, 0, 34, 22, 172, 0, 76, + 77, 173, 175, 0, 93, 0, 0, 0, 144, 0, + 0, 0, 154, 0, 0, 160, 0, 0, 165, 0, + 0, 180, 181, 182, 95, 131, 132, 89, 90, 33, + 0, 0, 23, 0, 129, 0, 0, 0, 112, 0, + 117, 0, 0, 0, 0, 0, 0, 126, 26, 9, + 0, 0, 82, 0, 105, 106, 0, 85, 86, 0, + 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 5, 3, 0, + 172, 0, 0, 149, 150, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 176, 94, 141, 139, 140, 0, + 0, 147, 148, 153, 0, 0, 0, 0, 0, 0, + 0, 0, 45, 0, 37, 39, 130, 109, 107, 26, + 24, 0, 111, 10, 0, 0, 116, 119, 0, 121, + 122, 0, 124, 125, 0, 128, 27, -2, 0, 102, + 83, 0, 80, 172, 57, 58, 104, 0, 0, 0, + 177, 0, 6, 61, 4, 62, -2, -2, -2, -2, + -2, -2, 69, -2, 71, 74, 0, 59, 0, 0, + 7, 0, 157, 133, 134, 135, 136, 137, 138, 0, + 46, 142, 0, 145, 0, 0, 152, 0, 0, 0, + 0, 93, 0, 0, 0, 36, 0, 25, 108, 110, + 113, 115, 0, 11, 120, 91, 123, 127, 0, 173, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 0, 40, 41, 0, 178, + 0, 73, 0, 8, 79, 78, 0, 174, 143, 146, + 151, 0, 0, 0, 164, 0, 0, 0, 96, 0, + 0, 12, 118, 92, 26, 0, 21, 97, 99, 100, + 101, 81, 0, 84, 0, 50, 51, 52, -2, 54, + 48, 0, 183, 42, 0, 60, 72, 47, 0, 93, + 93, 0, 0, 0, 0, 0, 38, 0, 0, 26, + 0, 98, 0, 0, 0, 103, 0, 179, 155, 156, + 158, 159, 0, 163, 166, 0, 167, 0, 0, 171, + 0, 0, -2, 17, 0, 55, 49, 0, 0, 93, + 0, 0, 0, 0, 26, 0, 0, 0, 161, 162, + 168, 169, 170, 0, -2, 15, 18, 43, 114, 0, + 0, 13, 16, 0, 14 +}; +short yytok1[] = +{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, + 13, 17, 103, 101, 11, 102, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 15, + 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 14, 18 +}; +short yytok2[] = +{ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 95, 96, 97, 98, 99, 100, 105, 106, 107, + 108, 109, 110, 111 +}; +long yytok3[] = +{ + 0 +}; +#define YYFLAG -1000 +#define YYERROR goto yyerrlab +#define YYACCEPT return(0) +#define YYABORT return(1) +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 + +#ifdef yydebug +#include "y.debug" +#else +#define yydebug 0 +char* yytoknames[1]; /* for debugging */ +char* yystates[1]; /* for debugging */ +#endif + +/* parser for yacc output */ + +int yynerrs = 0; /* number of errors */ +int yyerrflag = 0; /* error recovery flag */ + +extern int fprint(int, char*, ...); +extern int sprint(char*, char*, ...); + +char* +yytokname(int yyc) +{ + static char x[10]; + + if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0])) + if(yytoknames[yyc-1]) + return yytoknames[yyc-1]; + sprintf(x, "<%d>", yyc); + return x; +} + +char* +yystatname(int yys) +{ + static char x[10]; + + if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0])) + if(yystates[yys]) + return yystates[yys]; + sprintf(x, "<%d>\n", yys); + return x; +} + +long +yylex1(void) +{ + long yychar; + long *t3p; + int c; + + yychar = yylex(); + if(yychar <= 0) { + c = yytok1[0]; + goto out; + } + if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) { + c = yytok1[yychar]; + goto out; + } + if(yychar >= YYPRIVATE) + if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) { + c = yytok2[yychar-YYPRIVATE]; + goto out; + } + for(t3p=yytok3;; t3p+=2) { + c = t3p[0]; + if(c == yychar) { + c = t3p[1]; + goto out; + } + if(c == 0) + break; + } + c = 0; + +out: + if(c == 0) + c = yytok2[1]; /* unknown char */ + if(yydebug >= 3) + printf("lex %.4X %s\n", yychar, yytokname(c)); + return c; +} + +int +yyparse(void) +{ + struct + { + YYSTYPE yyv; + int yys; + } yys[YYMAXDEPTH], *yyp, *yypt; + short *yyxi; + int yyj, yym, yystate, yyn, yyg; + YYSTYPE save1, save2; + int save3, save4; + long yychar; + + save1 = yylval; + save2 = yyval; + save3 = yynerrs; + save4 = yyerrflag; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyp = &yys[-1]; + goto yystack; + +ret0: + yyn = 0; + goto ret; + +ret1: + yyn = 1; + goto ret; + +ret: + yylval = save1; + yyval = save2; + yynerrs = save3; + yyerrflag = save4; + return yyn; + +yystack: + /* put a state and value onto the stack */ + if(yydebug >= 4) + printf("char %s in %s", yytokname(yychar), yystatname(yystate)); + + yyp++; + if(yyp >= &yys[YYMAXDEPTH]) { + yyerror("yacc stack overflow"); + goto ret1; + } + yyp->yys = yystate; + yyp->yyv = yyval; + +yynewstate: + yyn = yypact[yystate]; + if(yyn <= YYFLAG) + goto yydefault; /* simple state */ + if(yychar < 0) + yychar = yylex1(); + yyn += yychar; + if(yyn < 0 || yyn >= YYLAST) + goto yydefault; + yyn = yyact[yyn]; + if(yychk[yyn] == yychar) { /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if(yyerrflag > 0) + yyerrflag--; + goto yystack; + } + +yydefault: + /* default state action */ + yyn = yydef[yystate]; + if(yyn == -2) { + if(yychar < 0) + yychar = yylex1(); + + /* look through exception table */ + for(yyxi=yyexca;; yyxi+=2) + if(yyxi[0] == -1 && yyxi[1] == yystate) + break; + for(yyxi += 2;; yyxi += 2) { + yyn = yyxi[0]; + if(yyn < 0 || yyn == yychar) + break; + } + yyn = yyxi[1]; + if(yyn < 0) + goto ret0; + } + if(yyn == 0) { + /* error ... attempt to resume parsing */ + switch(yyerrflag) { + case 0: /* brand new error */ + yyerror("syntax error"); + if(yydebug >= 1) { + printf("%s", yystatname(yystate)); + printf("saw %s\n", yytokname(yychar)); + } +yyerrlab: + yynerrs++; + + case 1: + case 2: /* incompletely recovered error ... try again */ + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + while(yyp >= yys) { + yyn = yypact[yyp->yys] + YYERRCODE; + if(yyn >= 0 && yyn < YYLAST) { + yystate = yyact[yyn]; /* simulate a shift of "error" */ + if(yychk[yystate] == YYERRCODE) + goto yystack; + } + + /* the current yyp has no shift onn "error", pop stack */ + if(yydebug >= 2) + printf("error recovery pops state %d, uncovers %d\n", + yyp->yys, (yyp-1)->yys ); + yyp--; + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1; + + case 3: /* no shift yet; clobber input char */ + if(yydebug >= YYEOFCODE) + printf("error recovery discards %s\n", yytokname(yychar)); + if(yychar == YYEOFCODE) + goto ret1; + yychar = -1; + goto yynewstate; /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if(yydebug >= 2) + printf("reduce %d in:\n\t%s", yyn, yystatname(yystate)); + + yypt = yyp; + yyp -= yyr2[yyn]; + yyval = (yyp+1)->yyv; + yym = yyn; + + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyg = yypgo[yyn]; + yyj = yyg + yyp->yys + 1; + + if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) + yystate = yyact[yyg]; + switch(yym) { + +case 1: +#line 98 "awkgram.y" +{ if (errorflag==0) + winner = (Node *)stat3(PROGRAM, beginloc, yypt[-0].yyv.p, endloc); } break; +case 2: +#line 100 "awkgram.y" +{ yyclearin; bracecheck(); ERROR "bailing out" SYNTAX; } break; +case 13: +#line 124 "awkgram.y" +{inloop++;} break; +case 14: +#line 125 "awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-9].yyv.p, notnull(yypt[-6].yyv.p), yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 15: +#line 126 "awkgram.y" +{inloop++;} break; +case 16: +#line 127 "awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-7].yyv.p, NIL, yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 17: +#line 128 "awkgram.y" +{inloop++;} break; +case 18: +#line 129 "awkgram.y" +{ --inloop; yyval.p = stat3(IN, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-0].yyv.p); } break; +case 19: +#line 133 "awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 20: +#line 134 "awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 21: +#line 138 "awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; +case 26: +#line 150 "awkgram.y" +{ yyval.i = 0; } break; +case 28: +#line 155 "awkgram.y" +{ yyval.i = 0; } break; +case 30: +#line 161 "awkgram.y" +{ yyval.p = 0; } break; +case 32: +#line 166 "awkgram.y" +{ yyval.p = 0; } break; +case 33: +#line 167 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 34: +#line 171 "awkgram.y" +{ yyval.p = notnull(yypt[-0].yyv.p); } break; +case 35: +#line 175 "awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 36: +#line 176 "awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 37: +#line 177 "awkgram.y" +{ yyval.p = pa2stat(yypt[-2].yyv.p, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 38: +#line 178 "awkgram.y" +{ yyval.p = pa2stat(yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 39: +#line 179 "awkgram.y" +{ yyval.p = stat2(PASTAT, NIL, yypt[-1].yyv.p); } break; +case 40: +#line 181 "awkgram.y" +{ beginloc = linkum(beginloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 41: +#line 183 "awkgram.y" +{ endloc = linkum(endloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 42: +#line 184 "awkgram.y" +{infunc++;} break; +case 43: +#line 185 "awkgram.y" +{ infunc--; curfname=0; defn((Cell *)yypt[-7].yyv.p, yypt[-5].yyv.p, yypt[-1].yyv.p); yyval.p = 0; } break; +case 45: +#line 190 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 47: +#line 195 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 48: +#line 199 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 49: +#line 201 "awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 50: +#line 203 "awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 51: +#line 205 "awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 52: +#line 206 "awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 53: +#line 208 "awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 54: +#line 212 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 55: +#line 213 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 56: +#line 214 "awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 59: +#line 220 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 60: +#line 222 "awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 61: +#line 224 "awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 62: +#line 226 "awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 63: +#line 227 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 64: +#line 228 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 65: +#line 229 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 66: +#line 230 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 67: +#line 231 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 68: +#line 232 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 69: +#line 233 "awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 70: +#line 235 "awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 71: +#line 239 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 72: +#line 240 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 73: +#line 241 "awkgram.y" +{ + if (safe) ERROR "cmd | getline is unsafe" SYNTAX; + else yyval.p = op3(GETLINE, yypt[-0].yyv.p, (Node*)yypt[-2].yyv.i, yypt[-3].yyv.p); } break; +case 74: +#line 244 "awkgram.y" +{ + if (safe) ERROR "cmd | getline is unsafe" SYNTAX; + else yyval.p = op3(GETLINE, (Node*)0, (Node*)yypt[-1].yyv.i, yypt[-2].yyv.p); } break; +case 75: +#line 247 "awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 78: +#line 253 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 79: +#line 254 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 81: +#line 259 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 82: +#line 263 "awkgram.y" +{ yyval.p = rectonode(); } break; +case 84: +#line 265 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 93: +#line 282 "awkgram.y" +{ yyval.p = op3(MATCH, NIL, rectonode(), (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 94: +#line 283 "awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 95: +#line 287 "awkgram.y" +{startreg();} break; +case 96: +#line 287 "awkgram.y" +{ yyval.s = yypt[-1].yyv.s; } break; +case 99: +#line 295 "awkgram.y" +{ + if (safe) ERROR "print | is unsafe" SYNTAX; + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, (Node *) yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 100: +#line 298 "awkgram.y" +{ + if (safe) ERROR "print >> is unsafe" SYNTAX; + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, (Node *) yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 101: +#line 301 "awkgram.y" +{ + if (safe) ERROR "print > is unsafe" SYNTAX; + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, (Node *) yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 102: +#line 304 "awkgram.y" +{ yyval.p = stat3(yypt[-1].yyv.i, yypt[-0].yyv.p, NIL, NIL); } break; +case 103: +#line 305 "awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 104: +#line 306 "awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-0].yyv.p), 0); } break; +case 105: +#line 307 "awkgram.y" +{ yyval.p = exptostat(yypt[-0].yyv.p); } break; +case 106: +#line 308 "awkgram.y" +{ yyclearin; ERROR "illegal statement" SYNTAX; } break; +case 109: +#line 317 "awkgram.y" +{ if (!inloop) ERROR "break illegal outside of loops" SYNTAX; + yyval.p = stat1(BREAK, NIL); } break; +case 110: +#line 319 "awkgram.y" +{ yyval.p = stat1(CLOSE, yypt[-1].yyv.p); } break; +case 111: +#line 320 "awkgram.y" +{ if (!inloop) ERROR "continue illegal outside of loops" SYNTAX; + yyval.p = stat1(CONTINUE, NIL); } break; +case 112: +#line 322 "awkgram.y" +{inloop++;} break; +case 113: +#line 322 "awkgram.y" +{--inloop;} break; +case 114: +#line 323 "awkgram.y" +{ yyval.p = stat2(DO, yypt[-6].yyv.p, notnull(yypt[-2].yyv.p)); } break; +case 115: +#line 324 "awkgram.y" +{ yyval.p = stat1(EXIT, yypt[-1].yyv.p); } break; +case 116: +#line 325 "awkgram.y" +{ yyval.p = stat1(EXIT, NIL); } break; +case 118: +#line 327 "awkgram.y" +{ yyval.p = stat3(IF, yypt[-3].yyv.p, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 119: +#line 328 "awkgram.y" +{ yyval.p = stat3(IF, yypt[-1].yyv.p, yypt[-0].yyv.p, NIL); } break; +case 120: +#line 329 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 121: +#line 330 "awkgram.y" +{ if (infunc) + ERROR "next is illegal inside a function" SYNTAX; + yyval.p = stat1(NEXT, NIL); } break; +case 122: +#line 333 "awkgram.y" +{ if (infunc) + ERROR "nextfile is illegal inside a function" SYNTAX; + yyval.p = stat1(NEXTFILE, NIL); } break; +case 123: +#line 336 "awkgram.y" +{ yyval.p = stat1(RETURN, yypt[-1].yyv.p); } break; +case 124: +#line 337 "awkgram.y" +{ yyval.p = stat1(RETURN, NIL); } break; +case 126: +#line 339 "awkgram.y" +{inloop++;} break; +case 127: +#line 339 "awkgram.y" +{ --inloop; yyval.p = stat2(WHILE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 128: +#line 340 "awkgram.y" +{ yyval.p = 0; } break; +case 130: +#line 345 "awkgram.y" +{ yyval.p = linkum(yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 133: +#line 353 "awkgram.y" +{ yyval.p = op2(ADD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 134: +#line 354 "awkgram.y" +{ yyval.p = op2(MINUS, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 135: +#line 355 "awkgram.y" +{ yyval.p = op2(MULT, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 136: +#line 356 "awkgram.y" +{ yyval.p = op2(DIVIDE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 137: +#line 357 "awkgram.y" +{ yyval.p = op2(MOD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 138: +#line 358 "awkgram.y" +{ yyval.p = op2(POWER, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 139: +#line 359 "awkgram.y" +{ yyval.p = op1(UMINUS, yypt[-0].yyv.p); } break; +case 140: +#line 360 "awkgram.y" +{ yyval.p = yypt[-0].yyv.p; } break; +case 141: +#line 361 "awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 142: +#line 362 "awkgram.y" +{ yyval.p = op2(BLTIN, (Node *) yypt[-2].yyv.i, rectonode()); } break; +case 143: +#line 363 "awkgram.y" +{ yyval.p = op2(BLTIN, (Node *) yypt[-3].yyv.i, yypt[-1].yyv.p); } break; +case 144: +#line 364 "awkgram.y" +{ yyval.p = op2(BLTIN, (Node *) yypt[-0].yyv.i, rectonode()); } break; +case 145: +#line 365 "awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-2].yyv.cp,CVAR), NIL); } break; +case 146: +#line 366 "awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-3].yyv.cp,CVAR), yypt[-1].yyv.p); } break; +case 147: +#line 367 "awkgram.y" +{ yyval.p = op1(PREDECR, yypt[-0].yyv.p); } break; +case 148: +#line 368 "awkgram.y" +{ yyval.p = op1(PREINCR, yypt[-0].yyv.p); } break; +case 149: +#line 369 "awkgram.y" +{ yyval.p = op1(POSTDECR, yypt[-1].yyv.p); } break; +case 150: +#line 370 "awkgram.y" +{ yyval.p = op1(POSTINCR, yypt[-1].yyv.p); } break; +case 151: +#line 371 "awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-2].yyv.p, (Node *)yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 152: +#line 372 "awkgram.y" +{ yyval.p = op3(GETLINE, NIL, (Node *)yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 153: +#line 373 "awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-0].yyv.p, NIL, NIL); } break; +case 154: +#line 374 "awkgram.y" +{ yyval.p = op3(GETLINE, NIL, NIL, NIL); } break; +case 155: +#line 376 "awkgram.y" +{ yyval.p = op2(INDEX, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 156: +#line 378 "awkgram.y" +{ ERROR "index() doesn't permit regular expressions" SYNTAX; + yyval.p = op2(INDEX, yypt[-3].yyv.p, (Node*)yypt[-1].yyv.s); } break; +case 157: +#line 380 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 158: +#line 382 "awkgram.y" +{ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(yypt[-1].yyv.s, 1)); } break; +case 159: +#line 384 "awkgram.y" +{ if (constnode(yypt[-1].yyv.p)) + yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(strnode(yypt[-1].yyv.p), 1)); + else + yyval.p = op3(MATCHFCN, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 160: +#line 388 "awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 161: +#line 390 "awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p, (Node*)STRING); } break; +case 162: +#line 392 "awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), (Node*)makedfa(yypt[-1].yyv.s, 1), (Node *)REGEXPR); } break; +case 163: +#line 394 "awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-3].yyv.p, makearr(yypt[-1].yyv.p), NIL, (Node*)STRING); } break; +case 164: +#line 395 "awkgram.y" +{ yyval.p = op1(yypt[-3].yyv.i, yypt[-1].yyv.p); } break; +case 165: +#line 396 "awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 166: +#line 398 "awkgram.y" +{ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(yypt[-3].yyv.s, 1), yypt[-1].yyv.p, rectonode()); } break; +case 167: +#line 400 "awkgram.y" +{ if (constnode(yypt[-3].yyv.p)) + yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-3].yyv.p), 1), yypt[-1].yyv.p, rectonode()); + else + yyval.p = op4(yypt[-5].yyv.i, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p, rectonode()); } break; +case 168: +#line 405 "awkgram.y" +{ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(yypt[-5].yyv.s, 1), yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 169: +#line 407 "awkgram.y" +{ if (constnode(yypt[-5].yyv.p)) + yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-5].yyv.p), 1), yypt[-3].yyv.p, yypt[-1].yyv.p); + else + yyval.p = op4(yypt[-7].yyv.i, (Node *)1, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 170: +#line 412 "awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 171: +#line 414 "awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-3].yyv.p, yypt[-1].yyv.p, NIL); } break; +case 174: +#line 420 "awkgram.y" +{ yyval.p = op2(ARRAY, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 175: +#line 421 "awkgram.y" +{ yyval.p = op1(INDIRECT, celltonode(yypt[-0].yyv.cp, CVAR)); } break; +case 176: +#line 422 "awkgram.y" +{ yyval.p = op1(INDIRECT, yypt[-0].yyv.p); } break; +case 177: +#line 426 "awkgram.y" +{ arglist = yyval.p = 0; } break; +case 178: +#line 427 "awkgram.y" +{ arglist = yyval.p = celltonode(yypt[-0].yyv.cp,CVAR); } break; +case 179: +#line 428 "awkgram.y" +{ + checkdup(yypt[-2].yyv.p, yypt[-0].yyv.cp); + arglist = yyval.p = linkum(yypt[-2].yyv.p,celltonode(yypt[-0].yyv.cp,CVAR)); } break; +case 180: +#line 434 "awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CVAR); } break; +case 181: +#line 435 "awkgram.y" +{ yyval.p = op1(ARG, (Node *) yypt[-0].yyv.i); } break; +case 182: +#line 436 "awkgram.y" +{ yyval.p = op1(VARNF, (Node *) yypt[-0].yyv.cp); } break; +case 183: +#line 441 "awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; + } + goto yystack; /* stack new state and value */ +} diff --git a/usr.bin/awk/ytab.h b/usr.bin/awk/ytab.h new file mode 100644 index 0000000..d18ddfd --- /dev/null +++ b/usr.bin/awk/ytab.h @@ -0,0 +1,100 @@ + +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern YYSTYPE yylval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 diff --git a/usr.bin/awk/ytabc.bak b/usr.bin/awk/ytabc.bak new file mode 100644 index 0000000..b1ce520 --- /dev/null +++ b/usr.bin/awk/ytabc.bak @@ -0,0 +1,1612 @@ + +#line 26 "awkgram.y" +#include +#include +#include "awk.h" + +void checkdup(Node *list, Cell *item); +int yywrap(void) { return(1); } + +Node *beginloc = 0; +Node *endloc = 0; +int infunc = 0; /* = 1 if in arglist or body of func */ +int inloop = 0; /* = 1 if in while, for, do */ +char *curfname = 0; /* current function name */ +Node *arglist = 0; /* list of args for current function */ + +#line 41 "awkgram.y" +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern int yyerrflag; +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 150 +#endif +YYSTYPE yylval; +YYSTYPE yyval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437 +#define YYEOFCODE 1 +#define YYERRCODE 2 + +#line 444 "awkgram.y" + + +void setfname(Cell *p) +{ + if (isarr(p)) + ERROR "%s is an array, not a function", p->nval SYNTAX; + else if (isfcn(p)) + ERROR "you can't define function %s more than once", p->nval SYNTAX; + curfname = p->nval; +} + +int constnode(Node *p) +{ + return isvalue(p) && ((Cell *) (p->narg[0]))->csub == CCON; +} + +char *strnode(Node *p) +{ + return ((Cell *)(p->narg[0]))->sval; +} + +Node *notnull(Node *n) +{ + switch (n->nobj) { + case LE: case LT: case EQ: case NE: case GT: case GE: + case BOR: case AND: case NOT: + return n; + default: + return op2(NE, n, nullnode); + } +} + +void checkdup(Node *vl, Cell *cp) /* check if name already in list */ +{ + char *s = cp->nval; + for ( ; vl; vl = vl->nnext) { + if (strcmp(s, ((Cell *)(vl->narg[0]))->nval) == 0) { + ERROR "duplicate argument %s", s SYNTAX; + break; + } + } +} +short yyexca[] = +{-1, 0, + 1, 28, + 8, 28, + 9, 28, + 12, 28, + 13, 28, + 16, 28, + 45, 28, + 46, 28, + 54, 28, + 55, 28, + 56, 28, + 58, 28, + 60, 28, + 78, 28, + 86, 28, + 87, 28, + 88, 28, + 89, 28, + 90, 28, + 91, 28, + 95, 28, + 97, 28, + 98, 28, + 101, 28, + 102, 28, + 105, 28, + 108, 28, + 109, 28, + 110, 28, + -2, 0, +-1, 1, + 1, -1, + -2, 0, +-1, 157, + 15, 30, + -2, 0, +-1, 176, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 63, +-1, 177, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 64, +-1, 178, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 65, +-1, 179, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 66, +-1, 180, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 67, +-1, 181, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 68, +-1, 183, + 14, 0, + 24, 0, + 38, 0, + 39, 0, + 40, 0, + 41, 0, + 42, 0, + 43, 0, + 44, 0, + -2, 70, +-1, 288, + 24, 0, + 44, 0, + -2, 53, +-1, 332, + 17, 30, + -2, 0, +-1, 354, + 17, 30, + -2, 0, +}; +#define YYNPROD 184 +#define YYPRIVATE 57344 +#define YYLAST 4108 +short yyact[] = +{ + 17, 137, 112, 66, 155, 228, 199, 24, 276, 124, + 185, 105, 42, 53, 253, 110, 100, 138, 243, 103, + 104, 307, 214, 102, 100, 249, 100, 100, 100, 42, + 62, 121, 122, 123, 82, 11, 223, 83, 313, 9, + 42, 50, 253, 79, 80, 110, 10, 252, 232, 42, + 205, 268, 244, 41, 22, 43, 113, 103, 104, 142, + 113, 146, 103, 104, 133, 149, 150, 152, 153, 190, + 41, 233, 43, 163, 234, 100, 148, 23, 315, 277, + 11, 41, 22, 43, 85, 275, 156, 190, 253, 132, + 41, 22, 43, 168, 169, 16, 257, 351, 134, 350, + 100, 182, 109, 111, 349, 23, 112, 100, 100, 100, + 100, 100, 100, 100, 23, 190, 190, 320, 317, 319, + 330, 334, 323, 42, 140, 100, 202, 204, 190, 139, + 107, 108, 109, 111, 277, 210, 112, 211, 86, 190, + 274, 190, 100, 219, 218, 283, 100, 221, 190, 190, + 190, 311, 100, 226, 264, 259, 258, 156, 170, 167, + 158, 230, 190, 100, 41, 216, 43, 157, 188, 130, + 140, 129, 100, 236, 100, 309, 100, 100, 100, 100, + 100, 100, 100, 3, 100, 6, 251, 100, 100, 47, + 7, 6, 154, 128, 48, 127, 7, 126, 125, 120, + 20, 100, 119, 51, 16, 140, 100, 273, 100, 100, + 100, 217, 143, 100, 100, 270, 96, 144, 131, 316, + 4, 346, 360, 363, 114, 1, 116, 117, 118, 49, + 269, 72, 100, 100, 100, 100, 163, 39, 163, 163, + 163, 163, 224, 5, 163, 58, 100, 238, 287, 67, + 222, 291, 61, 60, 292, 100, 100, 293, 248, 81, + 8, 159, 160, 2, 0, 0, 0, 0, 0, 299, + 300, 0, 0, 165, 0, 96, 0, 0, 0, 308, + 0, 0, 100, 0, 0, 100, 100, 100, 0, 100, + 0, 100, 156, 0, 312, 0, 100, 0, 100, 100, + 116, 239, 100, 54, 100, 100, 100, 96, 193, 194, + 195, 196, 197, 198, 332, 163, 0, 0, 0, 333, + 0, 0, 19, 0, 0, 206, 340, 156, 341, 0, + 339, 0, 100, 0, 0, 0, 230, 100, 345, 100, + 0, 0, 96, 100, 100, 0, 96, 337, 115, 354, + 0, 347, 96, 0, 355, 358, 0, 136, 230, 0, + 359, 162, 156, 242, 0, 147, 238, 0, 361, 238, + 238, 238, 96, 238, 96, 238, 96, 96, 96, 96, + 96, 96, 96, 21, 96, 0, 0, 96, 96, 0, + 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, + 0, 96, 0, 0, 0, 0, 260, 0, 96, 96, + 96, 0, 0, 96, 96, 0, 0, 0, 0, 0, + 239, 238, 0, 239, 239, 239, 0, 239, 0, 239, + 0, 0, 96, 278, 279, 280, 165, 136, 165, 165, + 165, 165, 0, 0, 165, 0, 96, 0, 220, 0, + 0, 0, 136, 0, 0, 96, 96, 166, 227, 0, + 0, 256, 74, 0, 0, 0, 0, 15, 0, 0, + 0, 0, 136, 136, 0, 239, 0, 0, 184, 0, + 0, 106, 242, 0, 0, 242, 242, 242, 0, 242, + 0, 242, 0, 0, 0, 0, 96, 0, 96, 96, + 0, 0, 96, 0, 96, 96, 96, 0, 0, 0, + 0, 0, 15, 0, 15, 165, 0, 0, 0, 141, + 0, 0, 145, 0, 0, 0, 272, 0, 151, 0, + 0, 0, 96, 0, 0, 0, 0, 242, 0, 96, + 0, 229, 0, 96, 96, 0, 0, 171, 173, 175, + 176, 177, 178, 179, 180, 181, 183, 0, 164, 0, + 164, 164, 164, 164, 186, 187, 164, 189, 191, 0, + 0, 0, 0, 136, 0, 0, 200, 0, 0, 0, + 0, 0, 200, 200, 0, 0, 0, 0, 207, 208, + 209, 200, 212, 213, 0, 0, 0, 281, 0, 284, + 285, 286, 288, 0, 0, 290, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 231, 235, 0, 106, 289, 0, 0, 0, 0, + 245, 0, 0, 0, 0, 0, 296, 164, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, + 356, 136, 254, 0, 255, 140, 0, 0, 18, 310, + 139, 44, 0, 0, 362, 0, 0, 364, 0, 261, + 262, 263, 0, 265, 266, 267, 336, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 42, 28, 0, 0, 0, 0, 0, 335, 189, 0, + 45, 46, 0, 33, 0, 34, 0, 200, 0, 0, + 294, 0, 0, 295, 0, 0, 0, 0, 0, 297, + 0, 0, 0, 37, 298, 301, 0, 0, 303, 304, + 305, 41, 22, 43, 29, 35, 38, 0, 0, 0, + 32, 0, 36, 40, 0, 106, 27, 26, 0, 0, + 25, 0, 0, 30, 31, 23, 0, 0, 0, 75, + 0, 0, 0, 0, 322, 325, 327, 328, 0, 16, + 18, 331, 68, 44, 189, 357, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 338, 0, 0, 0, 0, + 0, 342, 0, 343, 0, 0, 0, 0, 0, 0, + 0, 0, 42, 28, 55, 56, 57, 73, 69, 59, + 70, 0, 45, 46, 71, 33, 0, 34, 63, 64, + 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 77, 78, 37, 52, 0, 16, 18, + 0, 68, 44, 41, 22, 43, 29, 35, 38, 0, + 0, 0, 32, 65, 36, 40, 76, 0, 27, 26, + 0, 0, 25, 0, 0, 30, 31, 23, 0, 0, + 0, 42, 28, 55, 56, 57, 73, 69, 59, 70, + 0, 45, 46, 71, 33, 0, 34, 63, 64, 0, + 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 77, 78, 37, 16, 18, 0, 68, 44, + 0, 306, 41, 22, 43, 29, 35, 38, 0, 0, + 0, 32, 65, 36, 40, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 30, 31, 23, 0, 42, 28, + 55, 56, 57, 73, 69, 59, 70, 0, 45, 46, + 71, 33, 0, 34, 63, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 0, 77, + 78, 37, 271, 0, 16, 18, 0, 68, 44, 41, + 22, 43, 29, 35, 38, 0, 0, 0, 32, 65, + 36, 40, 76, 0, 27, 26, 0, 0, 25, 0, + 0, 30, 31, 23, 0, 0, 0, 42, 28, 55, + 56, 57, 73, 69, 59, 70, 0, 45, 46, 71, + 33, 0, 34, 63, 64, 0, 0, 0, 0, 0, + 0, 75, 0, 0, 0, 0, 0, 0, 77, 78, + 37, 16, 18, 0, 68, 44, 0, 247, 41, 22, + 43, 29, 35, 38, 0, 0, 0, 32, 65, 36, + 40, 76, 0, 27, 26, 0, 0, 25, 0, 0, + 30, 31, 23, 0, 42, 28, 55, 56, 57, 73, + 69, 59, 70, 0, 45, 46, 71, 33, 0, 34, + 63, 64, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 0, 0, 0, 77, 78, 37, 16, 18, + 0, 68, 44, 0, 246, 41, 22, 43, 29, 35, + 38, 0, 0, 0, 32, 65, 36, 40, 76, 0, + 27, 26, 0, 0, 25, 0, 0, 30, 31, 23, + 0, 42, 28, 55, 56, 57, 73, 69, 59, 70, + 0, 45, 46, 71, 33, 0, 34, 63, 64, 0, + 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, + 0, 0, 77, 78, 37, 16, 18, 0, 68, 44, + 0, 225, 41, 22, 43, 29, 35, 38, 0, 0, + 0, 32, 65, 36, 40, 76, 0, 27, 26, 0, + 0, 25, 0, 0, 30, 31, 23, 0, 42, 28, + 55, 56, 57, 73, 69, 59, 70, 0, 45, 46, + 71, 33, 0, 34, 63, 64, 0, 0, 0, 0, + 0, 0, 75, 0, 0, 0, 0, 0, 0, 77, + 78, 37, 16, 18, 0, 68, 44, 0, 215, 41, + 22, 43, 29, 35, 38, 0, 0, 0, 32, 65, + 36, 40, 76, 0, 27, 26, 0, 0, 25, 0, + 0, 30, 31, 23, 0, 42, 28, 55, 56, 57, + 73, 69, 59, 70, 0, 45, 46, 71, 33, 0, + 34, 63, 64, 0, 0, 0, 0, 0, 0, 75, + 0, 0, 0, 0, 0, 0, 77, 78, 37, 16, + 18, 0, 68, 44, 0, 135, 41, 22, 43, 29, + 35, 38, 0, 0, 0, 32, 65, 36, 40, 76, + 0, 27, 26, 0, 0, 25, 0, 0, 30, 31, + 23, 0, 42, 28, 55, 56, 57, 73, 69, 59, + 70, 0, 45, 46, 71, 33, 0, 34, 63, 64, + 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 0, 0, 0, 77, 78, 37, 16, 18, 0, 68, + 44, 0, 0, 41, 22, 43, 29, 35, 38, 0, + 0, 0, 32, 65, 36, 40, 76, 0, 27, 26, + 0, 0, 25, 0, 0, 30, 31, 23, 0, 42, + 28, 55, 56, 57, 73, 69, 59, 70, 0, 45, + 46, 71, 33, 0, 34, 63, 64, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 77, 78, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 0, 0, 32, + 65, 36, 40, 76, 0, 27, 26, 0, 0, 25, + 0, 0, 30, 31, 23, 190, 0, 101, 95, 0, + 0, 329, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 42, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 84, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 30, 31, 23, 190, 0, 101, 95, 0, + 0, 326, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 42, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 84, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 30, 31, 23, 190, 0, 101, 95, 0, + 0, 324, 0, 0, 0, 0, 0, 0, 93, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 97, 0, 87, 88, 89, 90, 91, 92, 94, 42, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 0, 84, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 0, 0, 99, + 0, 0, 30, 31, 23, 140, 0, 0, 101, 95, + 139, 0, 0, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 0, 0, + 99, 0, 0, 30, 31, 23, 190, 0, 101, 95, + 0, 0, 192, 0, 0, 0, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 101, 95, + 99, 0, 353, 30, 31, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 101, 95, + 99, 0, 352, 30, 31, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 101, 95, + 99, 0, 348, 30, 31, 23, 0, 0, 0, 93, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 98, 97, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 0, 84, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 0, 0, + 99, 0, 0, 30, 31, 23, 101, 95, 344, 0, + 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 101, 95, 99, 0, + 321, 30, 31, 23, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 101, 95, 99, 0, + 318, 30, 31, 23, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 101, 95, 99, 0, + 277, 30, 31, 23, 0, 0, 0, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 98, 97, + 0, 87, 88, 89, 90, 91, 92, 94, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 84, 0, 32, 0, + 36, 40, 0, 0, 27, 26, 0, 190, 99, 101, + 95, 30, 31, 23, 0, 0, 0, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 192, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 250, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 97, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 0, 84, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 101, + 95, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 98, 0, 0, 87, 88, 89, 90, 91, 92, + 94, 42, 28, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 0, 41, 22, 43, 29, 35, 38, 101, 95, + 0, 32, 0, 36, 40, 0, 0, 27, 26, 93, + 0, 99, 0, 0, 30, 31, 23, 0, 0, 0, + 0, 0, 0, 87, 88, 89, 90, 91, 92, 94, + 42, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 101, 0, 0, 0, + 0, 41, 22, 43, 29, 35, 38, 240, 0, 0, + 32, 0, 36, 40, 0, 0, 27, 26, 98, 97, + 99, 0, 0, 30, 31, 23, 0, 241, 42, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 46, + 0, 33, 0, 34, 0, 0, 75, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, + 44, 37, 0, 0, 0, 0, 0, 0, 0, 41, + 22, 43, 29, 35, 38, 0, 237, 314, 32, 0, + 36, 40, 0, 0, 27, 26, 0, 0, 99, 42, + 28, 30, 31, 23, 73, 0, 0, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 77, 78, 37, 0, 0, 101, 0, 0, 0, 0, + 41, 22, 43, 29, 35, 38, 240, 0, 0, 32, + 0, 36, 40, 0, 0, 27, 26, 98, 97, 25, + 0, 0, 30, 31, 23, 0, 241, 42, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 45, 46, 0, + 33, 0, 34, 0, 0, 0, 0, 0, 12, 13, + 0, 0, 16, 18, 0, 0, 44, 0, 0, 0, + 37, 0, 0, 0, 0, 0, 0, 0, 41, 22, + 43, 29, 35, 38, 0, 237, 0, 32, 0, 36, + 40, 0, 0, 27, 26, 42, 28, 99, 0, 0, + 30, 31, 23, 0, 14, 45, 46, 0, 33, 0, + 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, + 0, 101, 0, 0, 0, 0, 41, 22, 43, 29, + 35, 38, 240, 0, 0, 32, 0, 36, 40, 0, + 0, 27, 26, 98, 0, 25, 0, 0, 30, 31, + 23, 0, 241, 42, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 46, 0, 33, 0, 34, 0, + 0, 0, 0, 0, 0, 0, 253, 0, 0, 18, + 0, 0, 44, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 41, 22, 43, 29, 35, 38, + 0, 0, 0, 32, 101, 36, 40, 0, 0, 27, + 26, 42, 28, 99, 0, 240, 30, 31, 23, 0, + 0, 45, 46, 0, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 0, 0, 241, 42, 28, 0, 0, + 0, 0, 0, 0, 37, 0, 45, 46, 0, 33, + 0, 34, 41, 22, 43, 29, 35, 38, 0, 174, + 0, 32, 282, 36, 40, 44, 0, 27, 26, 37, + 0, 25, 0, 0, 30, 31, 23, 41, 22, 43, + 29, 35, 38, 0, 172, 0, 32, 282, 36, 40, + 44, 0, 27, 26, 42, 28, 99, 0, 0, 30, + 31, 23, 0, 0, 45, 46, 0, 33, 0, 34, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, + 28, 0, 0, 0, 0, 0, 0, 37, 0, 45, + 46, 0, 33, 0, 34, 41, 22, 43, 29, 35, + 38, 0, 253, 0, 32, 282, 36, 40, 44, 0, + 27, 26, 37, 0, 25, 0, 0, 30, 31, 23, + 41, 22, 43, 29, 35, 38, 0, 0, 0, 32, + 18, 36, 40, 44, 203, 27, 26, 42, 28, 25, + 0, 0, 30, 31, 23, 0, 0, 45, 46, 0, + 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 42, 28, 0, 0, 0, 0, 0, 0, + 37, 0, 45, 46, 0, 33, 0, 34, 41, 22, + 43, 29, 35, 38, 0, 0, 0, 32, 18, 36, + 40, 44, 201, 27, 26, 37, 0, 25, 0, 0, + 30, 31, 23, 41, 22, 43, 29, 35, 38, 0, + 174, 0, 32, 18, 36, 40, 44, 0, 27, 26, + 42, 28, 25, 0, 0, 30, 31, 23, 0, 0, + 45, 46, 0, 33, 0, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 42, 28, 0, 0, 0, + 0, 0, 0, 37, 0, 45, 46, 0, 33, 0, + 34, 41, 22, 43, 29, 35, 38, 0, 172, 0, + 32, 18, 36, 40, 44, 0, 27, 26, 37, 0, + 25, 0, 0, 30, 31, 23, 41, 22, 43, 29, + 35, 38, 0, 0, 0, 32, 18, 36, 40, 44, + 0, 27, 26, 42, 28, 25, 0, 0, 30, 31, + 23, 0, 0, 45, 46, 0, 33, 0, 34, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 28, + 0, 0, 0, 0, 0, 0, 37, 0, 45, 46, + 0, 33, 0, 34, 41, 22, 43, 29, 35, 38, + 0, 0, 0, 32, 282, 36, 40, 44, 0, 27, + 26, 37, 0, 25, 0, 0, 30, 31, 23, 41, + 22, 43, 29, 35, 38, 0, 0, 0, 32, 161, + 36, 40, 44, 0, 27, 26, 42, 28, 25, 0, + 0, 30, 31, 23, 0, 0, 45, 46, 0, 33, + 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 42, 28, 0, 0, 0, 0, 0, 0, 37, + 0, 45, 46, 0, 33, 0, 34, 41, 22, 43, + 29, 35, 38, 0, 0, 0, 32, 101, 36, 40, + 44, 0, 27, 26, 37, 0, 25, 0, 0, 30, + 31, 23, 41, 22, 43, 29, 35, 38, 0, 0, + 0, 32, 101, 36, 40, 0, 0, 27, 26, 42, + 28, 25, 0, 0, 30, 31, 23, 0, 0, 45, + 46, 0, 33, 0, 34, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 28, 0, 0, 0, 0, + 0, 0, 37, 0, 45, 46, 0, 33, 0, 34, + 41, 22, 43, 29, 35, 38, 0, 0, 0, 32, + 101, 36, 40, 0, 0, 27, 26, 37, 0, 25, + 0, 0, 30, 31, 23, 41, 22, 43, 29, 35, + 38, 0, 0, 0, 32, 0, 36, 40, 0, 0, + 27, 26, 42, 28, 99, 0, 0, 30, 31, 23, + 0, 0, 45, 46, 0, 33, 0, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, + 0, 0, 0, 41, 22, 43, 29, 35, 38, 0, + 0, 0, 0, 0, 36, 40, 0, 0, 27, 26, + 0, 0, 99, 0, 0, 30, 31, 23 +}; +short yypact[] = +{ + 181,-1000,-1000,-1000,3290, 179,-1000,-1000, 175,-1000, + 192, 826, 83, 83, -52,2866,-1000, -46,3773,-1000, + 29, 37,-1000,3939,-1000,3914,3939,3939, 189, 186, + -5, -5, -33, 185, 184,-1000, 182, 180,-1000, 158, + 156,-1000,-1000,-1000,-1000,-1000,-1000,-1000,-1000,3290, + 826,3773,-1000,1297,-1000, 114,3773, 114, 202, 645, +-1000,1364, 826, 114, 114, 645, 114,-1000, 195,-1000, + 154, 147,3856, -16,2866,-1000, 146,-1000,-1000, 826, + 826, 145,-1000,-1000,3773,3748,3690,3773,3773,3773, +3773,3773,3773,3773, -16, -85, 29,-1000,-1000,3939, + -89,3773,3773,-1000,-1000, 151,1865,3939,3939,3939, +3939,3939,3939,3773,-1000,-1000,-105,-105,-105,3665, +3607,-1000,-1000, 8,3939,3773,3773,3773,3773,3773, +3773, -70,-1000,1230, 83,-1000,-1000,-1000, 201, 195, +-1000,1765,-1000,-1000,1364,1765,-1000, -43,1163,-1000, +-1000,1765,-1000,-1000,1364,-1000, 201,3164,3773, 34, + 130,3773,3232, -51,-1000, 29, 33,3773,1096,1029, + -61,2776,-1000,2956,-1000,3035,3997,3997,3997,3997, +3997,3997,-1000,3997,-1000, -5,2686,2866, 3,3416, +-1000,3416,-1000, -1, -1,-105,-105,-105,-105, 76, +2866,-1000, 139,-1000, 138,3939, 29,2596,2596,2596, + 137, 130,2596,2596, 35,-1000, 826,-1000,-1000,-1000, +-1000,-1000, 962,-1000, 197,-1000,-1000,-1000, 125, 41, +-1000,2503,3939,3939,3939,3582, 128,3831,3524,3499, +3831, -16, 29,3831,3773,2503,-1000,-1000, 117,-1000, +3773,-1000, -16,-1000,2866,2866,3416,-1000,-1000,-1000, + 29,3416,3416, 78,-1000,3416,3416,3416,-1000, 893, + -78,-1000,-1000,-1000, 160, -16, 141,-1000, 29, 29, + 29,3232,3773, -6,3103,3358,3441,-1000,3997,-1000, +3232, 58, 141, 141, 32,2866,-1000,2866,2413, 102, + 100,2323, 105,1664,1564,1464,-1000, 107,3773, 195, + 62,-1000, 104, -16,3831,-1000, 83,-1000,-1000,-1000, +-1000,-1000,3416,-1000,-1000, 4,-1000, 4,3416,-1000, +3773,2233,3164, 141, -6,-1000,3232, 826,2135, 87, + 82, 80,2045,1955, 195, 62,1364, 757,-1000,-1000, +-1000,-1000,-1000, 114,3164, 141,-1000,-1000,-1000, 62, +1364, 141,-1000,1364,-1000 +}; +short yypgo[] = +{ + 0, 263, 462, 361, 11, 262, 6, 261, 200, 322, + 46, 39, 260, 7, 3, 5, 303, 13, 0, 383, + 259, 258, 253, 252, 250, 249, 245, 1, 243, 220, + 30, 242, 8, 461, 17, 4, 138, 84, 237, 231, + 225, 223, 222, 221, 219, 218, 217, 215, 192 +}; +short yyr1[] = +{ + 0, 40, 40, 36, 36, 37, 37, 33, 33, 26, + 26, 24, 24, 41, 22, 42, 22, 43, 22, 20, + 20, 23, 30, 30, 34, 34, 35, 35, 29, 29, + 15, 15, 1, 1, 10, 11, 11, 11, 11, 11, + 11, 11, 44, 11, 12, 12, 6, 6, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 5, 5, 7, 7, 7, 39, 39, 28, 28, 28, + 28, 31, 31, 9, 9, 45, 13, 32, 32, 14, + 14, 14, 14, 14, 14, 14, 14, 27, 27, 16, + 16, 16, 46, 47, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 48, 16, 16, 17, + 17, 38, 38, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 18, 18, 18, 18, 21, 21, 21, + 19, 19, 19, 25 +}; +short yyr2[] = +{ + 0, 1, 1, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 0, 12, 0, 10, 0, 8, 1, + 1, 4, 1, 2, 1, 2, 0, 1, 0, 1, + 0, 1, 1, 3, 1, 1, 4, 3, 6, 3, + 4, 4, 0, 9, 1, 3, 1, 3, 3, 5, + 3, 3, 3, 3, 3, 5, 2, 1, 1, 3, + 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 4, 3, 2, 1, 1, 3, 3, + 1, 3, 0, 1, 3, 1, 1, 1, 1, 2, + 2, 1, 2, 1, 2, 0, 4, 1, 2, 4, + 4, 4, 2, 5, 2, 1, 1, 1, 2, 2, + 3, 2, 0, 0, 9, 3, 2, 1, 4, 2, + 3, 2, 2, 3, 2, 2, 0, 3, 2, 1, + 2, 1, 1, 3, 3, 3, 3, 3, 3, 2, + 2, 2, 3, 4, 1, 3, 4, 2, 2, 2, + 2, 4, 3, 2, 1, 6, 6, 3, 6, 6, + 1, 8, 8, 6, 4, 1, 6, 6, 8, 8, + 8, 6, 1, 1, 4, 1, 2, 0, 1, 3, + 1, 1, 1, 4 +}; +short yychk[] = +{ +-1000, -40, -1, 2, -29, -28, 10, 15, -12, -11, + -10, -30, 8, 9, 54, -2, 12, -18, 13, -9, + -8, -19, 87, 110, -13, 105, 102, 101, 46, 89, + 108, 109, 95, 58, 60, 90, 97, 78, 91, -38, + 98, 86, 45, 88, 16, 55, 56, 10, 15, -29, + -30, 11, 10, -17, -16, 47, 48, 49, -26, 52, + -22, -23, -30, 61, 62, 96, -14, -25, 15, 51, + 53, 57, -39, 50, -2, 2, 99, 76, 77, -30, + -30, -20, 86, 89, 93, -37, -36, 38, 39, 40, + 41, 42, 43, 24, 44, 14, -8, 36, 35, 105, + -18, 13, 69, 108, 109, -4, -2, 101, 102, 103, + 16, 104, 107, 19, -8, -9, -8, -8, -8, 13, + 13, -18, -18, -18, 42, 13, 13, 13, 13, 13, + 13, -45, -11, -17, -10, 18, -16, -27, -34, 15, + 10, -2, -27, 10, -46, -2, -27, -16, -17, -27, + -27, -2, -27, -27, -48, -35, -34, 13, 13, -7, + -5, 13, -3, -18, -9, -8, -19, 13, -17, -17, + 13, -2, 10, -2, 10, -2, -2, -2, -2, -2, + -2, -2, -13, -2, -19, 95, -2, -2, 17, -33, + 11, -33, 17, -8, -8, -8, -8, -8, -8, -6, + -2, 17, -6, 17, -6, 42, -8, -2, -2, -2, + -6, -13, -2, -2, 92, 18, -30, 10, -35, -27, + -16, -27, -24, 79, -31, 18, -27, -16, -15, -19, + -14, -2, 14, 37, 40, -33, -4, 93, -37, -36, + 24, 44, -8, 69, 19, -2, 18, 18, -21, 86, + 94, -18, 44, 10, -2, -2, -33, 20, 17, 17, + -8, -33, -33, -33, 17, -33, -33, -33, 16, -17, + -47, 10, -16, 10, 15, 44, -32, 17, -8, -8, + -8, -3, 13, 17, -3, -3, -3, -13, -3, -19, + -3, -6, -32, -32, -33, -2, -19, -2, -2, -13, + -13, -2, -19, -2, -2, -2, 18, 99, -35, 15, + -19, 10, -4, 44, 94, 20, -44, 86, 17, 17, + 17, 17, -33, 17, 17, -33, 17, -33, -33, 17, + 13, -2, -35, -32, 17, -19, -3, -30, -2, -13, + -18, -18, -2, -2, 15, -15, -43, -17, 17, 17, + 17, 17, 17, 17, -35, -32, -16, 18, -27, -15, + -42, -32, -16, -41, -16 +}; +short yydef[] = +{ + -2, -2, 1, 2, 32, 29, 87, 88, 28, 44, + 35, 0, 0, 0, 0, 34, 22, 172, 0, 76, + 77, 173, 175, 0, 93, 0, 0, 0, 144, 0, + 0, 0, 154, 0, 0, 160, 0, 0, 165, 0, + 0, 180, 181, 182, 95, 131, 132, 89, 90, 33, + 0, 0, 23, 0, 129, 0, 0, 0, 112, 0, + 117, 0, 0, 0, 0, 0, 0, 126, 26, 9, + 0, 0, 82, 0, 105, 106, 0, 85, 86, 0, + 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 5, 3, 0, + 172, 0, 0, 149, 150, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 176, 94, 141, 139, 140, 0, + 0, 147, 148, 153, 0, 0, 0, 0, 0, 0, + 0, 0, 45, 0, 37, 39, 130, 109, 107, 26, + 24, 0, 111, 10, 0, 0, 116, 119, 0, 121, + 122, 0, 124, 125, 0, 128, 27, -2, 0, 102, + 83, 0, 80, 172, 57, 58, 104, 0, 0, 0, + 177, 0, 6, 61, 4, 62, -2, -2, -2, -2, + -2, -2, 69, -2, 71, 74, 0, 59, 0, 0, + 7, 0, 157, 133, 134, 135, 136, 137, 138, 0, + 46, 142, 0, 145, 0, 0, 152, 0, 0, 0, + 0, 93, 0, 0, 0, 36, 0, 25, 108, 110, + 113, 115, 0, 11, 120, 91, 123, 127, 0, 173, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 0, 40, 41, 0, 178, + 0, 73, 0, 8, 79, 78, 0, 174, 143, 146, + 151, 0, 0, 0, 164, 0, 0, 0, 96, 0, + 0, 12, 118, 92, 26, 0, 21, 97, 99, 100, + 101, 81, 0, 84, 0, 50, 51, 52, -2, 54, + 48, 0, 183, 42, 0, 60, 72, 47, 0, 93, + 93, 0, 0, 0, 0, 0, 38, 0, 0, 26, + 0, 98, 0, 0, 0, 103, 0, 179, 155, 156, + 158, 159, 0, 163, 166, 0, 167, 0, 0, 171, + 0, 0, -2, 17, 0, 55, 49, 0, 0, 93, + 0, 0, 0, 0, 26, 0, 0, 0, 161, 162, + 168, 169, 170, 0, -2, 15, 18, 43, 114, 0, + 0, 13, 16, 0, 14 +}; +short yytok1[] = +{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, + 13, 17, 103, 101, 11, 102, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 15, + 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 14, 18 +}; +short yytok2[] = +{ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 95, 96, 97, 98, 99, 100, 105, 106, 107, + 108, 109, 110, 111 +}; +long yytok3[] = +{ + 0 +}; +#define YYFLAG -1000 +#define YYERROR goto yyerrlab +#define YYACCEPT return(0) +#define YYABORT return(1) +#define yyclearin yychar = -1 +#define yyerrok yyerrflag = 0 + +#ifdef yydebug +#include "y.debug" +#else +#define yydebug 0 +char* yytoknames[1]; /* for debugging */ +char* yystates[1]; /* for debugging */ +#endif + +/* parser for yacc output */ + +int yynerrs = 0; /* number of errors */ +int yyerrflag = 0; /* error recovery flag */ + +extern int fprint(int, char*, ...); +extern int sprint(char*, char*, ...); + +char* +yytokname(int yyc) +{ + static char x[10]; + + if(yyc > 0 && yyc <= sizeof(yytoknames)/sizeof(yytoknames[0])) + if(yytoknames[yyc-1]) + return yytoknames[yyc-1]; + sprintf(x, "<%d>", yyc); + return x; +} + +char* +yystatname(int yys) +{ + static char x[10]; + + if(yys >= 0 && yys < sizeof(yystates)/sizeof(yystates[0])) + if(yystates[yys]) + return yystates[yys]; + sprintf(x, "<%d>\n", yys); + return x; +} + +long +yylex1(void) +{ + long yychar; + long *t3p; + int c; + + yychar = yylex(); + if(yychar <= 0) { + c = yytok1[0]; + goto out; + } + if(yychar < sizeof(yytok1)/sizeof(yytok1[0])) { + c = yytok1[yychar]; + goto out; + } + if(yychar >= YYPRIVATE) + if(yychar < YYPRIVATE+sizeof(yytok2)/sizeof(yytok2[0])) { + c = yytok2[yychar-YYPRIVATE]; + goto out; + } + for(t3p=yytok3;; t3p+=2) { + c = t3p[0]; + if(c == yychar) { + c = t3p[1]; + goto out; + } + if(c == 0) + break; + } + c = 0; + +out: + if(c == 0) + c = yytok2[1]; /* unknown char */ + if(yydebug >= 3) + printf("lex %.4X %s\n", yychar, yytokname(c)); + return c; +} + +int +yyparse(void) +{ + struct + { + YYSTYPE yyv; + int yys; + } yys[YYMAXDEPTH], *yyp, *yypt; + short *yyxi; + int yyj, yym, yystate, yyn, yyg; + YYSTYPE save1, save2; + int save3, save4; + long yychar; + + save1 = yylval; + save2 = yyval; + save3 = yynerrs; + save4 = yyerrflag; + + yystate = 0; + yychar = -1; + yynerrs = 0; + yyerrflag = 0; + yyp = &yys[-1]; + goto yystack; + +ret0: + yyn = 0; + goto ret; + +ret1: + yyn = 1; + goto ret; + +ret: + yylval = save1; + yyval = save2; + yynerrs = save3; + yyerrflag = save4; + return yyn; + +yystack: + /* put a state and value onto the stack */ + if(yydebug >= 4) + printf("char %s in %s", yytokname(yychar), yystatname(yystate)); + + yyp++; + if(yyp >= &yys[YYMAXDEPTH]) { + yyerror("yacc stack overflow"); + goto ret1; + } + yyp->yys = yystate; + yyp->yyv = yyval; + +yynewstate: + yyn = yypact[yystate]; + if(yyn <= YYFLAG) + goto yydefault; /* simple state */ + if(yychar < 0) + yychar = yylex1(); + yyn += yychar; + if(yyn < 0 || yyn >= YYLAST) + goto yydefault; + yyn = yyact[yyn]; + if(yychk[yyn] == yychar) { /* valid shift */ + yychar = -1; + yyval = yylval; + yystate = yyn; + if(yyerrflag > 0) + yyerrflag--; + goto yystack; + } + +yydefault: + /* default state action */ + yyn = yydef[yystate]; + if(yyn == -2) { + if(yychar < 0) + yychar = yylex1(); + + /* look through exception table */ + for(yyxi=yyexca;; yyxi+=2) + if(yyxi[0] == -1 && yyxi[1] == yystate) + break; + for(yyxi += 2;; yyxi += 2) { + yyn = yyxi[0]; + if(yyn < 0 || yyn == yychar) + break; + } + yyn = yyxi[1]; + if(yyn < 0) + goto ret0; + } + if(yyn == 0) { + /* error ... attempt to resume parsing */ + switch(yyerrflag) { + case 0: /* brand new error */ + yyerror("syntax error"); + if(yydebug >= 1) { + printf("%s", yystatname(yystate)); + printf("saw %s\n", yytokname(yychar)); + } +yyerrlab: + yynerrs++; + + case 1: + case 2: /* incompletely recovered error ... try again */ + yyerrflag = 3; + + /* find a state where "error" is a legal shift action */ + while(yyp >= yys) { + yyn = yypact[yyp->yys] + YYERRCODE; + if(yyn >= 0 && yyn < YYLAST) { + yystate = yyact[yyn]; /* simulate a shift of "error" */ + if(yychk[yystate] == YYERRCODE) + goto yystack; + } + + /* the current yyp has no shift onn "error", pop stack */ + if(yydebug >= 2) + printf("error recovery pops state %d, uncovers %d\n", + yyp->yys, (yyp-1)->yys ); + yyp--; + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1; + + case 3: /* no shift yet; clobber input char */ + if(yydebug >= YYEOFCODE) + printf("error recovery discards %s\n", yytokname(yychar)); + if(yychar == YYEOFCODE) + goto ret1; + yychar = -1; + goto yynewstate; /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if(yydebug >= 2) + printf("reduce %d in:\n\t%s", yyn, yystatname(yystate)); + + yypt = yyp; + yyp -= yyr2[yyn]; + yyval = (yyp+1)->yyv; + yym = yyn; + + /* consult goto table to find next state */ + yyn = yyr1[yyn]; + yyg = yypgo[yyn]; + yyj = yyg + yyp->yys + 1; + + if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) + yystate = yyact[yyg]; + switch(yym) { + +case 1: +#line 98 "awkgram.y" +{ if (errorflag==0) + winner = (Node *)stat3(PROGRAM, beginloc, yypt[-0].yyv.p, endloc); } break; +case 2: +#line 100 "awkgram.y" +{ yyclearin; bracecheck(); ERROR "bailing out" SYNTAX; } break; +case 13: +#line 124 "awkgram.y" +{inloop++;} break; +case 14: +#line 125 "awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-9].yyv.p, notnull(yypt[-6].yyv.p), yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 15: +#line 126 "awkgram.y" +{inloop++;} break; +case 16: +#line 127 "awkgram.y" +{ --inloop; yyval.p = stat4(FOR, yypt[-7].yyv.p, NIL, yypt[-3].yyv.p, yypt[-0].yyv.p); } break; +case 17: +#line 128 "awkgram.y" +{inloop++;} break; +case 18: +#line 129 "awkgram.y" +{ --inloop; yyval.p = stat3(IN, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-0].yyv.p); } break; +case 19: +#line 133 "awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 20: +#line 134 "awkgram.y" +{ setfname(yypt[-0].yyv.cp); } break; +case 21: +#line 138 "awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; +case 26: +#line 150 "awkgram.y" +{ yyval.i = 0; } break; +case 28: +#line 155 "awkgram.y" +{ yyval.i = 0; } break; +case 30: +#line 161 "awkgram.y" +{ yyval.p = 0; } break; +case 32: +#line 166 "awkgram.y" +{ yyval.p = 0; } break; +case 33: +#line 167 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 34: +#line 171 "awkgram.y" +{ yyval.p = notnull(yypt[-0].yyv.p); } break; +case 35: +#line 175 "awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 36: +#line 176 "awkgram.y" +{ yyval.p = stat2(PASTAT, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 37: +#line 177 "awkgram.y" +{ yyval.p = pa2stat(yypt[-2].yyv.p, yypt[-0].yyv.p, stat2(PRINT, rectonode(), NIL)); } break; +case 38: +#line 178 "awkgram.y" +{ yyval.p = pa2stat(yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 39: +#line 179 "awkgram.y" +{ yyval.p = stat2(PASTAT, NIL, yypt[-1].yyv.p); } break; +case 40: +#line 181 "awkgram.y" +{ beginloc = linkum(beginloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 41: +#line 183 "awkgram.y" +{ endloc = linkum(endloc, yypt[-1].yyv.p); yyval.p = 0; } break; +case 42: +#line 184 "awkgram.y" +{infunc++;} break; +case 43: +#line 185 "awkgram.y" +{ infunc--; curfname=0; defn((Cell *)yypt[-7].yyv.p, yypt[-5].yyv.p, yypt[-1].yyv.p); yyval.p = 0; } break; +case 45: +#line 190 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 47: +#line 195 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 48: +#line 199 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 49: +#line 201 "awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 50: +#line 203 "awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 51: +#line 205 "awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 52: +#line 206 "awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 53: +#line 208 "awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 54: +#line 212 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 55: +#line 213 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 56: +#line 214 "awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 59: +#line 220 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 60: +#line 222 "awkgram.y" +{ yyval.p = op3(CONDEXPR, notnull(yypt[-4].yyv.p), yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 61: +#line 224 "awkgram.y" +{ yyval.p = op2(BOR, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 62: +#line 226 "awkgram.y" +{ yyval.p = op2(AND, notnull(yypt[-2].yyv.p), notnull(yypt[-0].yyv.p)); } break; +case 63: +#line 227 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 64: +#line 228 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 65: +#line 229 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 66: +#line 230 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 67: +#line 231 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 68: +#line 232 "awkgram.y" +{ yyval.p = op2(yypt[-1].yyv.i, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 69: +#line 233 "awkgram.y" +{ yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 70: +#line 235 "awkgram.y" +{ if (constnode(yypt[-0].yyv.p)) + yyval.p = op3(yypt[-1].yyv.i, NIL, yypt[-2].yyv.p, (Node*)makedfa(strnode(yypt[-0].yyv.p), 0)); + else + yyval.p = op3(yypt[-1].yyv.i, (Node *)1, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 71: +#line 239 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-2].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 72: +#line 240 "awkgram.y" +{ yyval.p = op2(INTEST, yypt[-3].yyv.p, makearr(yypt[-0].yyv.p)); } break; +case 73: +#line 241 "awkgram.y" +{ + if (safe) ERROR "cmd | getline is unsafe" SYNTAX; + else yyval.p = op3(GETLINE, yypt[-0].yyv.p, (Node*)yypt[-2].yyv.i, yypt[-3].yyv.p); } break; +case 74: +#line 244 "awkgram.y" +{ + if (safe) ERROR "cmd | getline is unsafe" SYNTAX; + else yyval.p = op3(GETLINE, (Node*)0, (Node*)yypt[-1].yyv.i, yypt[-2].yyv.p); } break; +case 75: +#line 247 "awkgram.y" +{ yyval.p = op2(CAT, yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 78: +#line 253 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 79: +#line 254 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 81: +#line 259 "awkgram.y" +{ yyval.p = linkum(yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 82: +#line 263 "awkgram.y" +{ yyval.p = rectonode(); } break; +case 84: +#line 265 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 93: +#line 282 "awkgram.y" +{ yyval.p = op3(MATCH, NIL, rectonode(), (Node*)makedfa(yypt[-0].yyv.s, 0)); } break; +case 94: +#line 283 "awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 95: +#line 287 "awkgram.y" +{startreg();} break; +case 96: +#line 287 "awkgram.y" +{ yyval.s = yypt[-1].yyv.s; } break; +case 99: +#line 295 "awkgram.y" +{ + if (safe) ERROR "print | is unsafe" SYNTAX; + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, (Node *) yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 100: +#line 298 "awkgram.y" +{ + if (safe) ERROR "print >> is unsafe" SYNTAX; + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, (Node *) yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 101: +#line 301 "awkgram.y" +{ + if (safe) ERROR "print > is unsafe" SYNTAX; + else yyval.p = stat3(yypt[-3].yyv.i, yypt[-2].yyv.p, (Node *) yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 102: +#line 304 "awkgram.y" +{ yyval.p = stat3(yypt[-1].yyv.i, yypt[-0].yyv.p, NIL, NIL); } break; +case 103: +#line 305 "awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 104: +#line 306 "awkgram.y" +{ yyval.p = stat2(DELETE, makearr(yypt[-0].yyv.p), 0); } break; +case 105: +#line 307 "awkgram.y" +{ yyval.p = exptostat(yypt[-0].yyv.p); } break; +case 106: +#line 308 "awkgram.y" +{ yyclearin; ERROR "illegal statement" SYNTAX; } break; +case 109: +#line 317 "awkgram.y" +{ if (!inloop) ERROR "break illegal outside of loops" SYNTAX; + yyval.p = stat1(BREAK, NIL); } break; +case 110: +#line 319 "awkgram.y" +{ yyval.p = stat1(CLOSE, yypt[-1].yyv.p); } break; +case 111: +#line 320 "awkgram.y" +{ if (!inloop) ERROR "continue illegal outside of loops" SYNTAX; + yyval.p = stat1(CONTINUE, NIL); } break; +case 112: +#line 322 "awkgram.y" +{inloop++;} break; +case 113: +#line 322 "awkgram.y" +{--inloop;} break; +case 114: +#line 323 "awkgram.y" +{ yyval.p = stat2(DO, yypt[-6].yyv.p, notnull(yypt[-2].yyv.p)); } break; +case 115: +#line 324 "awkgram.y" +{ yyval.p = stat1(EXIT, yypt[-1].yyv.p); } break; +case 116: +#line 325 "awkgram.y" +{ yyval.p = stat1(EXIT, NIL); } break; +case 118: +#line 327 "awkgram.y" +{ yyval.p = stat3(IF, yypt[-3].yyv.p, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 119: +#line 328 "awkgram.y" +{ yyval.p = stat3(IF, yypt[-1].yyv.p, yypt[-0].yyv.p, NIL); } break; +case 120: +#line 329 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 121: +#line 330 "awkgram.y" +{ if (infunc) + ERROR "next is illegal inside a function" SYNTAX; + yyval.p = stat1(NEXT, NIL); } break; +case 122: +#line 333 "awkgram.y" +{ if (infunc) + ERROR "nextfile is illegal inside a function" SYNTAX; + yyval.p = stat1(NEXTFILE, NIL); } break; +case 123: +#line 336 "awkgram.y" +{ yyval.p = stat1(RETURN, yypt[-1].yyv.p); } break; +case 124: +#line 337 "awkgram.y" +{ yyval.p = stat1(RETURN, NIL); } break; +case 126: +#line 339 "awkgram.y" +{inloop++;} break; +case 127: +#line 339 "awkgram.y" +{ --inloop; yyval.p = stat2(WHILE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 128: +#line 340 "awkgram.y" +{ yyval.p = 0; } break; +case 130: +#line 345 "awkgram.y" +{ yyval.p = linkum(yypt[-1].yyv.p, yypt[-0].yyv.p); } break; +case 133: +#line 353 "awkgram.y" +{ yyval.p = op2(ADD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 134: +#line 354 "awkgram.y" +{ yyval.p = op2(MINUS, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 135: +#line 355 "awkgram.y" +{ yyval.p = op2(MULT, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 136: +#line 356 "awkgram.y" +{ yyval.p = op2(DIVIDE, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 137: +#line 357 "awkgram.y" +{ yyval.p = op2(MOD, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 138: +#line 358 "awkgram.y" +{ yyval.p = op2(POWER, yypt[-2].yyv.p, yypt[-0].yyv.p); } break; +case 139: +#line 359 "awkgram.y" +{ yyval.p = op1(UMINUS, yypt[-0].yyv.p); } break; +case 140: +#line 360 "awkgram.y" +{ yyval.p = yypt[-0].yyv.p; } break; +case 141: +#line 361 "awkgram.y" +{ yyval.p = op1(NOT, notnull(yypt[-0].yyv.p)); } break; +case 142: +#line 362 "awkgram.y" +{ yyval.p = op2(BLTIN, (Node *) yypt[-2].yyv.i, rectonode()); } break; +case 143: +#line 363 "awkgram.y" +{ yyval.p = op2(BLTIN, (Node *) yypt[-3].yyv.i, yypt[-1].yyv.p); } break; +case 144: +#line 364 "awkgram.y" +{ yyval.p = op2(BLTIN, (Node *) yypt[-0].yyv.i, rectonode()); } break; +case 145: +#line 365 "awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-2].yyv.cp,CVAR), NIL); } break; +case 146: +#line 366 "awkgram.y" +{ yyval.p = op2(CALL, celltonode(yypt[-3].yyv.cp,CVAR), yypt[-1].yyv.p); } break; +case 147: +#line 367 "awkgram.y" +{ yyval.p = op1(PREDECR, yypt[-0].yyv.p); } break; +case 148: +#line 368 "awkgram.y" +{ yyval.p = op1(PREINCR, yypt[-0].yyv.p); } break; +case 149: +#line 369 "awkgram.y" +{ yyval.p = op1(POSTDECR, yypt[-1].yyv.p); } break; +case 150: +#line 370 "awkgram.y" +{ yyval.p = op1(POSTINCR, yypt[-1].yyv.p); } break; +case 151: +#line 371 "awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-2].yyv.p, (Node *)yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 152: +#line 372 "awkgram.y" +{ yyval.p = op3(GETLINE, NIL, (Node *)yypt[-1].yyv.i, yypt[-0].yyv.p); } break; +case 153: +#line 373 "awkgram.y" +{ yyval.p = op3(GETLINE, yypt[-0].yyv.p, NIL, NIL); } break; +case 154: +#line 374 "awkgram.y" +{ yyval.p = op3(GETLINE, NIL, NIL, NIL); } break; +case 155: +#line 376 "awkgram.y" +{ yyval.p = op2(INDEX, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 156: +#line 378 "awkgram.y" +{ ERROR "index() doesn't permit regular expressions" SYNTAX; + yyval.p = op2(INDEX, yypt[-3].yyv.p, (Node*)yypt[-1].yyv.s); } break; +case 157: +#line 380 "awkgram.y" +{ yyval.p = yypt[-1].yyv.p; } break; +case 158: +#line 382 "awkgram.y" +{ yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(yypt[-1].yyv.s, 1)); } break; +case 159: +#line 384 "awkgram.y" +{ if (constnode(yypt[-1].yyv.p)) + yyval.p = op3(MATCHFCN, NIL, yypt[-3].yyv.p, (Node*)makedfa(strnode(yypt[-1].yyv.p), 1)); + else + yyval.p = op3(MATCHFCN, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 160: +#line 388 "awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 161: +#line 390 "awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p, (Node*)STRING); } break; +case 162: +#line 392 "awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-5].yyv.p, makearr(yypt[-3].yyv.p), (Node*)makedfa(yypt[-1].yyv.s, 1), (Node *)REGEXPR); } break; +case 163: +#line 394 "awkgram.y" +{ yyval.p = op4(SPLIT, yypt[-3].yyv.p, makearr(yypt[-1].yyv.p), NIL, (Node*)STRING); } break; +case 164: +#line 395 "awkgram.y" +{ yyval.p = op1(yypt[-3].yyv.i, yypt[-1].yyv.p); } break; +case 165: +#line 396 "awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CCON); } break; +case 166: +#line 398 "awkgram.y" +{ yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(yypt[-3].yyv.s, 1), yypt[-1].yyv.p, rectonode()); } break; +case 167: +#line 400 "awkgram.y" +{ if (constnode(yypt[-3].yyv.p)) + yyval.p = op4(yypt[-5].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-3].yyv.p), 1), yypt[-1].yyv.p, rectonode()); + else + yyval.p = op4(yypt[-5].yyv.i, (Node *)1, yypt[-3].yyv.p, yypt[-1].yyv.p, rectonode()); } break; +case 168: +#line 405 "awkgram.y" +{ yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(yypt[-5].yyv.s, 1), yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 169: +#line 407 "awkgram.y" +{ if (constnode(yypt[-5].yyv.p)) + yyval.p = op4(yypt[-7].yyv.i, NIL, (Node*)makedfa(strnode(yypt[-5].yyv.p), 1), yypt[-3].yyv.p, yypt[-1].yyv.p); + else + yyval.p = op4(yypt[-7].yyv.i, (Node *)1, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 170: +#line 412 "awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-5].yyv.p, yypt[-3].yyv.p, yypt[-1].yyv.p); } break; +case 171: +#line 414 "awkgram.y" +{ yyval.p = op3(SUBSTR, yypt[-3].yyv.p, yypt[-1].yyv.p, NIL); } break; +case 174: +#line 420 "awkgram.y" +{ yyval.p = op2(ARRAY, makearr(yypt[-3].yyv.p), yypt[-1].yyv.p); } break; +case 175: +#line 421 "awkgram.y" +{ yyval.p = op1(INDIRECT, celltonode(yypt[-0].yyv.cp, CVAR)); } break; +case 176: +#line 422 "awkgram.y" +{ yyval.p = op1(INDIRECT, yypt[-0].yyv.p); } break; +case 177: +#line 426 "awkgram.y" +{ arglist = yyval.p = 0; } break; +case 178: +#line 427 "awkgram.y" +{ arglist = yyval.p = celltonode(yypt[-0].yyv.cp,CVAR); } break; +case 179: +#line 428 "awkgram.y" +{ + checkdup(yypt[-2].yyv.p, yypt[-0].yyv.cp); + arglist = yyval.p = linkum(yypt[-2].yyv.p,celltonode(yypt[-0].yyv.cp,CVAR)); } break; +case 180: +#line 434 "awkgram.y" +{ yyval.p = celltonode(yypt[-0].yyv.cp, CVAR); } break; +case 181: +#line 435 "awkgram.y" +{ yyval.p = op1(ARG, (Node *) yypt[-0].yyv.i); } break; +case 182: +#line 436 "awkgram.y" +{ yyval.p = op1(VARNF, (Node *) yypt[-0].yyv.cp); } break; +case 183: +#line 441 "awkgram.y" +{ yyval.p = notnull(yypt[-1].yyv.p); } break; + } + goto yystack; /* stack new state and value */ +} diff --git a/usr.bin/awk/ytabh.bak b/usr.bin/awk/ytabh.bak new file mode 100644 index 0000000..d18ddfd --- /dev/null +++ b/usr.bin/awk/ytabh.bak @@ -0,0 +1,100 @@ + +typedef union { + Node *p; + Cell *cp; + int i; + char *s; +} YYSTYPE; +extern YYSTYPE yylval; +#define FIRSTTOKEN 57346 +#define PROGRAM 57347 +#define PASTAT 57348 +#define PASTAT2 57349 +#define XBEGIN 57350 +#define XEND 57351 +#define NL 57352 +#define ARRAY 57353 +#define MATCH 57354 +#define NOTMATCH 57355 +#define MATCHOP 57356 +#define FINAL 57357 +#define DOT 57358 +#define ALL 57359 +#define CCL 57360 +#define NCCL 57361 +#define CHAR 57362 +#define OR 57363 +#define STAR 57364 +#define QUEST 57365 +#define PLUS 57366 +#define AND 57367 +#define BOR 57368 +#define APPEND 57369 +#define EQ 57370 +#define GE 57371 +#define GT 57372 +#define LE 57373 +#define LT 57374 +#define NE 57375 +#define IN 57376 +#define ARG 57377 +#define BLTIN 57378 +#define BREAK 57379 +#define CLOSE 57380 +#define CONTINUE 57381 +#define DELETE 57382 +#define DO 57383 +#define EXIT 57384 +#define FOR 57385 +#define FUNC 57386 +#define SUB 57387 +#define GSUB 57388 +#define IF 57389 +#define INDEX 57390 +#define LSUBSTR 57391 +#define MATCHFCN 57392 +#define NEXT 57393 +#define NEXTFILE 57394 +#define ADD 57395 +#define MINUS 57396 +#define MULT 57397 +#define DIVIDE 57398 +#define MOD 57399 +#define ASSIGN 57400 +#define ASGNOP 57401 +#define ADDEQ 57402 +#define SUBEQ 57403 +#define MULTEQ 57404 +#define DIVEQ 57405 +#define MODEQ 57406 +#define POWEQ 57407 +#define PRINT 57408 +#define PRINTF 57409 +#define SPRINTF 57410 +#define ELSE 57411 +#define INTEST 57412 +#define CONDEXPR 57413 +#define POSTINCR 57414 +#define PREINCR 57415 +#define POSTDECR 57416 +#define PREDECR 57417 +#define VAR 57418 +#define IVAR 57419 +#define VARNF 57420 +#define CALL 57421 +#define NUMBER 57422 +#define STRING 57423 +#define REGEXPR 57424 +#define GETLINE 57425 +#define RETURN 57426 +#define SPLIT 57427 +#define SUBSTR 57428 +#define WHILE 57429 +#define CAT 57430 +#define NOT 57431 +#define UMINUS 57432 +#define POWER 57433 +#define DECR 57434 +#define INCR 57435 +#define INDIRECT 57436 +#define LASTTOKEN 57437