# examples/Calc.eyp
%right '='
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
%{
my %s; # symbol table
%}
%%
start:
input { \%s }
;
input: line *
;
line:
'\n' { undef }
| exp '\n' { $_[1] }
| exp '' { $_[1] } # exp followed by end of input
| error '\n'
{
$_[0]->YYErrok;
undef
}
;
exp:
NUM
| $VAR { $s{$VAR} }
| $VAR '=' $exp { $s{$VAR} = $exp }
| exp.left '+' exp.right { $left + $right }
| exp.left '-' exp.right { $left - $right }
| exp.left '*' exp.right { $left * $right }
| exp.left '/' exp.right
{
$_[3] and return($_[1] / $_[3]);
$_[0]->YYData->{ERRMSG} = "Illegal division by zero.\n";
$_[0]->YYError; # Pretend that a syntactic error ocurred: _Error will be called
undef
}
| '-' $exp %prec NEG { -$exp }
| exp.left '^' exp.right { $left ** $right }
| '(' $exp ')' { $exp }
;
%%
my $lineno = 1;
sub _Error {
my $parser = shift;
exists $parser->YYData->{ERRMSG}
and do {
print $parser->YYData->{ERRMSG};
delete $parser->YYData->{ERRMSG};
return;
};
my($token)=$parser->YYCurval;
my($what)= $token ? "input: '$token'" : "end of input";
my @expected = $parser->YYExpect();
local $" = ', ';
die << "ERRMSG";
Syntax error near $what (lin num $lineno).
Expected one of these terminals: @expected
ERRMSG
}
sub make_lexer {
return sub {
my $parser = shift;
for (${$parser->input}) {
m{\G[ \t]*}gc;
m{\G([0-9]+(?:\.[0-9]+)?)}gc and return ('NUM',$1);
m{\G([A-Za-z][A-Za-z0-9_]*)}gc and return ('VAR',$1);
m{\G\n}gc and do { $lineno++; return ("\n", "\n") };
m{\G(.)}gc and return ($1,$1);
return('',undef);
}
}
}
sub Run {
my($self)=shift;
$self->input(shift()) unless defined(${$self->input});
return $self->YYParse( yylex => make_lexer(), yyerror => \&_Error,
#yydebug =>0x1F
);
}