#!perl
use
5.010001;
use
POSIX
qw(setlocale LC_ALL)
;
POSIX::setlocale(LC_ALL,
"C"
);
my
$dsl
=
<<'END_OF_DSL';
# The BNF
:default ::= action => ::first
:start ::= sentence
sentence ::= element
array ::= 'A' <array count> '(' elements ')'
action => check_array
string ::= ( 'S' <string length> '(' ) text ( ')' )
elements ::= element+
action => ::array
element ::= string | array
# Declare the places where we pause before
# and after lexemes
:lexeme ~ <string length> pause => after event => 'string length'
event 'expecting text' = predicted <text>
# Declare the lexemes themselves
<array count> ~ [\d]+
<string length> ~ [\d]+
# define <text> as one character of anything, as a stub
# the external scanner determines its actual size and value
text ~ [\d\D]
END_OF_DSL
my
$grammar
= Marpa::R3::Scanless::G->new(
{
semantics_package
=>
'My_Actions'
,
source
=> \
$dsl
}
);
my
$recce
= Marpa::R3::Scanless::R->new( {
grammar
=>
$grammar
} );
my
$input
=
'A2(A2(S3(Hey)S13(Hello, World!))S5(Ciao!))'
;
my
$last_string_length
;
my
$input_length
=
length
$input
;
INPUT:
for
(
my
$pos
=
$recce
->
read
( \
$input
);
$pos
<
$input_length
;
$pos
=
$recce
->resume(
$pos
)
)
{
EVENT:
for
my
$event
( @{
$recce
->events() } ) {
my
(
$name
) = @{
$event
};
if
(
$name
eq
'expecting text'
) {
my
$text_length
=
$last_string_length
;
$recce
->lexeme_read(
'text'
,
$pos
,
$text_length
);
$pos
+=
$text_length
;
next
EVENT;
}
if
(
$name
eq
'string length'
) {
my
(
$start_pos
,
$length
) =
$recce
->pause_span();
$last_string_length
=
$recce
->literal(
$start_pos
,
$length
) + 0;
$pos
=
$start_pos
+
$length
;
next
EVENT;
}
die
"Unexpected event: "
,
join
q{ }
, @{
$event
};
}
}
my
$result
=
$recce
->value();
die
'No parse'
if
not
defined
$result
;
my
$received
= Data::Dumper::Dumper( ${
$result
} );
my
$expected
=
<<'EXPECTED_OUTPUT';
$VAR1 = [
[
'Hey',
'Hello, World!'
],
'Ciao!'
];
EXPECTED_OUTPUT
Test::More::is(
$received
,
$expected
,
'Dyck-Hollerith value'
);
sub
My_Actions::check_array {
my
(
undef
,
$v
) =
@_
;
my
(
undef
,
$declared_size
,
undef
,
$array
) = @{
$v
};
my
$actual_size
= @{
$array
};
warn
"Array size ($actual_size) does not match that specified ($declared_size)"
if
$declared_size
!=
$actual_size
;
return
$array
;
}