ANTLR中的“semantic predicate”是什么?
ANTLR 4
对于ANTLR 4中的谓词,请检查以下堆栈溢出的问答:
Antlr4中语义谓词的语法
ANTLR4中的语义谓词?
ANTLR 3
甲语义谓词是执行在使用时的明码语法操作的额外(语义)规则的方法。
语义谓词有3种类型:
语法范例
假设您有一小段文字,只包含用逗号分隔的数字,而忽略了任何空格。您想解析此输入,以确保数字最多为3个数字“长”(最多为999)。以下语法(Numbers.g
)可以做到这一点:
grammar Numbers;
// entry point of this parser: it parses an input string consisting of at least
// one number, optionally followed by zero or more comma's and numbers
parse
: number (',' number)* EOF
;
// matches a number that is between 1 and 3 digits long
number
: Digit Digit Digit
| Digit Digit
| Digit
;
// matches a single digit
Digit
: '0'..'9'
;
// ignore spaces
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
测验
可以使用以下类来测试语法:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
NumbersLexer lexer = new NumbersLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
NumbersParser parser = new NumbersParser(tokens);
parser.parse();
}
}
通过生成词法分析器和解析器,编译所有.java文件并运行Main类来对其进行测试:
java -cp antlr-3.2.jar org.antlr.Tool Numbers.g
javac -cp antlr-3.2.jar * .java
java -cp。:antlr-3.2.jar Main
这样做时,不会在控制台上打印任何内容,这表示没有错。尝试更改:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
变成:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7777 , 89");
并再次进行测试:您将在控制台上在string后面紧接出现错误777。
语义谓词
这将我们带入语义谓词。假设您要解析1到10位数字之间的数字。规则如下:
number
: Digit Digit Digit Digit Digit Digit Digit Digit Digit Digit
| Digit Digit Digit Digit Digit Digit Digit Digit Digit
/* ... */
| Digit Digit Digit
| Digit Digit
| Digit
;
会很麻烦。语义谓词可以帮助简化此类规则。
1.验证语义谓词
一个验证语义谓词无非是跟着一个问号的代码块:
RULE { /* a boolean expression in here */ }?
要使用验证 语义谓词解决以上问题number,请将语法规则更改为:
number
@init { int N = 0; }
: (Digit { N++; } )+ { N <= 10 }?
;
部分{ int N = 0; }
和{ N++; }
是纯Java语句,当解析器“输入”number规则时,第一个语句将初始化。实际的谓词是:{ N <= 10 }
?,FailedPredicateException
只要数字长于10位数字,解析器就会抛出a 。
使用以下命令进行测试ANTLRStringStream:
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
不会产生异常,而以下内容会引发异常:
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
2.门控语义谓词
阿门控语义谓词类似于验证语义谓词,只有门控版本产生的一个语法错误代替FailedPredicateException
。
门控语义谓词的语法为:
{ /* a boolean expression in here */ }?=> RULE
要改为使用门控谓词来解决最长10位数字的匹配问题,您可以编写以下代码:
number
@init { int N = 1; }
: ( { N <= 10 }?=> Digit { N++; } )+
;
再次对它们进行测试:
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
和:
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
您会看到最后一个会抛出错误。
3.消除语义谓词的歧义
谓词的最后一种类型是歧义语义谓词,它看起来有点像验证谓词({boolean-expression}?),但更像是门控语义谓词(当布尔表达式计算为时,不会引发异常false)。您可以在规则开始时使用它来检查规则的某些属性,并让解析器匹配所述规则。
假设示例语法创建了Number令牌(用词法分析器规则而不是解析器规则),这些令牌将匹配0..999范围内的数字。现在在解析器中,您要区分高低数字(低:0..500,高:501..999)。可以使用歧义语义谓词来完成此操作,在该谓词中,您可以检查流(input.LT(1))中下一个标记,以检查标记的高低。
演示:
grammar Numbers;
parse
: atom (',' atom)* EOF
;
atom
: low {System.out.println("low = " + $low.text);}
| high {System.out.println("high = " + $high.text);}
;
low
: {Integer.valueOf(input.LT(1).getText()) <= 500}? Number
;
high
: Number
;
Number
: Digit Digit Digit
| Digit Digit
| Digit
;
fragment Digit
: '0'..'9'
;
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
如果现在解析该字符串”123, 999, 456, 700, 89, 0”,则将看到以下输出:
low = 123
high = 999
low = 456
high = 700
low = 89
low = 0
问题内容: 在利用ANTLR 3.3的过程中,我正在更改当前语法以支持不带括号的输入。这是我的语法的第一个版本: 然后我以这种方式更改了它以支持适当的功能: 但是我一直面临以下错误: 有人知道我该如何克服这个错误? 问题答案: 您的令牌: 无效:您无法在lexer规则中匹配空字符串。 要匹配epsilon(什么都没有),您应该执行以下操作: 当然,可以安全删除评论。 请注意,当您按照当前语法那样进
ANTLR语法中解析器和词法分析器规则的调用顺序是什么?例如,在以下语法中,输入 223 始终标识为APLHANUMERIC而不是数字
所有:我正在尝试编写一个antlr解析器来解析一些文本,这些文本的格式如下: 基本上,所有行都有一个前导来指示一行文本的用途,最后一行应该以结尾,以指示这类行的结尾。文本也可以是任何东西。最后我需要的是文本。 我为此写了一个Antlr语法: 这里的思想是,当看到第一个RP_HEADER时,它会更改为RP_FREE_TEXT_MODE并因此跳过行间的任何RP_HEADER。当看到DOT_NEWLIN
刚学antlr,最简单的这个antlr应该是实现加减乘除法,但是一直报语法错误 有没有懂的大佬指教下!
ANTLR(ANother Tool for Language Recognition)它是Java开发的词法分析工具,它可以接受词文法语言描述,并能产生识别这些语言的语句的程序。作为翻译程序的一部分,你可以使用简单的操 作符和动作来参数化你的文法,使之告诉ANTLR怎样去创建抽象语法树(AST)和怎样产生输出。ANTLR知道怎样去生成识别程序,语言包括 Java,C++,C#. Hibernat
我有一个使用antlr插件的gradle 3.1 dagger2 antlr4项目。我在gradle idea插件和Intellij注释处理选项中配置了一个特定的生成源目录。如果我在Intellij 2016.2.4中构建它,dagger2生成的源将复制到build/generated src/antlr/main目录以及我配置的src/main/generated目录中。究竟为什么要将非Antl