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

I'm stumped on creating a grammar for PRD that will parse lines like these:

SomeName val1 val2 "this is val3"
NoValDefaultsTo1

I want to match the SomeName with one rule, and then
match each of the whitespace separated values separately. (i.e. (val1, val2, "this is val3") )
Here is my grammar:

single: key val(s) { [$item[1], $item[2]] } | key { [$item[1],1] } key: /\w+/ val: <perl_quotelike> { $item[1]->[2] }
Note: I know that the val terminal is not complete for what I'm trying to do.

My problem is, If I don't use the <perl_quotelike> directive,
(i.e. /.*?$/) then it grabs NoValDefaultsTo1 as a val of
SomeName instead of a key.

I am very new to PRD, any help/advise is greatly appreciated.

Thanks, MG

Update:
P.S. Could someone explain the difference between <leftop> and <rightop>
I couldn't find this anywhere.

Replies are listed 'Best First'.
•Re: Parse::RecDescent question
by merlyn (Sage) on Dec 12, 2003 at 15:24 UTC
    First of all, you need to tell PRD that you have a line-oriented syntax rather than a whitespace separated syntax. Otherwise, newlines will be swallowed between tokens arbitrarily. And then all you really have is a command and its args:
    grammar: line(s?) /\z/ { $item[1] } line: <skip:[ \t]+> command arg(s?) "\n" { [$item[2], $item[3]] } command: /\w+/ arg: <perl_quotelike>
    That should get you started. If you have more questions, the Parse::RecDescent mailing list can be accessed via http://lists.perl.org.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.


    update:My PRD coding skills may be a bit rusty, and I didn't have time to test this code. Hopefully, if you can't get it to work, it'll at least be a model to start debugging from.
    update2:OK, this works:
    grammar: line(s?) /\z/ { $item[1] } line: <skip:'[ \t]*'> command arg(s?) "\n" { [$item[2], @{$item[3]}] } command: /\w+/ arg: /\w+/ | <perl_quotelike> { $item[1][2] }
    the problem is that "perl_quotelike" doesn't match a bareword! So you have to have either barewords or quoted words.
      Unfortunately, that doesn't work.
      The following is the output that I recieved:

      | grammar |Trying rule: [grammar] | | grammar | |"TestDirective | | |"true"\nNoValDirect +ive | | |"test"\n" | grammar |Trying production: [line /\z/] | | grammar |Trying repeated subrule: [line] | | line |Trying rule: [line] | | line |Trying production: [] | | line |>>Matched production: []<< | | line |>>Matched rule<< (return value: | | |[line]) | | line |(consumed: []) | | grammar |>>Matched repeated subrule: [line]<< | | |(1 times) | | grammar |Trying terminal: [/\z/] | | grammar |<<Didn't match terminal>> | | grammar |<<Didn't match rule>> |

      Note: Sorry for the formatting it just doesn't translate well
      Yep, update2 works.

      Thank you so very much, merlyn.
      I greatly appreciate your time and effort.

Re: Parse::RecDescent question
by Abigail-II (Bishop) on Dec 12, 2003 at 15:33 UTC
    <perl_quotelike> must be something from a new version of PRD - I've never seen it. I can guess what it does, but then I'm surprised it doesn't eat NoValDefaultsTo1.

    I do understand why NoValDefaultsTo1 gets eaten as a 'val' if you use something like /.*?$/ or /\w+|"[^"]*"/. It's because you say that a "single" consists of a "key" followed by zero or more "val"s. There's no rule at all that says that NoValDefaultsTo1 can't be one of the vals. PRD will skip whitespace between tokens, and a newline is just the same as a space. PRD isn't saying "Heh, I say a newline. Let me see, the programmer wanted me to return from N levels of rule matching".

    P.S. Could someone explain the difference between <leftop> and <rightop>
    That's explained in the manual. But note that in many cases, it doesn't matter which one you use.

    Abigail