%token NUM VAR
%right '='
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
%{
use base q{Math::Tail};
my %s; # symbol table
our $VERSION = '1.1';
%}
%lexer {
my $beginline = $self->tokenline();
m{\G[ \t]*(\#.*)?}gc;
m{\G([0-9]+(?:\.[0-9]+)?)}gc and return ('NUM', [$1, $beginline]);
m{\G([A-Za-z][A-Za-z0-9_]*)}gc and return ('VAR', [$1, $beginline]);
m{\G\n}gc and do {
$self->tokenline(1);
return ("\n", ["\n", $beginline])
};
m{\G(.)}gc and return ($1, [$1, $beginline]);
return('',undef);
}
%%
start:
input { \%s }
;
input: line *
;
line:
'\n' { undef }
| exp '\n' { print "$_[1]\n" if defined($_[1]); $_[1] }
| exp '' { print "$_[1]\n" if defined($_[1]); $_[1] }
| error '\n'
{
$_[0]->YYErrok; # error recovery
undef
}
;
exp:
$NUM { $NUM->[0] }
| $VAR
{
my $id = $VAR->[0];
my $val = $s{$id};
$_[0]->semantic_error("Accesing undefined variable $id at line $VAR->[1].\n")
unless defined($val);
return $val;
}
| $VAR '=' $exp { $s{$VAR->[0]} = $exp }
| exp.x '+' exp.y { $x + $y }
| exp.x '-' exp.y { $x - $y }
| exp.x '*' exp.y { $x * $y }
| exp.x '/'.barr exp.y
{
return($x/$y) if $y;
$_[0]->semantic_error("Illegal division by zero at line $barr->[1].\n");
undef
}
| '-' $exp %prec NEG { -$exp }
| exp.x '^' exp.y { $x ** $y }
| '(' $exp ')' { $exp }
;
%%