Skip to content

Instantly share code, notes, and snippets.

@rns
Created October 1, 2014 05:20
Show Gist options
  • Save rns/0371dfcffa6887f4e5a2 to your computer and use it in GitHub Desktop.
Save rns/0371dfcffa6887f4e5a2 to your computer and use it in GitHub Desktop.
Case: 0. In count: 1:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Output: !->! OK count: 1.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 1. In count: 2:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Parse failure at (line, column) = (1, 3).
--------------------------------------------------
Case: 2. In count: 3:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse failure at (line, column) = (1, 3).
--------------------------------------------------
Case: 3. In count: 4:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse failure at (line, column) = (1, 3).
--------------------------------------------------
Case: 4. In count: 5:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Ambiguous parse (after loop, before calling value() ).
Output: !->! OK count: 2.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 5. In count: 6:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Parse failure at (line, column) = (1, 3).
--------------------------------------------------
Case: 6. In count: 7:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse failure at (line, column) = (1, 3).
--------------------------------------------------
Case: 7. In count: 8:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse failure at (line, column) = (1, 3).
--------------------------------------------------
Case: 8. In count: 9:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after loop, before calling value() ).
Output: !->! OK count: 3.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 9. In count: 10:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: No parse (after loop, before calling value() ).
Output: !->! OK count: 4.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 10. In count: 11:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: No parse (after loop, before calling value() ).
Output: !->! OK count: 5.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 11. In count: 12:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: No parse (after loop, before calling value() ).
Output: !->! OK count: 6.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 12. In count: 13:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Ambiguous parse (after loop, before calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after loop, before calling value() ).
Output: !->! OK count: 7.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 13. In count: 14:
Input: !->!
Event Start Span Lexeme
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: No parse (after loop, before calling value() ).
Output: !->! OK count: 8.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 14. In count: 15:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: No parse (after loop, before calling value() ).
Output: !->! OK count: 9.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Case: 15. In count: 16:
Input: !->!
Event Start Span Lexeme
Parse is ambiguous: No parse (inside loop).
directed_edge 0 2 ->
edge_id: !->!
Parse is ambiguous: No parse (after loop, before calling value() ).
Output: !->! OK count: 10.
Ambiguous parse (after calling value() ).
Parse is ambiguous: Ambiguous symch at Glade=5, Symbol=<edge_statement>:
The ambiguity is from line 1, column 1 to line 1, column 2
Text is: ->
There are 2 symches
Symch 0 is a rule: edge_statement ::= edge_name attribute_definition
Symch 1 is a rule: edge_statement ::= edge_name
(after calling value() ).
--------------------------------------------------
Counts: in => 16. success => 10.
Tool completed successfully
#!/usr/bin/env perl
use 5.018;
use strict;
use utf8;
use warnings;
use warnings qw(FATAL utf8); # Fatalize encoding glitches.
use open qw(:std :utf8); # Undeclared streams in UTF-8.
use charnames qw(:full :short); # Unneeded in v5.16.
use Marpa::R2;
use Try::Tiny;
# --------------------------------------------------
sub clean_after
{
my($s) = @_;
$s =~ s/^\s+//;
$s =~ s/\s+$//;
$s =~ s/^([\"\'])(.*)\1$/$2/; # The backslashes are just for the UltraEdit syntax hiliter.
#$s =~ s/^\s+//;
#$s =~ s/\s+$//;
return $s;
} # End of clean_after.
# --------------------------------------------------
sub clean_before
{
my($s) = @_;
$s =~ s/\s*;\s*$//;
$s =~ s/^\s+//;
$s =~ s/\s+$//;
$s =~ s/^(<)\s+/$1/;
$s =~ s/\s+(>)$/$1/;
return $s;
} # End of clean_before.
# ------------------------------------------------
sub decode_result
{
my($result) = @_;
my(@worklist) = $result;
my($obj);
my($ref_type);
my(@stack);
do
{
$obj = shift @worklist;
$ref_type = ref $obj;
if ($ref_type eq 'ARRAY')
{
unshift @worklist, @$obj;
}
elsif ($ref_type eq 'HASH')
{
push @stack, {%$obj};
}
elsif ($ref_type)
{
die "Unsupported object type $ref_type\n";
}
else
{
push @stack, $obj;
}
} while (@worklist);
return join('', @stack);
} # End of decode_result.
# --------------------------------------------------
sub process
{
my($case, $recce, $string) = @_;
$string = clean_before($string);
my($length) = length $string;
my($last_event) = '';
my($format) = "%-20s %5s %5s %-s\n";
# We use read()/lexeme_read()/resume() because we pause at each lexeme.
my($ambiguous_status);
my(@event, $event_name, $edge);
my(@fields);
my($lexeme_name, $lexeme, $literal);
my($span, $start);
print sprintf($format, 'Event', 'Start', 'Span', 'Lexeme');
for
(
my $pos = $recce -> read(\$string);
$pos < $length;
$pos = $recce -> resume($pos)
)
{
if ($case & 1)
{
if ($recce -> ambiguity_metric > 1)
{
print "Ambiguous parse (inside loop). \n";
}
}
if ($case & 2)
{
if ($ambiguous_status = $recce -> ambiguous)
{
print "Parse is ambiguous: $ambiguous_status (inside loop). \n";
}
}
@event = @{$recce -> events};
#print 'Event count: ' . ($#event + 1) . ': ' . join(', ', map{${$_}[0]} @event) . ". \n";
$event_name = ${$event[0]}[0];
($start, $span) = $recce -> pause_span;
$lexeme_name = $recce -> pause_lexeme;
$lexeme = $recce -> literal($start, $span);
print sprintf($format, $lexeme_name, $start, $span, $lexeme);
if ($event_name eq 'attribute_name')
{
$pos = $recce -> lexeme_read($lexeme_name);
$literal = substr($string, $start, $pos - $start);
push @fields, clean_after($literal);
}
elsif ($event_name eq 'attribute_value')
{
$pos = $recce -> lexeme_read($lexeme_name);
$literal = clean_after(substr($string, $start, $pos - $start) );
print "Attribute !$fields[0]! => !$fields[1]! \n";
@fields = ();
}
elsif ($event_name eq 'end_attributes')
{
$pos = $recce -> lexeme_read($lexeme_name);
$literal = substr($string, $start, $pos - $start);
}
elsif ($event_name eq 'start_attributes')
{
$pos = $recce -> lexeme_read($lexeme_name);
$literal = substr($string, $start, $pos - $start);
}
elsif ($event_name eq 'directed_edge')
{
$pos = $recce -> lexeme_read($lexeme_name);
$literal = substr($string, $start, $pos - $start);
print 'edge_id: !', clean_after($literal), "! \n";
}
else
{
die "Unexpected lexeme !$lexeme_name! with a pause. \n";
}
$last_event = $event_name;
}
if ($case & 4)
{
if ($recce -> ambiguity_metric > 1)
{
print "Ambiguous parse (after loop, before calling value() ). \n";
}
}
if ($case & 8)
{
if ($ambiguous_status = $recce -> ambiguous)
{
print "Parse is ambiguous: $ambiguous_status (after loop, before calling value() ). \n";
}
$recce -> series_restart();
}
# Return a defined value for success and undef for failure.
# The length test means we return success for empty input.
return $recce -> value;
} # End of process.
# ------------------------------------------------
my $bnf = <<'END_OF_GRAMMAR';
:default ::= action => [values]
lexeme default = latm => 1 # Longest Acceptable Token Match.
graph_grammar ::= graph_definition
# Graph stuff.
graph_definition ::= edge_statement
# Edge stuff
edge_statement ::= edge_name
| edge_name attribute_definition
edge_name ::= directed_edge
# Attribute stuff.
attribute_definition ::= attribute_statement* # The * causes the ambiguity I assume.
attribute_statement ::= start_attributes string_token_set end_attributes
string_token_set ::= string_token_pair+
string_token_pair ::= attribute_name (':') attribute_value
# Lexemes in alphabetical order.
:lexeme ~ attribute_name pause => before event => attribute_name
attribute_name ~ string_char_set+
:lexeme ~ attribute_value pause => before event => attribute_value
attribute_value ~ string_char_set+
:lexeme ~ directed_edge pause => before event => directed_edge priority => 2
directed_edge ~ '->'
:lexeme ~ end_attributes pause => before event => end_attributes priority => 1
end_attributes ~ '}'
escaped_char ~ '\' [[:print:]]
# Use ' here just for the UltraEdit syntax hiliter.
:lexeme ~ start_attributes pause => before event => start_attributes
start_attributes ~ '{'
string_char_set ~ escaped_char
| [^;:}\]] # Neither a separator [;:] nor a terminator [}\]].
# Lexemes in alphabetical order.
# Boilerplate.
:discard ~ whitespace
whitespace ~ [\s]+
END_OF_GRAMMAR
my($g) = Marpa::R2::Scanless::G->new({source => \$bnf});
my(%count) = (in => 0, success => 0);
my($ambiguous_status);
my($column);
my($input);
my($line);
my($recce);
my($value);
for my $case (0 .. 15)
{
$count{in}++;
$input = '->';
print "Case: $case. In count: $count{in}:\nInput: !$input! \n";
$recce = Marpa::R2::Scanless::R->new
({
grammar => $g,
#trace_terminals => 99,
});
try
{
$value = process($case, $recce, $input);
if (! defined $value)
{
($line, $column) = $recce -> line_column;
print "Parse failure at (line, column) = ($line, $column). \n";
}
else
{
$count{success}++;
print "\tOutput: !", decode_result($$value), "! OK count: $count{success}. \n";
if ($recce -> ambiguity_metric > 1)
{
print "Ambiguous parse (after calling value() ). \n";
}
$recce -> series_restart();
if ($ambiguous_status = $recce -> ambiguous)
{
print "Parse is ambiguous: $ambiguous_status (after calling value() ). \n";
}
}
}
catch
{
($line, $column) = $recce -> line_column;
$value = substr($input, $column - 1);
print "Exception: $_";
print "At (line, column) = ($line, $column). Remaining text: !$value! \n";
};
print '-' x 50, "\n";
}
print 'Counts: ', join('. ', map{"$_ => $count{$_}"} sort keys %count), ". \n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment