【问题标题】:Parsing of a logical expression and converting it to a tree in Perl解析逻辑表达式并将其转换为 Perl 中的树
【发布时间】:2010-12-23 10:07:46
【问题描述】:

我的复杂逻辑表达式如下所示:

((((!((cond1) || (cond2) || (cond3)) && (cond4))) && (cond5)) <= (((cond6) || (cond7) || (cond8)) || (cond9)))

每一行都有几十个表达式。允许的逻辑符号为||&amp;&amp;!&lt;=&lt;= 表示导引,如a &lt;= b表示b 导引a。

我需要检查这些语句并检查条件,因为其中一些不再有效。我希望能够将它解析为一棵树,然后检查它的每个叶子(每个叶子都是一个条件),删除不需要的叶子并重新构建完整和正确的表达式。

我知道树的每个节点都是由一对第一个括号和关闭它的括号定义的,但我不知道如何识别这些对以及如何识别它们之间的逻辑符号。

! 之外的所有符号都位于两个表达式之间。

【问题讨论】:

  • 这些表达式是 perl 还是其他语言?是否只用于一次代码清理?
  • 它不在 Perl 中,它是一个 .va 文件,我不确定它是什么语言。我想写一个 Perl 脚本来解析它们。
  • 你说得对,你应该使用正式的语法来解决你的问题。

标签: perl parsing logic


【解决方案1】:

听起来像是Parse::RecDescent 的案例:

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

my $text = '((((!((cond1) || (cond2) || (cond3)) && (cond4))) && (cond5)) <= (((cond6) || (cond7) || (cond8)) || (cond9)))';

#$::RD_TRACE=1;

my $grammar = q{

startrule: expr

expr: operand operation(s?)
    { $return = @{$item[2]} ? { 'operations' => $item[2], 'lvalue' => $item[1] } : $item[1] }

operation: /\|\||&&|<=/ operand
    { $return = { 'op' => $item[1], 'rvalue' => $item[2] } }

operand: '(' expr ')'
    { $return = $item[2] }

operand: '!' operand
    { $return = { 'op' => '!', 'value' => $item[2] } }

operand: /\w+/

};

my $parser = Parse::RecDescent->new($grammar);
my $result = $parser->startrule($text) or die "Couldn't parse!\n";

use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
print Dumper $result;

语法,英文:

整个事情都是一个表达。表达式是一个操作数,后跟零个或多个二元运算符及其操作数。每个操作数都是带括号的表达式,“!”后跟一个操作数或一个单词(例如cond1)。

生成树中的每个节点都采用以下形式之一:

  • cond1 - 一个条件
  • { 'op' =&gt; '!', 'value' =&gt; 'node' } - !应用于另一个节点
  • { 'lvalue' =&gt; 'node', 'operations' =&gt; [ one or more of: { 'op' =&gt; 'binop', 'rvalue' =&gt; 'node' } ] } - 一系列一个或多个操作,代表节点 binop 节点 binop 节点 ...

我没有将一系列二元运算(例如((cond1) || (cond2) || (cond3)))分解成二叉树,因为您没有提供有关优先级或关联性的信息。

您的示例的输出是:

$VAR1 = {
  'lvalue' => {
    'lvalue' => {
      'lvalue' => {
        'op' => '!',
        'value' => {
          'lvalue' => 'cond1',
          'operations' => [
            {
              'op' => '||',
              'rvalue' => 'cond2'
            },
            {
              'op' => '||',
              'rvalue' => 'cond3'
            }
          ]
        }
      },
      'operations' => [
        {
          'op' => '&&',
          'rvalue' => 'cond4'
        }
      ]
    },
    'operations' => [
      {
        'op' => '&&',
        'rvalue' => 'cond5'
      }
    ]
  },
  'operations' => [
    {
      'op' => '<=',
      'rvalue' => {
        'lvalue' => {
          'lvalue' => 'cond6',
          'operations' => [
            {
              'op' => '||',
              'rvalue' => 'cond7'
            },
            {
              'op' => '||',
              'rvalue' => 'cond8'
            }
          ]
        },
        'operations' => [
          {
            'op' => '||',
            'rvalue' => 'cond9'
          }
        ]
      }
    }
  ]
};

【讨论】:

  • 如果您使用 Perl 5.10 或更高版本,您还应该考虑 Regexp::Grammars,它是 Parse::RecDescent 的继承者。
  • 您能否解释一下它的作用,以及它以什么格式返回结果。我需要操作数据,但我不明白如何访问它。
  • @Ilya Melamed:我希望它是不言自明的,但我添加了一个解释尝试。
猜你喜欢
  • 2011-03-29
  • 2020-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
相关资源
最近更新 更多