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

I've been reading the Parse::RecDescent tutorial here and decided to modify the sample program used. What I wanted to do was extend the syntaxt that the print function took, so that the "expression" would be enclosed in parentheses, like print( expression ).

It is not working as I think it should, as illustrated by the program below, and its output (provided in readmore tags).

Any insight would be appreciated.
PS- I am writing a parser for !SCALASCRIPT, which is a pretty damn well structured , but and I'm making progress, but this is one thing tripping me up, and until I pass this hurdle, I cannot go on to muck with !SCALASCRIPT.

#!/usr/bin/perl -w use strict; use Parse::RecDescent; use Data::Dumper; use vars qw(%VARIABLE); # Enable warnings within the Parse::RecDescent module. $::RD_ERRORS = 1; # Make sure the parser dies when it encounters an er +ror $::RD_WARN = 1; # Enable warnings. This will warn on unused rules &c +. $::RD_HINT = 1; # Give out hints to help fix problems. my $grammar = <<'_EOGRAMMAR_'; # Terminals (macros that can't expand further) # OP : m([-+*/%]) # Mathematical operators INTEGER : /[-+]?\d+/ # Signed integers VARIABLE : /\w[a-z0-9_]*/i # Variable expression : INTEGER OP expression { return &::expression(@item) } | VARIABLE OP expression { return &::expression(@item) } | INTEGER | VARIABLE { return $::VARIABLE{$item{VARIABLE}} }

print_instruction : /print/i expression { use Data::Dumper; print Dumper \%item; print $item{expression}."\n" } assign_instruction : VARIABLE "=" expression { $::VARIABLE{$item{VARIABLE}} = $item{expression +} } myprint_instruction: 'print(' expression ')' # I want print(1+1) t +o work { print $item{expression}."\n" } range: '(' INTEGER '..' INTEGER ')' { print "Gosh darn, $item{INTEGER}\n"; } instruction : myprint_instruction | assign_instruction | print_instruction startrule: instruction(s /;/) # multiple instructions, separated by +; _EOGRAMMAR_ sub expression { shift; my ($lhs,$op,$rhs) = @_; $lhs = $VARIABLE{$lhs} if $lhs=~/[^-+0-9]/; return eval "$lhs $op $rhs"; } my $parser = Parse::RecDescent->new($grammar); print "a=2\n"; $parser->startrule("a=2"); print "a=1+3\n"; $parser->startrule("a=1+3"); print "print 5*7\n"; $parser->startrule("print 5*7"); print "print 2/4\n"; $parser->startrule("print 2/4"); print "print 2+2/4\n"; $parser->startrule("print 2+2/4"); print "print 2+-2/4\n"; $parser->startrule("print 2+-2/4"); print "a = 5 ; print a\n"; $parser->startrule("a = 5 ; print a"); print "a = 69 ; print(a)\n"; $parser->startrule("a = 69 ; print(a)"); +# WTF??? print "a = 69 ; print a ; print(a)\n"; $parser->startrule("a = 69 ; pr +int a ; print(a)"); # WTF??? print "print( 6 + 9 )\n"; $parser->myprint_instruction("print( 6 + 9 ) +"); # WTF?? print "print(69)\n"; $parser->myprint_instruction("print(69)"); # ok print "print(69)\n"; $parser->startrule("print(69)"); # ok print "(4..9)\n"; $parser->range("(4..4)"); # ok print Dumper $parser; __END__ a=2 a=1+3 print 5*7 $VAR1 = { 'expression' => 35, '__PATTERN1__' => 'print', '__RULE__' => 'print_instruction' }; 35 print 2/4 $VAR1 = { 'expression' => '0.5', '__PATTERN1__' => 'print', '__RULE__' => 'print_instruction' }; 0.5 print 2+2/4 $VAR1 = { 'expression' => '2.5', '__PATTERN1__' => 'print', '__RULE__' => 'print_instruction' }; 2.5 print 2+-2/4 $VAR1 = { 'expression' => '1.5', '__PATTERN1__' => 'print', '__RULE__' => 'print_instruction' }; 1.5 a = 5 ; print a $VAR1 = { 'expression' => '5', '__PATTERN1__' => 'print', '__RULE__' => 'print_instruction' }; 5 a = 69 ; print(a) a = 69 ; print a ; print(a) $VAR1 = { 'expression' => '69', '__PATTERN1__' => 'print', '__RULE__' => 'print_instruction' }; 69 print( 6 + 9 ) print(69) 69 print(69) 69 (4..9) God damn, 4

