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. It provides the ultimate in Marpa speed, power and flexibility.
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. It is also for those writing applications, when they want to eliminate the overhead of an upper layer, or when they want the flexibility provided by direct access to Libmarpa.
How this document is written
This document assumes that the reader is familiar with the other Marpa::R2 documentation, as well as 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 not specifically mentioned. Methods that are exceptions to the general pattern are described in detail. Those Libmarpa methods to which no Marpa thin interface method directly corresponds are identified.
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 contining 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, several 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 config class methods, and no Marpa thin interface object corresponds to Libmarpa's config 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 methods is an exception to the guidelines, or has other peculiarities, the corresponding Marpa thin interface method will be described in detail.
Libmarpa time objects and constructors
As a reminder, the classes of Libmarpa's time objects are, in sequence, grammar, recognizer, bocage, ordering, tree and value. The one-letter abbreviations for these are, respectively, c
, g
, r
, b
, o
, t
and v
. The thin interface implements a Perl class corresponding to each of Libmarpa major classes.
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
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 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, these must be able to set the Marpa thin interface to return failure, instead of throwing it.
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.
Newly created grammar objects take their throw setting from the $Marpa::R2::Thin::C::THROW
configuration variable. By default, $Marpa::R2::Thin::C::THROW
is set to 1. 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 two methods never obey the throw setting. throw_set()
and ruby_slippers_set()
themselves change the logic that controls the throwing of exceptions. For this reason it is safest to have these two 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 last 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 only be considered valid only if that method indicates that it sets 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, what a method will do with the error code and error description is usually unspecified, except that it will be one of the following three things:
A successful method may set the error code to
MARPA_ERR_NONE
, together with an error description that indicates there is no error.A successful method may leave the error code and error description as is.
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 being something of a misnomer. When a Libmarpa method might set an informational error code, that is explicitly stated in that method's description in the Libmarpa API document. Typically, informational error codes are ignored.
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. In the previous example, start_symbol_set()
will be in the Marpa::R2::Thin:G
Perl class.
Arguments
Libmarpa's class instance methods prototypes have an object of the appropriate class as their first ("self") argument. Zero or more non-self arguments follow this first time class 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. C language int
's are converted to Perl scalar integers. Arguments which belong to Libmarpa's numbered classes (for example, Marpa_Rule_ID
and Marpa_Symbol_ID
) 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, it 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.
Configuration variables
The Marpa thin interface has one configuration variable:
$Marpa::R2::Thin::C::THROW
If a Perl true, the Marpa thin interface throws failures as exceptions. If a Perl false, the Marpa thin interface methods return failure, as described for each method. Defaults to true.
Each grammar has its own "throw" flag. This variables controls only the initial setting of that variable. A grammar's "throw" flag can be reset using the $g->throw_set()
method, after which its setting is independent of the $Marpa::R2::Thin::C::THROW
variable.
Omitted methods
All of the functions performed by Libmarpa's configuration methods are handled in a more Perl-centric way by the Marpa thin interface. All of the methods of Libmarpa's configuration class are omitted in the Marpa thin interface.
Grammar methods
Marpa::R2::Thin::G->new()
my $grammar = Marpa::R2::Thin::G->new();
There are no arguments to the Marpa thin interface's grammar constructor. On success, its return value is a thin interface grammar object.
A failure occurs if there is a version mismatch, which should not happen -- it indicates a problem with the way that the library was built. new()
obeys the throw setting. On unthrown failure in scalar context, new()
returns a Perl undef
. On unthrown failure in array context, new()
returns a 2-element array whose first element is a Perl undef
and whose second element is the error code.
$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 themarpa_g_sequence_new()
method. It defaults to -1. proper
-
If the value of
proper
named argument is a Perl true value, theMARPA_PROPER_SEPARATION
flag will be set in the flags passed to themarpa_g_sequence_new()
method. Otherwise, theMARPA_PROPER_SEPARATION
flag will not be set. min
-
The value of the
separator
named argument will be treated as an integer, and passed as the separator ID argument to themarpa_g_sequence_new()
method. It defaults to 0.
On success, the return value is the 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.
Omitted 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 );
The thin interface's alternative()
method follows the general pattern, with one exception: The alternative()
method will not throw an exception if the Ruby Slippers flag is on. More precisely, the alternative()
method will throw failures as exceptions if and only if the base grammar's throw flag is on and the Ruby Slippers flag is off. For more, 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 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.
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 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 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 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->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 captialization variants. The string will usually be a description of the error.
Omitted 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. Because they are folded into the thin interface's $v->step()
method, the thin interface does not have any methods corresponding directly to the step accessor macros.
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();
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);
$valuator->rule_is_valued_set( $op_rule_id, 1 );
$valuator->rule_is_valued_set( $start_rule_id, 1 );
$valuator->rule_is_valued_set( $number_rule_id, 1 );
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 2012 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/.