perl - 使用 Parse::RecDescent 解析带有嵌套括号的字符串

标签 perl parsing parentheses parse-recdescent

我正在尝试使用 Parse::RecDescent制作一个可以解析括号表达式和一元运算符 ? 的解析器。

到目前为止,我在创建解析器时失败了,因为规则 expression 是左递归的:

use strict;
use warnings;
use Parse::RecDescent;

my $test = <<END;
((foo)? bar)
END

my $grammar = q(
    parse: expression(s)
    expression: string | parend | expression(s)
    parend : "(" (string | expression) ")" /\??/
    string : /\w+/ /\??/

);
my $parser = Parse::RecDescent->new($grammar);
my $result = $parser->parse($test);
if($result){
    print $result;
}else{
    print STDERR "Invalid grammar\n";
}

最佳答案

首先,您从最低优先级到最高优先级。

parse  : expr /\Z/

expr   : list

list   : unary(s?)

unary  : unary '?'
       | term

term   : '(' expr ')'
       | STRING

STRING : /\w+/

当然,

unary  : unary '?'
       | term

不起作用,因为它是左递归的。 Operator Associativity and Eliminating Left-Recursion in Parse::RecDescent可以帮助你摆脱它。我们得到

unary  : term unary_(s?)
unary_ : '?'

但这不会为我们构建正确的树。因此,让我们从展开“(s?)”开始。

unary  : term unary_
unary_ : '?' unary_
       |

然后我们可以使用子规则参数来创建正确的树。

unary  : term unary_[ $item[1] ]
unary_ : '?' unary_[ [ 'postfix?' => $arg[0] ] ]
       | { $arg[0] }

一起:

use strict;
use warnings;
use Data::Dumper      qw( Dumper );
use Parse::RecDescent qw( );

my $grammar = <<'END';
   {
      use strict;
      use warnings;
   }

   parse  : expr /\Z/ { $item[1] }

   expr   : list

   list   : unary(s?) { [ $item[0] => @{ $item[1] } ] }

   unary  : term unary_[ $item[1] ]
   unary_ : '?' unary_[ [ 'postfix?' => $arg[0] ] ]
          | { $arg[0] }

   term   : '(' expr ')' { $item[2] }
          | STRING { [ string => $item[1] ] }

   STRING : /\w+/

END

my $parser = Parse::RecDescent->new($grammar)
   or die "Invalid grammar\n";
my $tree = $parser->parse("((foo bar)? baz)\n")
   or die "Invalid text\n";
print(Dumper($tree));

关于perl - 使用 Parse::RecDescent 解析带有嵌套括号的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11350898/

相关文章:

php - 使用哪种后端网络编程语言

linux - linux 支持 win32::OLE 吗?

c - 访问不带括号的函数指针

c++ - 自动修复 C 中缺少的括号

c++ - 向构造函数调用添加括号会导致 xlc C++ 编译器出现重复参数错误

perl - 在网站上解析和显示 MIME 多部分电子邮件

perl - Perl 是否在当前目录 (.) 中查找模块?

c# - 当 TextFieldParser 抛出错误时,如何从它捕获有问题的行?

python - 在Python中,如何检查一个字符串以查看其中是否包含另一个字符串的任何组合?

python - 是否有一个 Python 模块可以从 crontab 样式的时间定义中获取下一个运行时?