in reply to Re^2: Help with Parse::RecDescent grammar
in thread Help with Parse::RecDescent grammar

Start by not using <autotree>. You need to override it 90% of the time (100% in this case), so you might as well make everything explicit.

use strict; use warnings; use Data::Dumper qw( Dumper ); use Parse::RecDescent qw( ); $::RD_ERRORS = 1; $::RD_WARN = 1; $::RD_HINT = 1; #$::RD_TRACE = 1; my $grammar = <<'_EOGRAMMAR_'; { # These apply to code in those block and all actions. use strict; use warnings; my %escapes = ( n => "\n", ); sub dequote_double { for (my $s = @_ ? $_[0] : $_) { s/^"//g; s/"$//g; s/\\(.)/$escapes{$1} || $1/eg; return $_; } } } parse : <skip:'(?:\s+|#[^\n]*\n)*'> portDef(s?) /\Z/ { $item[2] } portDef : "dbSetCellPortTypes" QSTRING QSTRING portList { [ @item[1..4] ] } portList : "'" "(" record(s?) ")" { $item[3] } record : "(" QSTRING(s?) ")" { $item[2] } QSTRING : /"(?:[^"\\]|\\.)*"/ { dequote_double($item[1]) } _EOGRAMMAR_ my $parser = Parse::RecDescent->new($grammar) or die "Bad grammar\n"; my $text = <<'_EOT_'; dbSetCellPortTypes "/opt/mylib/s956M" "*" '( ("gnd!" "Inout" "Ground" ) ("vint!" "Inout" "Power" ) ) #f _EOT_ my $net = $parser->parse($text) or die "bad netlist"; print Dumper $net;

Other fixes:

Update: Fixed portList. (Replaced { $item[2] } with { $item[3] }.)
Update: Fixed comment and missing (s?) in parse.

Replies are listed 'Best First'.
Re^4: Help with Parse::RecDescent grammar
by dramguy (Novice) on Dec 12, 2006 at 17:43 UTC
    Hello, Thanks for the reply.

    Does the  /\Z/ match the #f at the end of the DATA?

    Here is the output I get:

    $VAR1 = [ 'dbSetCellPortTypes', '/opt/mylib/s956M', '*', '(' ];

    Looks like the portLists are not being returned correctly...could this have something to do with the #f? Thanks,

    Frank

      Here is the output I get:

      Oops, portList should be

      portList : "'" "(" record(s?) ")" { $item[3] }

      I made a minor change (undid my mergine of ' and ( into a single token) right before posting without testing.

      By the way, "'(" means no whitespace (as defined by <skip>, \s* by default) is allwed between the two characters, while "'" "(" means whitespace IS allowed.

      could this have something to do with the #f?

      Is that a commment? I treated it as a comment, so I used <skip> to handle it.

      If it's not a comment, what is it? An unquoted string? Does it support any kind of escapes?

        The  #f is a boolean value used to tell a EDA program how to update the corresponding data. The #f, tells the system to only update new data, whereas #t tells the system to overwrite all previous data. This always comes after the last ")" and is never quoted. Im not sure what you would call this?

        I changed the code to return $item[3] and I now get a nice looking structure. One thing I notice is when I try to parse multiple entries, I get the bad netlist error again. For example:

        Consider my data is the following:

        my $text = <<'_EOT_'; dbSetCellPortTypes "/opt/mylib/s956M" "blahblah" '( ("gnd!" "Inout" "Ground" ) ("vint!" "Inout" "Power" ) ) #f dbSetCellPortTypes "/opt/mylib/s956M" "newCell" '( ("gnd!" "Inout" "Ground" ) ("vint!" "Inout" "Power" ) ) #f _EOT_

        I've tried changing the parse rule to the following as well:

        parse : <skip:'(?:\s*(?:#[^\n]*)?)'> portDef(s?) /\Z/ { $item[2] }

        What is the /\Z/ doing actually?

        Thanks,

        Frank