Link to home
Start Free TrialLog in
Avatar of anne2011
anne2011

asked on

Please help a RecDescent grammer if statement problem!

If my code is correct, I should be able to see %tree be dumped.
But it is not working and I have no idea where is wrong.

I am not sure if the 'expression' and 'if_statement' is in correct grammar.
Please help!

============== input file (only 1 line as below) ===============
if ( x == "on" ) endif






#!/usr/local/bin/perl
#
if ($#ARGV < 0) {
 print "Usage: $0 file\n";
 exit 0;
}

use lib ".../Parse-RecDescent-1.965001/lib";
use Data::Dumper;
use strict;
use warnings;

use Parse::RecDescent;

my $file=$ARGV[0];

# $::RD_HINT=0;
if(defined $ARGV[1]) {
 $::RD_TRACE=$ARGV[1];
}

my $g=<<'EndG';
<autoaction: {[@item]}>

template_file : statement(s?) EOF
                                { print "MATCH!\n"; 
                                  %::tree = %item;
                                }
expr :  '!' expr
         | '(' expr ')'

expression :  expr unary_operator expression
              | expr

statement :  if_statement                                   
 	     | EOL

set_statement : 'set' scalar_variable '=' expression ';' EOL

if_statement : 'if' <commit> '(' expression ')' <commit> statement(s) else_statement(s)

# else_statement : 'elsif' '(' expression ')' statement(s) else_statement
# 		| 'else' statement(s) 'endif'
# 		| 'endif'

else_statement : 'endif' 

unary_operator: '==' |  '!='  | '<=' | '=' | '<' | '>'

scalar_variable : IDENTIFIER

command_argument_list : command_argument ',' command_argument_list 
		| command_argument

command_argument : INTEGER 
		| QUOTED_STRING | IDENTIFIER 


INTEGER : /[-]?[0-9]+/                  
IDENTIFIER : /[a-zA-Z_][a-zA-Z0-9_]*/
QUOTED_STRING : /["][^"\n]+["]/

EOL : '\n'
EOF : /\s*\Z/             
empty : ""

EndG

my %tree = (); 

my $parse = new Parse::RecDescent $g  or  die "invalid grammar";

undef $/;
open(FILE, "<$file") || die $!;
my $lines=<FILE>;
close FILE;

$parse->template_file($lines);
print Data::Dumper->Dump([\%::tree], ["*tree"]);

Open in new window

SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of anne2011
anne2011

ASKER

Dear Savant,

Thanks a lot.  I have corrected x and "on" problem.

For the EOL problem, please help to see below grammar.
I think something wrong with the 'EOL'

file content:
--------------------
set a = c;
set b = a;
---------------------

The error message is :
Invalid stat: Was expecting EOL but found "set b = a;" instead


my $g=<<'EndG';

<autoaction: {[@item]}>
#<autoaction: { bless \%item, $item{__RULE__} }>

template_file : stat(s) EOF 

stat : 'set' scalar_variable '=' scalar_variable ';' EOL
        | EOL
        |<error>

scalar_variable : IDENTIFIER

IDENTIFIER : /[a-zA-Z_][a-zA-Z0-9_]*/

EOL : /\n/
EOF : /^\Z/

EndG

Open in new window

Dear,

I think something I did not figure out with $/ and \n

If I use :
  #undef $/;  
  my $lines=join("___EOL___", <FILE>);
with:
  EOL : /___EOL___/
It will work.

But if I use :
 my $lines=join("", <FILE>);
with:
  EOL : /\n/
It is not working. Why? I think  '\n' is still there inside $lines.

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Dear,

   I got it! Thank you!

Now I think I am stuck at the QUOTED_STRING rule

my $g=<<'EndG';

template_file : <skip: qr/[ \t]*/> statement(s?) EOF  

statement :    QUOTED_STRING ';' EOL
               | EOL

QUOTED_STRING : /["][^"\n]+["]/

EOL : /\n/
EOF : /^\Z/

EndG
   
But it could not match if a \"  is there :
"\"" ;


/"(\\.|[^"\n])*"/

Dear,

Thanks! The QUOTE_STRING now is working!!!

Back to the if_statement, now simple expression could be matched, but not all expressions.

