Karl Gaissmaier wrote:

....some suggestions for additional features of Parse::RecDescent, specifically
the ability to specify "required alternatives" within a repeated subrule:

   > statement: A! | B! | C | D

and "mutually exclusive alternations":

   > rule     : A ^ B ^ C


The problem with these proposed features is that they are not *localized*.

That is, the presence of an A! doesn't affect the rule that the A! is in,
it affects the rule that calls the rule that the A! is in. And that is difficult
to implement in a recursive descent parser.


> But I think that P::RD is by far no way just a CFG ParserGenerator, it's a beast. 

<grin> I should quote you in the documentation. ;-)


> I stumbled so many times over these two missing features (mandatory and xor)
> and my "feeling" tells me, there must be a gentler(general) solution
> than just doing this in action codes.

Clearly this has been a problem for you. But I would have solved it like so:

        $grammar = << 'EOGRAMMAR';
        contact   : statement(s)
                                                { $return = { map %$_ @{$item[-1]} } }
                    <reject: do{!($return->{email} && $return->{name})) >
        statement : email | name |  phone | fax
        email     : 'email' '=' value  {{email=>$item[-1]}}
        name      : 'name' '=' value   {{name=>$item[-1]}}
        phone     : 'phone' '=' value  {{phone=>$item[-1]}}
        fax       : 'fax' '=' value    {{fax=>$item[-1]}}
         value     : /".*?"/
        EOGRAMMAR

Since you needed to collect the data anyway, the actions would have had to be
there no matter what. So the overhead for the requirements testing is just the single
<reject> directive.

Likewise, if (for example) phone and fax were mutually exclusive, you could
just extend that to:

        $grammar = << 'EOGRAMMAR';
        contact   : statement(s)
                                                { $return = { map %$_ @{$item[-1]} } }
                    <reject: do{!($return->{email} && $return->{name})} >
                    <reject: do{  $return->{phone} && $return->{fax}  } >
        statement : email | name |  phone | fax
        email     : 'email' '=' value  {{email=>$item[-1]}}
        name      : 'name' '=' value   {{name=>$item[-1]}}
        phone     : 'phone' '=' value  {{phone=>$item[-1]}}
        fax       : 'fax' '=' value    {{fax=>$item[-1]}}
         value     : /".*?"/
        EOGRAMMAR


> Perhaps Damian can bring some light in the darkness.

Perhaps. But I doubt it. ;-)

However, since you've taken the trouble to mention (and obviously think about) 
this problem, I will certainly devote some time to it myself and see if I can 
develop a better solution; one that's consistent with a recursive descent 
implementation.

Damian

Reply via email to