File: Tutorial2.pod

package info (click to toggle)
libmarpa-r2-perl 12.000000-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,660 kB
  • sloc: perl: 42,628; ansic: 23,387; sh: 4,363; makefile: 157
file content (293 lines) | stat: -rw-r--r-- 8,382 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# Copyright 2022 Jeffrey Kegler
# This file is part of Marpa::R2.  Marpa::R2 is free software: you can
# redistribute it and/or modify it under the terms of the GNU Lesser
# General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# Marpa::R2 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.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser
# General Public License along with Marpa::R2.  If not, see
# http://www.gnu.org/licenses/.

=head1 NAME

Marpa::R2::Tutorial2 - Marpa Tutorial 2

=head1 Synopsis

=for Marpa::R2::Display
name: Tutorial 2 synopsis
normalize-whitespace: 1

    use Marpa::R2;

    my $dsl = <<'END_OF_DSL';
    :default ::= action => [name,values]
    lexeme default = latm => 1
    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::R2::Scanless::G->new( { source => \$dsl } );
    my $recce = Marpa::R2::Scanless::R->new(
        { grammar => $grammar, semantics_package => 'My_Actions' } );
    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;

    if ( my $ambiguous_status = $recce->ambiguous() ) {
        chomp $ambiguous_status;
        die "Parse is ambiguous\n", $ambiguous_status;
    }

    my $value_ref = $recce->value;
    my $value = ${$value_ref};

    sub My_Actions::do_add {
        my ( undef, $t1, undef, $t2 ) = @_;
        return $t1 + $t2;
    }

    sub My_Actions::do_multiply {
        my ( undef, $t1, undef, $t2 ) = @_;
        return $t1 * $t2;
    }

=for Marpa::R2::Display::End

=head1 Description

=head2 Overview

This document contains a second tutorial
of the Scanless interface (SLIF),
which 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 the lower level calls

=over 4

=item *

to use SLIF parse events;

=item *

to examine the values of multiple  parses of an ambiguous parse;

=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::R2>.
Most of the code is exactly the same in fact,
and we will skip it.
Here is what is new:

=head2 Marpa::R2::Scanless::R::new

=for Marpa::R2::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1

    my $recce = Marpa::R2::Scanless::R->new(
        { grammar => $grammar, semantics_package => 'My_Actions' } );

=for Marpa::R2::Display::End

C<Marpa::R2::Scanless::R::new> creates a new SLIF 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::R2 SLIF
grammar.

The second argument is optional, but you will use it frequently.
The "C<semantics_package>" named argument tells Marpa in which Perl package to
look for the closures implementing the semantics for this grammar.

=head2 Marpa::R2::Scanless::R::read

=for Marpa::R2::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1

    my $input = '42 * 1 + 7';
    my $length_read = $recce->read( \$input );

=for Marpa::R2::Display::End

To parse a string,
we use 
the C<Marpa::R2::Scanless::R::read()> method.
In its simplest form,
as here,
the C<Marpa::R2::Scanless::R::read()> method
takes a reference
to a string containing the input stream as its argument.

=head2 Checking for a premature end

=for Marpa::R2::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::R2::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::R2::Scanless::R::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's SLIF parse events.
SLIF parse events are an advanced feature, and are described
L<elsewhere|Marpa::R2::Event>.
In this example,
any premature ending caused by
the triggering of a SLIF 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 SLIF 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 Checking for an ambiguous parse

=for Marpa::R2::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1

    if ( my $ambiguous_status = $recce->ambiguous() ) {
        chomp $ambiguous_status;
        die "Parse is ambiguous\n", $ambiguous_status;
    }

=for Marpa::R2::Display::End

Much more likely than stray SLIF parse events are ambiguous parses --
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,

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.
The above code uses
L<the recognizer's C<ambigous()>
method|Marpa::R2::Scanless::R/"ambiguous()"> to spot ambiguous parses.
The L<C<ambigous()>
method|Marpa::R2::Scanless::R/"ambiguous()"> returns the empty string
if there was exactly one parse.
If there was no parse, 
the L<C<ambigous()>
method|Marpa::R2::Scanless::R/"ambiguous()"> returns a string stating that.
If there were two or more parses,
the L<C<ambigous()>
method|Marpa::R2::Scanless::R/"ambiguous()"> returns a string describing
the ambiguity.

=head2 Marpa::R2::Scanless::R::value

=for Marpa::R2::Display
name: Tutorial 2 synopsis
partial: 1
normalize-whitespace: 1

    my $value_ref = $recce->value;
    my $value = ${$value_ref};

=for Marpa::R2::Display::End

The C<Marpa::R2::Scanless::R::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::R2::Scanless::R::value()>
returns
C<undef>.
This code does not check for the case where there is
no parse result, because we already performed that
check along with the check for ambiguity.

The value of the parse is exactly the same,
and computed in exactly the same way,
as in the previous tutorial.

=head1 Copyright and License

=for Marpa::R2::Display
ignore: 1

  Copyright 2022 Jeffrey Kegler
  This file is part of Marpa::R2.  Marpa::R2 is free software: you can
  redistribute it and/or modify it under the terms of the GNU Lesser
  General Public License as published by the Free Software Foundation,
  either version 3 of the License, or (at your option) any later version.

  Marpa::R2 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.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser
  General Public License along with Marpa::R2.  If not, see
  http://www.gnu.org/licenses/.

=for Marpa::R2::Display::End

=cut

# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 100
# End:
# vim: expandtab shiftwidth=4: