# file: GeneratorE.eyp
# compile with: eyapp -C '' GeneratorE.eyp
# then run: ./GeneratorE.pm
%strict
%token NUM VARDEF VAR
%right '='
%left '-' '+'
%left '*' '/'
%right '^'
%defaultaction {
my $parser = shift;
return join '', @_;
}
%{
use base q{Parse::Eyapp::TokenGen};
%}
%%
stmts:
stmt
{
$_[0]->deltaweight(VAR => +2); # At least one variable is defined now
$_[1];
}
| stmts ';' { "\n" } stmt
;
stmt:
$VARDEF '=' $exp
{
my $parser = shift;
my $res = EVALUATE($exp);
return '' if $res =~ /^error/;
$parser->defined_variable($VARDEF, $exp, $res);
"$VARDEF=$exp";
}
;
exp:
NUM
| VAR
| exp '+' exp
| exp '-' exp
| exp '*' exp
| exp '/' exp
| exp '^' exp
| '(' { $_[0]->pushdeltaweight('(' => -1, ')' => +1, '+' => +1, ); }
exp
')'
{
$_[0]->popweight;
"($_[3])"
}
;
%%
my $prefix = "no warnings; no strict;\n";
use Getopt::Long;
use Test::LectroTest::Generator qw(:all);
my %st; # Symbol Table
sub defined_variable {
my ($parser, $var, $exp, $value) = @_;
$st{$var} = { exp => $exp, value => $value};
$prefix .= '$'."$var = $value;\n";
}
sub EVALUATE { # if possible
my $perlexp = shift;
$perlexp =~ s/\b([a-zA-Z])/\$$1/g; # substitute A by $A everywhere
$perlexp =~ s/\^/**/g; # substitute power operator: ^ by **
my $program = "$prefix$perlexp";
#print "***program***\n$program\n****\n";
my $res = eval $program;
if ($@) {
$@ =~ m{(.{1,10})};
$res = "error. $1";
}
$res;
}
use Data::Dumper;
sub main {
my $package = shift;
my $debug = shift || 0;
my $numtimes = shift || 1;
my $result = GetOptions (
"debug!" => \$debug,
"times=i" => \$numtimes,
);
$debug = 0x1F if $debug;
# LexerGen receives the parser object and the pairs
# token => [weight, generator] or token => weight
# and returns a generator subroutine
my $gen = $package->new();
$gen->LexerGen(
NUM => [ 2, Int(range=>[0, 9], sized=>0)],
VAR => [
0, # At the beginning, no variables are defined
Gen {
return Elements(keys %st)->generate if keys %st;
return Int(range=>[0, 9], sized=>0)->generate;
},
],
VARDEF => [
2,
String( length=>[1,2], charset=>"A-NP-Z", size => 100 )
],
'=' => 2, '-' => 1, '+' => 2,
'*' => 4, '/' => 2, '^' => 0.5,
';' => 3, '(' => 1, ')' => 2,
'' => 2, 'error' => 0,
);
for (1..$numtimes) {
my $exp = $gen->generate(
yydebug => $debug, # 0x1F
);
my $res = EVALUATE($exp);
print "\n# result: $res\n$exp\n";
#print "$_ = ".Dumper($st{$_})."\n" for keys(%st);
}
}