—# Marpa::R3 is Copyright (C) 2017, Jeffrey Kegler.
#
# This module is free software; you can redistribute it and/or modify it
# under the same terms as Perl 5.10.1. For more details, see the full text
# of the licenses in the directory LICENSES.
#
# This program is distributed in the hope that it will be
# useful, but it is provided "as is" and without any express
# or implied warranties. For details, see the full text of
# of the licenses in the directory LICENSES.
=head1 NAME
Marpa::R3::Tutorial2 - Marpa Tutorial 2
=head1 Synopsis
=for Marpa::R3::Display
name: Tutorial 2 synopsis
normalize-whitespace: 1
use Marpa::R3;
my $dsl = <<'END_OF_DSL';
Calculator ::= Expression action => ::first
Factor ::= Number action => ::first
Term ::=
Term '*' Factor action => do_multiply
| Factor action => ::first
Expression ::=
Expression '+' Term action => do_add
| Term action => ::first
Number ~ digits
digits ~ [\d]+
:discard ~ whitespace
whitespace ~ [\s]+
END_OF_DSL
my $grammar = Marpa::R3::Grammar->new(
{
semantics_package => 'My_Actions',
source => \$dsl
}
);
my $recce = Marpa::R3::Recognizer->new( { grammar => $grammar } );
my $input = '42 * 1 + 7';
my $length_read = $recce->read( \$input );
die "Read ended after $length_read of ", length $input, " characters"
if $length_read != length $input;
my $value_ref = $recce->value();
die "No parse" if not $value_ref;
my $value = ${$value_ref};
sub My_Actions::do_add {
my ( undef, $values ) = @_;
my ( $t1, undef, $t2 ) = @{$values};
return $t1 + $t2;
}
sub My_Actions::do_multiply {
my ( undef, $values ) = @_;
my ( $t1, undef, $t2 ) = @{$values};
return $t1 * $t2;
}
=for Marpa::R3::Display::End
=head1 Description
=head2 Overview
This document contains a second Marpa::R3 tutorial.
This tutorial demonstrates a lower level of method calls.
These lower level calls
allow access to more of Marpa's
features.
For example, users will need to
use these lower level calls
=over 4
=item *
to use parse events;
=item *
and to get finer control of the response to Marpa errors.
=back
This uses the same extremely simple calculator
as the tutorial in the L<landing page|Marpa::R3>.
Most of the code is exactly the same in fact,
and we will skip it.
Here is what is new:
=head2 Marpa::R3::Recognizer::new
=for Marpa::R3::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1
my $recce = Marpa::R3::Recognizer->new( { grammar => $grammar } );
=for Marpa::R3::Display::End
C<Marpa::R3::Recognizer::new> creates a new recognizer.
Its arguments are references to hashes of named arguments.
In this example the first named argument is
the required argument: "C<grammar>".
The value of the
C<grammar>
named argument must be a Marpa::R3
grammar.
=head2 Marpa::R3::Recognizer::read
=for Marpa::R3::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1
my $input = '42 * 1 + 7';
my $length_read = $recce->read( \$input );
=for Marpa::R3::Display::End
To parse a string,
we use
the C<Marpa::R3::Recognizer::read()> method.
In its simplest form,
as here,
the C<Marpa::R3::Recognizer::read()> method
takes a reference
to a string containing the input stream as its argument.
=head2 Checking for a premature end
=for Marpa::R3::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1
die "Read ended after $length_read of ", length $input, " characters"
if $length_read != length $input;
=for Marpa::R3::Display::End
Most premature endings occur when a parse is exhausted.
A parse is "exhausted" when there is no possible way for it
to continue on to success.
Premature parse exhaustion is thrown as a failure by
the C<Marpa::R3::Recognizer::read()> method,
and it is not necessary to check for it explicitly.
There are other premature endings
that are not necessarily failures,
and which therefore are not thrown.
These are Marpa::R3's parse events.
Parse events are an advanced feature, and are described
L<elsewhere|Marpa::R3::Event>.
In this example,
any premature ending caused by
the triggering of a parse event will be caused
by stray parse events --
unexpected parse events due to a mistake in writing the DSL.
Programming a stray parse event is a programming mistake that you
are not likely to make,
so arguably this check is not really necessary.
There are no parse events, stray or otherwise, in this example.
But this check is included for completeness,
and as an example of a cautious programming style.
=head2 Marpa::R3::Recognizer::value
=for Marpa::R3::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1
my $value_ref = $recce->value();
die "No parse" if not $value_ref;
my $value = ${$value_ref};
=for Marpa::R3::Display::End
The C<Marpa::R3::Recognizer::value()> method returns
a reference to the parse result's value,
if there was a parse result.
If there was no parse result,
C<Marpa::R3::Recognizer::value()>
returns
C<undef>.
The value of the parse is exactly the same,
and computed in exactly the same way,
as in the previous tutorial.
This code implicitly checks for parse ambiguity --
parses where the input can be parsed in two or more ways.
Ambiguous parses are not necessarily a problem -- some applications
may not care about them.
Other applications, as an advanced technique,
actually exploit ambiguity,
In this example, we assume that ambiguity, if it exists,
is a problem.
Beginners should regard an ambiguous parse
as a sign of trouble.
The existence of ambiguous parses should be tolerated
only if you understand the kind of ambiguity that exists
in your grammar,
and only if you know that ambiguities of that kind
will not cause trouble.
=head1 COPYRIGHT AND LICENSE
=for Marpa::R3::Display
ignore: 1
Marpa::R3 is Copyright (C) 2017, Jeffrey Kegler.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl 5.10.1. For more details, see the full text
of the licenses in the directory LICENSES.
This program is distributed in the hope that it will be
useful, but without any warranty; without even the implied
warranty of merchantability or fitness for a particular purpose.
=for Marpa::R3::Display::End
=cut
# vim: expandtab shiftwidth=4: