%{
#include "awk.h"
static NODE * fliplist ANSI((NODE *np));
%}
%union {
NODE *node;
};
%token <node> PARM ARRAY UFUNC FIELD IN INDEX CONCAT
%token <node> NOT AND OR EXP QUEST
%token <node> EQ NE GE LE GT LT
%token <node> ADD SUB MUL DIV REM INC DEC PRE_INC PRE_DEC
%token <node> GETLINE CALLFUNC RE TILDE NRE
%token ASG
%token <node> PRINT PRINTF
%token <node> EXIT RETURN BREAK CONTINUE NEXT
%token <node> DELETE WHILE DO FOR FORIN IF
%token <node> CONSTANT VAR FUNC
%token <node> DEFFUNC BEGIN END CLOSE ELSE PACT
%right ELSE
%token DOT CALLUFUNC
%token KEYWORD SVAR
%token PIPESYM
%token BAR
CARAT
LANGLE
RANGLE
PLUSC
HYPHEN
STAR
SLASH
PERCENT
EXCLAMATION
DOLLAR
LSQUARE
RSQUARE
LPAREN
RPAREN
SEMI
LBRACE
RBRACE
%left COMMA
%right BAR PIPE WRITE APPEND
%right ASG AADD ASUB AMUL ADIV AREM AEXP
%right QUEST COLON
%left OR
%left AND
%left IN
%left CARAT
%left TILDE NRE
%left EQ NE LANGLE RANGLE GE LE
%left CONCAT
%left PLUSC HYPHEN
%left STAR SLASH PERCENT
%right UPLUS UMINUS
%right EXCLAMATION
%right EXP
%right INC DEC URE
%left DOLLAR LSQUARE RSQUARE
%left LPAREN RPAREN
%type <node> prog rule pattern expr rvalue lvalue fexpr varlist varlist2
%type <node> statement statlist fileout exprlist eexprlist simplepattern
%type <node> getline optvar var
%type <node> dummy
%start dummy
%%
dummy:
prog {
yytree = fliplist(yytree);
}
;
prog:
rule {
yytree = $1;
}
| rule SEMI prog {
if ($1 != NNULL) {
if (yytree != NNULL)
yytree = node(COMMA, $1, yytree); else
yytree = $1;
}
}
;
rule: pattern LBRACE statlist RBRACE {
$$ = node(PACT, $1, $3);
doing_begin = 0;
}
| LBRACE statlist RBRACE {
npattern++;
$$ = node(PACT, NNULL, $2);
}
| pattern {
$$ = node(PACT, $1, node(PRINT, NNULL, NNULL));
doing_begin = 0;
}
| DEFFUNC VAR
{ $2->n_type = UFUNC; funparm = 1; }
LPAREN varlist RPAREN
{ funparm = 0; }
LBRACE statlist { uexit($5); } RBRACE {
$2->n_ufunc = node(DEFFUNC, $5, fliplist($9));
$$ = NNULL;
}
| DEFFUNC UFUNC {
awkerr((char *) gettext("function \"%S\" redefined"), $2->n_name);
}
| {
$$ = NNULL;
}
;
pattern:
simplepattern
| expr COMMA expr {
++npattern;
$$ = node(COMMA, $1, $3);
}
;
simplepattern:
BEGIN {
$$ = node(BEGIN, NNULL, NNULL);
doing_begin++;
}
| END {
++npattern;
$$ = node(END, NNULL, NNULL);
}
| expr {
++npattern;
$$ = $1;
}
;
eexprlist:
exprlist
| {
$$ = NNULL;
}
;
exprlist:
expr %prec COMMA
| exprlist COMMA expr {
$$ = node(COMMA, $1, $3);
}
;
varlist:
{
$$ = NNULL;
}
| varlist2
;
varlist2:
var
| var COMMA varlist2 {
$$ = node(COMMA, $1, $3);
}
;
fexpr:
expr
| {
$$ = NNULL;
}
;
expr:
expr PLUSC expr {
$$ = node(ADD, $1, $3);
}
| expr HYPHEN expr {
$$ = node(SUB, $1, $3);
}
| expr STAR expr {
$$ = node(MUL, $1, $3);
}
| expr SLASH expr {
$$ = node(DIV, $1, $3);
}
| expr PERCENT expr {
$$ = node(REM, $1, $3);
}
| expr EXP expr {
$$ = node(EXP, $1, $3);
}
| expr AND expr {
$$ = node(AND, $1, $3);
}
| expr OR expr {
$$ = node(OR, $1, $3);
}
| expr QUEST expr COLON expr {
$$ = node(QUEST, $1, node(COLON, $3, $5));
}
| lvalue ASG expr {
$$ = node(ASG, $1, $3);
}
| lvalue AADD expr {
$$ = node(AADD, $1, $3);
}
| lvalue ASUB expr {
$$ = node(ASUB, $1, $3);
}
| lvalue AMUL expr {
$$ = node(AMUL, $1, $3);
}
| lvalue ADIV expr {
$$ = node(ADIV, $1, $3);
}
| lvalue AREM expr {
$$ = node(AREM, $1, $3);
}
| lvalue AEXP expr {
$$ = node(AEXP, $1, $3);
}
| lvalue INC {
$$ = node(INC, $1, NNULL);
}
| lvalue DEC {
$$ = node(DEC, $1, NNULL);
}
| expr EQ expr {
$$ = node(EQ, $1, $3);
}
| expr NE expr {
$$ = node(NE, $1, $3);
}
| expr RANGLE expr {
$$ = node(GT, $1, $3);
}
| expr LANGLE expr {
$$ = node(LT, $1, $3);
}
| expr GE expr {
$$ = node(GE, $1, $3);
}
| expr LE expr {
$$ = node(LE, $1, $3);
}
| expr TILDE expr {
$$ = node(TILDE, $1, $3);
}
| expr NRE expr {
$$ = node(NRE, $1, $3);
}
| expr IN var {
$$ = node(IN, $3, $1);
}
| LPAREN exprlist RPAREN IN var {
$$ = node(IN, $5, $2);
}
| getline
| rvalue
| expr CONCAT expr {
$$ = node(CONCAT, $1, $3);
}
;
lvalue:
DOLLAR rvalue {
$$ = node(FIELD, $2, NNULL);
}
| var %prec COMMA
| var LSQUARE exprlist RSQUARE {
$$ = node(INDEX, $1, $3);
}
;
var:
VAR
| PARM
;
rvalue:
lvalue %prec COMMA
| CONSTANT
| LPAREN expr RPAREN term {
$$ = $2;
}
| EXCLAMATION expr {
$$ = node(NOT, $2, NNULL);
}
| HYPHEN expr %prec UMINUS {
$$ = node(SUB, const0, $2);
}
| PLUSC expr %prec UPLUS {
$$ = $2;
}
| DEC lvalue {
$$ = node(PRE_DEC, $2, NNULL);
}
| INC lvalue {
$$ = node(PRE_INC, $2, NNULL);
}
| FUNC {
$$ = node(CALLFUNC, $1, NNULL);
}
| FUNC LPAREN eexprlist RPAREN term {
$$ = node(CALLFUNC, $1, $3);
}
| UFUNC LPAREN eexprlist RPAREN term {
$$ = node(CALLUFUNC, $1, $3);
}
| VAR LPAREN eexprlist RPAREN term {
$$ = node(CALLUFUNC, $1, $3);
}
| SLASH {redelim='/';} URE SLASH %prec URE {
$$ = $<node>3;
}
;
statement:
FOR LPAREN fexpr SEMI fexpr SEMI fexpr RPAREN statement {
$$ = node(FOR, node(COMMA, $3, node(COMMA, $5, $7)), $9);
}
| FOR LPAREN var IN var RPAREN statement {
register NODE *np;
np = $7;
if (np != NNULL
&& np->n_type == DELETE
&& (np = np->n_left)->n_type == INDEX
&& np->n_left == $5
&& np->n_right == $3)
$$ = node(DELETE, $5, NNULL);
else
$$ = node(FORIN, node(IN, $3, $5), $7);
}
| WHILE LPAREN expr RPAREN statement {
$$ = node(WHILE, $3, $5);
}
| DO statement WHILE LPAREN expr RPAREN {
$$ = node(DO, $5, $2);
}
| IF LPAREN expr RPAREN statement ELSE statement {
$$ = node(IF, $3, node(ELSE, $5, $7));
}
| IF LPAREN expr RPAREN statement %prec ELSE {
$$ = node(IF, $3, node(ELSE, $5, NNULL));
}
| CONTINUE SEMI {
$$ = node(CONTINUE, NNULL, NNULL);
}
| BREAK SEMI {
$$ = node(BREAK, NNULL, NNULL);
}
| NEXT SEMI {
$$ = node(NEXT, NNULL, NNULL);
}
| DELETE lvalue SEMI {
$$ = node(DELETE, $2, NNULL);
}
| RETURN fexpr SEMI {
$$ = node(RETURN, $2, NNULL);
}
| EXIT fexpr SEMI {
$$ = node(EXIT, $2, NNULL);
}
| PRINT eexprlist fileout SEMI {
$$ = node(PRINT, $2, $3);
}
| PRINT LPAREN exprlist RPAREN fileout SEMI {
$$ = node(PRINT, $3, $5);
}
| PRINTF exprlist fileout SEMI {
$$ = node(PRINTF, $2, $3);
}
| PRINTF LPAREN exprlist RPAREN fileout SEMI {
$$ = node(PRINTF, $3, $5);
}
| expr SEMI {
$$ = $1;
}
| SEMI {
$$ = NNULL;
}
| LBRACE statlist RBRACE {
$$ = $2;
}
;
statlist:
statement
| statlist statement {
if ($1 == NNULL)
$$ = $2;
else if ($2 == NNULL)
$$ = $1;
else
$$ = node(COMMA, $1, $2);
}
;
fileout:
WRITE expr {
$$ = node(WRITE, $2, NNULL);
}
| APPEND expr {
$$ = node(APPEND, $2, NNULL);
}
| PIPE expr {
$$ = node(PIPE, $2, NNULL);
}
| {
$$ = NNULL;
}
;
getline:
GETLINE optvar %prec WRITE {
$$ = node(GETLINE, $2, NNULL);
}
| expr BAR GETLINE optvar {
$$ = node(GETLINE, $4, node(PIPESYM, $1, NNULL));
}
| GETLINE optvar LANGLE expr {
$$ = node(GETLINE, $2, node(LT, $4, NNULL));
}
;
optvar:
lvalue
| {
$$ = NNULL;
}
;
term:
{catterm = 1;}
;
%%
static NODE *
fliplist(NODE *np)
{
int type;
if (np!=NNULL && !isleaf(np->n_flags)
#if 0
&& (type = np->n_type)!=FUNC && type!=UFUNC
#endif
) {
np->n_right = fliplist(np->n_right);
if ((type=np->n_type)==COMMA) {
register NODE *lp;
while ((lp = np->n_left)!=NNULL && lp->n_type==COMMA) {
register NODE* *spp;
lp->n_right = fliplist(lp->n_right);
for (spp = &lp->n_right;
*spp != NNULL && (*spp)->n_type==COMMA;
spp = &(*spp)->n_right)
;
np->n_left = *spp;
*spp = np;
np = lp;
}
}
if (np->n_left != NULL &&
(type = np->n_left->n_type)!= FUNC && type!=UFUNC)
np->n_left = fliplist(np->n_left);
}
return (np);
}