Allow specification of semantic predicates.

These changes allow users to prefix an action with %? to indicate that it
is a semantic predicate---an expression that is evaluated immediately (not
deferred, even in GLR nondeterministic mode) and causes a syntax error if
false.  In GLR parsers, this has the effect of killing one of a set of
split-off parses, just as would an ordinary syntax error.

Changelog:

    * NEWS: Describe new semantic-predicate feature.
    * data/c.m4 (b4_predicate_case): New definition.
    * data/java.m4 (b4_predicate_case): New definition.
    * data/glr.c (yyimmediate): Add definition.
    (yydoAction): Remove comment, now obsolete.
    Do YY_REDUCE_PRINT here.
    (yyglrReduce): Alter comment to indicate that semantic values
    need not be deferred.
    Remove YY_REDUCE_PRINT from here; done in yydoAction.
    (yyprocessOneStack): Pass immediate flag.
    Delete stacks rejected by predicates in newly split-off parsers.
    Change handling of yyerr so that only current stack gets deleted
    when semantic predicate fails.
    (yyfillin): Don't crash if a semantic value is unresolved (as may
    happen in predicate rules).
    Copy lr state as well in debugging mode.
    Update comment on setting of yysval to include yyloc as well.
    (yy_reduce_print): Add yynormal argument.  Perform fillin properly.
    Report unresolved RHS values.
    (yyimmediate): New table.
    * src/gram.h (struct rule): Add is_predicate field.
    * src/output.c (user_actions_output): Use b4_predicate_case for
    predicates.
    (prepare_symbols): Output yyimmediate.
    * src/scan-gram.l: Add %? token, SC_PREDICATE state.
    * src/scan-code.l (code_props_rule_action_init): Add is_predicate
    argument.
    * src/scan-code.h (struct code_props): Add is_predicate field.
    (code_props_rule_action_init): New interface.
    * src/parse-gram.y (%?{...}): New token.
    (rhs): Add %?{...} rule.
    * src/parse-gram.c: Regenerate.
    * src/parse-gram.h: Regenerate.
    * src/reader.c (grammar_current_rule_action_append): Add
    immediate argument.
    (grammar_midrule_action): Use new interface for
    code_props_rule_action_init.
    (grammar_current_rule_action_append): Ditto.
    (packgram): Transfer is_predicate value.
    * src/reader.h (grammar_current_rule_action_append): New interface.
    * doc/bison.texinfo: Document semantic predicates (%?).

    * data/glr.c (yylhsNonterm, yyisDefaultedState,yyDefaultAction)
    (yygetLRActions,yynewGLRStackItem,yyaddDeferredAction,yyinitStateSet)
    (yyinitGLRStack,yyexpandGLRStack,yyupdateSplit,yymarkStackDeleted)
    (yyundeleteLastStack,yyglrShift,yyglrShiftDefer,yydoAction,yyglrReduce)
    (yyidenticalOptions,yymergeOptionSets,yyresolveStates,yyresolveAction)
    (yyresolveLocations,yyresolveValue,yyreducePrint): Update parameter
    names in comments and mention all parameters.
    (struct yyGLRState): Fix description of yyposn field.
    (yyresolveLocations): Correct comment so as not to imply action when
    yyn1==0.
This commit is contained in:
Paul Hilfinger
2010-07-22 19:08:10 -07:00
parent 804e83b26d
commit ca2a6d1587
16 changed files with 919 additions and 646 deletions

View File

@@ -1,3 +1,58 @@
2010-07-23 Paul Hilfinger <hilfingr@EECS.Berkeley.EDU>
* NEWS: Describe new semantic-predicate feature.
* data/c.m4 (b4_predicate_case): New definition.
* data/java.m4 (b4_predicate_case): New definition.
* data/glr.c (yyimmediate): Add definition.
(yydoAction): Remove comment, now obsolete.
Do YY_REDUCE_PRINT here.
(yyglrReduce): Alter comment to indicate that semantic values
need not be deferred.
Remove YY_REDUCE_PRINT from here; done in yydoAction.
(yyprocessOneStack): Pass immediate flag.
Delete stacks rejected by predicates in newly split-off parsers.
Change handling of yyerr so that only current stack gets deleted
when semantic predicate fails.
(yyfillin): Don't crash if a semantic value is unresolved (as may
happen in predicate rules).
Copy lr state as well in debugging mode.
Update comment on setting of yysval to include yyloc as well.
(yy_reduce_print): Add yynormal argument. Perform fillin properly.
Report unresolved RHS values.
(yyimmediate): New table.
* src/gram.h (struct rule): Add is_predicate field.
* src/output.c (user_actions_output): Use b4_predicate_case for
predicates.
(prepare_symbols): Output yyimmediate.
* src/scan-gram.l: Add %? token, SC_PREDICATE state.
* src/scan-code.l (code_props_rule_action_init): Add is_predicate
argument.
* src/scan-code.h (struct code_props): Add is_predicate field.
(code_props_rule_action_init): New interface.
* src/parse-gram.y (%?{...}): New token.
(rhs): Add %?{...} rule.
* src/parse-gram.c: Regenerate.
* src/parse-gram.h: Regenerate.
* src/reader.c (grammar_current_rule_action_append): Add
immediate argument.
(grammar_midrule_action): Use new interface for
code_props_rule_action_init.
(grammar_current_rule_action_append): Ditto.
(packgram): Transfer is_predicate value.
* src/reader.h (grammar_current_rule_action_append): New interface.
* doc/bison.texinfo: Document semantic predicates (%?).
* data/glr.c (yylhsNonterm, yyisDefaultedState,yyDefaultAction)
(yygetLRActions,yynewGLRStackItem,yyaddDeferredAction,yyinitStateSet)
(yyinitGLRStack,yyexpandGLRStack,yyupdateSplit,yymarkStackDeleted)
(yyundeleteLastStack,yyglrShift,yyglrShiftDefer,yydoAction,yyglrReduce)
(yyidenticalOptions,yymergeOptionSets,yyresolveStates,yyresolveAction)
(yyresolveLocations,yyresolveValue,yyreducePrint): Update parameter
names in comments and mention all parameters.
(struct yyGLRState): Fix description of yyposn field.
(yyresolveLocations): Correct comment so as not to imply action when
yyn1==0.
2010-06-17 Paul Eggert <eggert@cs.ucla.edu> 2010-06-17 Paul Eggert <eggert@cs.ucla.edu>
Update from GFDL GFDL 1.2 to 1.3. Update from GFDL GFDL 1.2 to 1.3.

9
NEWS
View File

@@ -51,6 +51,15 @@ Bison News
use of the %error-verbose directive is deprecated in favor of use of the %error-verbose directive is deprecated in favor of
%define parse.error "verbose". %define parse.error "verbose".
** Semantic predicates
The new, experimental, semantic-predicate feature allows actions of
the form %?{ BOOLEAN-EXPRESSION }, which cause syntax errors (as for
YYERROR) if the expression evaluates to 0, and are evaluated immediately
in GLR parsers, rather than being deferred. The result is that they
allow the programmer to prune possible parses based on the values of
runtime expressions.
* Changes in version 2.5 (????-??-??): * Changes in version 2.5 (????-??-??):
** Named References Support ** Named References Support

View File

@@ -417,6 +417,15 @@ b4_syncline([@oline@], [@ofile@])
break;]) break;])
# b4_predicate_case(LABEL, CONDITIONS)
# ------------------------------------
m4_define([b4_predicate_case],
[ case $1:
if (! ($2)) YYERROR;
b4_syncline([@oline@], [@ofile@])
break;])
# b4_yydestruct_generate(FUNCTION-DECLARATOR) # b4_yydestruct_generate(FUNCTION-DECLARATOR)
# ------------------------------------------- # -------------------------------------------
# Generate the "yydestruct" function, which declaration is issued using # Generate the "yydestruct" function, which declaration is issued using

View File

