Parsing binary AND/OR expressions, with brackets

[email protected] ((Alexander Farber)) Mon, 17 May 2004 23:46:25 +0000
Newsgroups perl.recdescent
Message-ID <[email protected]>
Hi,

could someone please help me few steps further?
I'm almost finished with the parser I need. 

The only missing part is grokking C-preprocessor-like
#if defined / #endif expressions, which can be surrounded
by brackets and contain && and || as binary operators.

Unfortunately my script fails already with 
some syntax error, which I couldn't fix yet:

Parse::RecDescent: Treating "conjunction:" as a rule declaration

	  Warning: Undefined (sub)rule "keyword" used in a production.
	    (Hint: Will you be providing this rule later, or did you
		   perhaps misspell "keyword"? Otherwise it will be
		   treated as an immediate <reject>.)

	  Warning: Undefined (sub)rule "value" used in a production.
	    (Hint: Will you be providing this rule later, or did you
		   perhaps misspell "value"? Otherwise it will be treated
		   as an immediate <reject>.)

Also, please any suggestions on how to handle the
nested brackets properly? I keep looking at the
demo_operator.pl and other P::RD examples but couldn't
figure it out yet...

What I also don't know yet, is in which datastructure
to save the binary operators and conditions that I'm
trying to parse. I'm trying to convert the format below 
to the GNU make's ifdef/ifndef

Regards
Alex


#!/usr/bin/perl -w

use strict;
use vars qw($parser $text %top);
use Data::Dumper;
use Parse::RecDescent;
$RD_WARN  = 1;
$RD_HINT  = 1;
$RD_TRACE = 120;
$parser = Parse::RecDescent->new(q(

mmpfile: chunk(s) /^\Z/
chunk: assignment | <error>

assignment: keyword <skip: '[ \t]+'> value(s) {
	push @{$::top{uc $item{keyword}}}, @{$item[-1]};
}

ifdef: /#\s*if/ <skip: '[ \t]+'> condition
		<skip: $item[2]> chunk(s?)
	/#\s*endif/

condition: '(' conjunction ')' | conjunction
conjunction: disjunction(s /&&/i)
disjunction: unary_expr(s /\|\|/i)
unary_expr: '!' defined_expr | defined_expr  
defined_expr: 'defined' '(' value ')' | 'defined' value

value:	/VAL\d+\b/i
keyword: /KEY\d+\b/i

)) or die 'Bad grammar';
$text .= $_ while (<DATA>);
defined $parser->mmpfile($text) or die 'Bad text';
print Data::Dumper->Dump([\%top], [qw(top)]);

__DATA__
#if defined val1
key1		val2
#endif

#if ! ( (defined ( val3 ) ) || ( defined (val4) ) )
key2		val5
#endif