Parse EBNF: Difference between revisions

→‎{{header|Perl 6}}: Updated to work with latest version of Rakudo. Minor syntax fixes
(→‎{{header|Perl 6}}: Updated to work with current specs (repetion operator changed). Also displays syntax tree now)
(→‎{{header|Perl 6}}: Updated to work with latest version of Rakudo. Minor syntax fixes)
Line 440:
 
=={{header|Perl 6}}==
{{works with|Rakudo|20122013.0509}}
 
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]>+ } #'" Defeat confused syntax highlighting
token literal { ["'" <-[']>+ "'" | '"' <-["]>+ '"'] } #'" Defeat confused syntax highlighting
token title { <literal> }
token comment { <literal> }
Line 463 ⟶ 464:
class EBNF::Actions {
method TOP($/) {
say "Syntax Tree:\n", $/; # Dump the syntax tree to STDOUT
make 'grammar ' ~
($<title> ?? $<title>.subst(/\W/, '', :g) ||!! 'unnamed') ~
" \{\n rule TOP \{^[<" ~ $/<production>[0]<name> ~
">]+\$\}\n " ~ $<production>>>.ast ~ "\}"
}
method production($/) {
make 'token ' ~ $<name> ~ ' {' ~
$<expression>.ast ~ "}\n"
}
method expression($/) { make join '|', $<term>>>.ast }
method term($/) { make join '\h*', $<factor>>>.ast }
method factor($/) {
make $<literal> ?? $<literal> !!
$<group> ?? '[' ~ $<group>.ast ~ ']' !!
$<repeat> ?? '[' ~ $<repeat>.ast ~ '\\s*]*' !!
$<optional> ?? '[' ~ $<optional>.ast ~ ']?' !!
'<' ~ $<identifier> ~ '>'
}
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 { diedefault { say " - $_" } };| );
my $len = [max] $test<teststrings>.flat>>.chars;
for $test<teststrings>.flat -> $s {
$fh.say( qq|printf "%{$len}s", '{$s}';\n| ~
qq|printf " - %s\\n", try ({$title}.parse('{$s}'))| ~
qq| ?? 'valid.' !! 'NOT valid.';|
);
}
$fh.say( '*'qq| x"\\n"} 79|);
$fh.close;
say qqx/perl6 $fn/;
say '*' x 79, "\n";
unlink $fn;
}
}</lang>
 
Output:
<pre>
*******************************************************************************
Syntax Tree:
q["a" {
a = "a1" ( "a2" | "a3" ) { "a4" } [ "a5" ] "a6" ;
} "z"]
title => q["a"]
literal => q["a"]
production => q[a「a = "a1" ( "a2" | "a3" ) { "a4" } [ "a5" ] "a6" ;
]
name => q[a]「a」
identifier => q[a]「a」
expression => q["a1" ( "a2" | "a3" ) { "a4" } [ "a5" ] "a6" ]
term => q["a1" ( "a2" | "a3" ) { "a4" } [ "a5" ] "a6" ]
factor => q["a1" ]
literal => q["a1"]
factor => q[( "a2" | "a3" ) ]
group => q[( "a2" | "a3" ) ]
expression => q["a2" | "a3" ]
term => q["a2" ]
factor => q["a2" ]
literal => q["a2"]
term => q[ "a3" ]
factor => q["a3" ]
literal => q["a3"]
factor => q[{ "a4" } ]
repeat => q[{ "a4" } ]
expression => q["a4" ]
term => q["a4" ]
factor => q["a4" ]
literal => q["a4"]
factor => q[[ "a5" ] ]
optional => q[[ "a5" ] ]
expression => q["a5" ]
term => q["a5" ]
factor => q["a5" ]
literal => q["a5"]
factor => q["a6" ]
literal => q["a6"]
comment => q["z"]
literal => q["z"]
 
Parsing EBNF grammar 'a':
Line 648 ⟶ 645:
 
*******************************************************************************
 
