我正在寻找关于我学校项目的一些建议。我应该创建一个程序,它采用逻辑表达式并为其输出真值表。实际上为我创建真值表并不困难,我已经用Java编写了这些方法。我想知道java中是否有任何类可以用来解析表达式并将其放入堆栈中。如果不是,我正在寻找解析表达式的帮助。每当我尝试思考它时,它就是括号。此外,如果在任何其他语言中这样做会更容易,我会愿意这样做。 Perl可能是我的下一个最佳语言。
一些例子 (P& Q) - > [R
(P || Q || R)&& ((P→R) - > Q)
答案 0 :(得分:11)
如果你被允许使用像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
类,请执行:
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! :)
答案 1 :(得分:4)
在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
答案 2 :(得分:1)
了解JavaCC或ANTLR。 正则表达式不起作用。
您也可以使用StreamTokenizer运行自己的解析器。
答案 3 :(得分:1)
构建表达式解析器很简单。在解析它时附加动作以计算值也很容易。
我假设您可以为您的表达语言编写BNF。
如果您有BNF,此答案将向您展示如何轻松构建解析器。
Is there an alternative for flex/bison that is usable on 8-bit embedded systems?
答案 4 :(得分:1)
如果您想编写自己的解析器,请使用Shunting-yard algorithm通过将表达式从中缀转换为postfix notation或直接转换为树来删除括号。
答案 5 :(得分:0)
另一个Java解析器生成器是CUP。