0

I'm trying to process what will eventually be Boolean logic using a grammar in Treetop-like Citrus for Ruby. I'm getting a recursion issue, but I'm unclear on exactly why. Here's the text I'm trying to process (it should have a newline at the very end):

COMMANDWORD # MYCOMMENT

Here's my Citrus grammar (intended to deal with more advanced stuff):

grammar Grammar
  rule commandset
    command+
  end

  rule command
    identifier command_detail* comment_to_eol* "\n"
  end

  rule command_detail
    assign_expr | expr
  end

  rule assign_expr
    identifier ":=" expr
  end

  rule expr
    # Stack overflow
    or_expr | gtor_expr
    # No problem!
    # or_expr
  end

  rule or_expr
    # Temporarily match everything except a comment...
    [^#]+
    # What I think will be correct in the future...
    # gtor_expr "OR" expr
  end

  rule gtor_expr
    and_expr | gtand_expr
  end

  rule and_expr
    gtand_expr "AND" gtor_expr
  end

  rule gtand_expr
    not_expr | gtnot_expr
  end

  rule not_expr
    "NOT" gtnot_expr | gtand_expr
  end

  rule gtnot_expr
    parens_expr | identifier
  end

  rule parens_expr
    "(" expr ")"
  end

  rule identifier
    ws* [a-zA-Z0-9]+ ws*
  end

  rule ws
    [ ]
  end

  rule comment_to_eol
    "#" [^\n]*
  end
end

The important things are in the rule expr and the rule or_expr. I've altered or_expr so it matches everything except a comment. If I stick with the current expr rule I get a stack overflow. But if I switch it so it doesn't have the choice between or_expr and gtor_expr it works fine.

My understanding of the "choice" is that it will try to evaluate them in order. If the first choice fails, then it will try the second. In this case, the first choice is obviously capable of succeeding, so why do I get a stack overflow if I include a second choice that should never be taken?

1010
  • 1,779
  • 17
  • 27
aardvarkk
  • 14,955
  • 7
  • 67
  • 96
  • 1
    At first glance, it appears that the `gtor_expr` depends on `and_expr` which depends on `gtor_expr`. Infinite loop. – Mark Thomas Sep 19 '14 at 21:00
  • @MarkThomas I know it seems strange. I'm basing it off of an Arithmetic Grammar from here https://github.com/mjackson/citrus/blob/master/lib/citrus/grammars/calc.citrus. In that case, notice that `term` depends on `additive` which depends on `term` again. I think it's OK because in both cases we specify that there must be a specific symbol preceding it (such as an "OR" or "AND"). – aardvarkk Sep 19 '14 at 21:03
  • I upvoted @MarkThomas but since and_expr consumes "AND" I dont't think this produces the SO. – 1010 Sep 22 '14 at 15:39

1 Answers1

1

the loop may result because gtand_expr -> not_expr, and not_expr -> gtand_expr.

I think you can replace not_expr's rule with

not_expr -> "NOT" not_expr | gtnot_expr

And you should try simpler rules using regexp operators:

expr -> orexpr
orexpr -> andexpr ("OR" andexpr)*
andexpr -> notexpr ("AND" notexpr)*
notexpr -> "NOT"? atomicexpr
atomicexpr -> id | "(" expr ")"
1010
  • 1,779
  • 17
  • 27