Search code examples
perlparse-recdescent

Parse::RecDescent and operators with quotes


I have something like the following:

((x=2 or y=3 ) and (r=3 and c=3) or (x=5 and g=6))

I defined:

Token : /\w \= \d/
operator or|and
expression : token operator(s)
quoted_expression : "("expression")"
query : expression (s)|quoted_expression(s)

But I have a problem with parsing the above condition any idea how to parse the above?


Solution

  • At the core, you want

    expr    : log_or
    
    log_or  : log_or 'or' log_and
            | log_and
    
    log_and : log_and 'and' cmp
            | cmp
    
    cmp     : cmp /=|<[>=]?|>=?/ term
            | term
    
    term    : '(' expr ')'
            | IDENT
            | NUMBER
    

    After eliminating left-recursion and adding the necessary code blocks, you get the following:

    my $grammar = <<'__EOS__';
    
       {
          # The code in rules is also covered by these pragmas.
          use strict;
          use warnings;
       }
    
       parse    : expr /\Z/ { $item[1] }
    
       # ----------------------------------------
       # Rules
    
       expr     : log_or { $item[1] }
    
       # ---vvv--- Lowest precedence ---vvv---
    
       log_or   : log_and log_or_[ $item[1] ]
       log_or_  : 'or' log_and log_or_[ [ $item[1], $arg[0], $item[2] ] ]
                | { $arg[0] }
    
       log_and  : cmp log_and_[ $item[1] ]
       log_and_ : 'and' cmp log_and_[ [ $item[1], $arg[0], $item[2] ] ]
                | { $arg[0] }
    
       cmp      : term cmp_[ $item[1] ]
       cmp_     : /=|<[>=]?|>=?/ term cmp_[ [ $item[1], $arg[0], $item[2] ] ]
                | { $arg[0] }
    
       # ---^^^--- Highest precedence ---^^^---
    
       term     : '(' expr ')' { $item[2] }
                | IDENT  { [ $item[0], $item[1] ] }
                | NUMBER { [ $item[0], $item[1] ] }
    
       # ----------------------------------------
       # Tokens
    
       IDENT    : /\w+/
       NUMBER   : /\d+/
    
    __EOS__