(Editor note Masem - breaking the output here to make the first part pretty-printed -- the D::D of the parser is not complete)

$VAR1 = bless( { '_AUTOTREE' => undef, 'rules' => { 'assign_instruction' => bless( { 'impcou +nt' => 0, 'line' +=> '24', 'prods' + => [ + bless( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 1, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'line' => '24', + 'subrule' => 'VARIABLE', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'description' => '\'=\'', + 'line' => '24', + 'pattern' => '=', + 'hashname' => '__STRING1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::InterpLit' +), + bless( { + 'line' => '24', + 'subrule' => 'expression', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '25', + 'code' => '{ $::VARIABLE{$item{V +ARIABLE}} = $item{expression} }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 + }, 'Parse::RecDescent::Production' ) + ], 'calls' + => [ + 'VARIABLE', + 'expression' + ], 'opcoun +t' => 0, 'change +d' => 0, 'vars' +=> '', 'name' +=> 'assign_instruction' }, 'Parse +::RecDescent::Rule' ), 'instruction' => bless( { 'impcount' => +0, 'line' => '36' +, 'prods' => [ b +less( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'line' => '36', + 'subrule' => 'myprint_instruction', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ) + ], + 'actcount' => 0 + }, 'Parse::RecDescent::Production' ), b +less( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 1, + 'error' => undef, + 'line' => '37', + 'items' => [ + bless( { + 'line' => '37', + 'subrule' => 'assign_instruction', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ) + ], + 'actcount' => 0 + }, 'Parse::RecDescent::Production' ), b +less( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 2, + 'error' => undef, + 'line' => '38', + 'items' => [ + bless( { + 'line' => '38', + 'subrule' => 'print_instruction', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ) + ], + 'actcount' => 0 + }, 'Parse::RecDescent::Production' ) ], 'calls' => [ ' +myprint_instruction', ' +assign_instruction', ' +print_instruction' ], 'opcount' => 0 +, 'changed' => 0 +, 'vars' => '', 'name' => 'ins +truction' }, 'Parse::RecDe +scent::Rule' ), 'OP' => bless( { 'impcount' => 0, 'line' => '3', 'prods' => [ bless( { ' +dircount' => 0, ' +uncommit' => undef, ' +patcount' => 1, ' +strcount' => 0, ' +number' => 0, ' +error' => undef, ' +line' => undef, ' +items' => [ + bless( { + 'description' => 'm([-+*/%])', + 'pattern' => '[-+*/%]', + 'mod' => '', + 'hashname' => '__PATTERN1__', + 'lookahead' => 0, + 'ldelim' => '(', + 'line' => '5', + 'rdelim' => ')' + }, 'Parse::RecDescent::Token' ) + ], ' +actcount' => 0 }, +'Parse::RecDescent::Production' ) ], 'calls' => [], 'opcount' => 0, 'changed' => 0, 'vars' => '', 'name' => 'OP' }, 'Parse::RecDescent::Ru +le' ), 'startrule' => bless( { 'impcount' => 0, 'line' => '40', 'prods' => [ ble +ss( { + 'dircount' => 1, + 'uncommit' => undef, + 'op' => [], + 'patcount' => 1, + 'strcount' => 0, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'expected' => '<leftop: instruction /;/ i +nstruction>', + 'rightarg' => bless( { + 'line' => '40', + 'subrule' => 'inst +ruction', + 'argcode' => undef +, + 'implicit' => unde +f, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescen +t::Subrule' ), + 'min' => 1, + 'max' => 100000000, + 'op' => bless( { + 'description' => '/;/', + 'pattern' => ';', + 'mod' => '', + 'hashname' => '__PATTERN +1__', + 'lookahead' => 0, + 'ldelim' => '/', + 'line' => '40', + 'rdelim' => '/' + }, 'Parse::RecDescent::Tok +en' ), + 'hashname' => '__DIRECTIVE1__', + 'leftarg' => bless( { + 'line' => '40', + 'subrule' => 'instr +uction', + 'argcode' => undef, + 'implicit' => undef +, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent +::Subrule' ), + 'type' => 'leftop' + }, 'Parse::RecDescent::Operator' ) + ], + 'actcount' => 0 + }, 'Parse::RecDescent::Production' ) ], 'calls' => [ 'in +struction' ], 'opcount' => 0, 'changed' => 0, 'vars' => '', 'name' => 'start +rule' }, 'Parse::RecDesc +ent::Rule' ), 'VARIABLE' => bless( { 'impcount' => 0, 'line' => '6', 'prods' => [ bles +s( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 1, + 'strcount' => 0, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'description' => '/\\\\w[a-z0-9_]*/i', + 'pattern' => '\\w[a-z0-9_]*', + 'mod' => 'i', + 'hashname' => '__PATTERN1__', + 'lookahead' => 0, + 'ldelim' => '/', + 'line' => '7', + 'rdelim' => '/' + }, 'Parse::RecDescent::Token' ) + ], + 'actcount' => 0 + }, 'Parse::RecDescent::Production' ) ], 'calls' => [], 'opcount' => 0, 'changed' => 0, 'vars' => '', 'name' => 'VARIAB +LE' }, 'Parse::RecDesce +nt::Rule' ), 'print_instruction' => bless( { 'impcoun +t' => 0, 'line' = +> '17', 'prods' +=> [ + bless( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 1, + 'strcount' => 0, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'description' => '/print/i', + 'pattern' => 'print', + 'mod' => 'i', + 'hashname' => '__PATTERN1__', + 'lookahead' => 0, + 'ldelim' => '/', + 'line' => '17', + 'rdelim' => '/' + }, 'Parse::RecDescent::Token' ), + bless( { + 'line' => '17', + 'subrule' => 'expression', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '18', + 'code' => '{ use Data::Dumper; print Dumper \\%item; print $item{expression}."\\n" }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 + }, 'Parse::RecDescent::Production' ) + ], 'calls' +=> [ + 'expression' + ], 'opcount +' => 0, 'changed +' => 0, 'vars' = +> '', 'name' = +> 'print_instruction' }, 'Parse: +:RecDescent::Rule' ), 'myprint_instruction' => bless( { 'impco +unt' => 0, 'line' + => '26', 'prods +' => [ + bless( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 2, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'description' => '\'print(\'', + 'line' => '26', + 'pattern' => 'print(', + 'hashname' => '__STRING1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Literal' ) +, + bless( { + 'line' => '26', + 'subrule' => 'expression', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ) +, + bless( { + 'description' => '\')\'', + 'line' => '26', + 'pattern' => ')', + 'hashname' => '__STRING2__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Literal' ) +, + bless( { + 'line' => '26', + 'code' => '{ print $item{expression}."\\n" }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 + }, 'Parse::RecDescent::Production' ) + ], 'calls +' => [ + 'expression' + ], 'opcou +nt' => 0, 'chang +ed' => 0, 'vars' + => '', 'name' + => 'myprint_instruction' }, 'Pars +e::RecDescent::Rule' ), 'expression' => bless( { 'impcount' => 0 +, 'line' => '7', 'prods' => [ bl +ess( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'line' => '9', + 'subrule' => 'INTEGER', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '9', + 'subrule' => 'OP', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '9', + 'subrule' => 'expression', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '10', + 'code' => '{ return &::expression(@item) + }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 + }, 'Parse::RecDescent::Production' ), bl +ess( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 1, + 'error' => undef, + 'line' => '11', + 'items' => [ + bless( { + 'line' => '11', + 'subrule' => 'VARIABLE', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '11', + 'subrule' => 'OP', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '11', + 'subrule' => 'expression', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '12', + 'code' => '{ return &::expression(@item) + }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 + }, 'Parse::RecDescent::Production' ), bl +ess( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 2, + 'error' => undef, + 'line' => '13', + 'items' => [ + bless( { + 'line' => '13', + 'subrule' => 'INTEGER', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ) + ], + 'actcount' => 0 + }, 'Parse::RecDescent::Production' ), bl +ess( { + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 0, + 'number' => 3, + 'error' => undef, + 'line' => '14', + 'items' => [ + bless( { + 'line' => '14', + 'subrule' => 'VARIABLE', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'line' => '15', + 'code' => '{ return $::VARIABLE{$item{VA +RIABLE}} }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 + }, 'Parse::RecDescent::Production' ) ], 'calls' => [ 'I +NTEGER', 'O +P', 'e +xpression', 'V +ARIABLE' ], 'opcount' => 0, 'changed' => 0, 'vars' => '', 'name' => 'expr +ession' }, 'Parse::RecDes +cent::Rule' ), 'range' => bless( { 'impcount' => 0, 'line' => '31', 'prods' => [ bless( +{ + 'dircount' => 0, + 'uncommit' => undef, + 'patcount' => 0, + 'strcount' => 3, + 'number' => 0, + 'error' => undef, + 'line' => undef, + 'items' => [ + bless( { + 'description' => '\'(\'', + 'line' => '31', + 'pattern' => '(', + 'hashname' => '__STRING1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Literal' ), + bless( { + 'line' => '31', + 'subrule' => 'INTEGER', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'description' => '\'..\'', + 'line' => '31', + 'pattern' => '..', + 'hashname' => '__STRING2__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Literal' ), + bless( { + 'line' => '31', + 'subrule' => 'INTEGER', + 'argcode' => undef, + 'implicit' => undef, + 'matchrule' => 0, + 'lookahead' => 0 + }, 'Parse::RecDescent::Subrule' ), + bless( { + 'description' => '\')\'', + 'line' => '31', + 'pattern' => ')', + 'hashname' => '__STRING3__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Literal' ), + bless( { + 'line' => '32', + 'code' => '{ print "God damn, $item{INTEGER}\\n"; }', + 'hashname' => '__ACTION1__', + 'lookahead' => 0 + }, 'Parse::RecDescent::Action' ) + ], + 'actcount' => 1 +}, 'Parse::RecDescent::Production' ) ], 'calls' => [ 'INTEGE +R' ], 'opcount' => 0, 'changed' => 0, 'vars' => '', 'name' => 'range' }, 'Parse::RecDescent: +:Rule' ), 'INTEGER' => bless( { 'impcount' => 0, 'line' => '5', 'prods' => [ bless +( { + 'dircount' => 0,

Replies are listed 'Best First'.
Re: Parse::RecDescent grammar and Parenthesis
by maverick (Curate) on Dec 17, 2001 at 13:29 UTC
    hmmm...have you tried adding a second rule for print_instruction that has the optional parens? not the most elegant solution, but it seems like it should work.
    print_instruction : /print/i expression { use Data::Dumper; print Dumper \%item; print $item{expression}."\n" } | /print/i '(' expression ')' { use Data::Dumper; print Dumper \%item; print $item{expression}."\n" }
    HTH

    /\/\averick
    perl -l -e "eval pack('h*','072796e6470272f2c5f2c5166756279636b672');"

      Yes I have, but it behaves the same as before (it will print a straight number, but not an expression).

      My original modifications look like they should work also, but sadly that is not the case ;(

      update:

      Upon the suggestion of jmcnamara i've set $::RD_TRACE = 1; and ran the beast and got the following in my STDERR (readmore follows)

       
      ___crazyinsomniac_______________________________________
      Disclaimer: Don't blame. It came from inside the void

      perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"

Re: Parse::RecDescent grammar and Parenthesis
by Masem (Monsignor) on Dec 17, 2001 at 19:32 UTC
    I don't think you want to invoke 'returns' in your grammar. Namely:
    expression : INTEGER OP expression { return &::expression(@item) } | VARIABLE OP expression { return &::expression(@item) } | INTEGER | VARIABLE { return $::VARIABLE{$item{VARIABLE}} }
    Should be the following instead:
    expression : INTEGER OP expression { $return = &::expression(@item) } | VARIABLE OP expression { $return = &::expression(@item) } | INTEGER | VARIABLE { $return = $::VARIABLE{$item{VARIABLE}} }
    Your forced returns may be interfering with code that acknowledges that you've matched something and to move on, which only seems to rear it's head in the print( something ) case.

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

Re: Parse::RecDescent grammar and Parenthesis
by ariels (Curate) on Dec 17, 2001 at 19:54 UTC
    Try losing the return when returning values. This fragment of the parser (for expression) works for me:
    expression : INTEGER OP expression { &::expression(@item) } | VARIABLE OP expression { &::expression(@item) } | INTEGER | VARIABLE { $::VARIABLE{$item{VARIABLE}} }
Re: Parse::RecDescent grammar and Parenthesis
by TheDamian (Vicar) on Dec 18, 2001 at 06:09 UTC
    Yes, as others have pointed out, it's the return statements that are the problem.

    Actions are transformed into do blocks within the subroutine that implements each rule. That means that if an action executes a return, the entire surrounding subroutine (i.e. the entire rule) returns. Immediately.

    In that case, subsequent items in the current production are not considered, nor are subsequent productions in the current rule. So typically, you get a "match", but not of the entire input. Or you get a "failed-to-match" on the next rule, even though the production that was supposed to match the previous input seems to succeed.

    Hmmmmm. This is becoming a frequently encountered trap as more and more people are using the module. That usually indicates that the original design is flawed (because the module isn't DWIMing). I suspect that a near-future release may translate:

    { action() }
    not to:
    do { action() }
    but to:
    { action() }->()
    so as to make the behaviour of embedded returns conform to people's expection.
      I think, as crazyinsomniac pointed out to me in privmsg, that while the POD and what I have here as a tutorial and some other sources all use $return, this tutorial at perl.com uses the return() form, which for their case, works, but doesn't work in the general case. Given that I bet a lot of people were introduced to this module via perl.com, I suspect this is where you are seeing this error pop up. CI says he was going to fire a message off to the author, Jeffory Goff, and see if he can't get it updated.

      -----------------------------------------------------
      Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
      "I can see my house from here!"
      It's not what you know, but knowing how to find it if you don't know that's important

Re: Parse::RecDescent grammar and Parenthesis
by japhy (Canon) on Dec 17, 2001 at 19:56 UTC
    You're in luck, if P::RD doesn't work out. This language isn't recursive, so it can be matched easily with a regex. (If it were recursive, it'd be a little harder, but still doable.)

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

(crazyinsomniac: thank you) Re: Parse::RecDescent grammar and Parenthesis
by crazyinsomniac (Prior) on Dec 18, 2001 at 07:23 UTC
    I would like to thank everybody for their help. Changing my explicit returns into $return = worked like a charm, as did removing the returns, thus doing an implicit return.

    I have notified Jeffrey Goff, the author of the Parse::RecDescent Tutorial on perl.com of this perlmonks thread and the issue with using return.

    update: It's been 2 days, and while that may be short time, I decided to notify the managing editor of oreillynet.com Derrick Story.

    For those curious, here is the relevant trace (in readmroe):

     
    ___crazyinsomniac_______________________________________
    Disclaimer: Don't blame. It came from inside the void

    perl -e "$q=$_;map({chr unpack qq;H*;,$_}split(q;;,q*H*));print;$q/$q;"