解析文本时是否有一个好的CPAN模块来实现状态机?

时间:2012-02-20 11:42:14

标签: perl parsing state-machine

解析文本时,我经常需要按照以下代码的通用格式实现迷你状态机。

是否有CPAN模块被认为是“最佳实践”并且非常适合以简单而优雅的方式实现这样的状态机逻辑?

我更喜欢没有Parse::RecDescent复杂的解决方案,但如果不存在,Parse::RecDescent比我想象的更容易应用于这个问题,我非常愿意考虑它而不是滚动我的就像我到目前为止一样。

示例通用解析代码:

my $state = 1;
while (my $token = get_next_token()) { # Usually next line
    if ($state == 1) {
        do_state1_processing();
        if (token_matches_transition_1_to_2($token)) {
            do_state_1_to_2_transition_processing();
            $state == 2;
            next;
        } elsif (token_matches_transition_1_to_4($token)) {
            do_state_1_to_4_transition_processing();
            $state == 4;
            next;
        } else {
             do_state1_continuation();
             next;
        }
    } elsif ($state == 5) {
        do_state5_processing();
        if (token_matches_transition_5_to_6($token)) {
            do_state_5_to_6_transition_processing();
            $state == 6;
            next;
        } elsif (token_matches_transition_5_to_4($token)) {
            do_state_5_to_4_transition_processing();
            $state == 4;
            next;
        } else {
             do_state5_continuation();
             next;
        }
    } else {

    }

}

4 个答案:

答案 0 :(得分:3)

我建议您查看MarpaMarpa::XS

只需看看this simple calculator

my $grammar = Marpa::XS::Grammar->new(
    {   start   => 'Expression',
        actions => 'My_Actions',
        default_action => 'first_arg',
        rules   => [
            { lhs => 'Expression', rhs => [qw'Term'] },
            { lhs => 'Term', rhs => [qw'Factor'] },
            { lhs => 'Factor', rhs => [qw'Number'] },
            { lhs => 'Term', rhs => [qw'Term Add Term'], action => 'do_add' },
            {   lhs    => 'Factor',
                rhs    => [qw'Factor Multiply Factor'],
                action => 'do_multiply'
            },
        ],
    }
);

您必须自己实施标记生成器。

答案 1 :(得分:2)

您可以使用Class::StateMachine

package Foo;
use parent 'Class::StateMachine';

sub new {
    my $class = shift;
    Class::StateMachine::bless {}, $class, 'state_1';
}

sub do_state_processing :OnState('state_1') {
  my $self = shift;
  if    (...) { $self->event_1 }
  elsif (...) { $self->event_2 }
  ...
}

sub do_state_processing :OnState('state_2') {
  ...
}

sub event_1 :OnState('state_1') {
  my $self = shift;
  $self->state('state_2');
}

sub event_2 :OnState('state_2') {
  my $self = shift;
  $self->state('state_3');
}

sub enter_state :OnState('state_1') {
  print "entering state 1";
  ...
}

sub enter_state :OnState('state_2') {
  ...
}

package main;

my $sm = Foo->new;
...
while (my $token = get_next_token()) {
  $sm->do_state_processing;
}

但是,特定于文本处理的模块可能更适合您的特定情况

答案 2 :(得分:1)

(在帮助下)几年前我写了一些名为Perl Formal Language Toolkit的内容,所以这可能会作为某种基础,但我认为你真正想要的是一个类似于Ragel Finite State Machine Compiler。不幸的是,它没有输出到Perl,并且我的后顾之二就是为Ragel实现Perl目标,并为我的位腐烂模块提供类似(但更多Perl导向)的功能。 / p>

答案 3 :(得分:0)

我写Parser::MGC主要是因为我发现尝试让Parse::RecDescent进行正确的错误报告非常困难,我不喜欢其奇怪的自定义嵌入式语法,包含perl代码的字符串引号,以及其他perl代码。 P::MGC程序只是perl代码;但写作类似于P::RD的语法结构的递归下降。