/* perly.y
*
- * Copyright (c) 1991-2002, Larry Wall
+ * Copyright (c) 1991-2002, 2003, 2004 Larry Wall
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
* All that is gold does not glitter, not all those who wander are lost.'
*/
-%{
-#include "EXTERN.h"
-#define PERL_IN_PERLY_C
-#include "perl.h"
-#ifdef EBCDIC
-#undef YYDEBUG
-#endif
-#define dep() deprecate("\"do\" to call subroutines")
-
-/* stuff included here to make perly_c.diff apply better */
-
-#define yydebug PL_yydebug
-#define yynerrs PL_yynerrs
-#define yyerrflag PL_yyerrflag
-#define yychar PL_yychar
-#define yyval PL_yyval
-#define yylval PL_yylval
-
-struct ysv {
- short* yyss;
- YYSTYPE* yyvs;
- int oldyydebug;
- int oldyynerrs;
- int oldyyerrflag;
- int oldyychar;
- YYSTYPE oldyyval;
- YYSTYPE oldyylval;
-};
-
-static void yydestruct(pTHX_ void *ptr);
-
-%}
+/* This file holds the grammar for the Perl language. If edited, you need
+ * to run regen_perly.pl, which re-creates the files perly.h, perly.tab
+ * and perly.act which are derived from this.
+ *
+ * The main job of of this grammar is to call the various newFOO()
+ * functions in op.c to build a syntax tree of OP structs.
+ * It relies on the lexer in toke.c to do the tokenizing.
+ */
-%start prog
+/* Make the parser re-entrant. */
-%{
-#if 0 /* get this from perly.h instead */
-%}
+%pure_parser
+
+%start prog
%union {
I32 ival;
GV *gvval;
}
-%{
-#endif /* 0 */
-
-#ifdef USE_PURE_BISON
-#define YYLEX_PARAM (&yychar)
-#define yylex yylex_r
-#endif
-
-%}
-
%token <ival> '{'
%token <opval> WORD METHOD FUNCMETH THING PMFUNC PRIVATEREF
%token <ival> LOCAL MY MYSUB
%token COLONATTR
-%type <ival> prog decl format startsub startanonsub startformsub
-%type <ival> progstart remember mremember '&'
+%type <ival> prog decl format startsub startanonsub startformsub mintro
+%type <ival> progstart remember mremember '&' savescope
%type <opval> block mblock lineseq line loop cond else
%type <opval> expr term subscripted scalar ary hsh arylen star amper sideff
-%type <opval> argexpr nexpr texpr iexpr mexpr mnexpr mtexpr miexpr
+%type <opval> argexpr nexpr texpr iexpr mexpr mnexpr miexpr
%type <opval> listexpr listexprcom indirob listop method
%type <opval> formname subname proto subbody cont my_scalar
%type <opval> subattrlist myattrlist mysubrout myattrterm myterm
%nonassoc PREC_LOW
%nonassoc LOOPEX
-%left <ival> OROP
+%left <ival> OROP DOROP
%left ANDOP
%right NOTOP
%nonassoc LSTOP LSTOPSUB
%right <ival> ASSIGNOP
%right '?' ':'
%nonassoc DOTDOT
-%left OROR
+%left OROR DORDOR
%left ANDAND
%left <ival> BITOROP
%left <ival> BITANDOP
progstart:
{
-#if defined(YYDEBUG) && defined(DEBUGGING)
- yydebug = (DEBUG_p_TEST);
-#endif
PL_expect = XSTATE; $$ = block_start(TRUE);
}
;
{ $$ = block_start(FALSE); }
;
+savescope: /* NULL */ /* remember stack pos in case of error */
+ { $$ = PL_savestack_ix; }
+
/* A collection of "lines" in the program */
lineseq : /* NULL */
{ $$ = Nullop; }
| lineseq decl
{ $$ = $1; }
- | lineseq line
- { $$ = append_list(OP_LINESEQ,
- (LISTOP*)$1, (LISTOP*)$2);
+ | lineseq savescope line
+ { LEAVE_SCOPE($2);
+ $$ = append_list(OP_LINESEQ,
+ (LISTOP*)$1, (LISTOP*)$3);
PL_pad_reset_pending = TRUE;
- if ($1 && $2) PL_hints |= HINT_BLOCK_SCOPE; }
+ if ($1 && $3) PL_hints |= HINT_BLOCK_SCOPE; }
;
/* A "line" in the program */
;
/* Loops: while, until, for, and a bare block */
-loop : label WHILE '(' remember mtexpr ')' mblock cont
+loop : label WHILE '(' remember texpr ')' mintro mblock cont
{ PL_copline = (line_t)$2;
$$ = block_end($4,
newSTATEOP(0, $1,
newWHILEOP(0, 1, (LOOP*)Nullop,
- $2, $5, $7, $8))); }
- | label UNTIL '(' remember miexpr ')' mblock cont
+ $2, $5, $8, $9, $7))); }
+ | label UNTIL '(' remember iexpr ')' mintro mblock cont
{ PL_copline = (line_t)$2;
$$ = block_end($4,
newSTATEOP(0, $1,
newWHILEOP(0, 1, (LOOP*)Nullop,
- $2, $5, $7, $8))); }
+ $2, $5, $8, $9, $7))); }
| label FOR MY remember my_scalar '(' mexpr ')' mblock cont
{ $$ = block_end($4,
newFOROP(0, $1, (line_t)$2, $5, $7, $9, $10)); }
| label FOR '(' remember mexpr ')' mblock cont
{ $$ = block_end($4,
newFOROP(0, $1, (line_t)$2, Nullop, $5, $7, $8)); }
- | label FOR '(' remember mnexpr ';' mtexpr ';' mnexpr ')' mblock
+ | label FOR '(' remember mnexpr ';' texpr ';' mintro mnexpr ')'
+ mblock
/* basically fake up an initialize-while lineseq */
{ OP *forop;
PL_copline = (line_t)$2;
forop = newSTATEOP(0, $1,
newWHILEOP(0, 1, (LOOP*)Nullop,
$2, scalar($7),
- $11, $9));
+ $12, $10, $9));
if ($5) {
forop = append_elem(OP_LINESEQ,
newSTATEOP(0, ($1?savepv($1):Nullch),
| label block cont /* a block is a loop that happens once */
{ $$ = newSTATEOP(0, $1,
newWHILEOP(0, 1, (LOOP*)Nullop,
- NOLINE, Nullop, $2, $3)); }
+ NOLINE, Nullop, $2, $3, 0)); }
;
+/* determine whether there are any new my declarations */
+mintro : /* NULL */
+ { $$ = (PL_min_intro_pending &&
+ PL_max_intro_pending >= PL_min_intro_pending);
+ intro_my(); }
+
/* Normal expression */
nexpr : /* NULL */
{ $$ = Nullop; }
{ $$ = $1; intro_my(); }
;
-mtexpr : texpr
- { $$ = $1; intro_my(); }
- ;
-
miexpr : iexpr
{ $$ = $1; intro_my(); }
;
package : PACKAGE WORD ';'
{ package($2); }
- | PACKAGE ';'
- { package(Nullop); }
;
use : USE startsub
{ $$ = newLOGOP(OP_AND, 0, $1, $3); }
| expr OROP expr
{ $$ = newLOGOP($2, 0, $1, $3); }
+ | expr DOROP expr
+ { $$ = newLOGOP(OP_DOR, 0, $1, $3); }
| argexpr %prec PREC_LOW
;
;
/* List operators */
-listop : LSTOP indirob argexpr /* print $fh @args */
+listop : LSTOP indirob argexpr /* map {...} @args or print $fh @args */
{ $$ = convert($1, OPf_STACKED,
prepend_elem(OP_LIST, newGVREF($1,$2), $3) ); }
| FUNC '(' indirob expr ')' /* print ($fh @args */
{ $$ = convert($1, 0, $2); }
| FUNC '(' listexprcom ')' /* print (@args) */
{ $$ = convert($1, 0, $3); }
- | LSTOPSUB startanonsub block /* map { foo } ... */
+ | LSTOPSUB startanonsub block /* sub f(&@); f { foo } ... */
{ $3 = newANONATTRSUB($2, 0, Nullop, $3); }
listexpr %prec LSTOP /* ... @bar */
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
subscripted: star '{' expr ';' '}' /* *main::{something} */
/* In this and all the hash accessors, ';' is
* provided by the tokeniser */
- { $$ = newBINOP(OP_GELEM, 0, $1, scalar($3)); }
+ { $$ = newBINOP(OP_GELEM, 0, $1, scalar($3));
+ PL_expect = XOPERATOR; }
| scalar '[' expr ']' /* $array[$element] */
{ $$ = newBINOP(OP_AELEM, 0, oopsAV($1), scalar($3)); }
| term ARROW '[' expr ']' /* somearef->[$element] */
{ $$ = newLOGOP(OP_AND, 0, $1, $3); }
| term OROR term /* $x || $y */
{ $$ = newLOGOP(OP_OR, 0, $1, $3); }
+ | term DORDOR term /* $x // $y */
+ { $$ = newLOGOP(OP_DOR, 0, $1, $3); }
| term MATCHOP term /* $x =~ /$y/ */
{ $$ = bind_match($2, $1, $3); }
;
{ $$ = newUNOP(OP_NOT, 0, scalar($2)); }
| UNIOP /* Unary op, $_ implied */
{ $$ = newOP($1, 0); }
- | UNIOP block /* eval { foo }, I *think* */
+ | UNIOP block /* eval { foo } */
{ $$ = newUNOP($1, 0, $2); }
| UNIOP term /* Unary op */
{ $$ = newUNOP($1, 0, $2); }
{ $$ = newUNOP(OP_ENTERSUB, OPf_STACKED,
scalar($1)); }
| FUNC1 '(' ')' /* not () */
- { $$ = newOP($1, OPf_SPECIAL); }
+ { $$ = $1 == OP_NOT ? newUNOP($1, 0, newSVOP(OP_CONST, 0, newSViv(0)))
+ : newOP($1, OPf_SPECIAL); }
| FUNC1 '(' expr ')' /* not($foo) */
{ $$ = newUNOP($1, 0, $3); }
- | PMFUNC '(' term ')' /* split (/foo/) */
- { $$ = pmruntime($1, $3, Nullop); }
- | PMFUNC '(' term ',' term ')' /* split (/foo/,$bar) */
- { $$ = pmruntime($1, $3, $5); }
+ | PMFUNC '(' argexpr ')' /* m//, s///, tr/// */
+ { $$ = pmruntime($1, $3, 1); }
| WORD
| listop
;
| PRIVATEREF
{ $$ = $1; }
;
-
-%% /* PROGRAM */
-
-/* more stuff added to make perly_c.diff easier to apply */
-
-#ifdef yyparse
-#undef yyparse
-#endif
-#define yyparse() Perl_yyparse(pTHX)
-