Skip to content

Instantly share code, notes, and snippets.

@daxim
Created January 16, 2019 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daxim/136891ec2d6a246c1e35d6db7c6fa1af to your computer and use it in GitHub Desktop.
Save daxim/136891ec2d6a246c1e35d6db7c6fa1af to your computer and use it in GitHub Desktop.
package Metagrammar;
use Marpa::R2;
use Regexp::Grammars;
sub parse {
my ($grammar, $input) = @_;
my $meta_grammar = qr{
<grammar>
<rule: grammar> grammar <identifier> <[somerules]>* end
<token: identifier> (?!grammar|rule|token|end) [a-zA-Z_]+
<rule: somerules> <rule> | <token>
<rule: rule> rule <identifier> <rulebody> end
<rule: rulebody> <[id_lit]>+
<rule: id_lit> <identifier> | <literal>
<token: literal> ['] [^']+ [']
<rule: token> token <identifier> <tokenbody> end
<token: tokenbody> [\[] [^\]]+ [\]] [+]?
}x;
$grammar =~ $meta_grammar;
my $dsl = <<'';
:default ::= action => [values] bless => ::lhs
lexeme default = action => [ start, length, value ] latm => 1 bless => ::name
:discard ~ whitespace
whitespace ~ [\s]+
for my $rt ($/{grammar}{somerules}->@*) {
if ($rt->{rule}) {
my $id_lit = join ' ', map { $_->{identifier} // $_->{literal} } $rt->{rule}{rulebody}{id_lit}->@*;
$dsl .= sprintf "%s ::= %s\n", $rt->{rule}{identifier}, $id_lit;
}
if ($rt->{token}) {
$dsl .= sprintf "%s ~ %s\n", $rt->{token}{identifier}, $rt->{token}{tokenbody};
}
}
my $g = Marpa::R2::Scanless::G->new({source => \$dsl, bless_package => $/{grammar}{identifier}});
return $g->parse(\$input);
}
1;
use 5.028;
use lib '.';
use Data::Dumper qw(Dumper);
use Metagrammar;
my $input = 'y = x';
say Dumper Metagrammar::parse(<<'', $input);
grammar Tiny_PPHP
rule TOP
statement
end
rule statement
assignment
end
rule assignment
varname eq varname
end
token eq
[=]
end
token varname
[a-zA-Z0-9-]+
end
end
# \bless( [
# bless( [
# bless( [
# bless( [ 0, 1, 'y' ], 'Tiny_PPHP::varname' ),
# bless( [ 2, 1, '=' ], 'Tiny_PPHP::eq' ),
# bless( [ 4, 1, 'x' ], 'Tiny_PPHP::varname' )
# ], 'Tiny_PPHP::assignment' )
# ], 'Tiny_PPHP::statement' )
# ], 'Tiny_PPHP::TOP' );
use v6;
grammar Tiny-PPHP {
rule TOP { <statement> }
rule statement { <assignment> }
rule assignment { <varname> <eq> <varname> }
token eq { '=' }
token varname { <[a..z A..Z 0..9 -]>+ }
}
Tiny-PPHP.parse('y = x').say;
# 「y = x」
# statement => 「y = x」
# assignment => 「y = x」
# varname => 「y」
# eq => 「=」
# varname => 「x」
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment