使用 Marpa:r2 perl 解析单引号字符串



如何使用Marpa:r2解析单引号字符串? 在下面的代码中,单引号字符串在解析时附加"\"。

法典:

use strict;
use Marpa::R2;
use Data::Dumper;

my $grammar = Marpa::R2::Scanless::G->new(
   {  default_action => '[values]',
      source         => (<<'END_OF_SOURCE'),
  lexeme default = latm => 1
:start ::= Expression
# include begin
Expression ::= Param
Param ::= Unquoted                                         
        | ('"') Quoted ('"') 
        | (') Quoted (')
:discard      ~ whitespace 
whitespace    ~ [s]+
Unquoted      ~ [^s/(),&:"~]+
Quoted        ~ [^s&:"~]+
END_OF_SOURCE
   });
my $input1 = 'foo';
#my $input2 = '"foo"';
#my $input3 = ''foo'';
my $recce = Marpa::R2::Scanless::R->new({ grammar => $grammar });
print "Trying to parse:n$input1nn";
$recce->read($input1);
my $value_ref = ${$recce->value};
print "Output:n".Dumper($value_ref);

输出的:

Trying to parse:
foo
Output:
$VAR1 = [
          [
            'foo'
          ]
        ];
Trying to parse:
"foo"
Output:
$VAR1 = [
          [
            'foo'
          ]
        ];
Trying to parse:
'foo'
Output:
$VAR1 = [
          [
            ''foo''
          ]
        ]; (don't want it to be parsed like this)

以上是所有输入的输出,我不希望第三个输入附加"\"和单引号。我希望它像OUTPUT2一样被解析。请指教。

理想情况下,它应该根据参数选择单引号之间的内容::= ('( 引用 ('(

关于 Data::D umper 输出的另一个答案是正确的。但是,您的语法并没有按照您期望的方式工作。

当你解析输入'foo'时,Marpa 会考虑三种Param备选方案。该位置的预测词素为:

  • Unquoted ~ [^s/(),&:"~]+
  • '"'
  • ') Quoted ('
是的,最后一个字面意思是 ) Quoted ( ,而不是任何包含单引号的内容。

即使它是([']) Quoted ([']):由于最长的标记匹配,无引号词法将匹配整个输入,包括单引号。

" foo "这样的输入(带双引号(会发生什么?现在,只有'"'词法匹配,然后丢弃任何空格,然后引用词素匹配,然后丢弃任何空格,然后匹配结束"

为了防止这种空格跳过行为并防止由于 LATM 而首选"不引号"规则,将带引号的字符串描述为词素是有意义的。例如:

Param ::= Unquoted | Quoted
Unquoted ~ [^'"]+
Quoted ~ DQ | SQ
DQ ~ '"' DQ_Body '"'  DQ_Body ~ [^"]*
SQ ~ ['] SQ_Body [']  SQ_Body ~ [^']*

然后,这些词素将包含任何引号和转义,因此您需要对词素内容进行后处理。您可以使用事件系统(在概念上很干净,但实现起来有点麻烦(来执行此操作,也可以添加在分析评估期间执行此处理的操作。

由于词素不能有动作,通常最好添加一个代理生产:

Param ::= Unquoted | Quoted
Unquoted ~ [^'"]+
Quoted ::= Quoted_Lexeme action => process_quoted
Quoted_Lexeme ~ DQ | SQ
DQ ~ '"' DQ_Body '"'  DQ_Body ~ [^"]*
SQ ~ ['] SQ_Body [']  SQ_Body ~ [^']*

然后,该操作可以执行以下操作:

sub process_quoted {
  my (undef, $s) = @_;
  # remove delimiters from double-quoted string
  return $1 if $s =~ /^"(.*)"$/s;
  # remove delimiters from single-quoted string
  return $1 if $s =~ /^'(.*)'$/s;
  die "String was not delimited with single or double quotes";
}

您的结果不包含',它包含'Dumper只是这样格式化结果,因此很清楚字符串中的内容和不的内容。

您可以自己测试此行为:

use Data::Dumper;
my $tick = chr(39);
my $back = chr(92);
print "Tick Dumper: " . Dumper($tick);
print "Tick Print:  " . $tick . "n";
print "Backslash Dumper: " . Dumper($back);
print "Backslash Print:  " . $back . "n";

您可以在此处查看演示:https://ideone.com/d1V8OE

如果不希望输出包含单引号,则可能需要自行将其从输入中删除。

我对Marpa::R2不太熟悉,但是您能否尝试对Expression规则进行操作:

Expression ::= Param action => strip_quotes

然后,实现一个简单的报价剥离器,如下所示:

sub MyActions::strip_quotes {
    @{$_[1]}[0] =~ s/^'|'$//gr;
}

相关内容

  • 没有找到相关文章

最新更新