As an example of parsing being tricky, note that your modification fails to handle precedence differences
( || less than && less than == less than < ). This may or may not be important for your particular task.
Since it may be, and I don't care for Parse::RecDescent when many levels of precedence are involved, here's
a Parse::Yapp version (with all the precedence stuff neatly packaged at the top).
# fortran2c.yp - yapp version of converting FORTRAN to C
%left '.and.' '.or.'
%right '.not.'
%nonassoc '.eq.' '.ne.' '.eqv.' '.neqv.'
%nonassoc '.ge.' '.le.' '.gt.' '.lt.'
%left '+' '-'
%left '*' '/'
%%
exp : exp '+' exp { "(($_[1]) + ($_[3]))" }
| exp '-' exp { "(($_[1]) - ($_[3]))" }
| exp '*' exp { "(($_[1]) * ($_[3]))" }
| exp '/' exp { "(($_[1]) / ($_[3]))" }
| exp '.and.' exp { "(($_[1]) && ($_[3]))" }
| exp '.or.' exp { "(($_[1]) || ($_[3]))" }
| exp '.eq.' exp { "(($_[1]) == ($_[3]))" }
| exp '.ne.' exp { "(($_[1]) != ($_[3]))" }
| exp '.eqv.' exp { "(($_[1]) == ($_[3]))" }
| exp '.neqv.' exp { "(($_[1]) != ($_[3]))" }
| exp '.lt.' exp { "(($_[1]) < ($_[3]))" }
| exp '.gt.' exp { "(($_[1]) > ($_[3]))" }
| exp '.le.' exp { "(($_[1]) <= ($_[3]))" }
| exp '.ge.' exp { "(($_[1]) >= ($_[3]))" }
| '.not.' exp { "(!($_[2]))" }
| '(' exp ')' { $_[2] }
| 'NUM' { $_[1] }
| 'NAME' '(' arglist ')' { $_[1] . $_[3] }
;
arglist
: exp { "[($_[1])-1]" }
| arglist ',' exp { "[($_[3])-1]$_[1]" }
;
%%
use warnings;
use strict;
sub lex
{
/\G\s+/gc, return
/\G((\d+(\.\d*)?|\.\d+)([Ee][-+]?\d+)?)/gc ? (NUM => $1) :
/\G(\.(?:and|or|eqv?|ne|neqv|lt|gt|le|ge|not)\.)/gc ? $1 :
/\G(\w+)/gc ? (NAME => $1) :
/\G(\w+|.)/gc ? $1 : ''
for $_[0]->YYData->{in};
}
sub error
{
for ($_[0]->YYData->{in})
{
substr $_, pos(), 0, '<-- HERE ';
die "parse ERROR: $_\n";
}
}
my $code = '.not.foo(1,bar(2)+1,3).and.baz(4,5)';
@ARGV and $code = "@ARGV";
my $parser = new fortran2c;
$parser->YYData->{in} = $code;
my $answer = $parser->YYParse(yylex => \&lex, yyerror => \&error)
or die "syntax error\n";
print "$answer\n";
__END__
# Makefile
all: fortran2c.pl
%.pl: %.yp
yapp -v -s -b '/usr/bin/perl' -o $@ $<
chmod +x $@
|