*******************************************************************************
Syntax Tree:
q[{
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 => q[expr「expr = term { plus term } .
]
name => q[expr]「expr」
identifier => q[expr]「expr」
expression => q[term「term { plus term } ]
term => q[term「term { plus term } ]
factor => q[term「term ]
identifier => q[term]「term」
factor => q[{ plus term } ]
repeat => q[{ plus term } ]
expression => q[plus「plus term ]
term => q[plus「plus term ]
factor => q[plus「plus ]
identifier => q[plus]「plus」
factor => q[term「term ]
identifier => q[term]「term」
production => q[term「term = factor { times factor } .
]
name => q[term]「term」
identifier => q[term]「term」
expression => q[factor「factor { times factor } ]
term => q[factor「factor { times factor } ]
factor => q[factor「factor ]
identifier => q[factor]「factor」
factor => q[{ times factor } ]
repeat => q[{ times factor } ]
expression => q[times「times factor ]
term => q[times「times factor ]
factor => q[times「times ]
identifier => q[times]「times」
factor => q[factor「factor ]
identifier => q[factor]「factor」
production => q[factor「factor = number | '(' expr ')' .
 
]
name => q[factor]「factor」
identifier => q[factor]「factor」
expression => q[number「number | '(' expr ')' ]
term => q[number「number ]
factor => q[number「number ]
identifier => q[number]「number」
term => q[ '(' expr ')' ]
factor => q['(' ]
literal => q['(']
factor => q[expr「expr ]
identifier => q[expr]「expr」
factor => q[')' ]
literal => q[')']
production => q[plus「plus = "+" | "-" .
]
name => q[plus]「plus」
identifier => q[plus]「plus」
expression => q["+" | "-" ]
term => q["+" ]
factor => q["+" ]
literal => q["+"]
term => q[ "-" ]
factor => q["-" ]
literal => q["-"]
production => q[times「times = "*" | "/" .
 
]
name => q[times]「times」
identifier => q[times]「times」
expression => q["*" | "/" ]
term => q["*" ]
factor => q["*" ]
literal => q["*"]
term => q[ "/" ]
factor => q["/" ]
literal => q["/"]
production => q[number「number = digit { digit } .
]
name => q[number]「number」
identifier => q[number]「number」
expression => q[digit「digit { digit } ]
term => q[digit「digit { digit } ]
factor => q[digit「digit ]
identifier => q[digit]「digit」
factor => q[{ digit } ]
repeat => q[{ digit } ]
expression => q[digit「digit ]
term => q[digit「digit ]
factor => q[digit「digit ]
identifier => q[digit]「digit」
production => q[digit「digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
]
name => q[digit]「digit」
identifier => q[digit]「digit」
expression => q["0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ]
term => q["0" ]
factor => q["0" ]
literal => q["0"]
term => q[ "1" ]
factor => q["1" ]
literal => q["1"]
term => q[ "2" ]
factor => q["2" ]
literal => q["2"]
term => q[ "3" ]
factor => q["3" ]
literal => q["3"]
term => q[ "4" ]
factor => q["4" ]
literal => q["4"]
term => q[ "5" ]
factor => q["5" ]
literal => q["5"]
term => q[ "6" ]
factor => q["6" ]
literal => q["6"]
term => q[ "7" ]
factor => q["7" ]
literal => q["7"]
term => q[ "8" ]
factor => q["8" ]
literal => q["8"]
term => q[ "9" ]
factor => q["9" ]
literal => q["9"]
 
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:
q[{ foo = bar . }]
production => q[foo「foo = bar . ]
name => q[foo]「foo」
identifier => q[foo]「foo」
expression => q[bar「bar ]
term => q[bar「bar ]
factor => q[bar「bar ]
identifier => q[bar]「bar」
 
Parsing EBNF grammar 'unnamed':
Line 853 ⟶ 847:
foobar - No such method 'bar' for invocant of type 'unnamed'
 
*******************************************************************************</pre>
</pre>
 
=={{header|PicoLisp}}==
10,333

edits