#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Parse::Yapp; my $grammar = join '', ; my $parser = Parse::Yapp->new(input => $grammar); my $yapptxt = $parser->Output(classname => 'Calc'); eval $yapptxt; # normally written to a file my $calc = Calc->new(); $calc->Ingest("11 - (4 + 4)^3 * sqrt(5 * (6 - 1)) + abs(-3)\n"); my $output = $calc->YYParse(yylex => \&Calc::Lexer); print $output; __DATA__ %left '-' '+' %left '*' '/' '%' %right '^' %nonassoc 'sqrt' 'abs' %% stack : | stack expr '\n' { push @{$_[1]}, $_[2]; $_[1][0] }; expr : add | del | mul | div | mod | pow | grp | sqrt | abs | NUM; add : expr '+' expr { $_[1] + $_[3] }; del : expr '-' expr { $_[1] - $_[3] }; mul : expr '*' expr { $_[1] * $_[3] }; div : expr '/' expr { $_[1] / $_[3] }; mod : expr '%' expr { $_[1] % $_[3] }; pow : expr '^' expr { $_[1] ** $_[3] }; grp : '(' expr ')' { $_[2] }; abs : 'abs' grp { abs($_[2]) }; sqrt : 'sqrt' grp { sqrt($_[2]) }; %% sub Lexer { my $parser = shift @_; local *_ = \$parser->YYData->{INPUT}; s/^[ \t]+//; # leading non-newline whitespace if (s/^(([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)//) { return ('NUM', $1); # borrowed from Scalar::Util } return ($1, $1) if s/^(sqrt|abs)//; return ($1, $1) if s/^(.)//s; } sub Ingest { my $self = shift @_; $self->YYData->{INPUT} = $_[0]; }