Since the original BNF will have left-recursive problem, I do not know how to rewrite it without left-recursive.
With my trial, if_statement will work only when there are no parentheses inside:

Working:
if ( getstr(A)  )
endif

if (C == 1 & A==3)
endif

Not working:
if ( getstr(A) == "hello" )
endif

if ((C == 1) & A==3)  
endif


my $g=<<'EndG';

<autoaction: { bless \%item, $item{__RULE__} }>

template_file : <skip: qr/[ \t]*/> statement(s?) EOF   
statement :    if_statement 
	      | EOL
               | <error>

#I tried to solve left recursive error...

expr :  command_argument
expression : expr '+' expression
		| expr '-' expression
		| expr '*' expression
		| expr '/' expression
		| expr '%' expression
		| expr '&' expression
		| expr '|' expression
		| expr '^' expression
		| '!' expression
		| expr '==' expression
		| expr '!=' expression
		| expr '<=' expression
		| expr '>=' expression
		| expr '<' expression
		| expr '>' expression
 		| function_name '(' command_argument_list ')'
 		| '(' expression ')' 
		| expr

function_name : 'getstr'

command_argument_list : command_argument ',' command_argument_list 
                | command_argument

if_statement : 'if' <commit> '(' expression ')' <commit> statement(s?) else_statement
else_statement : 'elsif' '(' expression ')' statement(s?) else_statement
		| 'else' statement(s?) 'endif'
 		| 'endif'

command_argument : INTEGER | QUOTED_STRING | IDENTIFIER 

IDENTIFIER : /[a-zA-Z_][a-zA-Z0-9_]*/
INTEGER : /[-]?[0-9]+/                  
QUOTED_STRING : /"(\\"|[^"\n]*)"/

EOL : /\n/
EOF : /^\Z/

EndG

Open in new window

expr :  command_argument
        | '(' expression ')'
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Dear my idol,

  one_variable : scalar_variable  | declare_array_variable

  scalar is ok. But b and c with array_dimension could not be matched.
  Is something still incorrect with the expression?
 
a
b[2]
c[1][2]


my $g=<<'EndG';

<autoaction: { bless \%item, $item{__RULE__} }>

template_file : <skip: qr/[ \t]*/> statement(s?) EOF   
        | <error>

statement : one_variable EOL
        | EOL

expression :  expr '+' expression
	| expr '-' expression
	| expr '*' expression
	| expr '/' expression
	| expr '%' expression
	| expr '&' expression
	| expr '|' expression
	| expr '^' expression
	| '!' expression
	| expr '==' expression
	| expr '!=' expression
	| expr '<=' expression
	| expr '>=' expression
	| expr '<' expression
	| expr '>' expression
        | function_name '(' command_argument_list ')' 
	| '(' expression ')'
        | command_argument
        | expr
        | <error>

expr :  function_name '(' command_argument_list ')' 
        | '(' expression ')'
        | command_argument


function_name : 'getArrayNoOfDimensions' 
		| 'getArraySize'
		| 'getI'

command_argument : INTEGER 
		| FLOATING_POINT
		| QUOTED_STRING | IDENTIFIER | set_array_variable 

command_argument_list : command_argument ',' command_argument_list 
                | command_argument

one_variable : scalar_variable 
		| declare_array_variable

scalar_variable : IDENTIFIER

declare_array_variable : IDENTIFIER declare_array_dimension(s)

declare_array_dimension : '[' expression ']'
		| '[' ']'

set_array_variable : IDENTIFIER set_array_dimension(s)

set_array_dimension : '[' expression ']'

IDENTIFIER : /[a-zA-Z_][a-zA-Z0-9_]*/

INTEGER : /[-]?[0-9]+/                  
FLOAT_SIMPLE : /[\+]?[0-9]*.[0-9]+/
FLOAT_SCIENTIFIC : /[\+]?[0-9]+(.[0-9]+)?[eE][\+]?[0-9]+/
FLOATING_POINT : FLOAT_SIMPLE|FLOAT_SCIENTIFIC

QUOTED_STRING : '"' quoted_char(s?) '"'

quoted_char:  /[^(?:\\(?="))]+/
              | /\\n/ { "\n" }
              | /\\"/ { "\"" }
EOL : /\n/
EOF : /^\Z/

EndG

Open in new window

Dear,
Thank you for solving my question.