我以一种虚拟语言为例:它只接受一个或多个“!”。它的词法分析器和语法规则是:
grammar Ns;
options {
output=AST;
ASTLabelType=CommonTree;
}
tokens {
NOTS;
}
@header {
package test;
}
@lexer::header {
package test;
}
ns : NOT+ EOF -> ^(NOTS NOT+);
NOT : '!';
Run Code Online (Sandbox Code Playgroud)
好的,如您所见,这代表一种接受“!”的语言 或者 '!!!' 或者 '!!!!!'...
我定义了一些有意义的类来构建 AST:
public class Not {
public static final Not SINGLETON = new Not();
private Not() {
}
}
public class Ns {
private List<Not> nots;
public Ns(String nots) {
this.nots = new ArrayList<Not>();
for (int i = 0; i < nots.length(); i++) …Run Code Online (Sandbox Code Playgroud) 我已经阅读了很多试图找到一种方法来干净地使用ANTLR的树语法中的列表.这是我尝试过的和他们的结果(我真的希望我错过了一些微不足道的事情)......
使用+ =语法
program returns [someInterface result]
: m+=method* EOF {result = new SomeClass(m);};
method returns [SomeMethod result] : <definition here>
Run Code Online (Sandbox Code Playgroud)
这失败了......
规则'+ ='列表标签不允许没有输出选项
如果我将输出设置为"AST"或"template"(唯一选项),则生成的类的方法签名会更改.也就是说,m不是由SomeMethod列表,而是分别是节点或模板列表.如果有办法使这种方法有效,我愿意接受建议.
使用规则范围
program returns [CompilesToJavaByteCode result]
scope {
List<SomeMethod> methods;
}
@init {
$program::methods = new ArrayList<SomeMethod>();
}
: (m=method {$program::methods.add(m);})*
EOF {result = new SomeClass($program::methods);};
Run Code Online (Sandbox Code Playgroud)
这似乎有效,但我承认我还没有用嵌套/递归的情况测试它.
最终目标
我想构建一组代表我的语言的类(Class,Method,Variable,Statement,ect),这样我就可以在生成编译代码之前做一些静态分析和优化.为此,我需要能够使用列表.我希望+ =语法"正常工作",但我可能会遗漏一些东西.第二种方法有效,但看起来过于冗长和不优雅.
问题
在ANTLR的树语法中使用列表传递给我的具体类的原因是什么?
我有一个令牌 OR:'OR'; 我用于评估布尔表达式(a==b OR a==c)我有另一个规则来解析字符列表AZ,AK,OR,GA中的状态缩写......我发现的是antlr在状态列表上有错误认为 OR 应该是一个or标记而不是
stateName
: CHAR CHAR (','|EOF) ->^(STATE CHAR+)
;
Run Code Online (Sandbox Code Playgroud)
我将如何解决这种歧义?
这是我试图解析的一些规则
这是我正在使用的语法
grammar PointFieldRule;
options
{
//language = 'CSharp3';
output=AST;
ASTLabelType=CommonTree;
}
tokens{
STATE;
}
rule : ifExpression? actionExpression EOF!
;
ifExpression
:'IF'! logicalConditionExpression
;
logicalConditionExpression
: booleanAndConditionExpression ( BigOR^ booleanAndConditionExpression)*
;
booleanAndConditionExpression
: logicalCondition ( BigAND^ logicalCondition )*
;
BigAND …Run Code Online (Sandbox Code Playgroud) 我有以下语法:
rule: 'aaa' | 'a' 'a';
Run Code Online (Sandbox Code Playgroud)
它可以成功解析字符串'aaa',但它无法解析'aa'并出现以下错误:
line 1:2 mismatched character '<EOF>' expecting 'a'
Run Code Online (Sandbox Code Playgroud)
仅供参考,这是词法分析器的问题而不是解析器,因为我甚至没有调用解析器.主要功能如下:
@members {
public static void main(String[] args) throws Exception {
RecipeLexer lexer = new RecipeLexer(new ANTLRInputStream(System.in));
for (Token t = lexer.nextToken(); t.getType() != EOF; t = lexer.nextToken())
System.out.println(t.getType());
}
}
Run Code Online (Sandbox Code Playgroud)
结果与更明显的版本相同:
rule: AAA | A A;
AAA: 'aaa';
A: 'a';
Run Code Online (Sandbox Code Playgroud)
显然,ANTLR词法分析器尝试将输入'aa'与失败的规则AAA匹配.除了ANTLR是一个LL(*)解析器或其他什么,词法分析器应该与解析器分开工作,它应该能够解决歧义.语法在良好的旧lex(或flex)下运行良好,但在ANTLR中似乎没有.那么这里的问题是什么?
谢谢您的帮助!
我是ANTLR的新手,我正在尝试扩展这里提供的简单计算器的例子.具体来说,我尝试添加一些简单的函数,负数等,以熟悉自己的ANTLR.但是,我在尝试实现"隐式"乘法时遇到了一些问题(例如,3cos(2)sin(2)将被解释为3*cos(2)*sin(2)).
我在Stack Overflow上发现了一个同样问题的问题(这里).解决这个问题的一般形式看起来就像我自己找到的那样,所以我不确定我的问题在哪里.
我的语法如下.如果没有这| p2 = signExpr {$value *= $p2.value;}条线(最后一条线multiplicationExpr),根据我的测试,一切似乎都能正常工作.当我添加此行并运行它时antlr,我收到以下错误:
error(211): calculator.g:24:3: [fatal] rule multiplicationExpr has non-LL(*) decision due to recursive rule invocations reachable from alts 3,4. Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
warning(200): calculator.g:24:3: Decision can match input such as "'-' FLOAT" using multiple alternatives: 3, 4
As a result, alternative(s) 4 were disabled for that input
Run Code Online (Sandbox Code Playgroud)
backtrack为我的一些(通常正常工作的)测试表达式启用错误计算结果.此外,警告谈论替代方案3和4 multiplicationExpr,但我只有三个替代方案,让我感到困惑.
有人能够指出我的语法中的错误,如下所示?
grammar calculator; …Run Code Online (Sandbox Code Playgroud) 在研究用于 Java 解析的 Antlr 3.5 语法时,注意到“ IDENTIFIER ”规则在 ANTLR 词法分析器语法中消耗了很少的关键字。词法分析器语法是
lexer grammar JavaLexer;
options {
//k=8;
language=Java;
filter=true;
//backtrack=true;
}
@lexer::header {
package java;
}
@lexer::members {
public ArrayList<String> keywordsList = new ArrayList<String>();
}
V_DECLARATION
:
( ((MODIFIERS)=>tok1=MODIFIERS WS+)? tok2=TYPE WS+ var=V_DECLARATOR WS* )
{...};
fragment
V_DECLARATOR
:
(
tok=IDENTIFIER WS* ( ',' | ';' | ASSIGN WS* V_VALUE )
)
{...};
fragment
V_VALUE
: (IDENTIFIER (DOT WS* IDENTIFIER WS* '(' | ',' | ';'))
;
MODIFIERS
:
(PUBLIC | …Run Code Online (Sandbox Code Playgroud) 下面的ANTLR语法中的'expr'规则显然是相互左递归的.作为一名ANTLR新手,很难解决这个问题.我在ANTLR参考书中读过"解决非LL(*)冲突",但我仍然没有看到解决方案.有什么指针吗?
LPAREN : ( '(' ) ;
RPAREN : ( ')' );
AND : ( 'AND' | '&' | 'EN' ) ;
OR : ( 'OR' | '|' | 'OF' );
NOT : ('-' | 'NOT' | 'NIET' );
WS : ( ' ' | '\t' | '\r' | '\n' ) {$channel=HIDDEN;} ;
WORD : (~( ' ' | '\t' | '\r' | '\n' | '(' | ')' | '"' ))*;
input : expr EOF;
expr : (andexpr | orexpr … 我无法搞清楚antlr3 API,所以我可以在一些javascript代码中生成并使用解析树.当我使用antlrWorks(他们的IDE)打开语法文件时,解释器能够向我显示解析树,它甚至是正确的.
我在使用antlr3运行时跟踪有关如何在我的代码中获取此解析树的资源时遇到很多困难.我一直在搞乱运行时和Parser文件中的各种函数,但无济于事:
var input = "(PR=5000)",
cstream = new org.antlr.runtime.ANTLRStringStream(input),
lexer = new TLexer(cstream),
tstream = new org.antlr.runtime.CommonTokenStream(lexer),
parser = new TParser(tstream);
var tree = parser.query().tree;
var nodeStream = new org.antlr.runtime.tree.CommonTreeNodeStream(tree);
nodeStream.setTokenStream(tstream);
parseTree = new org.antlr.runtime.tree.TreeParser(nodeStream);
Run Code Online (Sandbox Code Playgroud)
由于antlrWorks可以显示解析树而不需要我自己的任何树语法,并且因为我已经读过antlr自动从语法文件生成一个解析树,我假设我可以使用一些运行时函数来访问这个基本的解析树.可能没有意识到.我这个想法是否正确?
在ANTLR版本3中,如何在高级树解析器规则的@init操作中获取行号?
例如,在下面的@init操作中,我想将行号与句子文本一起推送.
sentence
@init { myNodeVisitor.pushScriptContext( new MyScriptContext( $sentence.text )); }
: assignCommand
| actionCommand;
finally {
m_nodeVisitor.popScriptContext();
}
Run Code Online (Sandbox Code Playgroud)
我需要在执行与规则中的符号相关联的操作之前推送上下文.
有些事情,不工作:
$sentence.line- 它没有定义,即使$sentence.text是.getTreeNodeStream().getTreeAdaptor().getToken( $sentence.start ).getLine(). 编辑: 实际上,这确实有效,如果$ sentence.start要么是真实的令牌,要么带有参考的虚构 - 请参阅下面的Bart Kiers答案.似乎我可以很容易地在@init规则中获得匹配的文本和第一个匹配的标记,因此应该有一种简单的方法来获取行号.
有没有人有一个如何设置sbt来构建一个ANTLR文件(到scala),然后编译生成的代码的例子.
我的文件布局
src/main/scala/Test.scala // scala test rig
src/main/scala/Test.g // antlr grammar
build/antlr/TestParser.scala // antlr output files
build/antlr/TestLexer.scala
Run Code Online (Sandbox Code Playgroud)
我的sbt应该包含什么?我知道有一个插件用于拉动ANTLR的规则,但我无法使其工作.(这个世界还是新手)
antlr3 ×10
antlr ×9
antlrworks ×2
java ×2
c# ×1
grammar ×1
lex ×1
lexer ×1
parse-tree ×1
parsing ×1
sbt ×1
scala ×1
tokenize ×1
tree-grammar ×1