• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 357
  • Last Modified:

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

0
anne2011
Asked:
anne2011
  • 6
  • 5
3 Solutions
 
ozoCommented:
I don't see how x or "on" can be part of an expression

It also looks like an if_statement must contain EOL

0
 
anne2011Author Commented:
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

0
 
anne2011Author Commented:
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.

0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

 
ozoCommented:
the default
$Parse::RecDescent::skip
would skip \n
0
 
anne2011Author Commented:
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 :
"\"" ;


0
 
ozoCommented:
/"(\\.|[^"\n])*"/
0
 
anne2011Author Commented:

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

0
 
ozoCommented:
expr :  command_argument
        | '(' expression ')'
0
 
ozoCommented:
expr :  command_argument
        | '(' expression ')'
        | function_name '(' command_argument_list ')'
0
 
anne2011Author Commented:
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

0
 
anne2011Author Commented:
Dear,
Thank you for solving my question.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now