Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks, hoping for some insight here.

I have the following BNF and am trying to get it to work with RecDescent. I'm evaluating the WHERE condition on a simplified SQL statement.

BNF

<cond> ::= <x> [ "OR" <cond> ] <x> ::= <y> [ "AND" <y> ] <y> ::= "(" <cond> ")" | <z> <op> <z> <z> ::= [tabname"."]colname | <value> <op> ::= "<" | ">" | "=" | "<>" | "<=" | ">="
tabname and colname are identifiers which have at most 20 characters, start with a letter, and cannot end in an underscore. colname as seen above can take the forme tabname.colname.

This is my grammar as I've converted it:

condition : x | x /OR/i condition x : y | y /AND/i y y : "(" condition ")" | z OP z z : TABCOLNAME | COLNAME | VALUE # Terminals TABCOLNAME : /([a-z]{1}[\w]{0,18}[^_])\.([a-z]{1}[\w]{0,18}[^_\ ])/i COLNAME : /([a-z]{1}[\w]{0,18}[^_\ ])/i VALUE : /(\w+)/ix OP : /(<>|<=|>=|=|<|>)/
It seems to check syntax okay put when I try to print @item after the y statement only the first part of a statement is printed. So if my string is: "ssn = 1234 and name = bob" only "ssn = 1234" gets put in @item.

Thanks for any help.

Dave

Replies are listed 'Best First'.
Re: Converting BNF for use in Parse::RecDescent
by Abigail-II (Bishop) on Oct 31, 2003 at 17:47 UTC
    That's because you give Parse::RecDescent options for the x and y rules. PRD will, just like Perl regexes, try alternatives in order, left one first. So, if PRD has to choose between "y" and "y /AND/i y", it'll first do the y, and only if that alternative fails, it'll try the alternative.

    You can fix this by requiring that after matching the SQL statement, it should match the end of the string. But, for efficiency, also reorganize the rules:

    condition: x /OR/i x | x x: y /AND/i y | y
    although this is still inefficient, as it may require backtracking.

    Abigail

Re: Converting BNF for use in Parse::RecDescent
by hanenkamp (Pilgrim) on Nov 01, 2003 at 17:23 UTC

    You might want to read the GOTCHAs section of Parse::Recdescent too. It has a formula for guaranteeing that either the whole thing parses, or nothing at all parses--assuming that the input string should be completely parsed. Anyway, if added to your code, you could add these two productions like this so that where is the new toplevel production:

    where : condition eofile eofile : /^\Z/

    If you don't need to parse the whole input, you could make eofile an appropriate end marker for the parsed input. Adding <error> directives in the right places in your other productions may also help.

Re: Converting BNF for use in Parse::RecDescent
by daveyh (Initiate) on Oct 31, 2003 at 18:26 UTC
    Thanks, that should get me going again.

    Dave