gpt4 book ai didi

java - ANTLR - 语法和树语法之间的 token 枚举不匹配

转载 作者:搜寻专家 更新时间:2023-11-01 03:11:48 24 4
gpt4 key购买 nike

背景

我正在尝试使用 AntlrWorks 编写一个简单的语法,用于测试值集是否存在(或不存在)指定元素的 boolean 方程。我已经创建了一个组合的词法分析器/解析器语法来生成所需的 AST。我还编写了一个似乎有效的对应树语法(通过 AntlrWorks 的调试功能)。


问题

但是,当我尝试在测试程序(即同一程序中的 lex、parse 和 tree parse)中将两者连接在一起时,我得到如下错误...

node from line 1:5 required (...)+ loop did not match anything at input 'and'

node from after line 1:8 mismatched tree node: UP expecting <DOWN>

作为完整性测试,我让测试程序输出 toStringTree() 的结果来自生成的 AST 和 toTokenTypeString()来自结果 TreeNodeStream .

我发现 TreeNodeStream 的枚举 token 类型值不匹配自动生成的树语法代码中的枚举标记类型值。


示例

  • 示例输入:"true and false"

  • 解析器提供的树中 toStringTree() 的输出:(and true false)

  • toTokenTypeString() 的输出来自包含上述 AST 的 TreeNodeStream:19 2 22 20 3 8

那个 token 流应该是AND <DOWN> 'true' 'false' <UP> NEWLINE但是 TreeParser 将其视为 CLOSEPAREN <DOWN> OR 'false' <UP> OPENPAREN (基于查看节点 token 类型输出并根据树语法中定义的枚举检查它)并抛出错误

1:5 required (...)+ loop did not match anything at input 'and'


底线

为什么我的树解析器没有设置为正确识别我的 AST?

以下是我的来源。对于我一定犯下的愚蠢错误,我很感激任何反馈:)

词法分析器/解析器语法

grammar INTc;

options {
output=AST;
ASTLabelType=CommonTree;
}

tokens {
OR='or';
AND='and';
NOT='not';
ALLIN='+';
PARTIN='^';
NOTIN='!';
SET;
OPENPAREN='(';
CLOSEPAREN=')';
OPENSET='{';
CLOSESET='}';
}
@header {
package INTc;
}

@lexer::header {
package INTc;
}

@members {
}

/**Begin Parser Rules*/
prog: stat+ ;

stat: expr
| NEWLINE
;

expr
: orExpr
;

orExpr returns [boolean value]
: a=andExpr(OR^ b=andExpr)*
;

andExpr returns [boolean value]
: a=notExpr (AND^ b=notExpr)*
;

notExpr returns [boolean value]
: a=atom
| '!' a=atom -> ^(NOT atom)
;

atom returns [boolean value]
: ALLIN OPENSET ((INT)(','INT)*) CLOSESET -> ^(ALLIN ^(SET INT+))
| PARTIN OPENSET ((INT)(','INT)*) CLOSESET -> ^(PARTIN ^(SET INT+))
| NOTIN OPENSET ((INT)(','INT)*) CLOSESET -> ^(NOTIN ^(SET INT+))
| TIMERANGE
| OPENPAREN! e=expr CLOSEPAREN!
| 'true'
| 'false'
;

/**Begin Lexer Rules*/
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ;
DIGIT : ('0'..'9');
INT : DIGIT+ ;
NEWLINE : '\r'? '\n' ;
WS : ( ' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
COMMENT
: '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
| '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
;

树语法

tree grammar INTcWalker;

options {
tokenVocab=INTc;
ASTLabelType=CommonTree;
}

@header {
package INTc;
import java.util.ArrayList;
import java.util.Arrays;
}

@members {
ArrayList<String> intSet;
boolean isFit = false;

public boolean getResult() {
return isFit;
}
public void setINTSet(ArrayList newSet) {
intSet = newSet;
isFit = false;
}
public ArrayList getINTSET(){return intSet;}
}

prog
: stat+
;
stat
: expr {
isFit = $expr.value;
//System.out.println(isFit);
}
| NEWLINE {}
;
expr returns [boolean value]
: ^(OR a=expr b=expr){}
| ^(AND a=expr b=expr){}
| ^(NOT a=expr){}
| ^(ALLIN ^(SET INT+)){}
| ^(PARTIN ^(SET INT+)){}
| ^(NOTIN ^(SET INT+)){}
| 'true' {$value = true;}
| 'false' {$value = false;}
;

测试程序

public class setTest {

public static void main(String args[]) throws Exception {
INTcLexer lex = new INTcLexer(new ANTLRFileStream("input.txt"));
CommonTokenStream tokens = new CommonTokenStream(lex);

INTcParser parser = new INTcParser(tokens);
INTcParser.prog_return r = parser.prog();
CommonTree t = (CommonTree)r.getTree();
CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
INTcWalker evaluator = new INTcWalker(nodes);

System.out.println(t.toStringTree());

System.out.println(nodes.toTokenTypeString());
nodes.reset();

try {
evaluator.prog();
} catch (RecognitionException e) {
e.printStackTrace();
}

System.out.println(evaluator.getResult());

}
}

最佳答案

如果我使用您的组合语法和树语法来创建词法分析器、解析器和树遍历器类,并运行以下类:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;

public class Main {
public static void main(String args[]) throws Exception {
INTcLexer lex = new INTcLexer(new ANTLRStringStream("true and false\n"));
CommonTokenStream tokens = new CommonTokenStream(lex);
INTcParser parser = new INTcParser(tokens);

CommonTree t = (CommonTree)parser.prog().getTree();
CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
INTcWalker evaluator = new INTcWalker(nodes);

System.out.println(t.toStringTree());

CommonTree tr;
while(true) {
Token token = ((CommonTree)nodes.nextElement()).getToken();
if(token.getType() == INTcParser.EOF) break;
System.out.printf("%-10s '%s'\n", INTcParser.tokenNames[token.getType()], token.getText());
}

System.out.println("\nresult=" + evaluator.getResult());
}
}

以下内容打印到控制台:

(and true false) 

AND 'and'
<DOWN> 'DOWN'
'true' 'true'
'false' 'false'
<UP> 'UP'
NEWLINE '
'

result=false

即:我看到了预期的输出:

  • 树没问题((和 true false));
  • CommonTreeNodeStream 包含适当的标记(或更好:树);
  • 正确的值 false 正在打印,解析器或树遍历器没有任何错误。

一些提示:

  • 'true''false' 创建标记(即 TRUE='true'; ...);<
  • 不要在树语法中使用文字(不是'true',而是TRUE);
  • 使 DIGIT 成为一个 fragment 规则,这样它就永远不会成为自己的标记,而只会在 INT(或其他词法分析器规则)。只需将关键字 fragment 放在其前面即可;
  • .*.+ 默认都是不贪婪的,因此您可以删除 options greedy=false;} :.<

关于java - ANTLR - 语法和树语法之间的 token 枚举不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8437855/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com