@@ -402,6 +402,13 @@ static const ]b4_int_type_for([b4_merger])[ yymerger[] =
]b4_merger[ ]b4_merger[
}; };
/* YYIMMEDIATE[RULE-NUM] -- True iff rule #RULE-NUM is not to be deferred, as
in the case of predicates. */
static const yybool yyimmediate[] =
{
]b4_immediate[
};
/* YYCONFLP[YYPACT[STATE-NUM]] -- Pointer into YYCONFL of start of /* YYCONFLP[YYPACT[STATE-NUM]] -- Pointer into YYCONFL of start of
list of conflicting reductions corresponding to action entry for list of conflicting reductions corresponding to action entry for
state STATE-NUM in yytable. 0 means no conflicts. The list in state STATE-NUM in yytable. 0 means no conflicts. The list in
@@ -693,7 +700,7 @@ struct yyGLRState {
yyStateNum yylrState; yyStateNum yylrState;
/** Preceding state in this stack */ /** Preceding state in this stack */
yyGLRState* yypred; yyGLRState* yypred;
/** Source position of the first token produced by my symbol */ /** Source position of the last token produced by my symbol */
size_t yyposn; size_t yyposn;
union { union {
/** First in a chain of alternative reductions producing the /** First in a chain of alternative reductions producing the
@@ -806,9 +813,16 @@ yyfillin (yyGLRStackItem *yyvsp, int yylow0, int yylow1)
s = yyvsp[yylow0].yystate.yypred; s = yyvsp[yylow0].yystate.yypred;
for (i = yylow0-1; i >= yylow1; i -= 1) for (i = yylow0-1; i >= yylow1; i -= 1)
{ {
YYASSERT (s->yyresolved); #if YYDEBUG
yyvsp[i].yystate.yyresolved = yytrue; yyvsp[i].yystate.yylrState = s->yylrState;
yyvsp[i].yystate.yysemantics.yysval = s->yysemantics.yysval; #endif
yyvsp[i].yystate.yyresolved = s->yyresolved;
if (s->yyresolved)
yyvsp[i].yystate.yysemantics.yysval = s->yysemantics.yysval;
else
/* The effect of using yysval or yyloc (in an immediate rule) is
* undefined. */
yyvsp[i].yystate.yysemantics.yyfirstVal = NULL;
yyvsp[i].yystate.yyloc = s->yyloc; yyvsp[i].yystate.yyloc = s->yyloc;
s = yyvsp[i].yystate.yypred = s->yypred; s = yyvsp[i].yystate.yypred = s->yypred;
} }
@@ -948,7 +962,7 @@ yydestroyGLRState (char const *yymsg, yyGLRState *yys]b4_user_formals[)
} }
} }
/** Left-hand-side symbol for rule #RULE. */ /** Left-hand-side symbol for rule #YYRULE. */
static inline yySymbol static inline yySymbol
yylhsNonterm (yyRuleNum yyrule) yylhsNonterm (yyRuleNum yyrule)
{ {
@@ -958,7 +972,7 @@ yylhsNonterm (yyRuleNum yyrule)
#define yypact_value_is_default(yystate) \ #define yypact_value_is_default(yystate) \
]b4_table_value_equals([[pact]], [[yystate]], [b4_pact_ninf])[ ]b4_table_value_equals([[pact]], [[yystate]], [b4_pact_ninf])[
/** True iff LR state STATE has only a default reduction (regardless /** True iff LR state YYSTATE has only a default reduction (regardless
* of token). */ * of token). */
static inline yybool static inline yybool
yyisDefaultedState (yyStateNum yystate) yyisDefaultedState (yyStateNum yystate)
@@ -966,7 +980,7 @@ yyisDefaultedState (yyStateNum yystate)
return yypact_value_is_default (yypact[yystate]); return yypact_value_is_default (yypact[yystate]);
} }
/** The default reduction for STATE, assuming it has one. */ /** The default reduction for YYSTATE, assuming it has one. */
static inline yyRuleNum static inline yyRuleNum
yydefaultAction (yyStateNum yystate) yydefaultAction (yyStateNum yystate)
{ {
@@ -981,8 +995,8 @@ yydefaultAction (yyStateNum yystate)
* R < 0: Reduce on rule -R. * R < 0: Reduce on rule -R.
* R = 0: Error. * R = 0: Error.
* R > 0: Shift to state R. * R > 0: Shift to state R.
* Set *CONFLICTS to a pointer into yyconfl to 0-terminated list of * Set *YYCONFLICTS to a pointer into yyconfl to a 0-terminated list
* conflicting reductions. * of conflicting reductions.
*/ */
static inline void static inline void
yygetLRActions (yyStateNum yystate, int yytoken, yygetLRActions (yyStateNum yystate, int yytoken,
@@ -1031,9 +1045,10 @@ yyisErrorAction (int yyaction)
/* GLRStates */ /* GLRStates */
/** Return a fresh GLRStackItem. Callers should call /** Return a fresh GLRStackItem in YYSTACKP. The item is an LR state
* YY_RESERVE_GLRSTACK afterwards to make sure there is sufficient * if YYISSTATE, and otherwise a semantic option. Callers should call
* headroom. */ * YY_RESERVE_GLRSTACK afterwards to make sure there is sufficient
* headroom. */
static inline yyGLRStackItem* static inline yyGLRStackItem*
yynewGLRStackItem (yyGLRStack* yystackp, yybool yyisState) yynewGLRStackItem (yyGLRStack* yystackp, yybool yyisState)
@@ -1046,9 +1061,9 @@ yynewGLRStackItem (yyGLRStack* yystackp, yybool yyisState)
} }
/** Add a new semantic action that will execute the action for rule /** Add a new semantic action that will execute the action for rule
* RULENUM on the semantic values in RHS to the list of * YYRULE on the semantic values in YYRHS to the list of
* alternative actions for STATE. Assumes that RHS comes from * alternative actions for YYSTATE. Assumes that YYRHS comes from
* stack #K of *STACKP. */ * stack #YYK of *YYSTACKP. */
static void static void
yyaddDeferredAction (yyGLRStack* yystackp, size_t yyk, yyGLRState* yystate, yyaddDeferredAction (yyGLRStack* yystackp, size_t yyk, yyGLRState* yystate,
yyGLRState* yyrhs, yyRuleNum yyrule) yyGLRState* yyrhs, yyRuleNum yyrule)
@@ -1073,7 +1088,7 @@ yyaddDeferredAction (yyGLRStack* yystackp, size_t yyk, yyGLRState* yystate,
/* GLRStacks */ /* GLRStacks */
/** Initialize SET to a singleton set containing an empty stack. */ /** Initialize YYSET to a singleton set containing an empty stack. */
static yybool static yybool
yyinitStateSet (yyGLRStateSet* yyset) yyinitStateSet (yyGLRStateSet* yyset)
{ {
@@ -1099,8 +1114,8 @@ static void yyfreeStateSet (yyGLRStateSet* yyset)
YYFREE (yyset->yylookaheadNeeds); YYFREE (yyset->yylookaheadNeeds);
} }
/** Initialize STACK to a single empty stack, with total maximum /** Initialize *YYSTACKP to a single empty stack, with total maximum
* capacity for all stacks of SIZE. */ * capacity for all stacks of YYSIZE. */
static yybool static yybool
yyinitGLRStack (yyGLRStack* yystackp, size_t yysize) yyinitGLRStack (yyGLRStack* yystackp, size_t yysize)
{ {
@@ -1122,7 +1137,7 @@ yyinitGLRStack (yyGLRStack* yystackp, size_t yysize)
# define YYRELOC(YYFROMITEMS,YYTOITEMS,YYX,YYTYPE) \ # define YYRELOC(YYFROMITEMS,YYTOITEMS,YYX,YYTYPE) \
&((YYTOITEMS) - ((YYFROMITEMS) - (yyGLRStackItem*) (YYX)))->YYTYPE &((YYTOITEMS) - ((YYFROMITEMS) - (yyGLRStackItem*) (YYX)))->YYTYPE
/** If STACK is expandable, extend it. WARNING: Pointers into the /** If *YYSTACKP is expandable, extend it. WARNING: Pointers into the
stack from outside should be considered invalid after this call. stack from outside should be considered invalid after this call.
We always expand when there are 1 or fewer items left AFTER an We always expand when there are 1 or fewer items left AFTER an
allocation, so that we can avoid having external pointers exist allocation, so that we can avoid having external pointers exist
@@ -1192,9 +1207,9 @@ yyfreeGLRStack (yyGLRStack* yystackp)
yyfreeStateSet (&yystackp->yytops); yyfreeStateSet (&yystackp->yytops);
} }
/** Assuming that S is a GLRState somewhere on STACK, update the /** Assuming that YYS is a GLRState somewhere on *YYSTACKP, update the
* splitpoint of STACK, if needed, so that it is at least as deep as * splitpoint of *YYSTACKP, if needed, so that it is at least as deep as
* S. */ * YYS. */
static inline void static inline void
yyupdateSplit (yyGLRStack* yystackp, yyGLRState* yys) yyupdateSplit (yyGLRStack* yystackp, yyGLRState* yys)
{ {
@@ -1202,7 +1217,7 @@ yyupdateSplit (yyGLRStack* yystackp, yyGLRState* yys)
yystackp->yysplitPoint = yys; yystackp->yysplitPoint = yys;
} }
/** Invalidate stack #K in STACK. */ /** Invalidate stack #YYK in *YYSTACKP. */
static inline void static inline void
yymarkStackDeleted (yyGLRStack* yystackp, size_t yyk) yymarkStackDeleted (yyGLRStack* yystackp, size_t yyk)
{ {
@@ -1211,8 +1226,8 @@ yymarkStackDeleted (yyGLRStack* yystackp, size_t yyk)
yystackp->yytops.yystates[yyk] = NULL; yystackp->yytops.yystates[yyk] = NULL;
} }
/** Undelete the last stack that was marked as deleted. Can only be /** Undelete the last stack in *YYSTACKP that was marked as deleted. Can
done once after a deletion, and only when all other stacks have only be done once after a deletion, and only when all other stacks have
been deleted. */ been deleted. */
static void static void
yyundeleteLastStack (yyGLRStack* yystackp) yyundeleteLastStack (yyGLRStack* yystackp)
@@ -1261,8 +1276,9 @@ yyremoveDeletes (yyGLRStack* yystackp)
} }
} }
/** Shift to a new state on stack #K of STACK, corresponding to LR state /** Shift to a new state on stack #YYK of *YYSTACKP, corresponding to LR
* LRSTATE, at input position POSN, with (resolved) semantic value SVAL. */ * state YYLRSTATE, at input position YYPOSN, with (resolved) semantic
* value *YYVALP and source location *YYLOCP. */
static inline void static inline void
yyglrShift (yyGLRStack* yystackp, size_t yyk, yyStateNum yylrState, yyglrShift (yyGLRStack* yystackp, size_t yyk, yyStateNum yylrState,
size_t yyposn, size_t yyposn,
@@ -1281,7 +1297,7 @@ yyglrShift (yyGLRStack* yystackp, size_t yyk, yyStateNum yylrState,
YY_RESERVE_GLRSTACK (yystackp); YY_RESERVE_GLRSTACK (yystackp);
} }
/** Shift stack #K of YYSTACK, to a new state corresponding to LR /** Shift stack #YYK of *YYSTACKP, to a new state corresponding to LR
* state YYLRSTATE, at input position YYPOSN, with the (unresolved) * state YYLRSTATE, at input position YYPOSN, with the (unresolved)
* semantic value of YYRHS under the action for YYRULE. */ * semantic value of YYRHS under the action for YYRULE. */
static inline void static inline void
@@ -1301,11 +1317,51 @@ yyglrShiftDefer (yyGLRStack* yystackp, size_t yyk, yyStateNum yylrState,
yyaddDeferredAction (yystackp, yyk, yynewState, yyrhs, yyrule); yyaddDeferredAction (yystackp, yyk, yynewState, yyrhs, yyrule);
} }
/** Pop the symbols consumed by reduction #RULE from the top of stack #if !YYDEBUG
* #K of STACK, and perform the appropriate semantic action on their # define YY_REDUCE_PRINT(Args)
#else
# define YY_REDUCE_PRINT(Args) \
do { \
if (yydebug) \
yy_reduce_print Args; \
} while (YYID (0))
/*----------------------------------------------------------------------.
| Report that stack #YYK of *YYSTACKP is going to be reduced by YYRULE. |
`----------------------------------------------------------------------*/
/*ARGSUSED*/ static inline void
yy_reduce_print (int yynormal, yyGLRStackItem* yyrhsVals, size_t yyk, yyRuleNum yyrule]b4_user_formals[)
{
int yynrhs = yyrhsLength (yyrule);
int yyi;
]b4_parse_param_use[]dnl
[ YYFPRINTF (stderr, "Reducing stack %lu by rule %d (line %lu):\n",
(unsigned long int) yyk, yyrule - 1,
(unsigned long int) yyrline[yyrule]);
if (! yynormal)
yyfillin (yyrhsVals, 1, -yynrhs);
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
YYFPRINTF (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr,
yystos[yyrhsVals[yyi - yynrhs + 1].yystate.yylrState],
&yyrhsVals[yyi - yynrhs + 1].yystate.yysemantics.yysval
]b4_locations_if([, &]b4_rhs_location(yynrhs, yyi + 1))[]dnl
b4_user_args[);
if (!yyrhsVals[yyi - yynrhs + 1].yystate.yyresolved)
YYFPRINTF (stderr, " (unresolved)");
YYFPRINTF (stderr, "\n");
}
}
#endif
/** Pop the symbols consumed by reduction #YYRULE from the top of stack
* #YYK of *YYSTACKP, and perform the appropriate semantic action on their
* semantic values. Assumes that all ambiguities in semantic values * semantic values. Assumes that all ambiguities in semantic values
* have been previously resolved. Set *VALP to the resulting value, * have been previously resolved. Set *YYVALP to the resulting value,
* and *LOCP to the computed location (if any). Return value is as * and *YYLOCP to the computed location (if any). Return value is as
* for userAction. */ * for userAction. */
static inline YYRESULTTAG static inline YYRESULTTAG
yydoAction (yyGLRStack* yystackp, size_t yyk, yyRuleNum yyrule, yydoAction (yyGLRStack* yystackp, size_t yyk, yyRuleNum yyrule,
@@ -1321,15 +1377,12 @@ yydoAction (yyGLRStack* yystackp, size_t yyk, yyRuleNum yyrule,
yystackp->yynextFree -= yynrhs; yystackp->yynextFree -= yynrhs;
yystackp->yyspaceLeft += yynrhs; yystackp->yyspaceLeft += yynrhs;
yystackp->yytops.yystates[0] = & yystackp->yynextFree[-1].yystate; yystackp->yytops.yystates[0] = & yystackp->yynextFree[-1].yystate;
YY_REDUCE_PRINT ((1, yyrhs, yyk, yyrule]b4_user_args[));
return yyuserAction (yyrule, yynrhs, yyrhs, return yyuserAction (yyrule, yynrhs, yyrhs,
yyvalp, yylocp, yystackp]b4_user_args[); yyvalp, yylocp, yystackp]b4_user_args[);
} }
else else
{ {
/* At present, doAction is never called in nondeterministic
* mode, so this branch is never taken. It is here in
* anticipation of a future feature that will allow immediate
* evaluation of selected actions in nondeterministic mode. */
int yyi; int yyi;
yyGLRState* yys; yyGLRState* yys;
yyGLRStackItem yyrhsVals[YYMAXRHS + YYMAXLEFT + 1]; yyGLRStackItem yyrhsVals[YYMAXRHS + YYMAXLEFT + 1];
@@ -1345,60 +1398,21 @@ yydoAction (yyGLRStack* yystackp, size_t yyk, yyRuleNum yyrule,
} }
yyupdateSplit (yystackp, yys); yyupdateSplit (yystackp, yys);
yystackp->yytops.yystates[yyk] = yys; yystackp->yytops.yystates[yyk] = yys;
YY_REDUCE_PRINT ((0, yyrhsVals + YYMAXRHS + YYMAXLEFT - 1, yyk, yyrule]b4_user_args[));
return yyuserAction (yyrule, yynrhs, yyrhsVals + YYMAXRHS + YYMAXLEFT - 1, return yyuserAction (yyrule, yynrhs, yyrhsVals + YYMAXRHS + YYMAXLEFT - 1,
yyvalp, yylocp, yystackp]b4_user_args[); yyvalp, yylocp, yystackp]b4_user_args[);
} }
} }
#if !YYDEBUG /** Pop items off stack #YYK of *YYSTACKP according to grammar rule YYRULE,
# define YY_REDUCE_PRINT(Args)
#else
# define YY_REDUCE_PRINT(Args) \
do { \
if (yydebug) \
yy_reduce_print Args; \
} while (YYID (0))
/*----------------------------------------------------------.
| Report that the RULE is going to be reduced on stack #K. |
`----------------------------------------------------------*/
/*ARGSUSED*/ static inline void
yy_reduce_print (yyGLRStack* yystackp, size_t yyk, yyRuleNum yyrule]b4_user_formals[)
{
int yynrhs = yyrhsLength (yyrule);
yybool yynormal __attribute__ ((__unused__)) =
(yystackp->yysplitPoint == NULL);
yyGLRStackItem* yyvsp = (yyGLRStackItem*) yystackp->yytops.yystates[yyk];
int yylow = 1;
int yyi;
]b4_parse_param_use[]dnl
[ YYFPRINTF (stderr, "Reducing stack %lu by rule %d (line %lu):\n",
(unsigned long int) yyk, yyrule - 1,
(unsigned long int) yyrline[yyrule]);
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
YYFPRINTF (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr,
]yystos@{b4_rhs_data(yynrhs, yyi + 1).yylrState@}[,
&]b4_rhs_value(yynrhs, yyi + 1)[
]b4_locations_if([, &]b4_rhs_location(yynrhs, yyi + 1))[]dnl
b4_user_args[);
YYFPRINTF (stderr, "\n");
}
}
#endif
/** Pop items off stack #K of STACK according to grammar rule RULE,
* and push back on the resulting nonterminal symbol. Perform the * and push back on the resulting nonterminal symbol. Perform the
* semantic action associated with RULE and store its value with the * semantic action associated with YYRULE and store its value with the
* newly pushed state, if FORCEEVAL or if STACK is currently * newly pushed state, if YYFORCEEVAL or if *YYSTACKP is currently
* unambiguous. Otherwise, store the deferred semantic action with * unambiguous. Otherwise, store the deferred semantic action with
* the new state. If the new state would have an identical input * the new state. If the new state would have an identical input
* position, LR state, and predecessor to an existing state on the stack, * position, LR state, and predecessor to an existing state on the stack,
* it is identified with that existing state, eliminating stack #K from * it is identified with that existing state, eliminating stack #YYK from
* the STACK. In this case, the (necessarily deferred) semantic value is * *YYSTACKP. In this case, the semantic value is
* added to the options for the existing state's semantic value. * added to the options for the existing state's semantic value.
*/ */
static inline YYRESULTTAG static inline YYRESULTTAG
@@ -1409,12 +1423,19 @@ yyglrReduce (yyGLRStack* yystackp, size_t yyk, yyRuleNum yyrule,
if (yyforceEval || yystackp->yysplitPoint == NULL) if (yyforceEval || yystackp->yysplitPoint == NULL)
{ {
YYRESULTTAG yyflag;
YYSTYPE yysval; YYSTYPE yysval;
YYLTYPE yyloc; YYLTYPE yyloc;
YY_REDUCE_PRINT ((yystackp, yyk, yyrule]b4_user_args[)); yyflag = yydoAction (yystackp, yyk, yyrule, &yysval,
YYCHK (yydoAction (yystackp, yyk, yyrule, &yysval, &yyloc]b4_user_args[);
&yyloc]b4_user_args[)); if (yyflag == yyerr)
{
YYDPRINTF ((stderr, "Parse on stack %lu rejected by rule #%d.\n",
(unsigned long int) yyk, yyrule - 1));
}
if (yyflag != yyok)
return yyflag;
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyrule], &yysval, &yyloc); YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyrule], &yysval, &yyloc);
yyglrShift (yystackp, yyk, yyglrShift (yystackp, yyk,
yyLRgotoState (yystackp->yytops.yystates[yyk]->yylrState, yyLRgotoState (yystackp->yytops.yystates[yyk]->yylrState,
@@ -1508,7 +1529,7 @@ yysplitStack (yyGLRStack* yystackp, size_t yyk)
return yystackp->yytops.yysize-1; return yystackp->yytops.yysize-1;
} }
/** True iff Y0 and Y1 represent identical options at the top level. /** True iff YYY0 and YYY1 represent identical options at the top level.
* That is, they represent the same rule applied to RHS symbols * That is, they represent the same rule applied to RHS symbols
* that produce the same terminal symbols. */ * that produce the same terminal symbols. */
static yybool static yybool
@@ -1530,8 +1551,8 @@ yyidenticalOptions (yySemanticOption* yyy0, yySemanticOption* yyy1)
return yyfalse; return yyfalse;
} }
/** Assuming identicalOptions (Y0,Y1), destructively merge the /** Assuming identicalOptions (YYY0,YYY1), destructively merge the
* alternative semantic values for the RHS-symbols of Y1 and Y0. */ * alternative semantic values for the RHS-symbols of YYY1 and YYY0. */
static void static void
yymergeOptionSets (yySemanticOption* yyy0, yySemanticOption* yyy1) yymergeOptionSets (yySemanticOption* yyy0, yySemanticOption* yyy1)
{ {
@@ -1612,11 +1633,11 @@ static YYRESULTTAG yyresolveValue (yyGLRState* yys,
yyGLRStack* yystackp]b4_user_formals[); yyGLRStack* yystackp]b4_user_formals[);
/** Resolve the previous N states starting at and including state S. If result /** Resolve the previous YYN states starting at and including state YYS
* != yyok, some states may have been left unresolved possibly with empty * on *YYSTACKP. If result != yyok, some states may have been left
* semantic option chains. Regardless of whether result = yyok, each state * unresolved possibly with empty semantic option chains. Regardless
* has been left with consistent data so that yydestroyGLRState can be invoked * of whether result = yyok, each state has been left with consistent
* if necessary. */ * data so that yydestroyGLRState can be invoked if necessary. */
static YYRESULTTAG static YYRESULTTAG
yyresolveStates (yyGLRState* yys, int yyn, yyresolveStates (yyGLRState* yys, int yyn,
yyGLRStack* yystackp]b4_user_formals[) yyGLRStack* yystackp]b4_user_formals[)
@@ -1631,9 +1652,10 @@ yyresolveStates (yyGLRState* yys, int yyn,
return yyok; return yyok;
} }
/** Resolve the states for the RHS of OPT, perform its user action, and return /** Resolve the states for the RHS of YYOPT on *YYSTACKP, perform its
* the semantic value and location. Regardless of whether result = yyok, all * user action, and return the semantic value and location in *YYVALP
* RHS states have been destroyed (assuming the user action destroys all RHS * and *YYLOCP. Regardless of whether result = yyok, all RHS states
* have been destroyed (assuming the user action destroys all RHS
* semantic values if invoked). */ * semantic values if invoked). */
static YYRESULTTAG static YYRESULTTAG
yyresolveAction (yySemanticOption* yyopt, yyGLRStack* yystackp, yyresolveAction (yySemanticOption* yyopt, yyGLRStack* yystackp,
@@ -1743,9 +1765,9 @@ yyreportAmbiguity (yySemanticOption* yyx0,
return yyabort; return yyabort;
} }
/** Starting at and including state S1, resolve the location for each of the /** Resolve the locations for each of the YYN1 states in *YYSTACKP,
* previous N1 states that is unresolved. The first semantic option of a state * ending at YYS1. Has no effect on previously resolved states.
* is always chosen. */ * The first semantic option of a state is always chosen. */
static void static void
yyresolveLocations (yyGLRState* yys1, int yyn1, yyresolveLocations (yyGLRState* yys1, int yyn1,
yyGLRStack *yystackp]b4_user_formals[) yyGLRStack *yystackp]b4_user_formals[)
@@ -1801,11 +1823,12 @@ yyresolveLocations (yyGLRState* yys1, int yyn1,
} }
} }
/** Resolve the ambiguity represented in state S, perform the indicated /** Resolve the ambiguity represented in state YYS in *YYSTACKP,
* actions, and set the semantic value of S. If result != yyok, the chain of * perform the indicated actions, and set the semantic value of YYS.
* semantic options in S has been cleared instead or it has been left * If result != yyok, the chain of semantic options in YYS has been
* unmodified except that redundant options may have been removed. Regardless * cleared instead or it has been left unmodified except that
* of whether result = yyok, S has been left with consistent data so that * redundant options may have been removed. Regardless of whether
* result = yyok, YYS has been left with consistent data so that
* yydestroyGLRState can be invoked if necessary. */ * yydestroyGLRState can be invoked if necessary. */
static YYRESULTTAG static YYRESULTTAG
yyresolveValue (yyGLRState* yys, yyGLRStack* yystackp]b4_user_formals[) yyresolveValue (yyGLRState* yys, yyGLRStack* yystackp]b4_user_formals[)
@@ -1950,6 +1973,7 @@ yyprocessOneStack (yyGLRStack* yystackp, size_t yyk,
int yyaction; int yyaction;
const short int* yyconflicts; const short int* yyconflicts;
yyRuleNum yyrule; yyRuleNum yyrule;
YYRESULTTAG yyflag;
while (yystackp->yytops.yystates[yyk] != NULL) while (yystackp->yytops.yystates[yyk] != NULL)
{ {
@@ -1969,11 +1993,21 @@ yyprocessOneStack (yyGLRStack* yystackp, size_t yyk,
yymarkStackDeleted (yystackp, yyk); yymarkStackDeleted (yystackp, yyk);
return yyok; return yyok;
} }
YYCHK (yyglrReduce (yystackp, yyk, yyrule, yyfalse]b4_user_args[)); yyflag = yyglrReduce (yystackp, yyk, yyrule, yyimmediate[yyrule]]b4_user_args[);
if (yyflag == yyerr)
{
YYDPRINTF ((stderr, "Stack %lu dies (predicate failure or explicit user error).\n",
(unsigned long int) yyk));
yymarkStackDeleted (yystackp, yyk);
return yyok;
}
if (yyflag != yyok)
return yyflag;
} }
else else
{ {
yySymbol yytoken; yySymbol yytoken;
yystackp->yytops.yylookaheadNeeds[yyk] = yytrue; yystackp->yytops.yylookaheadNeeds[yyk] = yytrue;
if (yychar == YYEMPTY) if (yychar == YYEMPTY)
{ {
@@ -1996,14 +2030,25 @@ yyprocessOneStack (yyGLRStack* yystackp, size_t yyk,
while (*yyconflicts != 0) while (*yyconflicts != 0)
{ {
YYRESULTTAG yyflag;
size_t yynewStack = yysplitStack (yystackp, yyk); size_t yynewStack = yysplitStack (yystackp, yyk);
YYDPRINTF ((stderr, "Splitting off stack %lu from %lu.\n", YYDPRINTF ((stderr, "Splitting off stack %lu from %lu.\n",
(unsigned long int) yynewStack, (unsigned long int) yynewStack,
(unsigned long int) yyk)); (unsigned long int) yyk));
YYCHK (yyglrReduce (yystackp, yynewStack, yyflag = yyglrReduce (yystackp, yynewStack,
*yyconflicts, yyfalse]b4_user_args[)); *yyconflicts,
YYCHK (yyprocessOneStack (yystackp, yynewStack, yyimmediate[*yyconflicts]]b4_user_args[);
yyposn]b4_pure_args[)); if (yyflag == yyok)
YYCHK (yyprocessOneStack (yystackp, yynewStack,
yyposn]b4_pure_args[));
else if (yyflag == yyerr)
{
YYDPRINTF ((stderr, "Stack %lu dies.\n",
(unsigned long int) yynewStack));
yymarkStackDeleted (yystackp, yynewStack);
}
else
return yyflag;
yyconflicts += 1; yyconflicts += 1;
} }
@@ -2017,8 +2062,19 @@ yyprocessOneStack (yyGLRStack* yystackp, size_t yyk,
break; break;
} }
else else
YYCHK (yyglrReduce (yystackp, yyk, -yyaction, {
yyfalse]b4_user_args[)); yyflag = yyglrReduce (yystackp, yyk, -yyaction,
yyimmediate[-yyaction]]b4_user_args[);
if (yyflag == yyerr)
{
YYDPRINTF ((stderr, "Stack %lu dies (predicate failure or explicit user error).\n",
(unsigned long int) yyk));
yymarkStackDeleted (yystackp, yyk);
break;
}
else if (yyflag != yyok)
return yyflag;
}
} }
} }
return yyok; return yyok;
@@ -2249,7 +2305,6 @@ yyrecoverSyntaxError (yyGLRStack* yystackp]b4_user_formals[)
} \ } \
} while (YYID (0)) } while (YYID (0))
/*----------. /*----------.
| yyparse. | | yyparse. |
`----------*/ `----------*/

View File

@@ -169,6 +169,13 @@ m4_define([b4_case], [ case $1:
break; break;
]) ])
# b4_predicate_case(LABEL, CONDITIONS)
# ------------------------------------
m4_define([b4_predicate_case], [ case $1:
if (! ($2)) YYERROR;
break;
])
## ---------------- ## ## ---------------- ##
## Default values. ## ## Default values. ##

View File

@@ -136,6 +136,7 @@ Writing @acronym{GLR} Parsers
* Simple GLR Parsers:: Using @acronym{GLR} parsers on unambiguous grammars. * Simple GLR Parsers:: Using @acronym{GLR} parsers on unambiguous grammars.
* Merging GLR Parses:: Using @acronym{GLR} parsers to resolve ambiguities. * Merging GLR Parses:: Using @acronym{GLR} parsers to resolve ambiguities.
* GLR Semantic Actions:: Deferred semantic actions have special concerns. * GLR Semantic Actions:: Deferred semantic actions have special concerns.
* Semantic Predicates:: Controlling a parse with arbitrary computations.
* Compiler Requirements:: @acronym{GLR} parsers require a modern C compiler. * Compiler Requirements:: @acronym{GLR} parsers require a modern C compiler.
Examples Examples
@@ -758,6 +759,7 @@ merged result.
* Simple GLR Parsers:: Using @acronym{GLR} parsers on unambiguous grammars. * Simple GLR Parsers:: Using @acronym{GLR} parsers on unambiguous grammars.
* Merging GLR Parses:: Using @acronym{GLR} parsers to resolve ambiguities. * Merging GLR Parses:: Using @acronym{GLR} parsers to resolve ambiguities.
* GLR Semantic Actions:: Deferred semantic actions have special concerns. * GLR Semantic Actions:: Deferred semantic actions have special concerns.
* Semantic Predicates:: Controlling a parse with arbitrary computations.
* Compiler Requirements:: @acronym{GLR} parsers require a modern C compiler. * Compiler Requirements:: @acronym{GLR} parsers require a modern C compiler.
@end menu @end menu
@@ -1163,6 +1165,65 @@ In a deferred semantic action, its effect is undefined.
Also, see @ref{Location Default Action, ,Default Action for Locations}, which Also, see @ref{Location Default Action, ,Default Action for Locations}, which
describes a special usage of @code{YYLLOC_DEFAULT} in @acronym{GLR} parsers. describes a special usage of @code{YYLLOC_DEFAULT} in @acronym{GLR} parsers.
@node Semantic Predicates
@subsection Controlling a Parse with Arbitrary Predicates
@findex %?
@cindex Semantic predicates in @acronym{GLR} parsers
In addition to the @code{%dprec} and @code{%merge} directives,
@acronym{GLR} parsers
allow you to reject parses on the basis of arbitrary computations executed
in user code, without having Bison treat this rejection as an error
if there are alternative parses. (This feature is experimental and may
evolve. We welcome user feedback.) For example,
@smallexample
widget :
%?@{ new_syntax @} "widget" id new_args @{ $$ = f($3, $4); @}
| %?@{ !new_syntax @} "widget" id old_args @{ $$ = f($3, $4); @}
;
@end smallexample
@noindent
is one way to allow the same parser to handle two different syntaxes for
widgets. The clause preceded by @code{%?} is treated like an ordinary
action, except that its text is treated as an expression and is always
evaluated immediately (even when in nondeterministic mode). If the
expression yields 0 (false), the clause is treated as a syntax error,
which, in a nondeterministic parser, causes the stack in which it is reduced
to die. In a deterministic parser, it acts like YYERROR.
As the example shows, predicates otherwise look like semantic actions, and
therefore you must be take them into account when determining the numbers
to use for denoting the semantic values of right-hand side symbols.
Predicate actions, however, have no defined value, and may not be given
labels.
There is a subtle difference between semantic predicates and ordinary
actions in nondeterministic mode, since the latter are deferred.
For example, we could try to rewrite the previous example as
@smallexample
widget :
@{ if (!new_syntax) YYERROR; @} "widget" id new_args @{ $$ = f($3, $4); @}
| @{ if (new_syntax) YYERROR; @} "widget" id old_args @{ $$ = f($3, $4); @}
;
@end smallexample
@noindent
(reversing the sense of the predicate tests to cause an error when they are
false). However, this
does @emph{not} have the same effect if @code{new_args} and @code{old_args}
have overlapping syntax.
Since the mid-rule actions testing @code{new_syntax} are deferred,
a @acronym{GLR} parser first encounters the unresolved ambiguous reduction
for cases where @code{new_args} and @code{old_args} recognize the same string
@emph{before} performing the tests of @code{new_syntax}. It therefore
reports an error.
Finally, be careful in writing predicates: deferred actions have not been
evaluated, so that using them in a predicate will have undefined effects.
@node Compiler Requirements @node Compiler Requirements
@subsection Considerations when Compiling @acronym{GLR} Parsers @subsection Considerations when Compiling @acronym{GLR} Parsers
@cindex @code{inline} @cindex @code{inline}
@@ -10610,6 +10671,19 @@ file. @xref{Grammar Outline, ,Outline of a Bison
Grammar}. Grammar}.
@end deffn @end deffn
@deffn {Directive} %?@{@var{expression}@}
Predicate actions. This is a type of action clause that may appear in
rules. The expression is evaluated, and if false, causes a syntax error. In
@acronym{GLR} parsers during nondeterministic operation,
this silently causes an alternative parse to die. During deterministic
operation, it is the same as the effect of YYERROR.
@xref{Semantic Predicates}.
This feature is experimental.
More user feedback will help to determine whether it should become a permanent
feature.
@end deffn
@deffn {Construct} /*@dots{}*/ @deffn {Construct} /*@dots{}*/
Comment delimiters, as in C. Comment delimiters, as in C.
@end deffn @end deffn

View File

@@ -194,6 +194,7 @@ typedef struct
location location; location location;
bool useful; bool useful;
bool is_predicate;
const char *action; const char *action;
location action_location; location action_location;

View File

@@ -204,7 +204,7 @@ prepare_symbols (void)
/*----------------------------------------------------------------. /*----------------------------------------------------------------.
| Prepare the muscles related to the rules: r1, r2, rline, dprec, | | Prepare the muscles related to the rules: r1, r2, rline, dprec, |
| merger. | | merger, immediate. |
`----------------------------------------------------------------*/ `----------------------------------------------------------------*/
static void static void
@@ -215,6 +215,7 @@ prepare_rules (void)
unsigned int *r2 = xnmalloc (nrules, sizeof *r2); unsigned int *r2 = xnmalloc (nrules, sizeof *r2);
int *dprec = xnmalloc (nrules, sizeof *dprec); int *dprec = xnmalloc (nrules, sizeof *dprec);
int *merger = xnmalloc (nrules, sizeof *merger); int *merger = xnmalloc (nrules, sizeof *merger);
int *immediate = xnmalloc (nrules, sizeof *immediate);
rule_number r; rule_number r;
for (r = 0; r < nrules; ++r) for (r = 0; r < nrules; ++r)
@@ -229,6 +230,8 @@ prepare_rules (void)
dprec[r] = rules[r].dprec; dprec[r] = rules[r].dprec;
/* Merger-function index (GLR). */ /* Merger-function index (GLR). */
merger[r] = rules[r].merger; merger[r] = rules[r].merger;
/* Immediate reduction flags (GLR). */
immediate[r] = rules[r].is_predicate;
} }
muscle_insert_unsigned_int_table ("rline", rline, 0, 0, nrules); muscle_insert_unsigned_int_table ("rline", rline, 0, 0, nrules);
@@ -236,6 +239,7 @@ prepare_rules (void)
muscle_insert_unsigned_int_table ("r2", r2, 0, 0, nrules); muscle_insert_unsigned_int_table ("r2", r2, 0, 0, nrules);
muscle_insert_int_table ("dprec", dprec, 0, 0, nrules); muscle_insert_int_table ("dprec", dprec, 0, 0, nrules);
muscle_insert_int_table ("merger", merger, 0, 0, nrules); muscle_insert_int_table ("merger", merger, 0, 0, nrules);
muscle_insert_int_table ("immediate", immediate, 0, 0, nrules);
MUSCLE_INSERT_INT ("rules_number", nrules); MUSCLE_INSERT_INT ("rules_number", nrules);
MUSCLE_INSERT_INT ("max_left_semantic_context", max_left_semantic_context); MUSCLE_INSERT_INT ("max_left_semantic_context", max_left_semantic_context);
@@ -349,8 +353,9 @@ user_actions_output (FILE *out)
for (r = 0; r < nrules; ++r) for (r = 0; r < nrules; ++r)
if (rules[r].action) if (rules[r].action)
{ {
fprintf (out, "b4_case(%d, [b4_syncline(%d, ", r + 1, fprintf (out, "b4_%scase(%d, [b4_syncline(%d, ",
rules[r].action_location.start.line); rules[r].is_predicate ? "predicate_" : "",
r + 1, rules[r].action_location.start.line);
escaped_output (out, rules[r].action_location.start.file); escaped_output (out, rules[r].action_location.start.file);
fprintf (out, ")\n[ %s]])\n\n", rules[r].action); fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
/* A Bison parser, made by GNU Bison 2.4.483-4ad39-dirty. */ /* A Bison parser, made by GNU Bison 2.4.516-804e. */
/* Interface for Bison's Yacc-like parsers in C /* Interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2010 Free Software Foundation, Inc. Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -31,7 +32,7 @@
version 2.2 of Bison. */ version 2.2 of Bison. */
/* "%code requires" blocks. */ /* "%code requires" blocks. */
/* Line 1658 of yacc.c */ /* Line 1658 of yacc.c */
#line 201 "src/parse-gram.y" #line 202 "src/parse-gram.y"
# ifndef PARAM_TYPE # ifndef PARAM_TYPE
# define PARAM_TYPE # define PARAM_TYPE
@@ -46,7 +47,7 @@
/* Line 1658 of yacc.c */ /* Line 1658 of yacc.c */
#line 50 "src/parse-gram.h" #line 51 "src/parse-gram.h"
/* Tokens. */ /* Tokens. */
#ifndef YYTOKENTYPE #ifndef YYTOKENTYPE
@@ -93,21 +94,22 @@
PERCENT_VERBOSE = 293, PERCENT_VERBOSE = 293,
PERCENT_YACC = 294, PERCENT_YACC = 294,
BRACED_CODE = 295, BRACED_CODE = 295,
BRACKETED_ID = 296, BRACED_PREDICATE = 296,
CHAR = 297, BRACKETED_ID = 297,
EPILOGUE = 298, CHAR = 298,
EQUAL = 299, EPILOGUE = 299,
ID = 300, EQUAL = 300,
ID_COLON = 301, ID = 301,
PERCENT_PERCENT = 302, ID_COLON = 302,
PIPE = 303, PERCENT_PERCENT = 303,
PROLOGUE = 304, PIPE = 304,
SEMICOLON = 305, PROLOGUE = 305,
TAG = 306, SEMICOLON = 306,
TAG_ANY = 307, TAG = 307,
TAG_NONE = 308, TAG_ANY = 308,
PERCENT_PARAM = 309, TAG_NONE = 309,
PERCENT_UNION = 310 PERCENT_PARAM = 310,
PERCENT_UNION = 311
}; };
#endif #endif
/* Tokens. */ /* Tokens. */
@@ -150,21 +152,22 @@
#define PERCENT_VERBOSE 293 #define PERCENT_VERBOSE 293
#define PERCENT_YACC 294 #define PERCENT_YACC 294
#define BRACED_CODE 295 #define BRACED_CODE 295
#define BRACKETED_ID 296 #define BRACED_PREDICATE 296
#define CHAR 297 #define BRACKETED_ID 297
#define EPILOGUE 298 #define CHAR 298
#define EQUAL 299 #define EPILOGUE 299
#define ID 300 #define EQUAL 300
#define ID_COLON 301 #define ID 301
#define PERCENT_PERCENT 302 #define ID_COLON 302
#define PIPE 303 #define PERCENT_PERCENT 303
#define PROLOGUE 304 #define PIPE 304
#define SEMICOLON 305 #define PROLOGUE 305
#define TAG 306 #define SEMICOLON 306
#define TAG_ANY 307 #define TAG 307
#define TAG_NONE 308 #define TAG_ANY 308
#define PERCENT_PARAM 309 #define TAG_NONE 309
#define PERCENT_UNION 310 #define PERCENT_PARAM 310
#define PERCENT_UNION 311
@@ -173,7 +176,7 @@
typedef union YYSTYPE typedef union YYSTYPE
{ {
/* Line 1658 of yacc.c */ /* Line 1658 of yacc.c */
#line 87 "src/parse-gram.y" #line 88 "src/parse-gram.y"
assoc assoc; assoc assoc;
char *code; char *code;
@@ -186,13 +189,13 @@ typedef union YYSTYPE
unsigned char character; unsigned char character;
/* Line 1658 of yacc.c */ /* Line 1658 of yacc.c */
#line 225 "src/parse-gram.y" #line 226 "src/parse-gram.y"
param_type param; param_type param;
/* Line 1658 of yacc.c */ /* Line 1658 of yacc.c */
#line 196 "src/parse-gram.h" #line 199 "src/parse-gram.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */

View File

@@ -118,7 +118,6 @@ static char const *char_name (char);
%token PERCENT_DPREC "%dprec" %token PERCENT_DPREC "%dprec"
%token PERCENT_MERGE "%merge" %token PERCENT_MERGE "%merge"
/*----------------------. /*----------------------.
| Global Declarations. | | Global Declarations. |
`----------------------*/ `----------------------*/
@@ -151,6 +150,7 @@ static char const *char_name (char);
; ;
%token BRACED_CODE "{...}" %token BRACED_CODE "{...}"
%token BRACED_PREDICATE "%?{...}"
%token BRACKETED_ID "[identifier]" %token BRACKETED_ID "[identifier]"
%token CHAR "char" %token CHAR "char"
%token EPILOGUE "epilogue" %token EPILOGUE "epilogue"
@@ -171,7 +171,7 @@ static char const *char_name (char);
/* braceless is not to be used for rule or symbol actions, as it /* braceless is not to be used for rule or symbol actions, as it
calls code_props_plain_init. */ calls code_props_plain_init. */
%type <chars> STRING "%{...%}" EPILOGUE braceless content.opt %type <chars> STRING "%{...%}" EPILOGUE braceless content.opt
%type <code> "{...}" %type <code> "{...}" "%?{...}"
%printer { fputs (quotearg_style (c_quoting_style, $$), stderr); } %printer { fputs (quotearg_style (c_quoting_style, $$), stderr); }
STRING STRING
%printer { fprintf (stderr, "{\n%s\n}", $$); } %printer { fprintf (stderr, "{\n%s\n}", $$); }
@@ -586,7 +586,9 @@ rhs:
| rhs symbol named_ref.opt | rhs symbol named_ref.opt
{ grammar_current_rule_symbol_append ($2, @2, $3); } { grammar_current_rule_symbol_append ($2, @2, $3); }
| rhs "{...}" named_ref.opt | rhs "{...}" named_ref.opt
{ grammar_current_rule_action_append ($2, @2, $3); } { grammar_current_rule_action_append ($2, @2, $3, false); }
| rhs "%?{...}"
{ grammar_current_rule_action_append ($2, @2, NULL, true); }
| rhs "%prec" symbol | rhs "%prec" symbol
{ grammar_current_rule_prec_set ($3, @3); } { grammar_current_rule_prec_set ($3, @3); }
| rhs "%dprec" INT | rhs "%dprec" INT
@@ -601,7 +603,6 @@ named_ref.opt:
BRACKETED_ID { $$ = named_ref_new($1, @1); } BRACKETED_ID { $$ = named_ref_new($1, @1); }
; ;
/*---------------------------. /*---------------------------.
| variable and content.opt. | | variable and content.opt. |
`---------------------------*/ `---------------------------*/

View File

@@ -377,7 +377,8 @@ grammar_midrule_action (void)
code_props_rule_action_init (&midrule->action_props, code_props_rule_action_init (&midrule->action_props,
current_rule->action_props.code, current_rule->action_props.code,
current_rule->action_props.location, current_rule->action_props.location,
midrule, 0); midrule, 0,
current_rule->action_props.is_predicate);
code_props_none_init (&current_rule->action_props); code_props_none_init (&current_rule->action_props);
if (previous_rule_end) if (previous_rule_end)
@@ -468,14 +469,14 @@ grammar_current_rule_symbol_append (symbol *sym, location loc,
void void
grammar_current_rule_action_append (const char *action, location loc, grammar_current_rule_action_append (const char *action, location loc,
named_ref *name) named_ref *name, bool is_predicate)
{ {
if (current_rule->action_props.code) if (current_rule->action_props.code)
grammar_midrule_action (); grammar_midrule_action ();
/* After all symbol declarations have been parsed, packgram invokes /* After all symbol declarations have been parsed, packgram invokes
code_props_translate_code. */ code_props_translate_code. */
code_props_rule_action_init (&current_rule->action_props, action, loc, code_props_rule_action_init (&current_rule->action_props, action, loc,
current_rule, name); current_rule, name, is_predicate);
} }
@@ -516,6 +517,7 @@ packgram (void)
rules[ruleno].useful = true; rules[ruleno].useful = true;
rules[ruleno].action = p->action_props.code; rules[ruleno].action = p->action_props.code;
rules[ruleno].action_location = p->action_props.location; rules[ruleno].action_location = p->action_props.location;
rules[ruleno].is_predicate = p->action_props.is_predicate;
/* If the midrule's $$ is set or its $n is used, remove the `$' from the /* If the midrule's $$ is set or its $n is used, remove the `$' from the
symbol name so that it's a user-defined symbol so that the default symbol name so that it's a user-defined symbol so that the default

View File

@@ -53,7 +53,7 @@ void grammar_current_rule_merge_set (uniqstr name, location loc);
void grammar_current_rule_symbol_append (symbol *sym, location loc, void grammar_current_rule_symbol_append (symbol *sym, location loc,
named_ref *named_ref); named_ref *named_ref);
void grammar_current_rule_action_append (const char *action, location loc, void grammar_current_rule_action_append (const char *action, location loc,
named_ref *named_ref); named_ref *named_ref, bool);
void reader (void); void reader (void);
void free_merger_functions (void); void free_merger_functions (void);

View File

@@ -63,6 +63,13 @@ typedef struct code_props {
*/ */
bool is_value_used; bool is_value_used;
/**
* \c true iff this code is an action that is not to be deferred in
* a non-deterministic parser.
*/
bool is_predicate;
/** \c NULL iff \c code_props::kind is not \c CODE_PROPS_RULE_ACTION. */ /** \c NULL iff \c code_props::kind is not \c CODE_PROPS_RULE_ACTION. */
struct symbol_list *rule; struct symbol_list *rule;
@@ -80,7 +87,7 @@ void code_props_none_init (code_props *self);
/** Equivalent to \c code_props_none_init. */ /** Equivalent to \c code_props_none_init. */
#define CODE_PROPS_NONE_INIT \ #define CODE_PROPS_NONE_INIT \
{CODE_PROPS_NONE, NULL, EMPTY_LOCATION_INIT, false, NULL, NULL} {CODE_PROPS_NONE, NULL, EMPTY_LOCATION_INIT, false, false, NULL, NULL}
/** Initialized by \c CODE_PROPS_NONE_INIT with no further modification. */ /** Initialized by \c CODE_PROPS_NONE_INIT with no further modification. */
extern code_props const code_props_none; extern code_props const code_props_none;
@@ -134,7 +141,7 @@ void code_props_symbol_action_init (code_props *self, char const *code,
*/ */
void code_props_rule_action_init (code_props *self, char const *code, void code_props_rule_action_init (code_props *self, char const *code,
location code_loc, struct symbol_list *rule, location code_loc, struct symbol_list *rule,
named_ref *name); named_ref *name, bool is_predicate);
/** /**
* \pre * \pre

View File

@@ -902,7 +902,7 @@ code_props_symbol_action_init (code_props *self, char const *code,
void void
code_props_rule_action_init (code_props *self, char const *code, code_props_rule_action_init (code_props *self, char const *code,
location code_loc, symbol_list *rule, location code_loc, symbol_list *rule,
named_ref *name) named_ref *name, bool is_predicate)
{ {
self->kind = CODE_PROPS_RULE_ACTION; self->kind = CODE_PROPS_RULE_ACTION;
self->code = code; self->code = code;
@@ -910,6 +910,7 @@ code_props_rule_action_init (code_props *self, char const *code,
self->is_value_used = false; self->is_value_used = false;
self->rule = rule; self->rule = rule;
self->named_ref = name; self->named_ref = name;
self->is_predicate = is_predicate;
} }
void void

View File

@@ -106,11 +106,12 @@ static void unexpected_newline (boundary, char const *);
/* A complex tag, with nested angles brackets. */ /* A complex tag, with nested angles brackets. */
%x SC_TAG %x SC_TAG
/* Three types of user code: /* Four types of user code:
- prologue (code between `%{' `%}' in the first section, before %%); - prologue (code between `%{' `%}' in the first section, before %%);
- actions, printers, union, etc, (between braced in the middle section); - actions, printers, union, etc, (between braced in the middle section);
- epilogue (everything after the second %%). */ - epilogue (everything after the second %%).
%x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE - predicate (code between `%?{' and `{' in middle section); */
%x SC_PROLOGUE SC_BRACED_CODE SC_EPILOGUE SC_PREDICATE
/* C and C++ comments in code. */ /* C and C++ comments in code. */
%x SC_COMMENT SC_LINE_COMMENT %x SC_COMMENT SC_LINE_COMMENT
/* Strings and characters in code. */ /* Strings and characters in code. */
@@ -285,6 +286,13 @@ splice (\\[ \f\t\v]*\n)*
BEGIN SC_BRACED_CODE; BEGIN SC_BRACED_CODE;
} }
/* Semantic predicate. */
"%?"[ \f\n\t\v]*"{" {
nesting = 0;
code_start = loc->start;
BEGIN SC_PREDICATE;
}
/* A type. */ /* A type. */
"<*>" return TAG_ANY; "<*>" return TAG_ANY;
"<>" return TAG_NONE; "<>" return TAG_NONE;
@@ -661,7 +669,7 @@ splice (\\[ \f\t\v]*\n)*
| Strings, comments etc. can be found in user code. | | Strings, comments etc. can be found in user code. |
`---------------------------------------------------*/ `---------------------------------------------------*/
<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE> <SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_PREDICATE>
{ {
"'" { "'" {
STRING_GROW; STRING_GROW;
@@ -691,14 +699,32 @@ splice (\\[ \f\t\v]*\n)*
/*-----------------------------------------------------------. /*-----------------------------------------------------------.
| Scanning some code in braces (actions). The initial "{" is | | Scanning some code in braces (actions, predicates). The |
| already eaten. | | initial "{" is already eaten. |
`-----------------------------------------------------------*/ `-----------------------------------------------------------*/
<SC_BRACED_CODE> <SC_BRACED_CODE,SC_PREDICATE>
{ {
"{"|"<"{splice}"%" STRING_GROW; nesting++; "{"|"<"{splice}"%" STRING_GROW; nesting++;
"%"{splice}">" STRING_GROW; nesting--; "%"{splice}">" STRING_GROW; nesting--;
/* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
(as `<' `<%'). */
"<"{splice}"<" STRING_GROW;
<<EOF>> {
int token = (YY_START == SC_BRACED_CODE) ? BRACED_CODE : BRACED_PREDICATE;
unexpected_eof (code_start, "}");
STRING_FINISH;
loc->start = code_start;
val->code = last_string;
BEGIN INITIAL;
return token;
}
}
<SC_BRACED_CODE>
{
"}" { "}" {
obstack_1grow (&obstack_for_string, '}'); obstack_1grow (&obstack_for_string, '}');
@@ -712,21 +738,24 @@ splice (\\[ \f\t\v]*\n)*
return BRACED_CODE; return BRACED_CODE;
} }
} }
/* Tokenize `<<%' correctly (as `<<' `%') rather than incorrrectly
(as `<' `<%'). */
"<"{splice}"<" STRING_GROW;
<<EOF>> {
unexpected_eof (code_start, "}");
STRING_FINISH;
loc->start = code_start;
val->code = last_string;
BEGIN INITIAL;
return BRACED_CODE;
}
} }
<SC_PREDICATE>
{
"}" {
--nesting;
if (nesting < 0)
{
STRING_FINISH;
loc->start = code_start;
val->code = last_string;
BEGIN INITIAL;
return BRACED_PREDICATE;
}
else
obstack_1grow (&obstack_for_string, '}');
}
}
/*--------------------------------------------------------------. /*--------------------------------------------------------------.
| Scanning some prologue: from "%{" (already scanned) to "%}". | | Scanning some prologue: from "%{" (already scanned) to "%}". |
@@ -774,8 +803,8 @@ splice (\\[ \f\t\v]*\n)*
| By default, grow the string obstack with the input. | | By default, grow the string obstack with the input. |
`-----------------------------------------------------*/ `-----------------------------------------------------*/
<SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>. | <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE,SC_STRING,SC_CHARACTER,SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>. |
<SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>\n STRING_GROW; <SC_COMMENT,SC_LINE_COMMENT,SC_BRACED_CODE,SC_PREDICATE,SC_PROLOGUE,SC_EPILOGUE>\n STRING_GROW;
%% %%