Parse EBNF: Difference between revisions
→{{header|Perl 6}}: Updated to work with latest version of Rakudo. Minor syntax fixes
Thundergnat (talk | contribs) (→{{header|Perl 6}}: Updated to work with current specs (repetion operator changed). Also displays syntax tree now) |
Thundergnat (talk | contribs) (→{{header|Perl 6}}: Updated to work with latest version of Rakudo. Minor syntax fixes) |
||
Line 440:
=={{header|Perl 6}}==
{{works with|Rakudo|
This parses the EBNF rule set using a perl 6 grammar, then if it parses as valid EBNF, constructs a grammar and parses the test strings with that. EBNF rule sets that are naively syntactically correct but missing rules will parse as valid but will give a runtime failure warning about missing methods.
It is implemented and exercised using the flavor of EBNF and test cases specified on the [[Parse EBNF/Tests|test page]].
<lang perl6># A perl 6 grammar to parse EBNF
Line 454 ⟶ 455:
rule repeat { '{' <expression> '}' }
rule optional { '[' <expression> ']' }
token identifier { <-[\|\(\)\{\}\[\]\.\;\"\'\s]>+ }
token literal { ["'" <-[']>+ "'" | '"' <-["]>+ '"'] } #
token title { <literal> }
token comment { <literal> }
Line 463 ⟶ 464:
class EBNF::Actions {
method TOP($/) {
($<title> ?? $<title>.subst(/\W/, '', :g)
" \{\n rule TOP \{^[<" ~ $/<production>[0]<name> ~
">]+\$\}\n " ~ $<production>>>.ast ~ "\}"
}
method production($/) {
}
method expression($/) { make join '|', $<term>>>.ast }
method term($/) { make join '\h*', $<factor>>>.ast }
method factor($/) {
}
method repeat($/) { make $<expression>.ast }
Line 550 ⟶ 551:
my $i = 1;
for @tests -> $test {
say '*' x 79;▼
unless EBNF.parse($test<ebnf>) {
say "Parsing EBNF grammar:\n";
Line 559 ⟶ 558:
next;
}
my $p = EBNF.parse($test<ebnf>, :actions(EBNF::Actions));
my $grammar = $p.ast;
Line 566 ⟶ 564:
my $fn = 'EBNFtest'~$i++;
my $fh = open($fn, :w) or die "$!\n";
$fh.say( "\{\n", $grammar );
$fh.say( qq|say "Parsing EBNF grammar '$title':\\n";| );
$fh.say( qq|say q<{$test<ebnf>.subst(/^^\h*/,'',:g)}>;| );
$fh.say( q|say "\nValid syntax.\n\nTesting:\n";| );
$fh.say( q|CATCH {
my $len = [max] $test<teststrings>.flat>>.chars;
for $test<teststrings>.flat -> $s {
$fh.say( qq|printf "%{$len}s", '{$s}';
qq|printf " - %s\\n",
qq| ?? 'valid.' !! 'NOT valid.';|
);
}
$fh.close;
say qqx/perl6 $fn/;
say '*' x 79, "\n";
unlink $fn;
}</lang>
Output:
<pre>
Syntax Tree:
a = "a1" ( "a2" | "a3" ) { "a4" } [ "a5" ] "a6" ;
} "z"
title =>
literal =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
literal =>
factor =>
group =>
expression =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
factor =>
repeat =>
expression =>
term =>
factor =>
literal =>
factor =>
optional =>
expression =>
term =>
factor =>
literal =>
factor =>
literal =>
comment =>
literal =>
Parsing EBNF grammar 'a':
Line 648 ⟶ 645:
*******************************************************************************
Syntax Tree:
expr = term { plus term } .
term = factor { times factor } .
Line 660 ⟶ 657:
number = digit { digit } .
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
}
production =>
name =>
identifier =>
expression =>
term =>
factor =>
identifier =>
factor =>
repeat =>
expression =>
term =>
factor =>
identifier =>
factor =>
identifier =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
identifier =>
factor =>
repeat =>
expression =>
term =>
factor =>
identifier =>
factor =>
identifier =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
identifier =>
term =>
factor =>
literal =>
factor =>
identifier =>
factor =>
literal =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
identifier =>
factor =>
repeat =>
expression =>
term =>
factor =>
identifier =>
production =>
name =>
identifier =>
expression =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
term =>
factor =>
literal =>
Parsing EBNF grammar 'unnamed':
Line 808 ⟶ 805:
*******************************************************************************
Parsing EBNF grammar:
Line 815 ⟶ 812:
Invalid syntax. Can not be parsed.
*******************************************************************************
Parsing EBNF grammar:
Line 823 ⟶ 819:
Invalid syntax. Can not be parsed.
*******************************************************************************
Parsing EBNF grammar:
Line 831 ⟶ 826:
Invalid syntax. Can not be parsed.
*******************************************************************************
Syntax Tree:
production =>
name =>
identifier =>
expression =>
term =>
factor =>
identifier =>
Parsing EBNF grammar 'unnamed':
Line 853 ⟶ 847:
foobar - No such method 'bar' for invocant of type 'unnamed'
*******************************************************************************</pre>
=={{header|PicoLisp}}==
|