寻求有关项目的建议。解析逻辑表达式
Posted
技术标签:
【中文标题】寻求有关项目的建议。解析逻辑表达式【英文标题】:Looking for advice on project. Parsing logical expression 【发布时间】:2011-11-14 03:43:02 【问题描述】:我正在就我的学校项目寻求一些建议。我应该创建一个程序,该程序采用逻辑表达式并为其输出真值表。对我来说,实际创建真值表一点也不难,而且我已经用 Java 为它编写了方法。我想知道java中是否有任何类可以用来为我解析表达式并将其放入堆栈中。如果不是,我正在寻求解析表达式的帮助。每当我尝试并仔细考虑时,括号都会让我受益匪浅。此外,如果这在任何其他语言中会更容易,我会愿意这样做。 Perl 可能是我最好的语言。
一些例子 (P && Q) -> R
(P || Q || R) && ((P -> R) -> Q)
【问题讨论】:
发布表达式,以便我们知道您在解析什么,您如何获得关于它的建议,我们顾问不知道格式 研究将表达式插入二叉树。它将充当表达式树,并且可以真正简化此任务。您只需要按顺序遍历并在到达运算符后评估每个表达式。 【参考方案1】:如果您被允许使用像 ANTLR 这样的解析器生成器工具,那么您可以从这里开始。简单逻辑语言的语法可能如下所示:
grammar Logic;
parse
: expression EOF
;
expression
: implication
;
implication
: or ('->' or)*
;
or
: and ('||' and)*
;
and
: not ('&&' not)*
;
not
: '~' atom
| atom
;
atom
: ID
| '(' expression ')'
;
ID : ('a'..'z' | 'A'..'Z')+;
Space : (' ' | '\t' | '\r' | '\n')+ $channel=HIDDEN;;
但是,如果您使用从上述语法生成的解析器来解析 (P || Q || R) && ((P -> R) -> Q)
之类的输入,则解析树将包含括号(解析表达式后您不感兴趣的东西)并且运算符不会每个子树的根,如果您有兴趣评估表达式,这不会让您的生活变得更轻松。
您需要告诉 ANTLR 从 AST 中省略某些标记(这可以通过在标记/规则之后放置 !
来完成)并使某些标记/规则成为他们的(子)树(这可以通过在其后放置^
来完成)。最后,您需要在语法的options
部分指出您希望创建正确的 AST 而不是简单的解析树。
所以,上面的语法应该是这样的:
// save it in a file called Logic.g
grammar Logic;
options
output=AST;
// parser/production rules start with a lower case letter
parse
: expression EOF! // omit the EOF token
;
expression
: implication
;
implication
: or ('->'^ or)* // make `->` the root
;
or
: and ('||'^ and)* // make `||` the root
;
and
: not ('&&'^ not)* // make `&&` the root
;
not
: '~'^ atom // make `~` the root
| atom
;
atom
: ID
| '('! expression ')'! // omit both `(` and `)`
;
// lexer/terminal rules start with an upper case letter
ID : ('a'..'z' | 'A'..'Z')+;
Space : (' ' | '\t' | '\r' | '\n')+ $channel=HIDDEN;;
您可以使用以下类测试解析器:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main
public static void main(String[] args) throws Exception
// the expression
String src = "(P || Q || R) && ((P -> R) -> Q)";
// create a lexer & parser
LogicLexer lexer = new LogicLexer(new ANTLRStringStream(src));
LogicParser parser = new LogicParser(new CommonTokenStream(lexer));
// invoke the entry point of the parser (the parse() method) and get the AST
CommonTree tree = (CommonTree)parser.parse().getTree();
// print the DOT representation of the AST
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
现在要运行Main
类,请执行以下操作:
*nix/MacOS
java -cp antlr-3.3.jar org.antlr.Tool Logic.g javac -cp antlr-3.3.jar *.java java -cp .:antlr-3.3.jar Main
窗口
java -cp antlr-3.3.jar org.antlr.Tool Logic.g javac -cp antlr-3.3.jar *.java java -cp .;antlr-3.3.jar Main
这将打印以下 AST 的 DOT source:
(使用graphviz-dev.appspot.com制作的图片)
现在所有您需要做的就是评估这个 AST! :)
【讨论】:
【参考方案2】:在 Perl 中,您可以使用 Regexp::Grammars
进行解析。它可能有点“手榴弹杀死蚂蚁”的一面,但它应该有效。
编辑:这是一个(非常快速的)示例,可能会让您继续前进。
#!/usr/bin/env perl
use strict;
use warnings;
use Regexp::Grammars;
use Data::Dumper;
my $parser = qr/
<nocontext:>
<Logic>
<rule: Logic> <[Element]>*
<rule: Element> <Group> | <Operator> | <Item>
<rule: Group> \( <[Element]>* \)
<rule: Operator> (?:&&) | (?:\|\|) | (?:\-\>)
<rule: Item> \w+
/xms; #/ #Fix Syntax Highlight
my $text = '(P && Q) -> R';
print Dumper \%/ if $text =~ $parser; #/ #Fix Syntax Highlight
【讨论】:
听起来不像上下文无关语法具有相同的表达能力。带括号的布尔表达式是上下文无关的 @Jochen,我确信这并没有使用可用的全部表达能力。我只根据需要使用这个模块。我不是专家。 @Jochen 的表达能力绝对不错,尽管如果你想找回任何理智的 AST,这是一种糟糕的解析方式。 @Jochen 我不想输入这个作为答案,但是使用 R::G 的更结构化的语法看起来像 gist.github.com/1207865 @hobbs,谢谢,正如我所说,我只用了足够多的 R::G 就可以了。你的好多了。【参考方案3】:查看 JavaCC 或 ANTLR。 正则表达式不起作用。
您也可以使用 StreamTokenizer 运行自己的解析器。
【讨论】:
【参考方案4】:构建表达式解析器很容易。在解析时附加操作以计算值也很容易。
我假设您可以为您的表达语言编写 BNF。
如果您有 BNF,此答案将向您展示如何轻松构建解析器。
Is there an alternative for flex/bison that is usable on 8-bit embedded systems?
【讨论】:
【参考方案5】:如果您想编写自己的解析器,请使用 Shunting-yard algorithm 通过将表达式从中缀转换为 postfix notation 或直接转换为树来去除括号。
【讨论】:
【参考方案6】:另一个 Java 解析器生成器是 CUP。
【讨论】:
以上是关于寻求有关项目的建议。解析逻辑表达式的主要内容,如果未能解决你的问题,请参考以下文章