%{ /* $RCSfile: a2p.y,v $$Revision: 4.1 $$Date: 92/08/07 18:29:12 $ * * Copyright (C) 1991, 1992, 1993, 1994, 1996, 1997, 1999, 2000, * by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * * $Log: a2p.y,v $ */ #include "INTERN.h" #include "a2p.h" int root; int begins = Nullop; int ends = Nullop; %} %token BEGIN END %token REGEX %token SEMINEW NEWLINE COMMENT %token FUN1 FUNN GRGR %token PRINT PRINTF SPRINTF_OLD SPRINTF_NEW SPLIT %token IF ELSE WHILE FOR IN %token EXIT NEXT BREAK CONTINUE RET %token GETLINE DO SUB GSUB MATCH %token FUNCTION USERFUN DELETE %right ASGNOP %right '?' ':' %left OROR %left ANDAND %left IN %left NUMBER VAR SUBSTR INDEX %left MATCHOP %left RELOP '<' '>' %left OR %left STRING %left '+' '-' %left '*' '/' '%' %right UMINUS %left NOT %right '^' %left INCR DECR %left FIELD VFIELD SVFIELD %% program : junk hunks { root = oper4(OPROG,$1,begins,$2,ends); } ; begin : BEGIN '{' maybe states '}' junk { begins = oper4(OJUNK,begins,$3,$4,$6); in_begin = FALSE; $$ = Nullop; } ; end : END '{' maybe states '}' { ends = oper3(OJUNK,ends,$3,$4); $$ = Nullop; } | end NEWLINE { $$ = $1; } ; hunks : hunks hunk junk { $$ = oper3(OHUNKS,$1,$2,$3); } | /* NULL */ { $$ = Nullop; } ; hunk : patpat { $$ = oper1(OHUNK,$1); need_entire = TRUE; } | patpat '{' maybe states '}' { $$ = oper2(OHUNK,$1,oper2(OJUNK,$3,$4)); } | FUNCTION USERFUN '(' arg_list ')' maybe '{' maybe states '}' { fixfargs($2,$4,0); $$ = oper5(OUSERDEF,$2,$4,$6,$8,$9); } | '{' maybe states '}' { $$ = oper2(OHUNK,Nullop,oper2(OJUNK,$2,$3)); } | begin | end ; arg_list: expr_list { $$ = rememberargs($$); } ; patpat : cond { $$ = oper1(OPAT,$1); } | cond ',' cond { $$ = oper2(ORANGE,$1,$3); } ; cond : expr | match | rel | compound_cond | cond '?' expr ':' expr { $$ = oper3(OCOND,$1,$3,$5); } ; compound_cond : '(' compound_cond ')' { $$ = oper1(OCPAREN,$2); } | cond ANDAND maybe cond { $$ = oper3(OCANDAND,$1,$3,$4); } | cond OROR maybe cond { $$ = oper3(OCOROR,$1,$3,$4); } | NOT cond { $$ = oper1(OCNOT,$2); } ; rel : expr RELOP expr { $$ = oper3(ORELOP,$2,$1,$3); } | expr '>' expr { $$ = oper3(ORELOP,string(">",1),$1,$3); } | expr '<' expr { $$ = oper3(ORELOP,string("<",1),$1,$3); } | '(' rel ')' { $$ = oper1(ORPAREN,$2); } ; match : expr MATCHOP expr { $$ = oper3(OMATCHOP,$2,$1,$3); } | expr MATCHOP REGEX { $$ = oper3(OMATCHOP,$2,$1,oper1(OREGEX,$3)); } | REGEX %prec MATCHOP { $$ = oper1(OREGEX,$1); } | '(' match ')' { $$ = oper1(OMPAREN,$2); } ; expr : term { $$ = $1; } | expr term { $$ = oper2(OCONCAT,$1,$2); } | expr '?' expr ':' expr { $$ = oper3(OCOND,$1,$3,$5); } | variable ASGNOP cond { $$ = oper3(OASSIGN,$2,$1,$3); if ((ops[$1].ival & 255) == OFLD) lval_field = TRUE; else if ((ops[$1].ival & 255) == OVFLD) lval_field = TRUE; } ; sprintf : SPRINTF_NEW | SPRINTF_OLD ; term : variable { $$ = $1; } | NUMBER { $$ = oper1(ONUM,$1); } | STRING { $$ = oper1(OSTR,$1); } | term '+' term { $$ = oper2(OADD,$1,$3); } | term '-' term { $$ = oper2(OSUBTRACT,$1,$3); } | term '*' term { $$ = oper2(OMULT,$1,$3); } | term '/' term { $$ = oper2(ODIV,$1,$3); } | term '%' term { $$ = oper2(OMOD,$1,$3); } | term '^' term { $$ = oper2(OPOW,$1,$3); } | term IN VAR { $$ = oper2(ODEFINED,aryrefarg($3),$1); } | variable INCR { $$ = oper1(OPOSTINCR,$1); if ((ops[$1].ival & 255) == OFLD) lval_field = TRUE; else if ((ops[$1].ival & 255) == OVFLD) lval_field = TRUE; } | variable DECR { $$ = oper1(OPOSTDECR,$1); if ((ops[$1].ival & 255) == OFLD) lval_field = TRUE; else if ((ops[$1].ival & 255) == OVFLD) lval_field = TRUE; } | INCR variable { $$ = oper1(OPREINCR,$2); if ((ops[$2].ival & 255) == OFLD) lval_field = TRUE; else if ((ops[$2].ival & 255) == OVFLD) lval_field = TRUE; } | DECR variable { $$ = oper1(OPREDECR,$2); if ((ops[$2].ival & 255) == OFLD) lval_field = TRUE; else if ((ops[$2].ival & 255) == OVFLD) lval_field = TRUE; } | '-' term %prec UMINUS { $$ = oper1(OUMINUS,$2); } | '+' term %prec UMINUS { $$ = oper1(OUPLUS,$2); } | '(' cond ')' { $$ = oper1(OPAREN,$2); } | GETLINE { $$ = oper0(OGETLINE); } | GETLINE variable { $$ = oper1(OGETLINE,$2); } | GETLINE '<' expr { $$ = oper3(OGETLINE,Nullop,string("<",1),$3); if (ops[$3].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; } | GETLINE variable '<' expr { $$ = oper3(OGETLINE,$2,string("<",1),$4); if (ops[$4].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; } | term 'p' GETLINE { $$ = oper3(OGETLINE,Nullop,string("|",1),$1); if (ops[$1].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; } | term 'p' GETLINE variable { $$ = oper3(OGETLINE,$4,string("|",1),$1); if (ops[$1].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; } | FUN1 { $$ = oper0($1); need_entire = do_chop = TRUE; } | FUN1 '(' ')' { $$ = oper1($1,Nullop); need_entire = do_chop = TRUE; } | FUN1 '(' expr ')' { $$ = oper1($1,$3); } | FUNN '(' expr_list ')' { $$ = oper1($1,$3); } | USERFUN '(' expr_list ')' { $$ = oper2(OUSERFUN,$1,$3); } | SPRINTF_NEW '(' expr_list ')' { $$ = oper1(OSPRINTF,$3); } | sprintf expr_list { $$ = oper1(OSPRINTF,$2); } | SUBSTR '(' expr ',' expr ',' expr ')' { $$ = oper3(OSUBSTR,$3,$5,$7); } | SUBSTR '(' expr ',' expr ')' { $$ = oper2(OSUBSTR,$3,$5); } | SPLIT '(' expr ',' VAR ',' expr ')' { $$ = oper3(OSPLIT,$3,aryrefarg(numary($5)),$7); } | SPLIT '(' expr ',' VAR ',' REGEX ')' { $$ = oper3(OSPLIT,$3,aryrefarg(numary($5)),oper1(OREGEX,$7));} | SPLIT '(' expr ',' VAR ')' { $$ = oper2(OSPLIT,$3,aryrefarg(numary($5))); } | INDEX '(' expr ',' expr ')' { $$ = oper2(OINDEX,$3,$5); } | MATCH '(' expr ',' REGEX ')' { $$ = oper2(OMATCH,$3,oper1(OREGEX,$5)); } | MATCH '(' expr ',' expr ')' { $$ = oper2(OMATCH,$3,$5); } | SUB '(' expr ',' expr ')' { $$ = oper2(OSUB,$3,$5); } | SUB '(' REGEX ',' expr ')' { $$ = oper2(OSUB,oper1(OREGEX,$3),$5); } | GSUB '(' expr ',' expr ')' { $$ = oper2(OGSUB,$3,$5); } | GSUB '(' REGEX ',' expr ')' { $$ = oper2(OGSUB,oper1(OREGEX,$3),$5); } | SUB '(' expr ',' expr ',' expr ')' { $$ = oper3(OSUB,$3,$5,$7); } | SUB '(' REGEX ',' expr ',' expr ')' { $$ = oper3(OSUB,oper1(OREGEX,$3),$5,$7); } | GSUB '(' expr ',' expr ',' expr ')' { $$ = oper3(OGSUB,$3,$5,$7); } | GSUB '(' REGEX ',' expr ',' expr ')' { $$ = oper3(OGSUB,oper1(OREGEX,$3),$5,$7); } ; variable: VAR { $$ = oper1(OVAR,$1); } | VAR '[' expr_list ']' { $$ = oper2(OVAR,aryrefarg($1),$3); } | FIELD { $$ = oper1(OFLD,$1); } | SVFIELD { $$ = oper1(OVFLD,oper1(OVAR,$1)); } | VFIELD term { $$ = oper1(OVFLD,$2); } ; expr_list : expr | clist | /* NULL */ { $$ = Nullop; } ; clist : expr ',' maybe expr { $$ = oper3(OCOMMA,$1,$3,$4); } | clist ',' maybe expr { $$ = oper3(OCOMMA,$1,$3,$4); } | '(' clist ')' /* these parens are invisible */ { $$ = $2; } ; junk : junk hunksep { $$ = oper2(OJUNK,$1,$2); } | /* NULL */ { $$ = Nullop; } ; hunksep : ';' { $$ = oper2(OJUNK,oper0(OSEMICOLON),oper0(ONEWLINE)); } | SEMINEW { $$ = oper2(OJUNK,oper0(OSEMICOLON),oper0(ONEWLINE)); } | NEWLINE { $$ = oper0(ONEWLINE); } | COMMENT { $$ = oper1(OCOMMENT,$1); } ; maybe : maybe nlstuff { $$ = oper2(OJUNK,$1,$2); } | /* NULL */ { $$ = Nullop; } ; nlstuff : NEWLINE { $$ = oper0(ONEWLINE); } | COMMENT { $$ = oper1(OCOMMENT,$1); } ; separator : ';' maybe { $$ = oper2(OJUNK,oper0(OSEMICOLON),$2); } | SEMINEW maybe { $$ = oper2(OJUNK,oper0(OSNEWLINE),$2); } | NEWLINE maybe { $$ = oper2(OJUNK,oper0(OSNEWLINE),$2); } | COMMENT maybe { $$ = oper2(OJUNK,oper1(OSCOMMENT,$1),$2); } ; states : states statement { $$ = oper2(OSTATES,$1,$2); } | /* NULL */ { $$ = Nullop; } ; statement : simple separator maybe { $$ = oper2(OJUNK,oper2(OSTATE,$1,$2),$3); } | ';' maybe { $$ = oper2(OSTATE,Nullop,oper2(OJUNK,oper0(OSEMICOLON),$2)); } | SEMINEW maybe { $$ = oper2(OSTATE,Nullop,oper2(OJUNK,oper0(OSNEWLINE),$2)); } | compound ; simpnull: simple | /* NULL */ { $$ = Nullop; } ; simple : expr | PRINT expr_list redir expr { $$ = oper3(OPRINT,$2,$3,$4); do_opens = TRUE; saw_ORS = saw_OFS = TRUE; if (!$2) need_entire = TRUE; if (ops[$4].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; } | PRINT expr_list { $$ = oper1(OPRINT,$2); if (!$2) need_entire = TRUE; saw_ORS = saw_OFS = TRUE; } | PRINTF expr_list redir expr { $$ = oper3(OPRINTF,$2,$3,$4); do_opens = TRUE; if (!$2) need_entire = TRUE; if (ops[$4].ival != OSTR + (1<<8)) do_fancy_opens = TRUE; } | PRINTF expr_list { $$ = oper1(OPRINTF,$2); if (!$2) need_entire = TRUE; } | BREAK { $$ = oper0(OBREAK); } | NEXT { $$ = oper0(ONEXT); } | EXIT { $$ = oper0(OEXIT); } | EXIT expr { $$ = oper1(OEXIT,$2); } | CONTINUE { $$ = oper0(OCONTINUE); } | RET { $$ = oper0(ORETURN); } | RET expr { $$ = oper1(ORETURN,$2); } | DELETE VAR '[' expr_list ']' { $$ = oper2(ODELETE,aryrefarg($2),$4); } ; redir : '>' %prec FIELD { $$ = oper1(OREDIR,string(">",1)); } | GRGR { $$ = oper1(OREDIR,string(">>",2)); } | '|' { $$ = oper1(OREDIR,string("|",1)); } ; compound : IF '(' cond ')' maybe statement { $$ = oper2(OIF,$3,bl($6,$5)); } | IF '(' cond ')' maybe statement ELSE maybe statement { $$ = oper3(OIF,$3,bl($6,$5),bl($9,$8)); } | WHILE '(' cond ')' maybe statement { $$ = oper2(OWHILE,$3,bl($6,$5)); } | DO maybe statement WHILE '(' cond ')' { $$ = oper2(ODO,bl($3,$2),$6); } | FOR '(' simpnull ';' cond ';' simpnull ')' maybe statement { $$ = oper4(OFOR,$3,$5,$7,bl($10,$9)); } | FOR '(' simpnull ';' ';' simpnull ')' maybe statement { $$ = oper4(OFOR,$3,string("",0),$6,bl($9,$8)); } | FOR '(' expr ')' maybe statement { $$ = oper2(OFORIN,$3,bl($6,$5)); } | '{' maybe states '}' maybe { $$ = oper3(OBLOCK,oper2(OJUNK,$2,$3),Nullop,$5); } ; %% int yyparse (void); #include "a2py.c"