%{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * awk -- YACC grammar * * Copyright (c) 1995 by Sun Microsystems, Inc. * * Copyright 1986, 1992 by Mortice Kern Systems Inc. All rights reserved. * * This Software is unpublished, valuable, confidential property of * Mortice Kern Systems Inc. Use is authorized only in accordance * with the terms and conditions of the source licence agreement * protecting this Software. Any unauthorized use or disclosure of * this Software is strictly prohibited and will result in the * termination of the licence agreement. * * NOTE: this grammar correctly produces NO shift/reduce conflicts from YACC. * */ /* * Do not use any character constants as tokens, so the resulting C file * is codeset independent. */ #ident "%Z%%M% %I% %E% SMI" #include "awk.h" static NODE * fliplist ANSI((NODE *np)); %} %union { NODE *node; }; /* * Do not use any character constants as tokens, so the resulting C file * is codeset independent. * * Declare terminal symbols before their operator * precedences to get them in a contiguous block * for giant switches in action() and exprreduce(). */ /* Tokens from exprreduce() */ %token PARM ARRAY UFUNC FIELD IN INDEX CONCAT %token NOT AND OR EXP QUEST %token EQ NE GE LE GT LT %token ADD SUB MUL DIV REM INC DEC PRE_INC PRE_DEC %token GETLINE CALLFUNC RE TILDE NRE /* Tokens shared by exprreduce() and action() */ %token ASG /* Tokens from action() */ %token PRINT PRINTF %token EXIT RETURN BREAK CONTINUE NEXT %token DELETE WHILE DO FOR FORIN IF /* * Terminal symbols not used in action() and exprrreduce() * switch statements. */ %token CONSTANT VAR FUNC %token DEFFUNC BEGIN END CLOSE ELSE PACT %right ELSE %token DOT CALLUFUNC /* * Tokens not used in grammar */ %token KEYWORD SVAR %token PIPESYM /* * Tokens representing character constants * TILDE, '~', taken care of above */ %token BAR /* '|' */ CARAT /* '^' */ LANGLE /* '<' */ RANGLE /* '>' */ PLUSC /* '+' */ HYPHEN /* '-' */ STAR /* '*' */ SLASH /* '/' */ PERCENT /* '%' */ EXCLAMATION /* '!' */ DOLLAR /* '$' */ LSQUARE /* '[' */ RSQUARE /* ']' */ LPAREN /* '(' */ RPAREN /* ')' */ SEMI /* ';' */ LBRACE /* '{' */ RBRACE /* '}' */ /* * Priorities of operators * Lowest to highest */ %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 prog rule pattern expr rvalue lvalue fexpr varlist varlist2 %type statement statlist fileout exprlist eexprlist simplepattern %type getline optvar var %type 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); /* NOTREACHED */ } | = { $$ = 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; } ; /* * Normal expression (includes regular expression) */ 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); } /* * Prevents conflict with FOR LPAREN var IN var RPAREN production */ | 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 = { $$ = $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; /* * attempt to optimize statements for the form * for (i in x) delete x[i] * to * delete x */ 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;} ; %% /* * Flip a left-recursively generated list * so that it can easily be traversed from left * to right without recursion. */ static NODE * fliplist(np) register 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); }