NAME¶
Marpa::R2::Advanced::Thin - Direct access to Libmarpa
About this document¶
Most Marpa users can ignore this document. It describes Marpa's "thin"
interface, which provides efficient access to Marpa's core library, Libmarpa.
The "thin" interface is very low-level and is not designed to be
convenient to use. User-friendliness is expected to be provided by an upper
layer. The "thin" interface is intended for use in writing those
upper layers. Libmarpa is also intended for writing applications, when the
programmer wants to eliminate the overhead of an upper layer, or wants the
flexibility provided by direct access to Libmarpa, and is willing to go to
some extra effort.
How this document is written¶
This document assumes that the reader is familiar with the other Marpa::R2
documentation, as well as with the Libmarpa API document. This means its
reader will have to know some C language -- at least enough to understand a
discussion written in terms of C functions, their parameters and return
values, and C language macros.
This document avoids duplicating the material in the Libmarpa API document. Most
Marpa thin interface functions correspond directly to a Libmarpa method, and
their implementation follows a "general pattern". This document
describes that "general pattern".
Methods that follow the general pattern are usually not mentioned specifically.
Methods that are exceptions to the general pattern are always mentioned, and
behaviors which deviate from the general pattern are always described in
detail. This document also identifies those Libmarpa methods to which no Marpa
thin interface method directly corresponds.
This style of documentation is very efficient, which is one reason that it is
the standard for C library interfaces to Perl. Admittedly, however, it is also
very terse. As an aid to the reader, an example of a script using the Marpa
thin interface is presented below. While small, the example is non-trival. It
is also full, in the sense it contains a complete logic flow, starting with
the definition of the grammar and continuing all the way to the iteration of
the values of an ambiguous parse.
Methods in the thin interface¶
While the thin interface has a few methods of its own, most of its methods are
wrappers for a method from the Libmarpa interface. On the other hand, many
Libmarpa methods do not have Marpa thin interface wrappers. No internal
Libmarpa method is part of the Marpa thin interface.
Additionally, many of the external Libmarpa methods are omitted because their
function is performed by the Marpa thin interface. No thin interface method
corresponds to the "marpa_check_version()" static method, because
the Marpa thin interface interface handles its own version matching.
No thin interface method corresponds to any of the Libmarpa configuration class
methods. No Marpa thin interface object corresponds to Libmarpa's
configuration objects. Configuration in the Marpa thin interface is done using
Perl variables.
No Marpa thin interface method corresponds to the "marpa_g_ref()" and
"marpa_g_unref()" methods because the thin interface handles the
reference counting of the Libmarpa objects it creates. The application can
rely on Libmarpa objects being cleaned up properly as part of Perl's usual
garbage collection. For the same reason, no Marpa thin interface method
corresponds to the "ref" and "unref" methods of the other
Libmarpa time classes.
Whenever an external Libmarpa method is not mentioned in this document, the
reader can assume that it has a wrapper that is implemented according to the
general pattern, as described below. Where the implementation of an external
Libmarpa method is an exception to the general pattern, its implementation
will be explicitly described and any corresponding Marpa thin interface method
will have a section devoted to it and specifying its differences from the
general pattern.
Libmarpa time objects and constructors¶
As a reminder, Libmarpa's major classes are, in sequence, configuration,
grammar, recognizer, bocage, ordering, tree and value. The one-letter
abbreviations for these are, respectively, "c", "g",
"r", "b", "o", "t" and "v".
Marpa_Config Marpa::R2::Thin::C
Marpa_Grammar Marpa::R2::Thin::G
Marpa_Recognizer Marpa::R2::Thin::R
Marpa_Bocage Marpa::R2::Thin::B
Marpa_Ordering Marpa::R2::Thin::O
Marpa_Tree Marpa::R2::Thin::T
Marpa_Value Marpa::R2::Thin::V
The thin interface implements a Perl class corresponding to each of Libmarpa
time classes. The thin interface does not implement a Perl class corresponding
to Libmarpa's configuration class.
Objects in the thin Marpa classes should be treated as opaque scalars.
Applications must not define new methods, constants or variables in a thin
Marpa classes. Similarly, applications must not redefine, overload or remove
existing elements. Thin Marpa classes must not be subclassed. Applications
should restrict their operation on objects in the Marpa thin classes to
assignments; calling methods of the class; and, in those cases where this
document states that it is appropriate, passing them as arguments.
Constructors for the time objects may be called using the "new" method
of the corresponding Perl class. For example,
my $recce = Marpa::R2::Thin::R->new($grammar);
Perl applications can destroy objects of the Marpa thin classes by undefining
them, or by letting them go out of scope. Application programmers do not need
to concern themselves with the reference counting of Libmarpa objects. The
Marpa thin interface handles this.
The throw setting¶
One of the most important functions of the Marpa thin interface to adapt
Libmarpa's error reporting to Perl. Perl allows two kinds of error reporting.
Perl methods can communicate failure via their return values, or they can
throw exceptions.
Each has its place. Throwing failure as an exception is the default in the Marpa
thin interface because it is safer, and because it is convenient for
prototyping and the first cuts at a new application. On the other hand, for
Marpa thin applications to have access to the full flexibility and power of
Libmarpa, they must be able to set the Marpa thin interface to return failure,
instead of throwing failure as an exception.
In choosing whether or not to throw a failure as an exception, almost every
Marpa thin method obeys the throw setting. If the throw setting is 1, failure
is thrown. If the throw setting is 0, failure is returned.
The throw setting is 1 in newly created grammar objects. Once created, the throw
setting of a grammar object can be changed using the "throw_set()"
method The throw setting of other objects is that of their base grammar.
Nearly every Marpa thin method always obeys the throw setting. Only three
methods never obey the throw setting. They are exceptions because their logic
controls the throw setting, so that a problem with them suggests the throw
setting itself may not be correct. The methods which never obey the throw
setting, are "Marpa::R2::Thin::G->new()", "throw_set()"
and "ruby_slippers_set()". These methods throw all failures.
One method allows the throw setting to be overriden. For convenience in using
the Ruby Slippers technique, the behavior of the "alternative()"
method is also affected by a separate "Ruby Slippers" flag. For
details, see the description of that method.
Error codes, names and descriptions¶
Errors in the Marpa thin interface come from two sources: Libmarpa, and the
Marpa thin interface itself. These will be called Libmarpa errors and thin
interface errors, respectively.
Internally, Marpa maintains two variables to track recent errors. These are the
error code and the error description. For every defined error code, there is
an error name. Together, the error code, the error name and the error
descriptions are called the "error variables".
When the most recent error was a Libmarpa error, the error code is the Libmarpa
error code, as described in the Libmarpa API document. A Libmarpa error code
is a non-negative integer. When the most recent error was a thin interface
error, the error code is a Perl "undef".
Libmarpa's integral error codes are rarely used directly, either in C or in
Perl. In C, the error codes are referred to using macros. The macro names are
available through the thin interface as error names. For details see the
section on error methods. Thin interface errors do not have error names.
In addition to error names, there are error descriptions.
- •
- Error names are short mnemonics. Error descriptions are typically
longer.
- •
- Error names and error codes have a one to one correspondence (bijection).
For a given error code, the error name will always be the same, and vice
versa. Error descriptions may contain text relating, not just to the error
code, but to the specific error instance.
- •
- The error name is defined if and only if the error code is defined. Error
descriptions always exist, whether or not there is an error code
defined.
- •
- A thin interface error will always have an error description. A thin
interface error will never have an error name.
- •
- The programmer may expect error codes and error names to remain stable and
may write code that relies on the numeric value of the error codes and the
text of the error name. Applications should treat the text of an error
description as suitable for the purpose of passing it on to a human user,
and should otherwise regard it as opaque.
Error descriptions, while typically longer than error names, are intended for
situations where it is most convenient if they fit into a single line, or at
most two. The Libmarpa API document contains a section on the Libmarpa error
codes. and there the descriptions are often longer and more detailed.
Error codes and error descriptions should be considered valid only if the most
recently called Marpa thin method indicated that it set the error code. An
application should assume that the error codes and error descriptions will be
overwritten by the next call to any thin interface method other than the
"error()" method.
Failure and the error variables¶
A method indicates failure either by throwing an exception or by returning a
value that indicates failure. If a method follows the general pattern, it
indicates failure if and only if its return value is less than or equal to -2.
Other methods indicate failure as stated in their descriptions in this
document.
Whenever a method indicates failure, that also indicates that it has set the
error variables. On Libmarpa failures, the error code is set to the Libmarpa
error code. On thin interface failure, the error code is set to a Perl
"undef". For both Libmarpa and thin interface failures, the error
description is set to a text that describes the error.
Success and the error variables¶
On success, a method will take one of the following three actions with respect
to the error variables:
- Reset the error code
- A successful method may set the error code to "MARPA_ERR_NONE",
together with an error description that indicates there is no error.
- Leave the error code as is
- A successful method may leave the error code and error description as
is.
- Set an informational error code
- A successful method may set a Libmarpa error code to a value other than
"MARPA_ERR_NONE". Error codes of this kind are called
informational error codes. The phrase "error code" in this
context is something of a misnomer. Informational error codes exist as a
convenience for some applications, but typically are ignored.
The Libmarpa API document sometimes specifies what a Libmarpa method does with
the error code on success. The Libmarpa API document always specifies if and
when a method sets an informational error code. If Libmarpa API document is
silent, the application should regard it as unspecified whether the error code
is reset or left as is.
The general pattern¶
Most Marpa thin interface methods correspond directly to a Libmarpa method, and
their behaviors are in most cases exactly the same. These behaviors are called
the "general pattern" in this document. To avoid repetition, Marpa
thin interface methods that follow the general pattern exactly are usually not
described explicitly in this document.
Method names¶
The name of a general pattern method is that of its corresponding Libmarpa
method, minus the 8-letter prefix which indicates its Libmarpa class. For
example, the Marpa thin interface method that corresponds to
"marpa_g_start_symbol_set" is "$g->start_symbol_set()".
The class of the general pattern method will be the Marpa thin class
corresponding to the time class of the Libmarpa method. For example,
"$g->start_symbol_set()" will be in the
"Marpa::R2::Thin:G" Perl class.
Arguments¶
Libmarpa's class instance methods take an object of the their class as their
first ("self") argument. Zero or more non-self arguments follow the
self argument. The arguments of the corresponding general pattern Marpa thin
method will be the same, converted from C types to Perl as described next.
(This discussion follows the convention used in perlobj, and considers the
"self" object to be a Perl method's first argument.)
In the general pattern, every argument whose type is one of Libmarpa's time
classes is converted to the corresponding Marpa thin interface class.
Arguments which belong to Libmarpa's numbered classes
("Marpa_Earley_Set_ID", "Marpa_Rank",
"Marpa_Rule_ID" and "Marpa_Symbol_ID") are converted to
Perl scalar integers. C language "int"'s are also converted to Perl
scalar integers.
The Marpa thin interface does not recognize booleans, either in C or in Perl.
For example, if a Perl true value is not a numeric 1, it will not be converted
to a numeric 1 in C, even in a situation where the Libmarpa method is clearly
looking for a boolean. The intent is to allow for future extensions to the
Libmarpa interface that accept and interpret other numeric values.
Return values¶
In the general pattern, the return value from a Libmarpa method will always
either belong to one of Libmarpa's numbered classes, or be a C language
"int". If the Libmarpa return value is a non-negative integer, the
corresponding general pattern Marpa thin method will return a numeric Perl
scalar. If the Libmarpa method returns -1, its corresponding general pattern
Marpa thin method will return a Perl "undef".
General pattern failures¶
General pattern methods consider failure to be a Libmarpa return value of -2 or
less. Failure is thrown if the throw setting is 1. On unthrown failure, the
return value of the Libmarpa method will be returned by the Marpa thin method
as a numeric Perl scalar.
An example of a general pattern method¶
Here is an example of a Libmarpa function whose corresponding Marpa thin method
follows the general pattern.
marpa_g_start_symbol_set (grammar, symbol_S);
and here is the corresonding thin Marpa call:
$grammar->start_symbol_set($symbol_S);
Error methods¶
The thin interface to Libmarpa provides error methods more appropriate to the
Perl environment than Libmarpa's own.
"$g->error()"¶
my ( $error_code, $error_description ) = $grammar->error();
my @error_names = Marpa::R2::Thin::error_names();
my $error_name = $error_names[$error_code];
In scalar context, the "error()" method returns the error description.
In array context, it returns a 2-element array. The first element of the array
is the error code, and the second element is the error description.
Applications should assume that a call to any other Marpa thin method will
overwrite the error code and error description. For "error()" to
successfully query the error code or error description of a method,
"error()" should be the next Marpa thin interface method called.
"$g->error_clear()"¶
The "error_clear()" method follows the general pattern.
"$g->error_names()"¶
For a synopsis, see the section on the "$g->error()" method. The
"error_names()" method returns a
reference to an array of
error names, indexed by Libmarpa error code.
"$g->throw_set()"¶
$grammar->throw_set(0);
The "throw_set()" method turns the throw flag for the grammar on or
off, according to whether its argument is 1 or 0. "throw_set()"
fails if its argument is not a numeric 0 or 1. "throw_set()" itself
never returns failure -- it always throws an exception.
Omitted configuration methods¶
All of the methods of Libmarpa's configuration class are omitted in the Marpa
thin interface. The functions performed by Libmarpa's configuration methods
are handled in a more Perl-centric way by the Marpa thin interface.
Grammar methods¶
"Marpa::R2::Thin::G->new()"¶
my $grammar = Marpa::R2::Thin::G->new( { if => 1 } );
The one argument to the Marpa thin interface's grammar constructor, is a
reference to a hash of named arguments. On success, the return value is a thin
interface grammar object. "new()" does not obey the throw setting --
errors are always thrown.
At present the only named argument allowed is "if", the interface
number. This argument is required and currently is required to have a value of
1, which specifies interface 1. The intent of the "if" argument is
to provide for backward compatibility in the future.
Although there is no error message or warning if the hash ref argument is
omitted, new code should treat the hash ref argument as a required argument.
Calling "new()" without an argument is deprecated. If the hash ref
argument is omitted, the thin layer uses interface 0. Interface 0 cannot be
specified directly, and is deprecated. The difference between interface 0 and
interface 1 is that, in interface 0, the default throw setting of the newly
created grammar object is unspecified. (In fact, the interface 0 throw setting
depends on an undocumented and deprecated global variable.)
"$g->event()"¶
my ( $event_type, $value ) = $grammar->event( $event_ix++ );
The "event()" method returns a two-element array on success. The first
element is a string naming the event type, and the second is a scalar
representing its value. The string for an event type is its macro name, as
given in the Libmarpa API document.
Some event types have an event "value". All event values are numeric
Perl scalars. The number is either a symbol ID or a count, as described in the
Libmarpa API document.
The permissible range of event indexes can be found with the Marpa thin
interface's "event_count()" grammar method, which corresponds to
Libmarpa's "marpa_g_event_count()" method. The thin interface's
"event_count()" method follows the general pattern.
Since "event()" returns the event value whenever it exists, the
Libmarpa "marpa_g_event_value()" method is unneeded. The Libmarpa
"marpa_g_event_value()" method has no corresponding Marpa thin
interface method.
"event()" obeys the throw setting. On unthrown failure,
"event()" returns a Perl "undef".
"$g->rule_new()"¶
my $start_rule_id = $grammar->rule_new( $symbol_S, [$symbol_E] );
The "rule_new()" grammar method is the Libmarpa thin interface method
corresponding to the "marpa_g_rule_new()" method. It takes two
arguments, both required. The first argument is a symbol ID representing the
rule's LHS, and the second argument is a reference to an array of symbol ID's.
The symbol ID's in the array represent the RHS. On success, the return value
is the ID of the new rule.
"rule_new()" obeys the throw setting. On unthrown failure, it returns
-2.
"$g->sequence_new()"¶
my $sequence_rule_id = $grammar->sequence_new(
$symbol_S,
$symbol_a,
{ separator => $symbol_sep,
proper => 0,
min => 1
}
);
The "sequence_new()" grammar method is the Libmarpa thin interface
method corresponding to the "marpa_g_sequence_new()" method. It
takes three arguments, all required. The first argument is a symbol ID
representing the sequence's LHS. The second argument is a symbol ID
representing the sequence's RHS. The third argument is a reference to a hash
of named arguments.
The hash of named arguments may be empty. If not empty, its keys, and their
values, must be one of the following:
- "separator"
- The value of the "separator" named argument will be treated as
an integer, and passed as the separator ID argument to the
"marpa_g_sequence_new()" method. It defaults to -1.
- "proper"
- If the value of "proper" named argument is a Perl true value,
the "MARPA_PROPER_SEPARATION" flag will be set in the flags
passed to the "marpa_g_sequence_new()" method. Otherwise, the
"MARPA_PROPER_SEPARATION" flag will not be set.
- "min"
- The value of the "min" named argument will be treated as an
integer, and passed as the "min" argument to the
"marpa_g_sequence_new()" method. The "min" argument
indicates the minimum number of repetitions of the sequence that are
required. It defaults to 1.
On success, the return value is the rule ID of the new sequence.
Users should be aware that all sequences at the Marpa thin interface level are
"keep separation". This differs from the higher-level interface,
which discards separators by default. At the Marpa thin interface level, it is
up to the programmer to discard separators, if that is what is wanted.
"sequence_new()" obeys the throw setting. On unthrown failure, it
returns -2.
"$g->precompute()"¶
$grammar->precompute();
The "precompute()" method follows the general pattern. In addition to
errors, "precompute()" also reports events. Events are queried using
the grammar's "event()" method.
On success, "precompute()" returns an event count. But, even when
there is an error, "precompute()" often reports one or more events.
It is not safe to assume that no events occurred unless
"precompute()" succeeds and reports an event count of zero.
"$g->rule_rank()"¶
The "rule_rank()" method is based on Libmarpa's
"marpa_g_rule_rank()" method. Its argument is the rule ID, and its
return value is the rank, or a -2 to indicate an unthrown error.
Note a return value of -2 is ambiguous -- it can indicate that the rank was -2,
or that a failure occurred. To distinguish the cases, the application can look
at the error code. The error code will be "MARPA_ERR_NONE" if and
only if the call was successful. The error code can be found using the
"error()" method. Applications may find it more convenient to have
"rule_rank()" always throw its errors.
"$g->rule_rank_set()"¶
The "rule_rank_set()" method is based on Libmarpa's
"marpa_g_rule_rank_set()" method. Its two arguments are the rule ID
and a rule rank. Its return value is the new value of the rank, or a -2 to
indicate an unthrown error.
Note a return value of -2 is ambiguous -- it can indicate that the rank was -2,
or that a failure occurred. To distinguish the cases, the application can look
at the error code. The error code will be "MARPA_ERR_NONE" if and
only if the call was successful. The error code can be found using the
"error()" method. Applications may find it more convenient to have
"rule_rank_set()" always throw its errors.
Omitted grammar methods¶
The "marpa_g_ref()" and "marpa_g_unref()" methods are
omitted because the Marpa thin interface performs their function. The
"marpa_g_event_value()" method is omitted because its function is
absorbed into the thin interface's "event()" grammar method.
General pattern methods¶
All grammar methods that are part of the Libmarpa external interface, but that
are not mentioned explicitly in this document, are implemented following the
general pattern, as described above.
Recognizer methods¶
"Marpa::R2::Thin::R->new()"¶
my $recce = Marpa::R2::Thin::R->new($grammar);
The "new()" method takes a Marpa thin grammar object as its one
argument. On success, it returns a Marpa thin recognizer object.
"new()" obeys the throw setting. On unthrown failure, it returns a
Perl "undef".
"$r->ruby_slippers_set()"¶
$recce->ruby_slippers_set(1);
With an argument of 1, the "ruby_slippers_set()" method enables
"Ruby Slippers" mode. An argument of 0 disables "Ruby
Slippers" mode. By default, Ruby Slippers mode is disabled. Note that
this default (disabled) is the opposite of that in the higher level Marpa::R2
interface.
The "alternative()" method will only throw exceptions when "Ruby
Slippers" mode is disabled and the throw flag is on. One way of
describing Ruby Slippers mode is as an override of the throw setting, one
which only applies to the "alternative()" method.
The "ruby_slippers_set()" method itself does
not obey the throw
setting. All failures by "ruby_slippers_set()" are thrown as
exceptions.
"$r->alternative()"¶
$recce->alternative( $symbol_number, 2, 1 );
In the Libmarpa API the "alternative()" method returns an error code,
with "MARPA_ERR_NONE" being the code returned if there was no error.
The "alternative()" method will throw the error code as an exception
if and only if all three of the following are true:
- •
- The base grammar's throw flag is on.
- •
- The Ruby Slippers flag is off.
- •
- The error code is not "MARPA_ERR_NONE".
Of major interest is the error code "MARPA_ERR_UNEXPECTED_TOKEN_ID",
which indicates that a token was not accepted because its token ID was not one
of those expected. Catching and recovering from this error is the basis of the
Ruby Slippers parsing technique. For more on the Ruby Slippers flag, see
"ruby_slippers_set()".
"$r->terminals_expected()"¶
my @terminals = $recce->terminals_expected();
The "terminals_expected()" method takes no arguments. On success, it
returns an array containing the symbol ID's of the expected terminals. Note
that the array of expected terminal ID's may be empty, so that an empty array
is NOT a failure indicator. "terminals_expected()" obeys the throw
setting. On unthrown failure, "terminals_expected()" returns a Perl
"undef".
"$r->progress_item()"¶
my $ordinal = $recce->latest_earley_set();
$recce->progress_report_start($ordinal);
ITEM: while (1) {
my ($rule_id, $dot_position, $origin) = $recce->progress_item();
last ITEM if not defined $rule_id;
push @{$report}, [$rule_id, $dot_position, $origin];
}
$recce->progress_report_finish();
The "progress_item()" method takes no arguments. On success, it
returns an array of 3 elements: the rule ID, the dot position, and the earley
set ID of the origin. If there are no more items, "progress_item()"
returns a Perl "undef".
"progress_item()" obeys the throw setting. On unthrown failure, the
rule ID element in the array returned by "progress_item()" will have
a value of -2.
Omitted recognizer methods¶
Because the Marpa thin interface handles reference counting internally, it does
not implement methods directly corresponding to Libmarpa's
"marpa_r_ref()" and "marpa_r_unref()" methods.
There are Marpa thin methods corresponding to Libmarpa's
"marpa_r_earley_set_value()" and
"marpa_r_earley_set_value_set()" methods, but not to Libmarpa's
"marpa_r_earley_set_values()" and
"marpa_r_earley_set_values_set()" methods. The difference between
these is that the "values" form allows an integer and a pointer
value to be set, while the "value" form allows only an integer to be
set. Perl applications which want to associate non-integer data with an Earley
set should create an array, and use the integer to index the array. The
elements of the array can contain arbitrary data.
The thin interface does not implement a way to set the Earley set pointer value,
because to do so would not add value. The thin interface would have to track
the reference count of a pointer, and this can done as easily and efficiently,
and with more flexibility, at the Perl level.
Methods not mentioned¶
All recognizer methods that are part of the Libmarpa external interface, but
that are not mentioned explicitly in this document, are implemented following
the general pattern, as described above.
Bocage methods¶
"Marpa::R2::Thin::B->new()"¶
my $latest_earley_set_ID = $recce->latest_earley_set();
my $bocage = Marpa::R2::Thin::B->new( $recce, $latest_earley_set_ID );
The "new()" method takes a Marpa thin recognizer object as its one
argument. On success, it returns a Marpa thin bocage object. "new()"
obeys the throw setting. On unthrown failure, it returns a Perl
"undef".
Omitted bocage methods¶
Because the Marpa thin interface handles reference counting internally, it does
not implement methods directly corresponding to Libmarpa's
"marpa_b_ref()" and "marpa_b_unref()" methods.
Methods not mentioned¶
All bocage methods that are part of the Libmarpa external interface, but that
are not mentioned explicitly in this document, are implemented following the
general pattern, as described above.
Ordering methods¶
"Marpa::R2::Thin::O->new()"¶
my $order = Marpa::R2::Thin::O->new($bocage);
The "new()" method takes a Marpa thin bocage object as its one
argument. On success, it returns a Marpa thin ordering object.
"new()" obeys the throw setting. On unthrown failure, it returns a
Perl "undef".
Omitted ordering methods¶
Because the Marpa thin interface handles reference counting internally, it does
not implement methods directly corresponding to Libmarpa's
"marpa_o_ref()" and "marpa_o_unref()" methods.
Methods not mentioned¶
All ordering methods that are part of the Libmarpa external interface, but that
are not mentioned explicitly in this document, are implemented following the
general pattern, as described above.
Tree methods¶
"Marpa::R2::Thin::T->new()"¶
my $tree = Marpa::R2::Thin::T->new($order);
The "new()" method takes a Marpa thin ordering object as its one
argument. On success, it returns a Marpa thin tree object. "new()"
obeys the throw setting. On unthrown failure, it returns a Perl
"undef".
Omitted tree methods¶
Because the Marpa thin interface handles reference counting internally, it does
not implement methods directly corresponding to Libmarpa's
"marpa_t_ref()" and "marpa_t_unref()" methods.
Methods not mentioned¶
All tree methods that are part of the Libmarpa external interface, but that are
not mentioned explicitly in this document, are implemented following the
general pattern, as described above.
Value methods¶
"Marpa::R2::Thin::V->new()"¶
my $valuator = Marpa::R2::Thin::V->new($tree);
The "new()" method takes a Marpa thin tree object as its one argument.
On success, it returns a Marpa thin value object. "new()" obeys the
throw setting. On unthrown failure, it returns a Perl "undef".
"$v->location()"¶
$type = $valuator->step_type();
my ( $start, $end ) = $valuator->location();
if ( $type eq 'MARPA_STEP_RULE' ) {
my ($rule_id) = @step_data;
$locations_report .= "Rule $rule_id is from $start to $end\n";
}
if ( $type eq 'MARPA_STEP_TOKEN' ) {
my ($token_id) = @step_data;
$locations_report .= "Token $token_id is from $start to $end\n";
}
if ( $type eq 'MARPA_STEP_NULLING_SYMBOL' ) {
my ($symbol_id) = @step_data;
$locations_report
.= "Nulling symbol $symbol_id is from $start to $end\n";
}
The "location()" method takes no arguments. The "location()"
method always succeeds, returning either an empty array or an array of two
elements.
- •
- If the last step was "MARPA_STEP_RULE", the array contains the
locations where the rule starts and ends, as returned by the Libmarpa
methods "marpa_v_rule_start_es_id()" and
"marpa_v_es_id()".
- •
- It the last step was "MARPA_STEP_TOKEN", the array contains the
locations where the token starts and ends, as returned by the Libmarpa
methods "marpa_v_token_start_es_id()" and
"marpa_v_es_id()".
- •
- It the last step was "MARPA_STEP_NULLING_SYMBOL", the array
contains the locations where the token starts and ends, as returned by the
Libmarpa methods "marpa_v_token_start_es_id()" and
"marpa_v_es_id()".
- •
- In any other case, the array is empty.
"$v->step()"¶
my ( $type, @step_data ) = $valuator->step();
The "step()" method takes no arguments. On success, "step()"
returns an array, whose contents are as follows:
- "MARPA_STEP_RULE"
- If the step type is "MARPA_STEP_RULE", "step()"
returns an array of 4 elements. These will be, in order:
- •
- The string ""MARPA_STEP_RULE"".
- •
- The rule id, as returned by the Libmarpa method
"marpa_v_rule_id()".
- •
- The stack location where the child values of the rule begin, as returned
by the Libmarpa method "marpa_v_token_arg_0()". This is also the
stack location to which the result should be written.
- •
- The stack location where the child values of the rule end, as returned by
the Libmarpa method "marpa_v_token_arg_n()".
- "MARPA_STEP_TOKEN"
- If the step type is "MARPA_STEP_TOKEN", "step()"
returns an array of 4 elements. These will be, in order:
- •
- The string ""MARPA_STEP_TOKEN"".
- •
- The token id, as returned by the Libmarpa method
"marpa_v_token()".
- •
- The token value, as returned by the Libmarpa method
"marpa_v_token_value()".
- •
- The stack location to which the token's value should be written, as
returned by the Libmarpa method "marpa_v_result()".
As a reminder, Libmarpa's token values are always integers. Applications will
often have a richer or different semantics for token values. One approach such
applications can take is to use Libmarpa's token values as indexes into an
array.
- "MARPA_STEP_NULLING_SYMBOL"
- If the step type is "MARPA_STEP_NULLING_SYMBOL",
"step()" returns an array of 3 elements. These will be, in
order:
- •
- The string ""MARPA_STEP_NULLING_SYMBOL"".
- •
- The ID of the nulling symbol, as returned by the Libmarpa method
"marpa_v_symbol()".
- •
- The stack location to which the nulling symbol's value should be written,
as returned by the Libmarpa method "marpa_v_result()".
- "MARPA_STEP_INACTIVE"
- If the step type is "MARPA_STEP_INACTIVE", "step()"
returns an empty array.
"step()" obeys the throw setting. On unthrown failure,
"step()" returns an array whose only element is a string not
reserved by Libmarpa. A string is not reserved by Libmarpa if it does not
begin with ""MARPA_"" in one of its capitalization
variants. The string will usually be a description of the error.
"$v->step_type()"¶
$type = $valuator->step_type();
The "step_type()" method takes no arguments. On success,
"step_type()" returns the string indicating the type of the last
Libmarpa valuator step. If the last call of the "step()" method
succeeded, the string returned by "step_type()" will be the same as
the one that was the first element of the array returned by
"step()".
"step_type()" obeys the throw setting. On unthrown failure,
"step()" returns an array whose only element is a string not
reserved by Libmarpa. A string is not reserved by Libmarpa if it does not
begin with ""MARPA_"" in one of its capitalization
variants. The string will usually be a description of the error.
Omitted value methods¶
Because the Marpa thin interface handles reference counting internally, it does
not implement methods directly corresponding to Libmarpa's
"marpa_v_ref()" and "marpa_v_unref()" methods. The step
accessor macros are folded into the thin interface's "$v->step()"
and "$v->location()" methods. For this reason, no thin interface
macro corresponds directly to most of the individual step accessors.
Methods not mentioned¶
All value methods that are part of the Libmarpa external interface, but that are
not mentioned explicitly in this document, are implemented following the
general pattern, as described above.
Example¶
my $grammar = Marpa::R2::Thin::G->new( { if => 1 } );
$grammar->force_valued();
my $symbol_S = $grammar->symbol_new();
my $symbol_E = $grammar->symbol_new();
$grammar->start_symbol_set($symbol_S);
my $symbol_op = $grammar->symbol_new();
my $symbol_number = $grammar->symbol_new();
my $start_rule_id = $grammar->rule_new( $symbol_S, [$symbol_E] );
my $op_rule_id =
$grammar->rule_new( $symbol_E, [ $symbol_E, $symbol_op, $symbol_E ] );
my $number_rule_id = $grammar->rule_new( $symbol_E, [$symbol_number] );
$grammar->precompute();
my $recce = Marpa::R2::Thin::R->new($grammar);
$recce->start_input();
# The numbers from 1 to 3 are themselves --
# that is, they index their own token value.
# Important: zero cannot be itself!
my @token_values = ( 0 .. 3 );
my $zero = -1 + push @token_values, 0;
my $minus_token_value = -1 + push @token_values, q{-};
my $plus_token_value = -1 + push @token_values, q{+};
my $multiply_token_value = -1 + push @token_values, q{*};
$recce->alternative( $symbol_number, 2, 1 );
$recce->earleme_complete();
$recce->alternative( $symbol_op, $minus_token_value, 1 );
$recce->earleme_complete();
$recce->alternative( $symbol_number, $zero, 1 );
$recce->earleme_complete();
$recce->alternative( $symbol_op, $multiply_token_value, 1 );
$recce->earleme_complete();
$recce->alternative( $symbol_number, 3, 1 );
$recce->earleme_complete();
$recce->alternative( $symbol_op, $plus_token_value, 1 );
$recce->earleme_complete();
$recce->alternative( $symbol_number, 1, 1 );
$recce->earleme_complete();
my $latest_earley_set_ID = $recce->latest_earley_set();
my $bocage = Marpa::R2::Thin::B->new( $recce, $latest_earley_set_ID );
my $order = Marpa::R2::Thin::O->new($bocage);
my $tree = Marpa::R2::Thin::T->new($order);
my @actual_values = ();
while ( $tree->next() ) {
my $valuator = Marpa::R2::Thin::V->new($tree);
my @stack = ();
STEP: while ( 1 ) {
my ( $type, @step_data ) = $valuator->step();
last STEP if not defined $type;
if ( $type eq 'MARPA_STEP_TOKEN' ) {
my ( undef, $token_value_ix, $arg_n ) = @step_data;
$stack[$arg_n] = $token_values[$token_value_ix];
next STEP;
}
if ( $type eq 'MARPA_STEP_RULE' ) {
my ( $rule_id, $arg_0, $arg_n ) = @step_data;
if ( $rule_id == $start_rule_id ) {
my ( $string, $value ) = @{ $stack[$arg_n] };
$stack[$arg_0] = "$string == $value";
next STEP;
}
if ( $rule_id == $number_rule_id ) {
my $number = $stack[$arg_0];
$stack[$arg_0] = [ $number, $number ];
next STEP;
}
if ( $rule_id == $op_rule_id ) {
my $op = $stack[ $arg_0 + 1 ];
my ( $right_string, $right_value ) = @{ $stack[$arg_n] };
my ( $left_string, $left_value ) = @{ $stack[$arg_0] };
my $value;
my $text = '(' . $left_string . $op . $right_string . ')';
if ( $op eq q{+} ) {
$stack[$arg_0] = [ $text, $left_value + $right_value ];
next STEP;
}
if ( $op eq q{-} ) {
$stack[$arg_0] = [ $text, $left_value - $right_value ];
next STEP;
}
if ( $op eq q{*} ) {
$stack[$arg_0] = [ $text, $left_value * $right_value ];
next STEP;
}
die "Unknown op: $op";
} ## end if ( $rule_id == $op_rule_id )
die "Unknown rule $rule_id";
} ## end if ( $type eq 'MARPA_STEP_RULE' )
die "Unexpected step type: $type";
} ## end while ( my ( $type, @step_data ) = $valuator->step() )
push @actual_values, $stack[0];
} ## end while ( $tree->next() )
Copyright and License¶
Copyright 2014 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/.