Pergunta

Here's what I'm trying:

foreach_in.Rule = ToTerm("foreach") + "(" + VARIABLE + "in" + list_obj + ")";
foreach_as.Rule = ToTerm("foreach") + "(" + list_obj + "as" + VARIABLE + ")";
for_loop.Rule = ToTerm("for") + "(" + simple_assignment + ";" + comparison + ";" + assignment + ")";
if_condition.Rule = ToTerm("if") + "(" + comparison + ")";
if_else.Rule = if_condition + block + "else"; // <-- PROBLEM
preset_directive.Rule = foreach_in | foreach_as | for_loop | if_else | if_condition;
directive.Rule = preset_directive | custom_directive;
directive_blk.Rule = directive + block;

But I get a shift-reduce conflict. I'm not quite sure why... shouldn't it greedily grab the "else" if it can? Not quite sure how else to define an else block such that it can only be followed by an "if" block.

I think an if_else block node with an if node and an else node would be optimal because then I don't have to go back and check the previous sibling when I try traverse the AST.

If you need to see more of the grammar...just let me know. A "block" is basically defined as { blah } (a bunch of statements between {}).


Trying it as an optional block:

custom_directive_kw.Rule = ToTerm("custom_directive1") | "custom_directive2";
custom_directive.Rule = custom_directive_kw + free_args_opt;
foreach_in.Rule = ToTerm("foreach") + "(" + variable + "in" + list_obj + ")" + block;
foreach_as.Rule = ToTerm("foreach") + "(" + list_obj + "as" + variable + ")" + block;
for_loop.Rule = ToTerm("for") + "(" + simple_assignment + ";" + comparison + ";" + assignment + ")" + block;
if_condition.Rule = ToTerm("if") + "(" + comparison + ")" + block + else_blk_opt;
else_blk.Rule = "else" + block;
else_blk_opt.Rule = else_blk | Empty;
preset_directive.Rule = foreach_in | foreach_as | for_loop | if_condition;
directive.Rule = preset_directive | custom_directive;
directive_blk.Rule = directive;

Doesn't like that either. Still throws the warning.

Foi útil?

Solução

Nevermind... Irony has this magical PreferShiftHere() function that does the trick.

foreach_in.Rule = ToTerm("foreach") + "(" + variable + "in" + list_obj + ")" + block;
foreach_as.Rule = ToTerm("foreach") + "(" + list_obj + "as" + variable + ")" + block;
for_loop.Rule = ToTerm("for") + "(" + simple_assignment + ";" + comparison + ";" + assignment + ")" + block;
if_condition.Rule = ToTerm("if") + "(" + comparison + ")" + block;
if_else.Rule = if_condition + PreferShiftHere() + "else" + block;
preset_directive.Rule = foreach_in | foreach_as | for_loop | if_else | if_condition;
directive_blk.Rule = preset_directive | custom_directive;

Outras dicas

I'm guessing here, but shouldn't you define the IF as:

if_condition.Rule = ToTerm("if") + "(" + comparison + ")" + block;

And then go on to define the else part as:

else_block.Rule = ToTerm("else") + block;

And Finally put it all together:

if_else.Rule = if_condition + else_block;

Once more, I'm guessing here, 'cause I haven't worked with EBNF yet.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top