CWB
view release on metacpan or search on metacpan
lib/CWB/CEQL/Parser.pm view on Meta::CPAN
will be created in the working copy of the parameter set and will only be
available during the current parse.
=cut
sub NewParam {
confess 'Usage: $self->NewParam($name, $default_value)'
unless @_ == 3;
my ($self, $name, $value) = @_;
## select either global parameter values (user level) or working copy (during parse)
my $param_set = (defined $self->{INPUT}) ? $self->{PARAM} : $self->{PARAM_DEFAULTS};
confess "CWB::CEQL::Parser: parameter '$name' already exists, cannot create with NewParam()"
if exists $param_set->{$name};
$param_set->{$name} = $value;
}
=item I<$result> = I<$self>->B<Call>(I<$rule>, I<$input>);
Apply rule I<$rule> to input string I<$input>. The return value I<$result>
depends on the grammar rule, but is usually a string containing a translated
version of I<$input>. Grammar rules may also annotate this string with
B<attributes> or by B<bless>ing it into a custom class, or return a complex
data structure such as a parse tree for I<$input>. The caller has to be aware
what kind of value I<$rule> returns.
Note that B<Call> never returns B<undef>. In case of an error, the entire
parse is aborted.
=cut
sub Call {
confess 'Usage: $result = $self->Call($rule, $input);'
unless @_ == 3;
my ($self, $rule, $input) = @_;
confess "Sorry, we're not parsing yet"
unless defined $self->{INPUT};
my $method = $self->can("$rule");
confess "the rule **$rule** does not exist in grammar **".ref($self)."** (internal error)\n"
unless defined $method;
my $frame = {RULE => $rule,
INPUT => $input};
push @{$self->{CALLSTACK}}, $frame;
my $result = $method->($self, $input);
die "rule **$rule** failed to return a result (internal error)\n"
unless defined $result;
my $return_frame = pop @{$self->{CALLSTACK}};
die "call stack has been corrupted (internal error)"
unless $return_frame eq $frame;
return $result;
}
=item I<$result> = I<$self>->B<Try>(I<$rule>, I<$input>);
Tentatively apply rule I<$rule> to the input string. If I<$input> is parsed
successfully, B<Try> returns the translated version I<$result> (or an
arbitrary data structure such as a parse tree for I<$input>) just as B<Call>
would. If parsing fails, B<Try> does not abort but simply returns B<undef>,
ignoring any error messages generated during the attempt. In addition, the
call stack is restored and all parameters are reset to their previous values,
so that parsing can continue as if nothing had happened (note, however, that
this is based on flat backup copies, so complex data structures may have been
altered destructively).
=cut
sub Try {
confess 'Usage: $result = $self->Try($rule, $input);'
unless @_ == 3;
my ($self, $rule, $input) = @_;
confess "Sorry, we're not parsing yet"
unless defined $self->{INPUT};
## make flat backup copies of important data structures and ensure they are restored upon return
## (this is not completely safe, but should undo most changes that a failed parse may have made)
my $back_param = [ @{$self->{PARAM}} ];
my $back_callstack = [ @{$self->{CALLSTACK}} ];
my ($back_groups, $back_current_group, $back_groupstack) = (undef, undef, undef);
if (defined $self->{GROUPS}) {
$back_groups = [ @{$self->{GROUPS}} ];
$back_current_group = [ @{$back_groups->[0]} ]
if @$back_groups > 0;
}
if (defined $self->{GROUPSTACK}) {
$back_groupstack = [ @{$self->{GROUPSTACK}} ];
}
my $result = eval { $self->Call($rule, $input) };
## if parsing failed, restore internal data structures from backup copies
if (not defined $result) {
$self->{PARAM} = $back_param;
$self->{CALLSTACK} = $back_callstack;
$self->{GROUPS} = $back_groups;
if (defined $back_groups and defined $back_current_group) {
$self->{GROUPS}->[0] = $back_current_group;
}
$self->{GROUPSTACK} = $back_groupstack;
}
return $result;
}
=item I<@results> = I<$self>->B<Apply>(I<$rule>, I<@items>);
Apply rule I<$rule> to each input string in the list I<@items>. The return
values are collected and returned as a list I<@results>, which has to be
further processed by the caller. Note that empty strings (C<"">) are
automatically removed from the list of return values.
=cut
sub Apply {
confess 'Usage: @results = $self->Apply($rule, @items);'
unless @_ >= 2;
my $self = shift;
my $rule = shift;
my $frame = {RULE => "APPLY",
APPLY_ITEMS => [ @_ ],
APPLY_DONE => []};
push @{$self->{CALLSTACK}}, $frame;
## data structures for nested groups and result values must be restored on exit (in case of nested Apply())
local $self->{GROUPS} = [ [] ]; # set up data structure to collect result values of nested groups
local $self->{GROUPSTACK} = []; # stack of nested groups (keeps track of nesting depth and ensures proper nesting)
## process each input item in turn
while (@{$frame->{APPLY_ITEMS}}) {
my $input = shift @{$frame->{APPLY_ITEMS}};
push @{$frame->{APPLY_DONE}}, $input;
my $result = $self->Call($rule, $input);
push @{$self->{GROUPS}->[0]}, $result
unless $result eq "" and not ref $result; # plain empty string indicates that this item does not generate output
}
## check that nested bracketing was balanced and that data structure for result values is sane
if (@{$self->{GROUPSTACK}} > 0) {
my $next_type = pop @{$self->{GROUPSTACK}};
my $type_msg = ($next_type eq "*") ? "" : "of type ''$next_type''";
die "bracketing is not balanced: too many opening delimiters $type_msg\n";
}
confess "data structure for result values is corrupt in Apply() call (internal error)"
unless @{$self->{GROUPS}} == 1;
my @results = @{$self->{GROUPS}->[0]};
my $return_frame = pop @{$self->{CALLSTACK}};
die "call stack has been corrupted (internal error)"
unless $return_frame eq $frame;
return @results;
}
( run in 0.560 second using v1.01-cache-2.11-cpan-df04353d9ac )