Search code examples
perlparse-recdescent

Parse::RecDescent and Grammar


I defined the following grammar using Parse::RecDescent

my $grammar = q{

top : operand equal value { print $item{value} }

operand: /\w+/     

equal : /\=/

value : { my $value = extract_quotelike($text) ;$return =$value;} 

};

which i wants it to handle the following cases :

X = 2 -> should print 2

X = "2" -> should print 2

x = '2' -> should print 2

but the above grammar provide different results :

for x=2 it fail to parse it

for x="2" -> it print "2"

for x ='2' -> it pring '2'

any idea to change the above grammar to print 2 on all the the 3 above cases , i.e removing the quotes


Solution

  • build_parser.pl:

    use strict;
    use warnings;
    
    use Parse::RecDescent qw( );
    
    Parse::RecDescent->Precompile(<<'__EOS__', "Parser");
       {
          # The code in rules is also covered by these pragmas.
          use strict;
          use warnings;
    
          sub dequote { substr($_[0], 1, -1) =~ s/\\(.)/$1/srg }
       }
    
       start     : assign /\Z/ { $item[1] }
    
       assign    : lvalue '=' expr { [ 'assign', $item[1], $item[3] ] }
    
       lvalue    : IDENT
    
       expr      : NUM_LIT { [ 'num_const', $item[1] ] }
                 | STR_LIT { [ 'str_const', $item[1] ] }
    
       # TOKENS
       # ----------------------------------------
    
       IDENT     : \w+
    
       NUM_LIT   : /[0-9]+/
    
       STR_LIT   : /'(?:[^'\\]++|\\.)*+'/s { dequote($item[1]) }
                 | /"(?:[^"\\]++|\\.)*+"/s { dequote($item[1]) }
    
    __EOS__
    

    Adjust the definition of string literals to your needs (but remember to adjust both the rule and dequote).

    Running build_parser.pl will generate Parser.pm, which can be used as follows:

    use strict;
    use warnings;
    
    use FindBin qw( $RealBin );
    use lib $RealBin;
    
    use Data::Dumper qw( Dumper );
    use Parser       qw( );
    
    my $parser = Parser->new();
    print(Dumper( $parser->start('x = 2') ));