Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Parse::RecDescent and AUTOSTUB

by hagus (Monk)
on Jan 29, 2004 at 08:57 UTC ( [id://324900]=perlquestion: print w/replies, xml ) Need Help??

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

I've been playing with a little grammar here to parse SQL "CREATE TABLE" syntax:
my $grammar = q{ startrule: create_table_syntax create_table_syntax: 'CREATE TABLE' '(' column_definition(s /,/) + ')' column_definition: column_name data_type column_attributes(?) column_name: /\w+/ data_type: "INT" | "VARCHAR" column_attributes: key_or_not_null key_or_not_null: primary(?) 'KEY' }
At the moment I'm experimenting with AUTOSTUB to get the key_or_not_null bit working. In BNF it looks like:
<key_or_not_null_spec> ::=   [PRIMARY] KEY | NOT NULL [WITH DEFAULT]
As I understand it, the square braces around PRIMARY indicate that it can be matched "zero or one" times. So I tried "primary"(?) in PRD grammar and that bombed. Now I'm trying primary(?) with AUTOSTUB turned on and that's bombing too. I really don't want to have to make a subrule that just says:
primary: 'primary'
But I don't really like the idea of using AUTOSTUB either - it seems kludgy. Ideally I want to be able to say "match this literal string zero or one times". Should I use a regex? Or is there some PRD grammar wisdom that I'm missing?

--
Ash OS durbatulk, ash OS gimbatul,
Ash OS thrakatulk, agh burzum-ishi krimpatul!
Uzg-Microsoft-ishi amal fauthut burguuli.

Replies are listed 'Best First'.
Re: Parse::RecDescent and AUTOSTUB
by Abigail-II (Bishop) on Jan 29, 2004 at 09:24 UTC
    You should be able to do
    key_or_not_null: "primary"(?) "KEY"
    Or you can write it with a regexp:
    key_or_not_null: /(?:primary)?/ "KEY"
    Or even:
    key_or_not_null: "PRIMARY KEY" | "KEY"

    Abigail

      Me hearties, it be a fine piece o' code. But ye canna write:
      my $grammar = q { startrule: test test: "primary"(?) "key" };
      Cause ye gets an error! Arr!
      ERROR (line 4): Untranslatable item encountered: "?" (Hint: Did you misspell "?" or forget to comment it ou +t?)
      RD_TRACE told me:
      Parse::RecDescent: Treating "startrule:" as a rule declaration Parse::RecDescent: Treating "test" as a subrule match Parse::RecDescent: Treating "test:" as a rule declaration Parse::RecDescent: Treating ""primary"" as an interpolated literal terminal Parse::RecDescent: Treating "( ? )" as an implicit subrule Parse::RecDescent: Treating "_alternation_1_of_production_1_of_rul +e_test :" as a rule declaration ERROR (line 4): Untranslatable item encountered: "?" (Hint: Did you misspell "?" or forget to comment it ou +t?) Parse::RecDescent: Treating "_alternation_1_of_production_1_of_rul +e_test" as a subrule match Parse::RecDescent: Treating ""key"" as an interpolated literal ter +minal
      Arr.

      --
      Ash OS durbatulk, ash OS gimbatul,
      Ash OS thrakatulk, agh burzum-ishi krimpatul!
      Uzg-Microsoft-ishi amal fauthut burguuli.
        Sure, but you can write:
        test: ("primary")(?) "key"

        Abigail

Re: Parse::RecDescent and AUTOSTUB
by allolex (Curate) on Jan 29, 2004 at 15:25 UTC

    Abigail-II has it right (of course). The point is that PRD recognizes unquoted strings in subrules as productions. If you set $RD_HINT = 1 at the beginning of the script, PRD should tell you that a production has no matching rule, or something of the sort. Alternatively, you could look at the output from code run with the RD_TRACE flag set.

    --
    Allolex

Re: Parse::RecDescent and AUTOSTUB
by Stevie-O (Friar) on Jan 29, 2004 at 23:09 UTC
    You need to code it like this:
    key_or_not_null: ('primary')(?) 'key' | 'not' 'null' # if you put 'not null' then it won't gr +ok things with two spaces

    Also, there are other things to keep in mind:

    1. By default (i.e. if you're not using autoaction) each item evaluates to the last object on its line. That means your 'key_or_not_null' will return 'KEY'.
    2. Doing that ('primary')(?) thing still makes a new rule, it's jut that P::RD makes the rule for you (naming it 'anonymous_subrule_1_of_production_1_of_key_or_not_null' or something similar). This is because P::RD can't backtrack within a rule (so it can't backtrack if it doesn't match the word 'primary').

    You probably want to use something like this:

    key_or_not_null: m/primary|/i 'KEY'
    • Using a regex with /i gives it proper case-insensitivity (as SQL is case-insensitive for its keywords)
    • That won't fork off into a second subrule. Instead, $item[1] will be either 'primary' or '' to indicate the absence of the word 'primary'.
    --Stevie-O
    $"=$,,$_=q>|\p4<6 8p<M/_|<('=> .q>.<4-KI<l|2$<6%s!<qn#F<>;$, .=pack'N*',"@{[unpack'C*',$_] }"for split/</;$_=$,,y[A-Z a-z] {}cd;print lc

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://324900]
Approved by Corion
Front-paged by Courage
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-19 22:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found