Skip to content

Instantly share code, notes, and snippets.

@arodland
Created January 8, 2013 17:28
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save arodland/4485844 to your computer and use it in GitHub Desktop.
package Math::Parser;
use strict;
use warnings;
use Method::Signatures::Simple;
use Marpa::R2 2.026;
use MarpaX::Lex::Easy;
my $grammar = Marpa::R2::Grammar->new({
actions => 'Math::Parser::Actions',
start => 'Expression',
rules => q{
Expression ::= NUMBER action => number
| (LPAREN) Expression (RPAREN) action => parens assoc => group
|| Expression (ASTERISK) Expression action => multiply
| Expression (SLASH) Expression action => divide
|| Expression (PLUS) Expression action => add
| Expression (MINUS) Expression action => subtract
},
});
$grammar->precompute;
print $grammar->show_rules;
my %tokens = (
'LPAREN' => [ qr/\G[(]/ ],
'RPAREN' => [ qr/\G[)]/ ],
'ASTERISK' => [ qr/\G[*]/ ],
'SLASH' => [ qr/\G[\/]/ ],
'PLUS' => [ qr/\G[+]/ ],
'MINUS' => [ qr/\G[-]/ ],
'NUMBER' => [ qr/\G([-+]?[0-9.]+(?:e[+-]?[0-9]+)?)/, sub { 0 + $1 } ],
);
method parse_line ($line) {
my $rec = Marpa::R2::Recognizer->new({
grammar => $grammar,
ranking_method => 'rule',
trace_terminals => 1,
trace_actions => 1,
trace_values => 1,
});
my $lex = MarpaX::Lex::Easy->new(
tokens => \%tokens,
recognizer => $rec,
automatic_whitespace => 1,
whitespace_pattern => qr/\G\s+/,
);
return $lex->read_and_parse($line);
}
package Math::Parser::Actions;
sub parens {
return $_[1];
}
sub multiply {
return $_[1] * $_[2];
}
sub divide {
return $_[1] / $_[2];
}
sub add {
return $_[1] + $_[2];
}
sub subtract {
return $_[1] - $_[2];
}
sub number {
return $_[1];
}
package main;
while (<>) {
chomp;
print Math::Parser->parse_line($_), "\n";
}
package Math::Parser;
use strict;
use warnings;
use Method::Signatures::Simple;
use Marpa::R2 2.026;
my $grammar = Marpa::R2::Scanless::G->new({
action_object => 'Math::Parser::Actions',
source => \q{
:start ::= Expression
Expression ::= NUMBER action => number
| ('(') Expression (')') action => parens assoc => group
|| Expression ('*') Expression action => multiply
| Expression ('/') Expression action => divide
|| Expression ('+') Expression action => add
| Expression ('-') Expression action => subtract
NUMBER ~ SIGN FLOATING EXPONENT
SIGN ~ [-+]
SIGN ~
FLOATING ~ [0-9.]+
EXPONENT ~ 'e' SIGN DIGITS
EXPONENT ~
DIGITS ~ [0-9]+
:discard ~ WS
WS ~ [\s]+
},
});
print $grammar->show_rules;
method parse_line ($line) {
my $rec = Marpa::R2::Scanless::R->new({
grammar => $grammar,
trace_terminals => 1,
trace_values => 1,
});
$rec->read(\$line);
my $value = $rec->value;
if (defined $value) {
return $$value;
} else {
die "Parse error";
}
}
package Math::Parser::Actions;
# I really just wanted actions, not action_object ;)
sub new {
return bless {};
}
sub parens {
return $_[1];
}
sub multiply {
return $_[1] * $_[2];
}
sub divide {
return $_[1] / $_[2];
}
sub add {
return $_[1] + $_[2];
}
sub subtract {
return $_[1] - $_[2];
}
sub number {
return $_[1];
}
package main;
while (<>) {
chomp;
print Math::Parser->parse_line($_), "\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment