mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-04-22 14:54:43 +00:00
parent
ee49b71be2
commit
2f1679e5cf
20 changed files with 11715 additions and 0 deletions
1
Makefile
1
Makefile
|
@ -158,6 +158,7 @@ include third_party/maxmind/maxmind.mk
|
||||||
include net/finger/finger.mk
|
include net/finger/finger.mk
|
||||||
include third_party/double-conversion/double-conversion.mk
|
include third_party/double-conversion/double-conversion.mk
|
||||||
include third_party/lua/lua.mk
|
include third_party/lua/lua.mk
|
||||||
|
include third_party/awk/awk.mk
|
||||||
include third_party/make/make.mk
|
include third_party/make/make.mk
|
||||||
include third_party/finger/finger.mk
|
include third_party/finger/finger.mk
|
||||||
include third_party/argon2/argon2.mk
|
include third_party/argon2/argon2.mk
|
||||||
|
|
23
third_party/awk/LICENSE
vendored
Normal file
23
third_party/awk/LICENSE
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/****************************************************************
|
||||||
|
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.
|
||||||
|
****************************************************************/
|
17
third_party/awk/README.cosmo
vendored
Normal file
17
third_party/awk/README.cosmo
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
DESCRIPTION
|
||||||
|
|
||||||
|
The One True Awk
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
SOURCE
|
||||||
|
|
||||||
|
https://github.com/onetrueawk/awk
|
||||||
|
|
||||||
|
commit b92d8cecd132ce8e02a373e28dd42e6be34d3d59
|
||||||
|
Author: ozan yigit <ozan.yigit@gmail.com>
|
||||||
|
Date: Mon May 30 11:34:52 2022 -0400
|
||||||
|
|
||||||
|
added YACC definition for byacc.
|
632
third_party/awk/awk.1
vendored
Normal file
632
third_party/awk/awk.1
vendored
Normal file
|
@ -0,0 +1,632 @@
|
||||||
|
.de EX
|
||||||
|
.nf
|
||||||
|
.ft CW
|
||||||
|
..
|
||||||
|
.de EE
|
||||||
|
.br
|
||||||
|
.fi
|
||||||
|
.ft 1
|
||||||
|
..
|
||||||
|
.de TF
|
||||||
|
.IP "" "\w'\fB\\$1\ \ \fP'u"
|
||||||
|
.PD 0
|
||||||
|
..
|
||||||
|
.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
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.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
|
||||||
|
.I 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
|
||||||
|
.I 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
|
||||||
|
.I 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 the 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
|
||||||
|
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]\fR'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 ] \fR)
|
||||||
|
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
|
||||||
|
.I 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 atan2 ,
|
||||||
|
.BR cos ,
|
||||||
|
.BR exp ,
|
||||||
|
.BR log ,
|
||||||
|
.BR sin ,
|
||||||
|
and
|
||||||
|
.B sqrt
|
||||||
|
are built in.
|
||||||
|
Other built-in functions:
|
||||||
|
.TF length
|
||||||
|
.TP
|
||||||
|
.B length
|
||||||
|
the length of its argument
|
||||||
|
taken as a string,
|
||||||
|
number of elements in an array for an array argument,
|
||||||
|
or length 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
|
||||||
|
\fBsubstr(\fIs\fB, \fIm\fR [\fB, \fIn\^\fR]\fB)\fR
|
||||||
|
the
|
||||||
|
.IR n -character
|
||||||
|
substring of
|
||||||
|
.I s
|
||||||
|
that begins at position
|
||||||
|
.I m
|
||||||
|
counted from 1.
|
||||||
|
If no
|
||||||
|
.IR n ,
|
||||||
|
use the rest of the string.
|
||||||
|
.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
|
||||||
|
\fBsplit(\fIs\fB, \fIa \fR[\fB, \fIfs\^\fR]\fB)\fR
|
||||||
|
splits the string
|
||||||
|
.I s
|
||||||
|
into array elements
|
||||||
|
.IB a [1] \fR,
|
||||||
|
.IB a [2] \fR,
|
||||||
|
\&...,
|
||||||
|
.IB a [ n ] \fR,
|
||||||
|
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
|
||||||
|
\fBsub(\fIr\fB, \fIt \fR[, \fIs\^\fR]\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
|
||||||
|
\fBgsub(\fIr\fB, \fIt \fR[, \fIs\^\fR]\fB)
|
||||||
|
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
|
||||||
|
.IR fmt .
|
||||||
|
.TP
|
||||||
|
.BI system( cmd )
|
||||||
|
executes
|
||||||
|
.I cmd
|
||||||
|
and returns its exit status. This will be \-1 upon error,
|
||||||
|
.IR cmd 's
|
||||||
|
exit status upon a normal exit,
|
||||||
|
256 +
|
||||||
|
.I sig
|
||||||
|
upon death-by-signal, where
|
||||||
|
.I sig
|
||||||
|
is the number of the murdering signal,
|
||||||
|
or 512 +
|
||||||
|
.I sig
|
||||||
|
if there was a core dump.
|
||||||
|
.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
|
||||||
|
.B ~
|
||||||
|
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
|
||||||
|
.I relop
|
||||||
|
is any of the six relational operators in C,
|
||||||
|
and a
|
||||||
|
.I 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.
|
||||||
|
They may appear multiple times in a program and execute
|
||||||
|
in the order they are read by
|
||||||
|
.IR awk .
|
||||||
|
.PP
|
||||||
|
Variable names with special meanings:
|
||||||
|
.TF FILENAME
|
||||||
|
.TP
|
||||||
|
.B ARGC
|
||||||
|
argument count, assignable.
|
||||||
|
.TP
|
||||||
|
.B ARGV
|
||||||
|
argument array, assignable;
|
||||||
|
non-null members are taken as filenames.
|
||||||
|
.TP
|
||||||
|
.B CONVFMT
|
||||||
|
conversion format used when converting numbers
|
||||||
|
(default
|
||||||
|
.BR "%.6g" ).
|
||||||
|
.TP
|
||||||
|
.B ENVIRON
|
||||||
|
array of environment variables; subscripts are names.
|
||||||
|
.TP
|
||||||
|
.B FILENAME
|
||||||
|
the name of the current input file.
|
||||||
|
.TP
|
||||||
|
.B FNR
|
||||||
|
ordinal number of the current record in the current file.
|
||||||
|
.TP
|
||||||
|
.B FS
|
||||||
|
regular expression used to separate fields; also settable
|
||||||
|
by option
|
||||||
|
.BI \-F fs\fR.
|
||||||
|
.TP
|
||||||
|
.BR NF
|
||||||
|
number of fields in the current record.
|
||||||
|
.TP
|
||||||
|
.B NR
|
||||||
|
ordinal number of the current record.
|
||||||
|
.TP
|
||||||
|
.B OFMT
|
||||||
|
output format for numbers (default
|
||||||
|
.BR "%.6g" ).
|
||||||
|
.TP
|
||||||
|
.B OFS
|
||||||
|
output field separator (default space).
|
||||||
|
.TP
|
||||||
|
.B ORS
|
||||||
|
output record separator (default newline).
|
||||||
|
.TP
|
||||||
|
.B RLENGTH
|
||||||
|
the length of a string matched by
|
||||||
|
.BR match .
|
||||||
|
.TP
|
||||||
|
.B RS
|
||||||
|
input record separator (default newline).
|
||||||
|
If empty, blank lines separate records.
|
||||||
|
If more than one character long,
|
||||||
|
.B RS
|
||||||
|
is treated as a regular expression, and records are
|
||||||
|
separated by text matching the expression.
|
||||||
|
.TP
|
||||||
|
.B RSTART
|
||||||
|
the start position of a string matched by
|
||||||
|
.BR match .
|
||||||
|
.TP
|
||||||
|
.B SUBSEP
|
||||||
|
separates multiple subscripts (default 034).
|
||||||
|
.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 ENVIRONMENT VARIABLES
|
||||||
|
If
|
||||||
|
.B POSIXLY_CORRECT
|
||||||
|
is set in the environment, then
|
||||||
|
.I awk
|
||||||
|
follows the POSIX rules for
|
||||||
|
.B sub
|
||||||
|
and
|
||||||
|
.B gsub
|
||||||
|
with respect to consecutive backslashes and ampersands.
|
||||||
|
.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 spaces 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 grep (1),
|
||||||
|
.IR lex (1),
|
||||||
|
.IR sed (1)
|
||||||
|
.br
|
||||||
|
A. V. Aho, B. W. Kernighan, P. J. Weinberger,
|
||||||
|
.IR "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.
|
||||||
|
.PP
|
||||||
|
The scope rules for variables in functions are a botch;
|
||||||
|
the syntax is worse.
|
||||||
|
.PP
|
||||||
|
Only eight-bit characters sets are handled correctly.
|
||||||
|
.SH UNUSUAL FLOATING-POINT VALUES
|
||||||
|
.I Awk
|
||||||
|
was designed before IEEE 754 arithmetic defined Not-A-Number (NaN)
|
||||||
|
and Infinity values, which are supported by all modern floating-point
|
||||||
|
hardware.
|
||||||
|
.PP
|
||||||
|
Because
|
||||||
|
.I awk
|
||||||
|
uses
|
||||||
|
.IR strtod (3)
|
||||||
|
and
|
||||||
|
.IR atof (3)
|
||||||
|
to convert string values to double-precision floating-point values,
|
||||||
|
modern C libraries also convert strings starting with
|
||||||
|
.B inf
|
||||||
|
and
|
||||||
|
.B nan
|
||||||
|
into infinity and NaN values respectively. This led to strange results,
|
||||||
|
with something like this:
|
||||||
|
.PP
|
||||||
|
.EX
|
||||||
|
.nf
|
||||||
|
echo nancy | awk '{ print $1 + 0 }'
|
||||||
|
.fi
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
printing
|
||||||
|
.B nan
|
||||||
|
instead of zero.
|
||||||
|
.PP
|
||||||
|
.I Awk
|
||||||
|
now follows GNU AWK, and prefilters string values before attempting
|
||||||
|
to convert them to numbers, as follows:
|
||||||
|
.TP
|
||||||
|
.I "Hexadecimal values"
|
||||||
|
Hexadecimal values (allowed since C99) convert to zero, as they did
|
||||||
|
prior to C99.
|
||||||
|
.TP
|
||||||
|
.I "NaN values"
|
||||||
|
The two strings
|
||||||
|
.B +nan
|
||||||
|
and
|
||||||
|
.B \-nan
|
||||||
|
(case independent) convert to NaN. No others do.
|
||||||
|
(NaNs can have signs.)
|
||||||
|
.TP
|
||||||
|
.I "Infinity values"
|
||||||
|
The two strings
|
||||||
|
.B +inf
|
||||||
|
and
|
||||||
|
.B \-inf
|
||||||
|
(case independent) convert to positive and negative infinity, respectively.
|
||||||
|
No others do.
|
258
third_party/awk/awk.h
vendored
Normal file
258
third_party/awk/awk.h
vendored
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#if __STDC_VERSION__ <= 199901L
|
||||||
|
#define noreturn
|
||||||
|
#else
|
||||||
|
#include <stdnoreturn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef double Awkfloat;
|
||||||
|
|
||||||
|
/* unsigned char is more trouble than it's worth */
|
||||||
|
|
||||||
|
typedef unsigned char uschar;
|
||||||
|
|
||||||
|
#define xfree(a) { if ((a) != NULL) { free((void *)(intptr_t)(a)); (a) = NULL; } }
|
||||||
|
/*
|
||||||
|
* We sometimes cheat writing read-only pointers to NUL-terminate them
|
||||||
|
* and then put back the original value
|
||||||
|
*/
|
||||||
|
#define setptr(ptr, a) (*(char *)(intptr_t)(ptr)) = (a)
|
||||||
|
|
||||||
|
#define NN(p) ((p) ? (p) : "(null)") /* guaranteed non-null for DPRINTF
|
||||||
|
*/
|
||||||
|
#define DEBUG
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define DPRINTF(...) if (dbg) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define DPRINTF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern enum compile_states {
|
||||||
|
RUNNING,
|
||||||
|
COMPILING,
|
||||||
|
ERROR_PRINTING
|
||||||
|
} compile_time;
|
||||||
|
|
||||||
|
extern bool safe; /* false => unsafe, true => safe */
|
||||||
|
|
||||||
|
#define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */
|
||||||
|
extern int recsize; /* size of current record, orig RECSIZE */
|
||||||
|
|
||||||
|
extern char EMPTY[]; /* this avoid -Wwritable-strings issues */
|
||||||
|
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 bool donefld; /* true if record broken into fields */
|
||||||
|
extern bool donerec; /* true if record is valid (no fld has changed */
|
||||||
|
extern int dbg;
|
||||||
|
|
||||||
|
extern const 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 */
|
||||||
|
int tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE|CONVC|CONVO */
|
||||||
|
char *fmt; /* CONVFMT/OFMT value used to convert from number */
|
||||||
|
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 *fsloc; /* FS */
|
||||||
|
extern Cell *nfloc; /* NF */
|
||||||
|
extern Cell *ofsloc; /* OFS */
|
||||||
|
extern Cell *orsloc; /* ORS */
|
||||||
|
extern Cell *rsloc; /* RS */
|
||||||
|
extern Cell *rstartloc; /* RSTART */
|
||||||
|
extern Cell *rlengthloc; /* RLENGTH */
|
||||||
|
extern Cell *subseploc; /* SUBSEP */
|
||||||
|
extern Cell *symtabloc; /* SYMTAB */
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
#define CONVC 0400 /* string was converted from number via CONVFMT */
|
||||||
|
#define CONVO 01000 /* string was converted from number via OFMT */
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 || (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+3) /* 256 handles 8-bit chars; 128 does 7-bit */
|
||||||
|
/* watch out in match(), etc. */
|
||||||
|
#define HAT (NCHARS+2) /* matches ^ in regular expr */
|
||||||
|
#define NSTATES 32
|
||||||
|
|
||||||
|
typedef struct rrow {
|
||||||
|
long ltype; /* long avoids pointer warnings on 64-bit */
|
||||||
|
union {
|
||||||
|
int i;
|
||||||
|
Node *np;
|
||||||
|
uschar *up;
|
||||||
|
} lval; /* because Al stores a pointer in it! */
|
||||||
|
int *lfollow;
|
||||||
|
} rrow;
|
||||||
|
|
||||||
|
typedef struct fa {
|
||||||
|
unsigned int **gototab;
|
||||||
|
uschar *out;
|
||||||
|
uschar *restr;
|
||||||
|
int **posns;
|
||||||
|
int state_count;
|
||||||
|
bool anchor;
|
||||||
|
int use;
|
||||||
|
int initstat;
|
||||||
|
int curstat;
|
||||||
|
int accept;
|
||||||
|
struct rrow re[1]; /* variable: actual size set by calling malloc */
|
||||||
|
} fa;
|
||||||
|
|
||||||
|
|
||||||
|
#include "proto.h"
|
67
third_party/awk/awk.mk
vendored
Normal file
67
third_party/awk/awk.mk
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||||
|
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||||
|
|
||||||
|
PKGS += THIRD_PARTY_AWK
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_SRCS = $(THIRD_PARTY_AWK_A_SRCS)
|
||||||
|
THIRD_PARTY_AWK_HDRS = $(THIRD_PARTY_AWK_A_HDRS)
|
||||||
|
THIRD_PARTY_AWK_INCS = $(THIRD_PARTY_AWK_A_INCS)
|
||||||
|
THIRD_PARTY_AWK_BINS = $(THIRD_PARTY_AWK_COMS) $(THIRD_PARTY_AWK_COMS:%=%.dbg)
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_ARTIFACTS += THIRD_PARTY_AWK_A
|
||||||
|
THIRD_PARTY_AWK = $(THIRD_PARTY_AWK_A_DEPS) $(THIRD_PARTY_AWK_A)
|
||||||
|
THIRD_PARTY_AWK_A = o/$(MODE)/third_party/awk/awk.a
|
||||||
|
THIRD_PARTY_AWK_A_FILES := $(wildcard third_party/awk/*)
|
||||||
|
THIRD_PARTY_AWK_A_HDRS = $(filter %.h,$(THIRD_PARTY_AWK_A_FILES))
|
||||||
|
THIRD_PARTY_AWK_A_INCS = $(filter %.inc,$(THIRD_PARTY_AWK_A_FILES))
|
||||||
|
THIRD_PARTY_AWK_A_SRCS = $(filter %.c,$(THIRD_PARTY_AWK_A_FILES))
|
||||||
|
THIRD_PARTY_AWK_A_OBJS = $(THIRD_PARTY_AWK_A_SRCS:%.c=o/$(MODE)/%.o)
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_A_DIRECTDEPS = \
|
||||||
|
LIBC_FMT \
|
||||||
|
LIBC_INTRIN \
|
||||||
|
LIBC_MEM \
|
||||||
|
LIBC_NEXGEN32E \
|
||||||
|
LIBC_RUNTIME \
|
||||||
|
LIBC_CALLS \
|
||||||
|
LIBC_STDIO \
|
||||||
|
LIBC_SYSV \
|
||||||
|
LIBC_STR \
|
||||||
|
LIBC_STUBS
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_A_DEPS := \
|
||||||
|
$(call uniq,$(foreach x,$(THIRD_PARTY_AWK_A_DIRECTDEPS),$($(x))))
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_A_CHECKS = \
|
||||||
|
$(THIRD_PARTY_AWK_A).pkg \
|
||||||
|
$(THIRD_PARTY_AWK_A_HDRS:%=o/$(MODE)/%.ok)
|
||||||
|
|
||||||
|
$(THIRD_PARTY_AWK_A): \
|
||||||
|
third_party/awk/ \
|
||||||
|
$(THIRD_PARTY_AWK_A).pkg \
|
||||||
|
$(THIRD_PARTY_AWK_A_OBJS)
|
||||||
|
|
||||||
|
$(THIRD_PARTY_AWK_A).pkg: \
|
||||||
|
$(THIRD_PARTY_AWK_A_OBJS) \
|
||||||
|
$(foreach x,$(THIRD_PARTY_AWK_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
|
o/$(MODE)/third_party/awk/awk.com.dbg: \
|
||||||
|
$(THIRD_PARTY_AWK) \
|
||||||
|
o/$(MODE)/third_party/awk/awk.o \
|
||||||
|
$(CRT) \
|
||||||
|
$(APE_NO_MODIFY_SELF)
|
||||||
|
@$(APELINK)
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_COMS = \
|
||||||
|
o/$(MODE)/third_party/awk/awk.com
|
||||||
|
|
||||||
|
THIRD_PARTY_AWK_LIBS = $(foreach x,$(THIRD_PARTY_AWK_ARTIFACTS),$($(x)))
|
||||||
|
THIRD_PARTY_AWK_SRCS = $(foreach x,$(THIRD_PARTY_AWK_ARTIFACTS),$($(x)_SRCS))
|
||||||
|
THIRD_PARTY_AWK_CHECKS = $(foreach x,$(THIRD_PARTY_AWK_ARTIFACTS),$($(x)_CHECKS))
|
||||||
|
THIRD_PARTY_AWK_OBJS = $(foreach x,$(THIRD_PARTY_AWK_ARTIFACTS),$($(x)_OBJS))
|
||||||
|
$(THIRD_PARTY_AWK_OBJS): $(BUILD_FILES) third_party/awk/awk.mk
|
||||||
|
|
||||||
|
.PHONY: o/$(MODE)/third_party/awk
|
||||||
|
o/$(MODE)/third_party/awk: \
|
||||||
|
$(THIRD_PARTY_AWK_BINS) \
|
||||||
|
$(THIRD_PARTY_AWK_CHECKS)
|
3392
third_party/awk/awkgram.tab.c
vendored
Normal file
3392
third_party/awk/awkgram.tab.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
115
third_party/awk/awkgram.tab.h
vendored
Normal file
115
third_party/awk/awkgram.tab.h
vendored
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#ifndef COSMOPOLITAN_THIRD_PARTY_AWK_AWKGRAM_TAB_H_
|
||||||
|
#define COSMOPOLITAN_THIRD_PARTY_AWK_AWKGRAM_TAB_H_
|
||||||
|
#include "third_party/awk/awk.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define FIRSTTOKEN 257
|
||||||
|
#define PROGRAM 258
|
||||||
|
#define PASTAT 259
|
||||||
|
#define PASTAT2 260
|
||||||
|
#define XBEGIN 261
|
||||||
|
#define XEND 262
|
||||||
|
#define NL 263
|
||||||
|
#define ARRAY 264
|
||||||
|
#define MATCH 265
|
||||||
|
#define NOTMATCH 266
|
||||||
|
#define MATCHOP 267
|
||||||
|
#define FINAL 268
|
||||||
|
#define DOT 269
|
||||||
|
#define ALL 270
|
||||||
|
#define CCL 271
|
||||||
|
#define NCCL 272
|
||||||
|
#define CHAR 273
|
||||||
|
#define OR 274
|
||||||
|
#define STAR 275
|
||||||
|
#define QUEST 276
|
||||||
|
#define PLUS 277
|
||||||
|
#define EMPTYRE 278
|
||||||
|
#define ZERO 279
|
||||||
|
#define AND 280
|
||||||
|
#define BOR 281
|
||||||
|
#define APPEND 282
|
||||||
|
#define EQ 283
|
||||||
|
#define GE 284
|
||||||
|
#define GT 285
|
||||||
|
#define LE 286
|
||||||
|
#define LT 287
|
||||||
|
#define NE 288
|
||||||
|
#define IN 289
|
||||||
|
#define ARG 290
|
||||||
|
#define BLTIN 291
|
||||||
|
#define BREAK 292
|
||||||
|
#define CLOSE 293
|
||||||
|
#define CONTINUE 294
|
||||||
|
#define DELETE 295
|
||||||
|
#define DO 296
|
||||||
|
#define EXIT 297
|
||||||
|
#define FOR 298
|
||||||
|
#define FUNC 299
|
||||||
|
#define SUB 300
|
||||||
|
#define GSUB 301
|
||||||
|
#define IF 302
|
||||||
|
#define INDEX 303
|
||||||
|
#define LSUBSTR 304
|
||||||
|
#define MATCHFCN 305
|
||||||
|
#define NEXT 306
|
||||||
|
#define NEXTFILE 307
|
||||||
|
#define ADD 308
|
||||||
|
#define MINUS 309
|
||||||
|
#define MULT 310
|
||||||
|
#define DIVIDE 311
|
||||||
|
#define MOD 312
|
||||||
|
#define ASSIGN 313
|
||||||
|
#define ASGNOP 314
|
||||||
|
#define ADDEQ 315
|
||||||
|
#define SUBEQ 316
|
||||||
|
#define MULTEQ 317
|
||||||
|
#define DIVEQ 318
|
||||||
|
#define MODEQ 319
|
||||||
|
#define POWEQ 320
|
||||||
|
#define PRINT 321
|
||||||
|
#define PRINTF 322
|
||||||
|
#define SPRINTF 323
|
||||||
|
#define ELSE 324
|
||||||
|
#define INTEST 325
|
||||||
|
#define CONDEXPR 326
|
||||||
|
#define POSTINCR 327
|
||||||
|
#define PREINCR 328
|
||||||
|
#define POSTDECR 329
|
||||||
|
#define PREDECR 330
|
||||||
|
#define VAR 331
|
||||||
|
#define IVAR 332
|
||||||
|
#define VARNF 333
|
||||||
|
#define CALL 334
|
||||||
|
#define NUMBER 335
|
||||||
|
#define STRING 336
|
||||||
|
#define REGEXPR 337
|
||||||
|
#define GETLINE 338
|
||||||
|
#define RETURN 339
|
||||||
|
#define SPLIT 340
|
||||||
|
#define SUBSTR 341
|
||||||
|
#define WHILE 342
|
||||||
|
#define CAT 343
|
||||||
|
#define NOT 344
|
||||||
|
#define UMINUS 345
|
||||||
|
#define UPLUS 346
|
||||||
|
#define POWER 347
|
||||||
|
#define DECR 348
|
||||||
|
#define INCR 349
|
||||||
|
#define INDIRECT 350
|
||||||
|
#define LASTTOKEN 351
|
||||||
|
#ifndef YYSTYPE_DEFINED
|
||||||
|
#define YYSTYPE_DEFINED
|
||||||
|
typedef union {
|
||||||
|
Node *p;
|
||||||
|
Cell *cp;
|
||||||
|
int i;
|
||||||
|
char *s;
|
||||||
|
} YYSTYPE;
|
||||||
|
#endif /* YYSTYPE_DEFINED */
|
||||||
|
extern YYSTYPE yylval;
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_THIRD_PARTY_AWK_AWKGRAM_TAB_H_ */
|
492
third_party/awk/awkgram.y
vendored
Normal file
492
third_party/awk/awkgram.y
vendored
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "awk.h"
|
||||||
|
|
||||||
|
void checkdup(Node *list, Cell *item);
|
||||||
|
int yywrap(void) { return(1); }
|
||||||
|
|
||||||
|
Node *beginloc = 0;
|
||||||
|
Node *endloc = 0;
|
||||||
|
bool infunc = false; /* = true if in arglist or body of func */
|
||||||
|
int inloop = 0; /* >= 1 if in while, for, do; can't be bool, since loops can next */
|
||||||
|
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 <i> FIRSTTOKEN /* must be first */
|
||||||
|
%token <p> PROGRAM PASTAT PASTAT2 XBEGIN XEND
|
||||||
|
%token <i> NL ',' '{' '(' '|' ';' '/' ')' '}' '[' ']'
|
||||||
|
%token <i> ARRAY
|
||||||
|
%token <i> MATCH NOTMATCH MATCHOP
|
||||||
|
%token <i> FINAL DOT ALL CCL NCCL CHAR OR STAR QUEST PLUS EMPTYRE ZERO
|
||||||
|
%token <i> AND BOR APPEND EQ GE GT LE LT NE IN
|
||||||
|
%token <i> ARG BLTIN BREAK CLOSE CONTINUE DELETE DO EXIT FOR FUNC
|
||||||
|
%token <i> SUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NEXTFILE
|
||||||
|
%token <i> ADD MINUS MULT DIVIDE MOD
|
||||||
|
%token <i> ASSIGN ASGNOP ADDEQ SUBEQ MULTEQ DIVEQ MODEQ POWEQ
|
||||||
|
%token <i> PRINT PRINTF SPRINTF
|
||||||
|
%token <p> ELSE INTEST CONDEXPR
|
||||||
|
%token <i> POSTINCR PREINCR POSTDECR PREDECR
|
||||||
|
%token <cp> VAR IVAR VARNF CALL NUMBER STRING
|
||||||
|
%token <s> REGEXPR
|
||||||
|
|
||||||
|
%type <p> pas pattern ppattern plist pplist patlist prarg term re
|
||||||
|
%type <p> pa_pat pa_stat pa_stats
|
||||||
|
%type <s> reg_expr
|
||||||
|
%type <p> simple_stmt opt_simple_stmt stmt stmtlist
|
||||||
|
%type <p> var varname funcname varlist
|
||||||
|
%type <p> for if else while
|
||||||
|
%type <i> do st
|
||||||
|
%type <i> pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor
|
||||||
|
%type <i> subop print
|
||||||
|
%type <cp> string
|
||||||
|
|
||||||
|
%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 UPLUS
|
||||||
|
%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(); SYNTAX("bailing out"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
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 ',' opt_nl pa_pat { $$ = pa2stat($1, $4, stat2(PRINT, rectonode(), NIL)); }
|
||||||
|
| pa_pat ',' opt_nl pa_pat lbrace stmtlist '}' { $$ = pa2stat($1, $4, $6); }
|
||||||
|
| 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 = true;} lbrace stmtlist '}'
|
||||||
|
{ infunc = false; 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) SYNTAX("cmd | getline is unsafe");
|
||||||
|
else $$ = op3(GETLINE, $4, itonp($2), $1); }
|
||||||
|
| pattern '|' GETLINE {
|
||||||
|
if (safe) SYNTAX("cmd | getline is unsafe");
|
||||||
|
else $$ = op3(GETLINE, (Node*)0, itonp($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) SYNTAX("print | is unsafe");
|
||||||
|
else $$ = stat3($1, $2, itonp($3), $4); }
|
||||||
|
| print prarg APPEND term {
|
||||||
|
if (safe) SYNTAX("print >> is unsafe");
|
||||||
|
else $$ = stat3($1, $2, itonp($3), $4); }
|
||||||
|
| print prarg GT term {
|
||||||
|
if (safe) SYNTAX("print > is unsafe");
|
||||||
|
else $$ = stat3($1, $2, itonp($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; SYNTAX("illegal statement"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
st:
|
||||||
|
nl
|
||||||
|
| ';' opt_nl
|
||||||
|
;
|
||||||
|
|
||||||
|
stmt:
|
||||||
|
BREAK st { if (!inloop) SYNTAX("break illegal outside of loops");
|
||||||
|
$$ = stat1(BREAK, NIL); }
|
||||||
|
| CONTINUE st { if (!inloop) SYNTAX("continue illegal outside of loops");
|
||||||
|
$$ = 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)
|
||||||
|
SYNTAX("next is illegal inside a function");
|
||||||
|
$$ = stat1(NEXT, NIL); }
|
||||||
|
| NEXTFILE st { if (infunc)
|
||||||
|
SYNTAX("nextfile is illegal inside a function");
|
||||||
|
$$ = 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
|
||||||
|
;
|
||||||
|
|
||||||
|
string:
|
||||||
|
STRING
|
||||||
|
| string STRING { $$ = catstr($1, $2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
term:
|
||||||
|
term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); }
|
||||||
|
| 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 { $$ = op1(UPLUS, $2); }
|
||||||
|
| NOT term %prec UMINUS { $$ = op1(NOT, notnull($2)); }
|
||||||
|
| BLTIN '(' ')' { $$ = op2(BLTIN, itonp($1), rectonode()); }
|
||||||
|
| BLTIN '(' patlist ')' { $$ = op2(BLTIN, itonp($1), $3); }
|
||||||
|
| BLTIN { $$ = op2(BLTIN, itonp($1), rectonode()); }
|
||||||
|
| CALL '(' ')' { $$ = op2(CALL, celltonode($1,CVAR), NIL); }
|
||||||
|
| CALL '(' patlist ')' { $$ = op2(CALL, celltonode($1,CVAR), $3); }
|
||||||
|
| CLOSE term { $$ = op1(CLOSE, $2); }
|
||||||
|
| 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, itonp($3), $4); }
|
||||||
|
| GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($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 ')'
|
||||||
|
{ SYNTAX("index() doesn't permit regular expressions");
|
||||||
|
$$ = 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, itonp($1)); }
|
||||||
|
| VARNF { $$ = op1(VARNF, (Node *) $1); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
while:
|
||||||
|
WHILE '(' pattern rparen { $$ = notnull($3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
void setfname(Cell *p)
|
||||||
|
{
|
||||||
|
if (isarr(p))
|
||||||
|
SYNTAX("%s is an array, not a function", p->nval);
|
||||||
|
else if (isfcn(p))
|
||||||
|
SYNTAX("you can't define function %s more than once", p->nval);
|
||||||
|
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) {
|
||||||
|
SYNTAX("duplicate argument %s", s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1341
third_party/awk/b.c
vendored
Normal file
1341
third_party/awk/b.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
601
third_party/awk/lex.c
vendored
Normal file
601
third_party/awk/lex.c
vendored
Normal file
|
@ -0,0 +1,601 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "awk.h"
|
||||||
|
#include "awkgram.tab.h"
|
||||||
|
|
||||||
|
extern YYSTYPE yylval;
|
||||||
|
extern bool infunc;
|
||||||
|
|
||||||
|
int lineno = 1;
|
||||||
|
int bracecnt = 0;
|
||||||
|
int brackcnt = 0;
|
||||||
|
int parencnt = 0;
|
||||||
|
|
||||||
|
typedef struct Keyword {
|
||||||
|
const char *word;
|
||||||
|
int sub;
|
||||||
|
int type;
|
||||||
|
} Keyword;
|
||||||
|
|
||||||
|
const 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 RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
|
||||||
|
|
||||||
|
static int peek(void)
|
||||||
|
{
|
||||||
|
int c = input();
|
||||||
|
unput(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gettok(char **pbuf, int *psz) /* get next input token */
|
||||||
|
{
|
||||||
|
int c, retc;
|
||||||
|
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, "gettok"))
|
||||||
|
FATAL( "out of space for name %.10s...", buf );
|
||||||
|
if (isalnum(c) || c == '_')
|
||||||
|
*bp++ = c;
|
||||||
|
else {
|
||||||
|
*bp = 0;
|
||||||
|
unput(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*bp = 0;
|
||||||
|
retc = 'a'; /* alphanumeric */
|
||||||
|
} else { /* maybe it's a number, but could be . */
|
||||||
|
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, "gettok"))
|
||||||
|
FATAL( "out of space for number %.10s...", buf );
|
||||||
|
if (isdigit(c) || c == 'e' || c == 'E'
|
||||||
|
|| c == '.' || c == '+' || c == '-')
|
||||||
|
*bp++ = c;
|
||||||
|
else {
|
||||||
|
unput(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*bp = 0;
|
||||||
|
strtod(buf, &rem); /* parse the number */
|
||||||
|
if (rem == buf) { /* it wasn't a valid number at all */
|
||||||
|
buf[1] = 0; /* return one character as token */
|
||||||
|
retc = (uschar)buf[0]; /* character is its own type */
|
||||||
|
unputstr(rem+1); /* put rest back for later */
|
||||||
|
} else { /* some prefix was a number */
|
||||||
|
unputstr(rem); /* put rest back for later */
|
||||||
|
rem[0] = 0; /* truncate buf after number part */
|
||||||
|
retc = '0'; /* type is number */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pbuf = buf;
|
||||||
|
*psz = sz;
|
||||||
|
return retc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int word(char *);
|
||||||
|
int string(void);
|
||||||
|
int regexpr(void);
|
||||||
|
bool sc = false; /* true => return a } right now */
|
||||||
|
bool reg = false; /* true => return a REGEXPR now */
|
||||||
|
|
||||||
|
int yylex(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
static char *buf = NULL;
|
||||||
|
static int bufsize = 5; /* BUG: setting this small causes core dump! */
|
||||||
|
|
||||||
|
if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL)
|
||||||
|
FATAL( "out of space in yylex" );
|
||||||
|
if (sc) {
|
||||||
|
sc = false;
|
||||||
|
RET('}');
|
||||||
|
}
|
||||||
|
if (reg) {
|
||||||
|
reg = false;
|
||||||
|
return regexpr();
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
c = gettok(&buf, &bufsize);
|
||||||
|
if (c == 0)
|
||||||
|
return 0;
|
||||||
|
if (isalpha(c) || c == '_')
|
||||||
|
return word(buf);
|
||||||
|
if (isdigit(c)) {
|
||||||
|
char *cp = tostring(buf);
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if (is_number(cp, & result))
|
||||||
|
yylval.cp = setsymtab(buf, cp, result, CON|NUM, symtab);
|
||||||
|
else
|
||||||
|
yylval.cp = setsymtab(buf, cp, 0.0, STR, symtab);
|
||||||
|
free(cp);
|
||||||
|
/* should this also have STR set? */
|
||||||
|
RET(NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
yylval.i = c;
|
||||||
|
switch (c) {
|
||||||
|
case '\n': /* {EOL} */
|
||||||
|
lineno++;
|
||||||
|
RET(NL);
|
||||||
|
case '\r': /* assume \n is coming */
|
||||||
|
case ' ': /* {WS}+ */
|
||||||
|
case '\t':
|
||||||
|
break;
|
||||||
|
case '#': /* #.* strip comments */
|
||||||
|
while ((c = input()) != '\n' && c != 0)
|
||||||
|
;
|
||||||
|
unput(c);
|
||||||
|
/*
|
||||||
|
* Next line is a hack, itcompensates for
|
||||||
|
* unput's treatment of \n.
|
||||||
|
*/
|
||||||
|
lineno++;
|
||||||
|
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 '/':
|
||||||
|
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 (isalpha(c)) {
|
||||||
|
if (strcmp(buf, "NF") == 0) { /* very special */
|
||||||
|
unputstr("(NF)");
|
||||||
|
RET(INDIRECT);
|
||||||
|
}
|
||||||
|
c = peek();
|
||||||
|
if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
|
||||||
|
unputstr(buf);
|
||||||
|
RET(INDIRECT);
|
||||||
|
}
|
||||||
|
yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
|
||||||
|
RET(IVAR);
|
||||||
|
} else if (c == 0) { /* */
|
||||||
|
SYNTAX( "unexpected end of input after $" );
|
||||||
|
RET(';');
|
||||||
|
} else {
|
||||||
|
unputstr(buf);
|
||||||
|
RET(INDIRECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
case '}':
|
||||||
|
if (--bracecnt < 0)
|
||||||
|
SYNTAX( "extra }" );
|
||||||
|
sc = true;
|
||||||
|
RET(';');
|
||||||
|
case ']':
|
||||||
|
if (--brackcnt < 0)
|
||||||
|
SYNTAX( "extra ]" );
|
||||||
|
RET(']');
|
||||||
|
case ')':
|
||||||
|
if (--parencnt < 0)
|
||||||
|
SYNTAX( "extra )" );
|
||||||
|
RET(')');
|
||||||
|
case '{':
|
||||||
|
bracecnt++;
|
||||||
|
RET('{');
|
||||||
|
case '[':
|
||||||
|
brackcnt++;
|
||||||
|
RET('[');
|
||||||
|
case '(':
|
||||||
|
parencnt++;
|
||||||
|
RET('(');
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
return string(); /* BUG: should be like tran.c ? */
|
||||||
|
|
||||||
|
default:
|
||||||
|
RET(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int string(void)
|
||||||
|
{
|
||||||
|
int c, n;
|
||||||
|
char *s, *bp;
|
||||||
|
static char *buf = NULL;
|
||||||
|
static int bufsz = 500;
|
||||||
|
|
||||||
|
if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
|
||||||
|
FATAL("out of space for strings");
|
||||||
|
for (bp = buf; (c = input()) != '"'; ) {
|
||||||
|
if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
|
||||||
|
FATAL("out of space for string %.10s...", buf);
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case 0:
|
||||||
|
*bp = '\0';
|
||||||
|
SYNTAX( "non-terminated string %.10s...", buf );
|
||||||
|
if (c == 0) /* hopeless */
|
||||||
|
FATAL( "giving up" );
|
||||||
|
lineno++;
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
c = input();
|
||||||
|
switch (c) {
|
||||||
|
case '\n': break;
|
||||||
|
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", (unsigned int *) &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);
|
||||||
|
free(s);
|
||||||
|
RET(STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int binsearch(char *w, const 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)
|
||||||
|
{
|
||||||
|
const Keyword *kp;
|
||||||
|
int c, n;
|
||||||
|
|
||||||
|
n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
|
||||||
|
if (n != -1) { /* found in table */
|
||||||
|
kp = keywords + n;
|
||||||
|
yylval.i = kp->sub;
|
||||||
|
switch (kp->type) { /* special handling */
|
||||||
|
case BLTIN:
|
||||||
|
if (kp->sub == FSYSTEM && safe)
|
||||||
|
SYNTAX( "system is unsafe" );
|
||||||
|
RET(kp->type);
|
||||||
|
case FUNC:
|
||||||
|
if (infunc)
|
||||||
|
SYNTAX( "illegal nested function" );
|
||||||
|
RET(kp->type);
|
||||||
|
case RETURN:
|
||||||
|
if (!infunc)
|
||||||
|
SYNTAX( "return not in function" );
|
||||||
|
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 yylex will return a regular expression */
|
||||||
|
{
|
||||||
|
reg = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int regexpr(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
static char *buf = NULL;
|
||||||
|
static int bufsz = 500;
|
||||||
|
char *bp;
|
||||||
|
|
||||||
|
if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
|
||||||
|
FATAL("out of space for rex expr");
|
||||||
|
bp = buf;
|
||||||
|
for ( ; (c = input()) != '/' && c != 0; ) {
|
||||||
|
if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
|
||||||
|
FATAL("out of space for reg expr %.10s...", buf);
|
||||||
|
if (c == '\n') {
|
||||||
|
*bp = '\0';
|
||||||
|
SYNTAX( "newline in regular expression %.10s...", buf );
|
||||||
|
unput('\n');
|
||||||
|
break;
|
||||||
|
} else if (c == '\\') {
|
||||||
|
*bp++ = '\\';
|
||||||
|
*bp++ = input();
|
||||||
|
} else {
|
||||||
|
*bp++ = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*bp = 0;
|
||||||
|
if (c == 0)
|
||||||
|
SYNTAX("non-terminated regular expression %.10s...", buf);
|
||||||
|
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 = NULL;
|
||||||
|
|
||||||
|
int input(void) /* get next lexical input character */
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
extern char *lexprog;
|
||||||
|
|
||||||
|
if (yysptr > yysbuf)
|
||||||
|
c = (uschar)*--yysptr;
|
||||||
|
else if (lexprog != NULL) { /* awk '...' */
|
||||||
|
if ((c = (uschar)*lexprog) != 0)
|
||||||
|
lexprog++;
|
||||||
|
} else /* awk -f ... */
|
||||||
|
c = pgetc();
|
||||||
|
if (c == EOF)
|
||||||
|
c = 0;
|
||||||
|
if (ep >= ebuf + sizeof ebuf)
|
||||||
|
ep = ebuf;
|
||||||
|
*ep = c;
|
||||||
|
if (c != 0) {
|
||||||
|
ep++;
|
||||||
|
}
|
||||||
|
return (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unput(int c) /* put lexical character back on input */
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
lineno--;
|
||||||
|
if (yysptr >= yysbuf + sizeof(yysbuf))
|
||||||
|
FATAL("pushed back too much: %.20s...", yysbuf);
|
||||||
|
*yysptr++ = c;
|
||||||
|
if (--ep < ebuf)
|
||||||
|
ep = ebuf + sizeof(ebuf) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unputstr(const char *s) /* put a string back on input */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = strlen(s)-1; i >= 0; i--)
|
||||||
|
unput(s[i]);
|
||||||
|
}
|
842
third_party/awk/lib.c
vendored
Normal file
842
third_party/awk/lib.c
vendored
Normal file
|
@ -0,0 +1,842 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "awk.h"
|
||||||
|
|
||||||
|
char EMPTY[] = { '\0' };
|
||||||
|
FILE *infile = NULL;
|
||||||
|
bool innew; /* true = infile has not been read by readrec */
|
||||||
|
char *file = EMPTY;
|
||||||
|
char *record;
|
||||||
|
int recsize = RECSIZE;
|
||||||
|
char *fields;
|
||||||
|
int fieldssize = RECSIZE;
|
||||||
|
|
||||||
|
Cell **fldtab; /* pointers to Cells */
|
||||||
|
static size_t len_inputFS = 0;
|
||||||
|
static char *inputFS = NULL; /* FS at time of input, for field splitting */
|
||||||
|
|
||||||
|
#define MAXFLD 2
|
||||||
|
int nfields = MAXFLD; /* last allocated slot for $i */
|
||||||
|
|
||||||
|
bool donefld; /* true = implies rec broken into fields */
|
||||||
|
bool donerec; /* true = 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, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL };
|
||||||
|
static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL };
|
||||||
|
|
||||||
|
void recinit(unsigned int n)
|
||||||
|
{
|
||||||
|
if ( (record = (char *) malloc(n)) == NULL
|
||||||
|
|| (fields = (char *) malloc(n+1)) == NULL
|
||||||
|
|| (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL
|
||||||
|
|| (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL)
|
||||||
|
FATAL("out of space for $0 and fields");
|
||||||
|
*record = '\0';
|
||||||
|
*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(**fldtab));
|
||||||
|
if (fldtab[i] == NULL)
|
||||||
|
FATAL("out of space in makefields %d", i);
|
||||||
|
*fldtab[i] = dollar1;
|
||||||
|
snprintf(temp, sizeof(temp), "%d", i);
|
||||||
|
fldtab[i]->nval = tostring(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initgetrec(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for (i = 1; i < *ARGC; i++) {
|
||||||
|
p = getargv(i); /* find 1st real filename */
|
||||||
|
if (p == NULL || *p == '\0') { /* deleted or zapped */
|
||||||
|
argno++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isclvar(p)) {
|
||||||
|
setsval(lookup("FILENAME", symtab), p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setclvar(p); /* a commandline assignment before filename */
|
||||||
|
argno++;
|
||||||
|
}
|
||||||
|
infile = stdin; /* no filenames, so use stdin */
|
||||||
|
innew = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POSIX specifies that fields are supposed to be evaluated as if they were
|
||||||
|
* split using the value of FS at the time that the record's value ($0) was
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* Since field-splitting is done lazily, we save the current value of FS
|
||||||
|
* whenever a new record is read in (implicitly or via getline), or when
|
||||||
|
* a new value is assigned to $0.
|
||||||
|
*/
|
||||||
|
void savefs(void)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
if ((len = strlen(getsval(fsloc))) < len_inputFS) {
|
||||||
|
strcpy(inputFS, *FS); /* for subsequent field splitting */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len_inputFS = len + 1;
|
||||||
|
inputFS = (char *) realloc(inputFS, len_inputFS);
|
||||||
|
if (inputFS == NULL)
|
||||||
|
FATAL("field separator %.10s... is too long", *FS);
|
||||||
|
memcpy(inputFS, *FS, len_inputFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool firsttime = true;
|
||||||
|
|
||||||
|
int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record */
|
||||||
|
{ /* note: cares whether buf == record */
|
||||||
|
int c;
|
||||||
|
char *buf = *pbuf;
|
||||||
|
uschar saveb0;
|
||||||
|
int bufsize = *pbufsize, savebufsize = bufsize;
|
||||||
|
|
||||||
|
if (firsttime) {
|
||||||
|
firsttime = false;
|
||||||
|
initgetrec();
|
||||||
|
}
|
||||||
|
DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
|
||||||
|
*RS, *FS, *ARGC, *FILENAME);
|
||||||
|
if (isrecord) {
|
||||||
|
donefld = false;
|
||||||
|
donerec = true;
|
||||||
|
savefs();
|
||||||
|
}
|
||||||
|
saveb0 = buf[0];
|
||||||
|
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 == NULL || *file == '\0') { /* deleted or 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)
|
||||||
|
FATAL("can't open file %s", file);
|
||||||
|
innew = true;
|
||||||
|
setfval(fnrloc, 0.0);
|
||||||
|
}
|
||||||
|
c = readrec(&buf, &bufsize, infile, innew);
|
||||||
|
if (innew)
|
||||||
|
innew = false;
|
||||||
|
if (c != 0 || buf[0] != '\0') { /* normal record */
|
||||||
|
if (isrecord) {
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if (freeable(fldtab[0]))
|
||||||
|
xfree(fldtab[0]->sval);
|
||||||
|
fldtab[0]->sval = buf; /* buf == record */
|
||||||
|
fldtab[0]->tval = REC | STR | DONTFREE;
|
||||||
|
if (is_number(fldtab[0]->sval, & result)) {
|
||||||
|
fldtab[0]->fval = result;
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
buf[0] = saveb0;
|
||||||
|
*pbuf = buf;
|
||||||
|
*pbufsize = savebufsize;
|
||||||
|
return 0; /* true end of file */
|
||||||
|
}
|
||||||
|
|
||||||
|
void nextfile(void)
|
||||||
|
{
|
||||||
|
if (infile != NULL && infile != stdin)
|
||||||
|
fclose(infile);
|
||||||
|
infile = NULL;
|
||||||
|
argno++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */
|
||||||
|
{
|
||||||
|
int sep, c, isrec;
|
||||||
|
char *rr, *buf = *pbuf;
|
||||||
|
int bufsize = *pbufsize;
|
||||||
|
char *rs = getsval(rsloc);
|
||||||
|
|
||||||
|
if (*rs && rs[1]) {
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
fa *pfa = makedfa(rs, 1);
|
||||||
|
if (newflag)
|
||||||
|
found = fnematch(pfa, inf, &buf, &bufsize, recsize);
|
||||||
|
else {
|
||||||
|
int tempstat = pfa->initstat;
|
||||||
|
pfa->initstat = 2;
|
||||||
|
found = fnematch(pfa, inf, &buf, &bufsize, recsize);
|
||||||
|
pfa->initstat = tempstat;
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
setptr(patbeg, '\0');
|
||||||
|
isrec = (found == 0 && *buf == '\0') ? false : true;
|
||||||
|
} else {
|
||||||
|
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"))
|
||||||
|
FATAL("input record `%.30s...' too long", buf);
|
||||||
|
*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"))
|
||||||
|
FATAL("input record `%.30s...' too long", buf);
|
||||||
|
*rr++ = '\n';
|
||||||
|
*rr++ = c;
|
||||||
|
}
|
||||||
|
if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
|
||||||
|
FATAL("input record `%.30s...' too long", buf);
|
||||||
|
*rr = 0;
|
||||||
|
isrec = (c == EOF && rr == buf) ? false : true;
|
||||||
|
}
|
||||||
|
*pbuf = buf;
|
||||||
|
*pbufsize = bufsize;
|
||||||
|
DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec);
|
||||||
|
return isrec;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getargv(int n) /* get ARGV[n] */
|
||||||
|
{
|
||||||
|
Cell *x;
|
||||||
|
char *s, temp[50];
|
||||||
|
extern Array *ARGVtab;
|
||||||
|
|
||||||
|
snprintf(temp, sizeof(temp), "%d", n);
|
||||||
|
if (lookup(temp, ARGVtab) == NULL)
|
||||||
|
return NULL;
|
||||||
|
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 *e, *p;
|
||||||
|
Cell *q;
|
||||||
|
double result;
|
||||||
|
|
||||||
|
for (p=s; *p != '='; p++)
|
||||||
|
;
|
||||||
|
e = p;
|
||||||
|
*p++ = 0;
|
||||||
|
p = qstring(p, '\0');
|
||||||
|
q = setsymtab(s, p, 0.0, STR, symtab);
|
||||||
|
setsval(q, p);
|
||||||
|
if (is_number(q->sval, & result)) {
|
||||||
|
q->fval = result;
|
||||||
|
q->tval |= NUM;
|
||||||
|
}
|
||||||
|
DPRINTF("command line set %s to |%s|\n", s, p);
|
||||||
|
*e = '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 */
|
||||||
|
/* possibly with a final trailing \0 not associated with any field */
|
||||||
|
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+2)) == NULL) /* possibly 2 final \0s */
|
||||||
|
FATAL("out of space for fields in fldbld %d", n);
|
||||||
|
fieldssize = n;
|
||||||
|
}
|
||||||
|
fr = fields;
|
||||||
|
i = 0; /* number of fields accumulated here */
|
||||||
|
if (inputFS == NULL) /* make sure we have a copy of FS */
|
||||||
|
savefs();
|
||||||
|
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 += n) {
|
||||||
|
char buf[MB_LEN_MAX + 1];
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i > nfields)
|
||||||
|
growfldtab(i);
|
||||||
|
if (freeable(fldtab[i]))
|
||||||
|
xfree(fldtab[i]->sval);
|
||||||
|
n = mblen(r, MB_LEN_MAX);
|
||||||
|
if (n < 0)
|
||||||
|
n = 1;
|
||||||
|
memcpy(buf, r, n);
|
||||||
|
buf[n] = '\0';
|
||||||
|
fldtab[i]->sval = tostring(buf);
|
||||||
|
fldtab[i]->tval = FLD | STR;
|
||||||
|
}
|
||||||
|
*fr = 0;
|
||||||
|
} else if (*r != 0) { /* if 0, it's a null field */
|
||||||
|
/* subtlecase : if length(FS) == 1 && length(RS > 0)
|
||||||
|
* \n is NOT a field separator (cf awk book 61,84).
|
||||||
|
* this variable is tested in the inner while loop.
|
||||||
|
*/
|
||||||
|
int rtest = '\n'; /* normal case */
|
||||||
|
if (strlen(*RS) > 0)
|
||||||
|
rtest = '\0';
|
||||||
|
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 != rtest && *r != '\0') /* \n is always a separator */
|
||||||
|
*fr++ = *r++;
|
||||||
|
*fr++ = 0;
|
||||||
|
if (*r++ == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*fr = 0;
|
||||||
|
}
|
||||||
|
if (i > nfields)
|
||||||
|
FATAL("record `%.30s...' has too many fields; can't happen", r);
|
||||||
|
cleanfld(i+1, lastfld); /* clean out junk from previous record */
|
||||||
|
lastfld = i;
|
||||||
|
donefld = true;
|
||||||
|
for (j = 1; j <= lastfld; j++) {
|
||||||
|
double result;
|
||||||
|
|
||||||
|
p = fldtab[j];
|
||||||
|
if(is_number(p->sval, & result)) {
|
||||||
|
p->fval = result;
|
||||||
|
p->tval |= NUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setfval(nfloc, (Awkfloat) lastfld);
|
||||||
|
donerec = true; /* restore */
|
||||||
|
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 = EMPTY,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
|
||||||
|
{
|
||||||
|
if (n < 0)
|
||||||
|
FATAL("cannot set NF to a negative value");
|
||||||
|
if (n > nfields)
|
||||||
|
growfldtab(n);
|
||||||
|
|
||||||
|
if (lastfld < n)
|
||||||
|
cleanfld(lastfld+1, n);
|
||||||
|
else
|
||||||
|
cleanfld(n+1, lastfld);
|
||||||
|
|
||||||
|
lastfld = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell *fieldadr(int n) /* get nth field */
|
||||||
|
{
|
||||||
|
if (n < 0)
|
||||||
|
FATAL("trying to access out of range field %d", n);
|
||||||
|
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;
|
||||||
|
size_t s;
|
||||||
|
|
||||||
|
if (n > nf)
|
||||||
|
nf = n;
|
||||||
|
s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
|
||||||
|
if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
|
||||||
|
fldtab = (Cell **) realloc(fldtab, s);
|
||||||
|
else /* overflow sizeof int */
|
||||||
|
xfree(fldtab); /* make it null */
|
||||||
|
if (fldtab == NULL)
|
||||||
|
FATAL("out of space creating %d fields", nf);
|
||||||
|
makefields(nfields+1, nf);
|
||||||
|
nfields = nf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int refldbld(const char *rec, const 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)
|
||||||
|
FATAL("out of space for fields in refldbld %d", n);
|
||||||
|
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 *sep = getsval(ofsloc);
|
||||||
|
|
||||||
|
if (donerec)
|
||||||
|
return;
|
||||||
|
r = record;
|
||||||
|
for (i = 1; i <= *NF; i++) {
|
||||||
|
p = getsval(fldtab[i]);
|
||||||
|
if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
|
||||||
|
FATAL("created $0 `%.30s...' too long", record);
|
||||||
|
while ((*r = *p++) != 0)
|
||||||
|
r++;
|
||||||
|
if (i < *NF) {
|
||||||
|
if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
|
||||||
|
FATAL("created $0 `%.30s...' too long", record);
|
||||||
|
for (p = sep; (*r = *p++) != 0; )
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
|
||||||
|
FATAL("built giant record `%.30s...'", record);
|
||||||
|
*r = '\0';
|
||||||
|
DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
|
||||||
|
|
||||||
|
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, (void*)fldtab[0]);
|
||||||
|
DPRINTF("recbld = |%s|\n", record);
|
||||||
|
donerec = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int errorflag = 0;
|
||||||
|
|
||||||
|
void yyerror(const char *s)
|
||||||
|
{
|
||||||
|
SYNTAX("%s", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SYNTAX(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
extern char *cmdname, *curfname;
|
||||||
|
static int been_here = 0;
|
||||||
|
va_list varg;
|
||||||
|
|
||||||
|
if (been_here++ > 2)
|
||||||
|
return;
|
||||||
|
fprintf(stderr, "%s: ", cmdname);
|
||||||
|
va_start(varg, fmt);
|
||||||
|
vfprintf(stderr, fmt, varg);
|
||||||
|
va_end(varg);
|
||||||
|
fprintf(stderr, " at source line %d", lineno);
|
||||||
|
if (curfname != NULL)
|
||||||
|
fprintf(stderr, " in function %s", curfname);
|
||||||
|
if (compile_time == COMPILING && cursource() != NULL)
|
||||||
|
fprintf(stderr, " source file %s", cursource());
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
errorflag = 2;
|
||||||
|
eprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 FATAL(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
extern char *cmdname;
|
||||||
|
va_list varg;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
fprintf(stderr, "%s: ", cmdname);
|
||||||
|
va_start(varg, fmt);
|
||||||
|
vfprintf(stderr, fmt, varg);
|
||||||
|
va_end(varg);
|
||||||
|
error();
|
||||||
|
if (dbg > 1) /* core dump if serious debugging on */
|
||||||
|
abort();
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WARNING(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
extern char *cmdname;
|
||||||
|
va_list varg;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
fprintf(stderr, "%s: ", cmdname);
|
||||||
|
va_start(varg, fmt);
|
||||||
|
vfprintf(stderr, fmt, varg);
|
||||||
|
va_end(varg);
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void error()
|
||||||
|
{
|
||||||
|
extern Node *curnode;
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
if (compile_time != ERROR_PRINTING) {
|
||||||
|
if (NR && *NR > 0) {
|
||||||
|
fprintf(stderr, " input record number %d", (int) (*FNR));
|
||||||
|
if (strcmp(*FILENAME, "-") != 0)
|
||||||
|
fprintf(stderr, ", file %s", *FILENAME);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
if (curnode)
|
||||||
|
fprintf(stderr, " source line number %d", curnode->lineno);
|
||||||
|
else if (lineno)
|
||||||
|
fprintf(stderr, " source line number %d", lineno);
|
||||||
|
if (compile_time == COMPILING && cursource() != NULL)
|
||||||
|
fprintf(stderr, " source file %s", cursource());
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
eprint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != COMPILING || been_here++ > 0 || ebuf == ep)
|
||||||
|
return;
|
||||||
|
if (ebuf == ep)
|
||||||
|
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, const char *s)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (errno == EDOM) {
|
||||||
|
errno = 0;
|
||||||
|
WARNING("%s argument out of domain", s);
|
||||||
|
x = 1;
|
||||||
|
} else if (errno == ERANGE) {
|
||||||
|
errno = 0;
|
||||||
|
WARNING("%s result out of range", s);
|
||||||
|
x = 1;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int isclvar(const char *s) /* is s of form var=something ? */
|
||||||
|
{
|
||||||
|
const char *os = s;
|
||||||
|
|
||||||
|
if (!isalpha((uschar) *s) && *s != '_')
|
||||||
|
return 0;
|
||||||
|
for ( ; *s; s++)
|
||||||
|
if (!(isalnum((uschar) *s) || *s == '_'))
|
||||||
|
break;
|
||||||
|
return *s == '=' && s > os;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strtod is supposed to be a proper test of what's a valid number */
|
||||||
|
/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
|
||||||
|
/* wrong: violates 4.10.1.4 of ansi C standard */
|
||||||
|
|
||||||
|
/* well, not quite. As of C99, hex floating point is allowed. so this is
|
||||||
|
* a bit of a mess. We work around the mess by checking for a hexadecimal
|
||||||
|
* value and disallowing it. Similarly, we now follow gawk and allow only
|
||||||
|
* +nan, -nan, +inf, and -inf for NaN and infinity values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine now has a more complicated interface, the main point
|
||||||
|
* being to avoid the double conversion of a string to double, and
|
||||||
|
* also to convey out, if requested, the information that the numeric
|
||||||
|
* value was a leading string or is all of the string. The latter bit
|
||||||
|
* is used in getfval().
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool is_valid_number(const char *s, bool trailing_stuff_ok,
|
||||||
|
bool *no_trailing, double *result)
|
||||||
|
{
|
||||||
|
double r;
|
||||||
|
char *ep;
|
||||||
|
bool retval = false;
|
||||||
|
bool is_nan = false;
|
||||||
|
bool is_inf = false;
|
||||||
|
|
||||||
|
if (no_trailing)
|
||||||
|
*no_trailing = false;
|
||||||
|
|
||||||
|
while (isspace(*s))
|
||||||
|
s++;
|
||||||
|
|
||||||
|
// no hex floating point, sorry
|
||||||
|
if (s[0] == '0' && tolower(s[1]) == 'x')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// allow +nan, -nan, +inf, -inf, any other letter, no
|
||||||
|
if (s[0] == '+' || s[0] == '-') {
|
||||||
|
is_nan = (strncasecmp(s+1, "nan", 3) == 0);
|
||||||
|
is_inf = (strncasecmp(s+1, "inf", 3) == 0);
|
||||||
|
if ((is_nan || is_inf)
|
||||||
|
&& (isspace(s[4]) || s[4] == '\0'))
|
||||||
|
goto convert;
|
||||||
|
else if (! isdigit(s[1]) && s[1] != '.')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (! isdigit(s[0]) && s[0] != '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
convert:
|
||||||
|
errno = 0;
|
||||||
|
r = strtod(s, &ep);
|
||||||
|
if (ep == s || errno == ERANGE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isnan(r) && s[0] == '-' && signbit(r) == 0)
|
||||||
|
r = -r;
|
||||||
|
|
||||||
|
if (result != NULL)
|
||||||
|
*result = r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for trailing stuff
|
||||||
|
*/
|
||||||
|
while (isspace(*ep))
|
||||||
|
ep++;
|
||||||
|
|
||||||
|
if (no_trailing != NULL)
|
||||||
|
*no_trailing = (*ep == '\0');
|
||||||
|
|
||||||
|
// return true if found the end, or trailing stuff is allowed
|
||||||
|
retval = *ep == '\0' || trailing_stuff_ok;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
257
third_party/awk/main.c
vendored
Normal file
257
third_party/awk/main.c
vendored
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
/****************************************************************
|
||||||
|
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.
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
const char *version = "version 20220530";
|
||||||
|
|
||||||
|
#define DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include "awk.h"
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
extern int nfields;
|
||||||
|
|
||||||
|
int dbg = 0;
|
||||||
|
Awkfloat srand_seed = 1;
|
||||||
|
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 */
|
||||||
|
enum compile_states compile_time = ERROR_PRINTING;
|
||||||
|
|
||||||
|
static char **pfile; /* program filenames from -f's */
|
||||||
|
static size_t maxpfile; /* max program filename */
|
||||||
|
static size_t npfile; /* number of filenames */
|
||||||
|
static size_t curpfile; /* current filename */
|
||||||
|
|
||||||
|
bool safe = false; /* true => "safe" mode */
|
||||||
|
|
||||||
|
static noreturn void fpecatch(int n
|
||||||
|
#ifdef SA_SIGINFO
|
||||||
|
, siginfo_t *si, void *uc
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#ifdef SA_SIGINFO
|
||||||
|
static const char *emsg[] = {
|
||||||
|
[0] = "Unknown error",
|
||||||
|
[FPE_INTDIV] = "Integer divide by zero",
|
||||||
|
[FPE_INTOVF] = "Integer overflow",
|
||||||
|
[FPE_FLTDIV] = "Floating point divide by zero",
|
||||||
|
[FPE_FLTOVF] = "Floating point overflow",
|
||||||
|
[FPE_FLTUND] = "Floating point underflow",
|
||||||
|
[FPE_FLTRES] = "Floating point inexact result",
|
||||||
|
[FPE_FLTINV] = "Invalid Floating point operation",
|
||||||
|
[FPE_FLTSUB] = "Subscript out of range",
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
FATAL("floating point exception"
|
||||||
|
#ifdef SA_SIGINFO
|
||||||
|
": %s", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
|
||||||
|
emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can this work with recursive calls? I don't think so.
|
||||||
|
void segvcatch(int n)
|
||||||
|
{
|
||||||
|
FATAL("segfault. Do you have an unbounded recursive call?", n);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
setfs(char *p)
|
||||||
|
{
|
||||||
|
/* wart: t=>\t */
|
||||||
|
if (p[0] == 't' && p[1] == '\0')
|
||||||
|
return "\t";
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
getarg(int *argc, char ***argv, const char *msg)
|
||||||
|
{
|
||||||
|
if ((*argv)[1][2] != '\0') { /* arg is -fsomething */
|
||||||
|
return &(*argv)[1][2];
|
||||||
|
} else { /* arg is -f something */
|
||||||
|
(*argc)--; (*argv)++;
|
||||||
|
if (*argc <= 1)
|
||||||
|
FATAL("%s", msg);
|
||||||
|
return (*argv)[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const char *fs = NULL;
|
||||||
|
char *fn, *vn;
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
|
||||||
|
cmdname = argv[0];
|
||||||
|
if (argc == 1) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: %s [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]\n",
|
||||||
|
cmdname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#ifdef SA_SIGINFO
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_sigaction = fpecatch;
|
||||||
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
(void)sigaction(SIGFPE, &sa, NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)signal(SIGFPE, fpecatch);
|
||||||
|
#endif
|
||||||
|
/*signal(SIGSEGV, segvcatch); experiment */
|
||||||
|
|
||||||
|
/* Set and keep track of the random seed */
|
||||||
|
srand_seed = 1;
|
||||||
|
srandom((unsigned long) srand_seed);
|
||||||
|
|
||||||
|
yyin = NULL;
|
||||||
|
symtab = makesymtab(NSYMTAB/NSYMTAB);
|
||||||
|
while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
|
||||||
|
if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) {
|
||||||
|
printf("awk %s\n", version);
|
||||||
|
return 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 = true;
|
||||||
|
break;
|
||||||
|
case 'f': /* next argument is program filename */
|
||||||
|
fn = getarg(&argc, &argv, "no program filename");
|
||||||
|
if (npfile >= maxpfile) {
|
||||||
|
maxpfile += 20;
|
||||||
|
pfile = (char **) realloc(pfile, maxpfile * sizeof(*pfile));
|
||||||
|
if (pfile == NULL)
|
||||||
|
FATAL("error allocating space for -f options");
|
||||||
|
}
|
||||||
|
pfile[npfile++] = fn;
|
||||||
|
break;
|
||||||
|
case 'F': /* set field separator */
|
||||||
|
fs = setfs(getarg(&argc, &argv, "no field separator"));
|
||||||
|
break;
|
||||||
|
case 'v': /* -v a=1 to be done NOW. one -v for each */
|
||||||
|
vn = getarg(&argc, &argv, "no variable name");
|
||||||
|
if (isclvar(vn))
|
||||||
|
setclvar(vn);
|
||||||
|
else
|
||||||
|
FATAL("invalid -v option argument: %s", vn);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
dbg = atoi(&argv[1][2]);
|
||||||
|
if (dbg == 0)
|
||||||
|
dbg = 1;
|
||||||
|
printf("awk %s\n", version);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARNING("unknown option %s ignored", argv[1]);
|
||||||
|
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);
|
||||||
|
FATAL("no program given");
|
||||||
|
}
|
||||||
|
DPRINTF("program = |%s|\n", argv[1]);
|
||||||
|
lexprog = argv[1];
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
recinit(recsize);
|
||||||
|
syminit();
|
||||||
|
compile_time = COMPILING;
|
||||||
|
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 0
|
||||||
|
// Doing this would comply with POSIX, but is not compatible with
|
||||||
|
// other awks and with what most users expect. So comment it out.
|
||||||
|
setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
|
||||||
|
#endif
|
||||||
|
if (fs)
|
||||||
|
*FS = qstring(fs, '\0');
|
||||||
|
DPRINTF("errorflag=%d\n", errorflag);
|
||||||
|
if (errorflag == 0) {
|
||||||
|
compile_time = RUNNING;
|
||||||
|
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)
|
||||||
|
FATAL("can't open file %s", pfile[curpfile]);
|
||||||
|
lineno = 1;
|
||||||
|
}
|
||||||
|
if ((c = getc(yyin)) != EOF)
|
||||||
|
return c;
|
||||||
|
if (yyin != stdin)
|
||||||
|
fclose(yyin);
|
||||||
|
yyin = NULL;
|
||||||
|
curpfile++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *cursource(void) /* current source file name */
|
||||||
|
{
|
||||||
|
if (npfile > 0)
|
||||||
|
return pfile[curpfile < npfile ? curpfile : curpfile - 1];
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
192
third_party/awk/maketab.c
vendored
Normal file
192
third_party/awk/maketab.c
vendored
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 awkgram.tab.h, produced by bison.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "awk.h"
|
||||||
|
#include "awkgram.tab.h"
|
||||||
|
|
||||||
|
struct xx
|
||||||
|
{ int token;
|
||||||
|
const char *name;
|
||||||
|
const 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", " -" },
|
||||||
|
{ UPLUS, "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, "awkdelete", "awkdelete" },
|
||||||
|
{ 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, "awkgetline", "getline" },
|
||||||
|
{ 0, "", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZE (LASTTOKEN - FIRSTTOKEN + 1)
|
||||||
|
const char *table[SIZE];
|
||||||
|
char *names[SIZE];
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const struct xx *p;
|
||||||
|
int i, n, tok;
|
||||||
|
char c;
|
||||||
|
FILE *fp;
|
||||||
|
char buf[200], name[200], def[200];
|
||||||
|
enum { TOK_UNKNOWN, TOK_ENUM, TOK_DEFINE } tokentype = TOK_UNKNOWN;
|
||||||
|
|
||||||
|
printf("#include <stdio.h>\n");
|
||||||
|
printf("#include \"awk.h\"\n");
|
||||||
|
printf("#include \"awkgram.tab.h\"\n\n");
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "usage: maketab YTAB_H\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((fp = fopen(argv[1], "r")) == NULL) {
|
||||||
|
fprintf(stderr, "maketab can't open %s!\n", argv[1]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("static const char * const printname[%d] = {\n", SIZE);
|
||||||
|
i = 0;
|
||||||
|
while (fgets(buf, sizeof buf, fp) != NULL) {
|
||||||
|
// 199 is sizeof(def) - 1
|
||||||
|
if (tokentype != TOK_ENUM) {
|
||||||
|
n = sscanf(buf, "%1c %199s %199s %d", &c, def, name,
|
||||||
|
&tok);
|
||||||
|
if (n == 4 && c == '#' && strcmp(def, "define") == 0) {
|
||||||
|
tokentype = TOK_DEFINE;
|
||||||
|
} else if (tokentype != TOK_UNKNOWN) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tokentype != TOK_DEFINE) {
|
||||||
|
/* not a valid #define, bison uses enums now */
|
||||||
|
n = sscanf(buf, "%199s = %d,\n", name, &tok);
|
||||||
|
if (n != 2)
|
||||||
|
continue;
|
||||||
|
tokentype = TOK_ENUM;
|
||||||
|
}
|
||||||
|
if (strcmp(name, "YYSTYPE_IS_DECLARED") == 0) {
|
||||||
|
tokentype = TOK_UNKNOWN;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tok < FIRSTTOKEN || tok > LASTTOKEN) {
|
||||||
|
tokentype = TOK_UNKNOWN;
|
||||||
|
/* fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
names[tok-FIRSTTOKEN] = strdup(name);
|
||||||
|
if (names[tok-FIRSTTOKEN] == NULL) {
|
||||||
|
fprintf(stderr, "maketab out of space copying %s", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("\t\"%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<SIZE; i++)
|
||||||
|
printf("\t%s,\t/* %s */\n",
|
||||||
|
table[i] ? table[i] : "nullproc", names[i] ? names[i] : "");
|
||||||
|
printf("};\n\n");
|
||||||
|
|
||||||
|
printf("const char *tokname(int n)\n"); /* print a tokname() function */
|
||||||
|
printf("{\n");
|
||||||
|
printf("\tstatic char buf[100];\n\n");
|
||||||
|
printf("\tif (n < FIRSTTOKEN || n > LASTTOKEN) {\n");
|
||||||
|
printf("\t\tsnprintf(buf, sizeof(buf), \"token %%d\", n);\n");
|
||||||
|
printf("\t\treturn buf;\n");
|
||||||
|
printf("\t}\n");
|
||||||
|
printf("\treturn printname[n-FIRSTTOKEN];\n");
|
||||||
|
printf("}\n");
|
||||||
|
return 0;
|
||||||
|
}
|
276
third_party/awk/parse.c
vendored
Normal file
276
third_party/awk/parse.c
vendored
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "awk.h"
|
||||||
|
#include "awkgram.tab.h"
|
||||||
|
|
||||||
|
Node *nodealloc(int n)
|
||||||
|
{
|
||||||
|
Node *x;
|
||||||
|
|
||||||
|
x = (Node *) malloc(sizeof(*x) + (n-1) * sizeof(x));
|
||||||
|
if (x == NULL)
|
||||||
|
FATAL("out of space in nodealloc");
|
||||||
|
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))
|
||||||
|
SYNTAX( "%s is a function, not an array", cp->nval );
|
||||||
|
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, itonp(paircnt));
|
||||||
|
if (paircnt++ >= PA2NUM)
|
||||||
|
SYNTAX( "limited to %d pat,pat statements", PA2NUM );
|
||||||
|
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)) {
|
||||||
|
SYNTAX( "`%s' is an array name and a function name", v->nval );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isarg(v->nval) != -1) {
|
||||||
|
SYNTAX( "`%s' is both function name and argument name", v->nval );
|
||||||
|
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(const 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 != NULL; p = p->nnext, n++)
|
||||||
|
if (strcmp(((Cell *)(p->narg[0]))->nval, s) == 0)
|
||||||
|
return n;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ptoi(void *p) /* convert pointer to integer */
|
||||||
|
{
|
||||||
|
return (int) (long) p; /* swearing that p fits, of course */
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *itonp(int i) /* and vice versa */
|
||||||
|
{
|
||||||
|
return (Node *) (long) i;
|
||||||
|
}
|
216
third_party/awk/proctab.c
vendored
Normal file
216
third_party/awk/proctab.c
vendored
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
// clang-format off
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/stdio/lock.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/stdio/temp.h"
|
||||||
|
#include "third_party/awk/awk.h"
|
||||||
|
#include "third_party/awk/awkgram.tab.h"
|
||||||
|
|
||||||
|
static const char * const printname[95] = {
|
||||||
|
"FIRSTTOKEN", /* 258 */
|
||||||
|
"PROGRAM", /* 259 */
|
||||||
|
"PASTAT", /* 260 */
|
||||||
|
"PASTAT2", /* 261 */
|
||||||
|
"XBEGIN", /* 262 */
|
||||||
|
"XEND", /* 263 */
|
||||||
|
"NL", /* 264 */
|
||||||
|
"ARRAY", /* 265 */
|
||||||
|
"MATCH", /* 266 */
|
||||||
|
"NOTMATCH", /* 267 */
|
||||||
|
"MATCHOP", /* 268 */
|
||||||
|
"FINAL", /* 269 */
|
||||||
|
"DOT", /* 270 */
|
||||||
|
"ALL", /* 271 */
|
||||||
|
"CCL", /* 272 */
|
||||||
|
"NCCL", /* 273 */
|
||||||
|
"CHAR", /* 274 */
|
||||||
|
"OR", /* 275 */
|
||||||
|
"STAR", /* 276 */
|
||||||
|
"QUEST", /* 277 */
|
||||||
|
"PLUS", /* 278 */
|
||||||
|
"EMPTYRE", /* 279 */
|
||||||
|
"ZERO", /* 280 */
|
||||||
|
"AND", /* 281 */
|
||||||
|
"BOR", /* 282 */
|
||||||
|
"APPEND", /* 283 */
|
||||||
|
"EQ", /* 284 */
|
||||||
|
"GE", /* 285 */
|
||||||
|
"GT", /* 286 */
|
||||||
|
"LE", /* 287 */
|
||||||
|
"LT", /* 288 */
|
||||||
|
"NE", /* 289 */
|
||||||
|
"IN", /* 290 */
|
||||||
|
"ARG", /* 291 */
|
||||||
|
"BLTIN", /* 292 */
|
||||||
|
"BREAK", /* 293 */
|
||||||
|
"CLOSE", /* 294 */
|
||||||
|
"CONTINUE", /* 295 */
|
||||||
|
"DELETE", /* 296 */
|
||||||
|
"DO", /* 297 */
|
||||||
|
"EXIT", /* 298 */
|
||||||
|
"FOR", /* 299 */
|
||||||
|
"FUNC", /* 300 */
|
||||||
|
"SUB", /* 301 */
|
||||||
|
"GSUB", /* 302 */
|
||||||
|
"IF", /* 303 */
|
||||||
|
"INDEX", /* 304 */
|
||||||
|
"LSUBSTR", /* 305 */
|
||||||
|
"MATCHFCN", /* 306 */
|
||||||
|
"NEXT", /* 307 */
|
||||||
|
"NEXTFILE", /* 308 */
|
||||||
|
"ADD", /* 309 */
|
||||||
|
"MINUS", /* 310 */
|
||||||
|
"MULT", /* 311 */
|
||||||
|
"DIVIDE", /* 312 */
|
||||||
|
"MOD", /* 313 */
|
||||||
|
"ASSIGN", /* 314 */
|
||||||
|
"ASGNOP", /* 315 */
|
||||||
|
"ADDEQ", /* 316 */
|
||||||
|
"SUBEQ", /* 317 */
|
||||||
|
"MULTEQ", /* 318 */
|
||||||
|
"DIVEQ", /* 319 */
|
||||||
|
"MODEQ", /* 320 */
|
||||||
|
"POWEQ", /* 321 */
|
||||||
|
"PRINT", /* 322 */
|
||||||
|
"PRINTF", /* 323 */
|
||||||
|
"SPRINTF", /* 324 */
|
||||||
|
"ELSE", /* 325 */
|
||||||
|
"INTEST", /* 326 */
|
||||||
|
"CONDEXPR", /* 327 */
|
||||||
|
"POSTINCR", /* 328 */
|
||||||
|
"PREINCR", /* 329 */
|
||||||
|
"POSTDECR", /* 330 */
|
||||||
|
"PREDECR", /* 331 */
|
||||||
|
"VAR", /* 332 */
|
||||||
|
"IVAR", /* 333 */
|
||||||
|
"VARNF", /* 334 */
|
||||||
|
"CALL", /* 335 */
|
||||||
|
"NUMBER", /* 336 */
|
||||||
|
"STRING", /* 337 */
|
||||||
|
"REGEXPR", /* 338 */
|
||||||
|
"GETLINE", /* 339 */
|
||||||
|
"RETURN", /* 340 */
|
||||||
|
"SPLIT", /* 341 */
|
||||||
|
"SUBSTR", /* 342 */
|
||||||
|
"WHILE", /* 343 */
|
||||||
|
"CAT", /* 344 */
|
||||||
|
"NOT", /* 345 */
|
||||||
|
"UMINUS", /* 346 */
|
||||||
|
"UPLUS", /* 347 */
|
||||||
|
"POWER", /* 348 */
|
||||||
|
"DECR", /* 349 */
|
||||||
|
"INCR", /* 350 */
|
||||||
|
"INDIRECT", /* 351 */
|
||||||
|
"LASTTOKEN", /* 352 */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Cell *(*proctab[95])(Node **, int) = {
|
||||||
|
nullproc, /* FIRSTTOKEN */
|
||||||
|
program, /* PROGRAM */
|
||||||
|
pastat, /* PASTAT */
|
||||||
|
dopa2, /* PASTAT2 */
|
||||||
|
nullproc, /* XBEGIN */
|
||||||
|
nullproc, /* XEND */
|
||||||
|
nullproc, /* NL */
|
||||||
|
array, /* ARRAY */
|
||||||
|
matchop, /* MATCH */
|
||||||
|
matchop, /* NOTMATCH */
|
||||||
|
nullproc, /* MATCHOP */
|
||||||
|
nullproc, /* FINAL */
|
||||||
|
nullproc, /* DOT */
|
||||||
|
nullproc, /* ALL */
|
||||||
|
nullproc, /* CCL */
|
||||||
|
nullproc, /* NCCL */
|
||||||
|
nullproc, /* CHAR */
|
||||||
|
nullproc, /* OR */
|
||||||
|
nullproc, /* STAR */
|
||||||
|
nullproc, /* QUEST */
|
||||||
|
nullproc, /* PLUS */
|
||||||
|
nullproc, /* EMPTYRE */
|
||||||
|
nullproc, /* ZERO */
|
||||||
|
boolop, /* AND */
|
||||||
|
boolop, /* BOR */
|
||||||
|
nullproc, /* APPEND */
|
||||||
|
relop, /* EQ */
|
||||||
|
relop, /* GE */
|
||||||
|
relop, /* GT */
|
||||||
|
relop, /* LE */
|
||||||
|
relop, /* LT */
|
||||||
|
relop, /* NE */
|
||||||
|
instat, /* IN */
|
||||||
|
arg, /* ARG */
|
||||||
|
bltin, /* BLTIN */
|
||||||
|
jump, /* BREAK */
|
||||||
|
closefile, /* CLOSE */
|
||||||
|
jump, /* CONTINUE */
|
||||||
|
awkdelete, /* DELETE */
|
||||||
|
dostat, /* DO */
|
||||||
|
jump, /* EXIT */
|
||||||
|
forstat, /* FOR */
|
||||||
|
nullproc, /* FUNC */
|
||||||
|
sub, /* SUB */
|
||||||
|
gsub, /* GSUB */
|
||||||
|
ifstat, /* IF */
|
||||||
|
sindex, /* INDEX */
|
||||||
|
nullproc, /* LSUBSTR */
|
||||||
|
matchop, /* MATCHFCN */
|
||||||
|
jump, /* NEXT */
|
||||||
|
jump, /* NEXTFILE */
|
||||||
|
arith, /* ADD */
|
||||||
|
arith, /* MINUS */
|
||||||
|
arith, /* MULT */
|
||||||
|
arith, /* DIVIDE */
|
||||||
|
arith, /* MOD */
|
||||||
|
assign, /* ASSIGN */
|
||||||
|
nullproc, /* ASGNOP */
|
||||||
|
assign, /* ADDEQ */
|
||||||
|
assign, /* SUBEQ */
|
||||||
|
assign, /* MULTEQ */
|
||||||
|
assign, /* DIVEQ */
|
||||||
|
assign, /* MODEQ */
|
||||||
|
assign, /* POWEQ */
|
||||||
|
printstat, /* PRINT */
|
||||||
|
awkprintf, /* PRINTF */
|
||||||
|
awksprintf, /* SPRINTF */
|
||||||
|
nullproc, /* ELSE */
|
||||||
|
intest, /* INTEST */
|
||||||
|
condexpr, /* CONDEXPR */
|
||||||
|
incrdecr, /* POSTINCR */
|
||||||
|
incrdecr, /* PREINCR */
|
||||||
|
incrdecr, /* POSTDECR */
|
||||||
|
incrdecr, /* PREDECR */
|
||||||
|
nullproc, /* VAR */
|
||||||
|
nullproc, /* IVAR */
|
||||||
|
getnf, /* VARNF */
|
||||||
|
call, /* CALL */
|
||||||
|
nullproc, /* NUMBER */
|
||||||
|
nullproc, /* STRING */
|
||||||
|
nullproc, /* REGEXPR */
|
||||||
|
awkgetline, /* GETLINE */
|
||||||
|
jump, /* RETURN */
|
||||||
|
split, /* SPLIT */
|
||||||
|
substr, /* SUBSTR */
|
||||||
|
whilestat, /* WHILE */
|
||||||
|
cat, /* CAT */
|
||||||
|
boolop, /* NOT */
|
||||||
|
arith, /* UMINUS */
|
||||||
|
arith, /* UPLUS */
|
||||||
|
arith, /* POWER */
|
||||||
|
nullproc, /* DECR */
|
||||||
|
nullproc, /* INCR */
|
||||||
|
indirect, /* INDIRECT */
|
||||||
|
nullproc, /* LASTTOKEN */
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *tokname(int n)
|
||||||
|
{
|
||||||
|
static char buf[100];
|
||||||
|
|
||||||
|
if (n < FIRSTTOKEN || n > LASTTOKEN) {
|
||||||
|
snprintf(buf, sizeof(buf), "token %d", n);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
return printname[n-FIRSTTOKEN];
|
||||||
|
}
|
206
third_party/awk/proto.h
vendored
Normal file
206
third_party/awk/proto.h
vendored
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
/****************************************************************
|
||||||
|
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(const char *);
|
||||||
|
extern int yylook(void);
|
||||||
|
extern int yyback(int *, int);
|
||||||
|
extern int yyinput(void);
|
||||||
|
|
||||||
|
extern fa *makedfa(const char *, bool);
|
||||||
|
extern fa *mkdfa(const char *, bool);
|
||||||
|
extern int makeinit(fa *, bool);
|
||||||
|
extern void penter(Node *);
|
||||||
|
extern void freetr(Node *);
|
||||||
|
extern int hexstr(const uschar **);
|
||||||
|
extern int quoted(const uschar **);
|
||||||
|
extern char *cclenter(const char *);
|
||||||
|
extern noreturn void overflo(const char *);
|
||||||
|
extern void cfoll(fa *, Node *);
|
||||||
|
extern int first(Node *);
|
||||||
|
extern void follow(Node *);
|
||||||
|
extern int member(int, const char *);
|
||||||
|
extern int match(fa *, const char *);
|
||||||
|
extern int pmatch(fa *, const char *);
|
||||||
|
extern int nematch(fa *, const char *);
|
||||||
|
extern bool fnematch(fa *, FILE *, char **, int *, int);
|
||||||
|
extern Node *reparse(const 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 char *cursource(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(const char *);
|
||||||
|
extern const char *tokname(int);
|
||||||
|
extern Cell *(*proctab[])(Node **, int);
|
||||||
|
extern int ptoi(void *);
|
||||||
|
extern Node *itonp(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 *, const char *);
|
||||||
|
extern Cell *setsymtab(const char *, const char *, double, unsigned int, Array *);
|
||||||
|
extern int hash(const char *, int);
|
||||||
|
extern void rehash(Array *);
|
||||||
|
extern Cell *lookup(const char *, Array *);
|
||||||
|
extern double setfval(Cell *, double);
|
||||||
|
extern void funnyvar(Cell *, const char *);
|
||||||
|
extern char *setsval(Cell *, const char *);
|
||||||
|
extern double getfval(Cell *);
|
||||||
|
extern char *getsval(Cell *);
|
||||||
|
extern char *getpssval(Cell *); /* for print */
|
||||||
|
extern char *tostring(const char *);
|
||||||
|
extern char *tostringN(const char *, size_t);
|
||||||
|
extern char *qstring(const char *, int);
|
||||||
|
extern Cell *catstr(Cell *, Cell *);
|
||||||
|
|
||||||
|
extern void recinit(unsigned int);
|
||||||
|
extern void initgetrec(void);
|
||||||
|
extern void makefields(int, int);
|
||||||
|
extern void growfldtab(int n);
|
||||||
|
extern void savefs(void);
|
||||||
|
extern int getrec(char **, int *, bool);
|
||||||
|
extern void nextfile(void);
|
||||||
|
extern int readrec(char **buf, int *bufsize, FILE *inf, bool isnew);
|
||||||
|
extern char *getargv(int);
|
||||||
|
extern void setclvar(char *);
|
||||||
|
extern void fldbld(void);
|
||||||
|
extern void cleanfld(int, int);
|
||||||
|
extern void newfld(int);
|
||||||
|
extern void setlastfld(int);
|
||||||
|
extern int refldbld(const char *, const char *);
|
||||||
|
extern void recbld(void);
|
||||||
|
extern Cell *fieldadr(int);
|
||||||
|
extern void yyerror(const char *);
|
||||||
|
extern void bracecheck(void);
|
||||||
|
extern void bcheck2(int, int, int);
|
||||||
|
extern void SYNTAX(const char *, ...)
|
||||||
|
__attribute__((__format__(__printf__, 1, 2)));
|
||||||
|
extern noreturn void FATAL(const char *, ...)
|
||||||
|
__attribute__((__format__(__printf__, 1, 2)));
|
||||||
|
extern void WARNING(const char *, ...)
|
||||||
|
__attribute__((__format__(__printf__, 1, 2)));
|
||||||
|
extern void error(void);
|
||||||
|
extern void eprint(void);
|
||||||
|
extern void bclass(int);
|
||||||
|
extern double errcheck(double, const char *);
|
||||||
|
extern int isclvar(const char *);
|
||||||
|
extern bool is_valid_number(const char *s, bool trailing_stuff_ok,
|
||||||
|
bool *no_trailing, double *result);
|
||||||
|
#define is_number(s, val) is_valid_number(s, false, NULL, val)
|
||||||
|
|
||||||
|
extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, const 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 *awkgetline(Node **, int);
|
||||||
|
extern Cell *getnf(Node **, int);
|
||||||
|
extern Cell *array(Node **, int);
|
||||||
|
extern Cell *awkdelete(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 *, const 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, const char *, bool *);
|
||||||
|
extern const 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 *);
|
||||||
|
|
||||||
|
extern const char *flags2str(int flags);
|
2141
third_party/awk/run.c
vendored
Normal file
2141
third_party/awk/run.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
645
third_party/awk/tran.c
vendored
Normal file
645
third_party/awk/tran.c
vendored
Normal file
|
@ -0,0 +1,645 @@
|
||||||
|
/****************************************************************
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "awk.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 *fsloc; /* FS */
|
||||||
|
Cell *nrloc; /* NR */
|
||||||
|
Cell *nfloc; /* NF */
|
||||||
|
Cell *fnrloc; /* FNR */
|
||||||
|
Cell *ofsloc; /* OFS */
|
||||||
|
Cell *orsloc; /* ORS */
|
||||||
|
Cell *rsloc; /* RS */
|
||||||
|
Array *ARGVtab; /* symbol table containing ARGV[...] */
|
||||||
|
Array *ENVtab; /* symbol table containing ENVIRON[...] */
|
||||||
|
Cell *rstartloc; /* RSTART */
|
||||||
|
Cell *rlengthloc; /* RLENGTH */
|
||||||
|
Cell *subseploc; /* SUBSEP */
|
||||||
|
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);
|
||||||
|
|
||||||
|
fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
|
||||||
|
FS = &fsloc->sval;
|
||||||
|
rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
|
||||||
|
RS = &rsloc->sval;
|
||||||
|
ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
|
||||||
|
OFS = &ofsloc->sval;
|
||||||
|
orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
|
||||||
|
ORS = &orsloc->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;
|
||||||
|
subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
|
||||||
|
SUBSEP = &subseploc->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);
|
||||||
|
free(symtabloc->sval);
|
||||||
|
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 */
|
||||||
|
free(cp->sval);
|
||||||
|
cp->sval = (char *) ARGVtab;
|
||||||
|
for (i = 0; i < ac; i++) {
|
||||||
|
double result;
|
||||||
|
|
||||||
|
sprintf(temp, "%d", i);
|
||||||
|
if (is_number(*av, & result))
|
||||||
|
setsymtab(temp, *av, result, 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);
|
||||||
|
free(cp->sval);
|
||||||
|
cp->sval = (char *) ENVtab;
|
||||||
|
for ( ; *envp; envp++) {
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if ((p = strchr(*envp, '=')) == NULL)
|
||||||
|
continue;
|
||||||
|
if( p == *envp ) /* no left hand side name in env string */
|
||||||
|
continue;
|
||||||
|
*p++ = 0; /* split into two strings at = */
|
||||||
|
if (is_number(p, & result))
|
||||||
|
setsymtab(*envp, p, result, 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(*ap));
|
||||||
|
tp = (Cell **) calloc(n, sizeof(*tp));
|
||||||
|
if (ap == NULL || tp == NULL)
|
||||||
|
FATAL("out of space in makesymtab");
|
||||||
|
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->nelem--;
|
||||||
|
}
|
||||||
|
tp->tab[i] = NULL;
|
||||||
|
}
|
||||||
|
if (tp->nelem != 0)
|
||||||
|
WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
|
||||||
|
free(tp->tab);
|
||||||
|
free(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeelem(Cell *ap, const 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(const char *n, const 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",
|
||||||
|
(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval);
|
||||||
|
return(p);
|
||||||
|
}
|
||||||
|
p = (Cell *) malloc(sizeof(*p));
|
||||||
|
if (p == NULL)
|
||||||
|
FATAL("out of space for symbol table at %s", n);
|
||||||
|
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",
|
||||||
|
(void*)p, p->nval, p->sval, p->fval, p->tval);
|
||||||
|
return(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash(const 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(*np));
|
||||||
|
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(const char *s, Array *tp) /* look for s in tp */
|
||||||
|
{
|
||||||
|
Cell *p;
|
||||||
|
int h;
|
||||||
|
|
||||||
|
h = hash(s, tp->size);
|
||||||
|
for (p = tp->tab[h]; p != NULL; 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;
|
||||||
|
|
||||||
|
f += 0.0; /* normalise negative zero to positive zero */
|
||||||
|
if ((vp->tval & (NUM | STR)) == 0)
|
||||||
|
funnyvar(vp, "assign to");
|
||||||
|
if (isfld(vp)) {
|
||||||
|
donerec = false; /* mark $0 invalid */
|
||||||
|
fldno = atoi(vp->nval);
|
||||||
|
if (fldno > *NF)
|
||||||
|
newfld(fldno);
|
||||||
|
DPRINTF("setting field %d to %g\n", fldno, f);
|
||||||
|
} else if (&vp->fval == NF) {
|
||||||
|
donerec = false; /* mark $0 invalid */
|
||||||
|
setlastfld(f);
|
||||||
|
DPRINTF("setting NF to %g\n", f);
|
||||||
|
} else if (isrec(vp)) {
|
||||||
|
donefld = false; /* mark $1... invalid */
|
||||||
|
donerec = true;
|
||||||
|
savefs();
|
||||||
|
} else if (vp == ofsloc) {
|
||||||
|
if (!donerec)
|
||||||
|
recbld();
|
||||||
|
}
|
||||||
|
if (freeable(vp))
|
||||||
|
xfree(vp->sval); /* free any previous string */
|
||||||
|
vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
|
||||||
|
vp->fmt = NULL;
|
||||||
|
vp->tval |= NUM; /* mark number ok */
|
||||||
|
if (f == -0) /* who would have thought this possible? */
|
||||||
|
f = 0;
|
||||||
|
DPRINTF("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval);
|
||||||
|
return vp->fval = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void funnyvar(Cell *vp, const char *rw)
|
||||||
|
{
|
||||||
|
if (isarr(vp))
|
||||||
|
FATAL("can't %s %s; it's an array name.", rw, vp->nval);
|
||||||
|
if (vp->tval & FCN)
|
||||||
|
FATAL("can't %s %s; it's a function.", rw, vp->nval);
|
||||||
|
WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
|
||||||
|
(void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
int fldno;
|
||||||
|
Awkfloat f;
|
||||||
|
|
||||||
|
DPRINTF("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
|
||||||
|
(void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld);
|
||||||
|
if ((vp->tval & (NUM | STR)) == 0)
|
||||||
|
funnyvar(vp, "assign to");
|
||||||
|
if (isfld(vp)) {
|
||||||
|
donerec = false; /* mark $0 invalid */
|
||||||
|
fldno = atoi(vp->nval);
|
||||||
|
if (fldno > *NF)
|
||||||
|
newfld(fldno);
|
||||||
|
DPRINTF("setting field %d to %s (%p)\n", fldno, s, (const void*)s);
|
||||||
|
} else if (isrec(vp)) {
|
||||||
|
donefld = false; /* mark $1... invalid */
|
||||||
|
donerec = true;
|
||||||
|
savefs();
|
||||||
|
} else if (vp == ofsloc) {
|
||||||
|
if (!donerec)
|
||||||
|
recbld();
|
||||||
|
}
|
||||||
|
t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
|
||||||
|
if (freeable(vp))
|
||||||
|
xfree(vp->sval);
|
||||||
|
vp->tval &= ~(NUM|DONTFREE|CONVC|CONVO);
|
||||||
|
vp->tval |= STR;
|
||||||
|
vp->fmt = NULL;
|
||||||
|
DPRINTF("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
|
||||||
|
(void*)vp, NN(vp->nval), t, (void*)t, vp->tval, donerec, donefld);
|
||||||
|
vp->sval = t;
|
||||||
|
if (&vp->fval == NF) {
|
||||||
|
donerec = false; /* mark $0 invalid */
|
||||||
|
f = getfval(vp);
|
||||||
|
setlastfld(f);
|
||||||
|
DPRINTF("setting NF to %g\n", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(vp->sval);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
fldbld();
|
||||||
|
else if (isrec(vp) && !donerec)
|
||||||
|
recbld();
|
||||||
|
if (!isnum(vp)) { /* not a number */
|
||||||
|
double fval;
|
||||||
|
bool no_trailing;
|
||||||
|
|
||||||
|
if (is_valid_number(vp->sval, true, & no_trailing, & fval)) {
|
||||||
|
vp->fval = fval;
|
||||||
|
if (no_trailing && !(vp->tval&CON))
|
||||||
|
vp->tval |= NUM; /* make NUM only sparingly */
|
||||||
|
} else
|
||||||
|
vp->fval = 0.0;
|
||||||
|
}
|
||||||
|
DPRINTF("getfval %p: %s = %g, t=%o\n",
|
||||||
|
(void*)vp, NN(vp->nval), vp->fval, vp->tval);
|
||||||
|
return(vp->fval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *get_inf_nan(double d)
|
||||||
|
{
|
||||||
|
if (isinf(d)) {
|
||||||
|
return (d < 0 ? "-inf" : "+inf");
|
||||||
|
} else if (isnan(d)) {
|
||||||
|
return (signbit(d) != 0 ? "-nan" : "+nan");
|
||||||
|
} else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
|
||||||
|
{
|
||||||
|
char s[256];
|
||||||
|
double dtemp;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if ((vp->tval & (NUM | STR)) == 0)
|
||||||
|
funnyvar(vp, "read value of");
|
||||||
|
if (isfld(vp) && ! donefld)
|
||||||
|
fldbld();
|
||||||
|
else if (isrec(vp) && ! donerec)
|
||||||
|
recbld();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ADR: This is complicated and more fragile than is desirable.
|
||||||
|
* Retrieving a string value for a number associates the string
|
||||||
|
* value with the scalar. Previously, the string value was
|
||||||
|
* sticky, meaning if converted via OFMT that became the value
|
||||||
|
* (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
|
||||||
|
* changed after a string value was retrieved, the original value
|
||||||
|
* was maintained and used. Also not per POSIX.
|
||||||
|
*
|
||||||
|
* We work around this design by adding two additional flags,
|
||||||
|
* CONVC and CONVO, indicating how the string value was
|
||||||
|
* obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
|
||||||
|
* of the pointer to the xFMT format string used for the
|
||||||
|
* conversion. This pointer is only read, **never** dereferenced.
|
||||||
|
* The next time we do a conversion, if it's coming from the same
|
||||||
|
* xFMT as last time, and the pointer value is different, we
|
||||||
|
* know that the xFMT format string changed, and we need to
|
||||||
|
* redo the conversion. If it's the same, we don't have to.
|
||||||
|
*
|
||||||
|
* There are also several cases where we don't do a conversion,
|
||||||
|
* such as for a field (see the checks below).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Don't duplicate the code for actually updating the value */
|
||||||
|
#define update_str_val(vp) \
|
||||||
|
{ \
|
||||||
|
if (freeable(vp)) \
|
||||||
|
xfree(vp->sval); \
|
||||||
|
if ((p = get_inf_nan(vp->fval)) != NULL) \
|
||||||
|
strcpy(s, p); \
|
||||||
|
else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
|
||||||
|
snprintf(s, sizeof (s), "%.30g", vp->fval); \
|
||||||
|
else \
|
||||||
|
snprintf(s, sizeof (s), *fmt, vp->fval); \
|
||||||
|
vp->sval = tostring(s); \
|
||||||
|
vp->tval &= ~DONTFREE; \
|
||||||
|
vp->tval |= STR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isstr(vp) == 0) {
|
||||||
|
update_str_val(vp);
|
||||||
|
if (fmt == OFMT) {
|
||||||
|
vp->tval &= ~CONVC;
|
||||||
|
vp->tval |= CONVO;
|
||||||
|
} else {
|
||||||
|
/* CONVFMT */
|
||||||
|
vp->tval &= ~CONVO;
|
||||||
|
vp->tval |= CONVC;
|
||||||
|
}
|
||||||
|
vp->fmt = *fmt;
|
||||||
|
} else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
|
||||||
|
goto done;
|
||||||
|
} else if (isstr(vp)) {
|
||||||
|
if (fmt == OFMT) {
|
||||||
|
if ((vp->tval & CONVC) != 0
|
||||||
|
|| ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
|
||||||
|
update_str_val(vp);
|
||||||
|
vp->tval &= ~CONVC;
|
||||||
|
vp->tval |= CONVO;
|
||||||
|
vp->fmt = *fmt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* CONVFMT */
|
||||||
|
if ((vp->tval & CONVO) != 0
|
||||||
|
|| ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
|
||||||
|
update_str_val(vp);
|
||||||
|
vp->tval &= ~CONVO;
|
||||||
|
vp->tval |= CONVC;
|
||||||
|
vp->fmt = *fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
DPRINTF("getsval %p: %s = \"%s (%p)\", t=%o\n",
|
||||||
|
(void*)vp, NN(vp->nval), vp->sval, (void*)vp->sval, vp->tval);
|
||||||
|
return(vp->sval);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getsval(Cell *vp) /* get string val of a Cell */
|
||||||
|
{
|
||||||
|
return get_str_val(vp, CONVFMT);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getpssval(Cell *vp) /* get string val of a Cell for print */
|
||||||
|
{
|
||||||
|
return get_str_val(vp, OFMT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *tostring(const char *s) /* make a copy of string s */
|
||||||
|
{
|
||||||
|
char *p = strdup(s);
|
||||||
|
if (p == NULL)
|
||||||
|
FATAL("out of space in tostring on %s", s);
|
||||||
|
return(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tostringN(const char *s, size_t n) /* make a copy of string s */
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = (char *) malloc(n);
|
||||||
|
if (p == NULL)
|
||||||
|
FATAL("out of space in tostring on %s", s);
|
||||||
|
strcpy(p, s);
|
||||||
|
return(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
|
||||||
|
{
|
||||||
|
Cell *c;
|
||||||
|
char *p;
|
||||||
|
char *sa = getsval(a);
|
||||||
|
char *sb = getsval(b);
|
||||||
|
size_t l = strlen(sa) + strlen(sb) + 1;
|
||||||
|
p = (char *) malloc(l);
|
||||||
|
if (p == NULL)
|
||||||
|
FATAL("out of space concatenating %s and %s", sa, sb);
|
||||||
|
snprintf(p, l, "%s%s", sa, sb);
|
||||||
|
|
||||||
|
l++; // add room for ' '
|
||||||
|
char *newbuf = (char *) malloc(l);
|
||||||
|
if (newbuf == NULL)
|
||||||
|
FATAL("out of space concatenating %s and %s", sa, sb);
|
||||||
|
// See string() in lex.c; a string "xx" is stored in the symbol
|
||||||
|
// table as "xx ".
|
||||||
|
snprintf(newbuf, l, "%s ", p);
|
||||||
|
c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
|
||||||
|
free(p);
|
||||||
|
free(newbuf);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *qstring(const char *is, int delim) /* collect string up to next delim */
|
||||||
|
{
|
||||||
|
const char *os = is;
|
||||||
|
int c, n;
|
||||||
|
const uschar *s = (const uschar *) is;
|
||||||
|
uschar *buf, *bp;
|
||||||
|
|
||||||
|
if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
|
||||||
|
FATAL( "out of space in qstring(%s)", s);
|
||||||
|
for (bp = buf; (c = *s) != delim; s++) {
|
||||||
|
if (c == '\n')
|
||||||
|
SYNTAX( "newline in string %.20s...", os );
|
||||||
|
else if (c != '\\')
|
||||||
|
*bp++ = c;
|
||||||
|
else { /* \something */
|
||||||
|
c = *++s;
|
||||||
|
if (c == 0) { /* \ at end */
|
||||||
|
*bp++ = '\\';
|
||||||
|
break; /* for loop */
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
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;
|
||||||
|
case 'v': *bp++ = '\v'; break;
|
||||||
|
case 'a': *bp++ = '\a'; 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 (char *) buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *flags2str(int flags)
|
||||||
|
{
|
||||||
|
static const struct ftab {
|
||||||
|
const char *name;
|
||||||
|
int value;
|
||||||
|
} flagtab[] = {
|
||||||
|
{ "NUM", NUM },
|
||||||
|
{ "STR", STR },
|
||||||
|
{ "DONTFREE", DONTFREE },
|
||||||
|
{ "CON", CON },
|
||||||
|
{ "ARR", ARR },
|
||||||
|
{ "FCN", FCN },
|
||||||
|
{ "FLD", FLD },
|
||||||
|
{ "REC", REC },
|
||||||
|
{ "CONVC", CONVC },
|
||||||
|
{ "CONVO", CONVO },
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
static char buf[100];
|
||||||
|
int i;
|
||||||
|
char *cp = buf;
|
||||||
|
|
||||||
|
for (i = 0; flagtab[i].name != NULL; i++) {
|
||||||
|
if ((flags & flagtab[i].value) != 0) {
|
||||||
|
if (cp > buf)
|
||||||
|
*cp++ = '|';
|
||||||
|
strcpy(cp, flagtab[i].name);
|
||||||
|
cp += strlen(cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
1
third_party/third_party.mk
vendored
1
third_party/third_party.mk
vendored
|
@ -4,6 +4,7 @@
|
||||||
.PHONY: o/$(MODE)/third_party
|
.PHONY: o/$(MODE)/third_party
|
||||||
o/$(MODE)/third_party: \
|
o/$(MODE)/third_party: \
|
||||||
o/$(MODE)/third_party/argon2 \
|
o/$(MODE)/third_party/argon2 \
|
||||||
|
o/$(MODE)/third_party/awk \
|
||||||
o/$(MODE)/third_party/bzip2 \
|
o/$(MODE)/third_party/bzip2 \
|
||||||
o/$(MODE)/third_party/chibicc \
|
o/$(MODE)/third_party/chibicc \
|
||||||
o/$(MODE)/third_party/compiler_rt \
|
o/$(MODE)/third_party/compiler_rt \
|
||||||
|
|
Loading…
Add table
Reference in a new issue