- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个像这样的语法(任何看起来复杂的东西都是因为它是实际语法的子集,其中包含更多红鲱鱼):
grammar Query;
startExpression
: WS? expression WS? EOF
;
expression
| maybeDefaultBooleanExpression
;
maybeDefaultBooleanExpression
: defaultBooleanExpression
| queryFragment
;
defaultBooleanExpression
: nested += queryFragment (WS nested += queryFragment)+
;
queryFragment
: unquotedQuery
| quotedQuery
;
unquotedQuery
: UNQUOTED
;
quotedQuery
: QUOTED
;
UNQUOTED
: UnquotedStartChar
UnquotedChar*
;
fragment
UnquotedStartChar
: EscapeSequence
| ~( ' ' | '\r' | '\t' | '\u000C' | '\n' | '\\' | ':'
| '"' | '\u201C' | '\u201D' // DoubleQuote
| '\'' | '\u2018' | '\u2019' // SingleQuote
| '(' | ')' | '[' | ']' | '{' | '}' | '~'
| '&' | '|' | '!' | '^' | '?' | '*' | '/' | '+' | '-' | '$' )
;
fragment
UnquotedChar
: EscapeSequence
| ~( ' ' | '\r' | '\t' | '\u000C' | '\n' | '\\' | ':'
| '"' | '\u201C' | '\u201D' // DoubleQuote
| '\'' | '\u2018' | '\u2019' // SingleQuote
| '(' | ')' | '[' | ']' | '{' | '}' | '~'
| '&' | '|' | '!' | '^' | '?' | '*' )
;
QUOTED
: '"'
QuotedChar*
'"'
;
fragment
QuotedChar
: ~( '\\'
| | '\u201C' | '\u201D' // DoubleQuote
| '\r' | '\n' | '?' | '*' )
;
WS : ( ' ' | '\r' | '\t' | '\u000C' | '\n' )+;
如果我直接调用词法分析器:
CharStream input = CharStreams.fromString("A \"");
QueryLexer lexer = new QueryLexer(input);
lexer.removeErrorListeners();
CommonTokenStream tokens = new CommonTokenStream(lexer);
System.out.println(tokens.LT(0));
System.out.println(tokens.LT(1));
System.out.println(tokens.LT(2));
System.out.println(tokens.LT(3));
我得到:
java.lang.StringIndexOutOfBoundsException: String index out of range: 4
at java.lang.String.checkBounds(String.java:385)
at java.lang.String.<init>(String.java:462)
at org.antlr.v4.runtime.CodePointCharStream$CodePoint8BitCharStream.getText(CodePointCharStream.java:160)
at org.antlr.v4.runtime.Lexer.notifyListeners(Lexer.java:360)
at org.antlr.v4.runtime.Lexer.nextToken(Lexer.java:144)
at org.antlr.v4.runtime.BufferedTokenStream.fetch(BufferedTokenStream.java:169)
at org.antlr.v4.runtime.BufferedTokenStream.sync(BufferedTokenStream.java:152)
at org.antlr.v4.runtime.CommonTokenStream.LT(CommonTokenStream.java:100)
这在某种程度上是有道理的,尽管我认为适当的 ANTLR 异常(exception)可能会更好。
不过,我真正不明白的是,当我通过完整的解析器提供它时:
QueryParser parser = new QueryParser(tokens);
parser.removeErrorListeners();
parser.addErrorListener(LoggingErrorListener.get());
parser.setErrorHandler(new BailErrorStrategy());
// Performance hack as per the ANTLR v4 FAQ
parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
ParseTree expression;
try
{
expression = parser.startExpression();
}
catch (Exception e)
{
// It catches a StringIndexOutOfBoundsException here.
parser.reset();
parser.getInterpreter().setPredictionMode(PredictionMode.LL);
expression = parser.startExpression();
}
我得到:
tokens = {org.antlr.v4.runtime.CommonTokenStream@1811}
channel = 0
tokenSource = {MyQueryLexer@1810}
tokens = {java.util.ArrayList@1816} size = 3
0 = {org.antlr.v4.runtime.CommonToken@1818} "[@0,0:0='A',<13>,1:0]"
1 = {org.antlr.v4.runtime.CommonToken@1819} "[@1,1:1=' ',<32>,1:1]"
2 = {org.antlr.v4.runtime.CommonToken@1820} "[@2,3:2='<EOF>',<-1>,1:3]"
p = 2
fetchedEOF = true
expression = {MyQueryParser$StartExpressionContext@1813} "[]"
children = {java.util.ArrayList@1827} size = 3
0 = {MyQueryParser$ExpressionContext@1831} "[87]"
1 = {org.antlr.v4.runtime.tree.TerminalNodeImpl@1832} " "
2 = {org.antlr.v4.runtime.tree.TerminalNodeImpl@1833} "<EOF>"
在这里,我本希望得到一个RecognitionException
,但不知何故解析成功了,并且最后丢失了 token 数据的无效位。
问题是:
(1) 这是设计使然吗?
(2) 如果是这样,我如何检测到它并将其视为语法错误?
进一步调查
当我寻找捕获 StringIndexOutOfBoudsException 并吃掉它的罪魁祸首时,结果发现它一直到我们的 catch block 中。所以我猜 ANTLR 永远没有机会完成最后一个无效 token 的构建..?
我不完全确定会发生什么,但我想我预计 ANTLR 会捕获它,创建一个无效 token 并继续。
然后,我进一步深入研究,发现 Token#nextToken() 抛出了异常,而文档让这看起来不应该发生,所以我最终提交了有关该问题的票证。
最佳答案
直到最近的版本,ANTLR4 的自适应机制具有以下“功能”:如果 token 流的该部分中只有一种可行的替代方案,则能够从单个 token 缺失和单个额外 token 解析中恢复。现在最近,apparently that behavior has changed.因此,如果您像我一样使用较旧的版本,您仍然会看到自适应解析。也许帕尔和哈威尔会解决这个问题。
和您一样,我认识到需要完美的输入流和零解析错误,无论是否“被忽视”。要创建“严格解析器”,请按照下列步骤操作:
创建一个名为“StrictErrorStrategy”的类,该类继承/扩展 DefaultErrorStrategy。您需要重写 Recover、RecoverInline 和 Sync 方法。底线是我们对任何出错的情况抛出异常,并且不进行任何尝试在额外/丢失 token 后重新同步代码。这是我的 C# 代码,您的 java 看起来非常相似:
public class StrictErrorStrategy : DefaultErrorStrategy
{
public override void Recover(Parser recognizer, RecognitionException e)
{
IToken token = recognizer.CurrentToken;
string message = string.Format("parse error at line {0}, position {1} right before {2} ", token.Line, token.Column, GetTokenErrorDisplay(token));
throw new Exception(message, e);
}
public override IToken RecoverInline(Parser recognizer)
{
IToken token = recognizer.CurrentToken;
string message = string.Format("parse error at line {0}, position {1} right before {2} ", token.Line, token.Column, GetTokenErrorDisplay(token));
throw new Exception(message, new InputMismatchException(recognizer));
}
public override void Sync(Parser recognizer) { /* do nothing to resync */}
}
创建一个实现单个方法的新词法分析器:
public class StrictLexer : <YourGeneratedLexerNameHere>
{
public override void Recover(LexerNoViableAltException e)
{
string message = string.Format("lex error after token {0} at position {1}", _lasttoken.Text, e.StartIndex);
throw new ParseCanceledException(BasicEnvironment.SyntaxError);
}
}
使用您的词法分析器和策略:
AntlrInputStream inputStream = new AntlrInputStream(stream);
StrictLexer lexer = new BailLexer(inputStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
LISBASICParser parser = new LISBASICParser(tokenStream);
parser.RemoveErrorListeners();
parser.ErrorHandler = new StrictErrorStrategy();
这非常有效,来 self 的一个项目的实际代码,该项目对语法错误有“零容忍规则”。我从 Terence Parr 关于 ANTLR4 的伟大著作中获得了代码和想法。
关于java - 为什么 ANTLR 省略了最后的标记*并且*没有产生错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45025556/
我在 Chrome 上做了一些测试,requestAnimationFrame 产生了 61 fps 而 setTimeOut( callback, 0 ) 产生了 233 fps。 如果一个人想要超
当我调试代码时,我发现 GCC 和 Clang 都为 0.0/0.0 产生 nan,这是我所期望的,但 GCC 产生的 nan 将符号位设置为 1,而Clang 将其设置为 0(如果我没记错的话,与
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
我在 R Studio 中有一个时间序列。现在我想计算这个系列的log()。我尝试了以下方法: i <- (x-y) ii <- log(i) 但是我得到以下信息:Warning message: I
我有兴趣了解 JavaScript 的内部结构.我试图阅读 SpiderMonkey 的来源和 Rhino但是绕过我的头是相当复杂的。 我问的原因是:为什么像 (![]+[])[+!![]+[]] 生
我们在 Delphi 中使用标准 TWebbrowser 组件,该组件在内部使用 mshtml.dll。另外,我们使用注册表来确保页面使用新的渲染引擎( Web-Browser-Control-Spe
我必须实现一个序列化/反序列化类,并且我正在使用 System.Xml.Serialization 。我有一些IList类型属性并希望在 IList 中序列化解码属于具有特定区域性信息的列表的所有十进
我有一个 Java 应用程序,它读取包含 SQL 查询的 JSON 文件,并使用 JDBC 在数据库上触发它们。 现在我有 5 万个这样的文件,我需要生成 5 万个独立线程来读取每个文件并将它们上传到
我正在尝试将 TensorFlow 入门页面上的示例线性回归程序调整为二次回归。为此,我只是添加了另一个变量并更改了函数。然而,这似乎会导致 NaN 值。这是我的代码: import numpy as
申请后KernelPCA到我的数据并将其传递给分类器 ( SVC ) 我收到以下错误: ValueError: Input contains NaN, infinity or a value too
这背后的想法是,如果我的数据库中存在登录名(正确的用户名+密码),我将重定向到一个页面,并且在进行此身份验证后,他们可以将消息存储在文本文件中。代码非常简单尽管我不确定为什么会收到 IllegalSt
我有一个返回 log10 值的函数。在将它们转换为正常数字时,出现溢出错误。 OverflowError: (34, 'Numerical result out of range') 我检查了日志值,
nosetests 抛出一个 ImportError,尽管我认为这是一个正确配置的 virtualenv。 ==============================================
我是这个网站的新手,所以如果我做错了什么,我提前道歉。当我尝试使用 kivy-garden 的 ScrollLabel 时,它给了我一个错误。基本上我正在尝试创建一个控制台日志,并且我需要能够在文本框
任何人都对 MDSJ 有任何经验?以下输入仅产生 NaN 结果,我不明白为什么。文档非常稀少。 import mdsj.Data; import mdsj.MDSJ; public class MDS
我有一个非常简单的 scala jcuda 程序,它添加了一个非常大的数组。一切都编译和运行得很好,直到我想从我的设备复制超过 4 个字节到主机。当我尝试复制超过 4 个字节时,我收到 CUDA_ER
我正在使用 Hero 组件在两个页面之间创建动画。Hero 组件用于包装一个 Image 小部件(没问题)和一个 Container 小部件(有问题)。 抛出以下溢出错误: ══╡ EXCEPTIO
我无法理解页面 https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/void 中的这一段: This ope
当在 Angular 中使用不立即触发事件的异步管道时(http 请求或任何有延迟的可观察对象),第一个值为 null为什么会这样?如何避免这种情况? 第一个变化: SimpleChange {
如果一个导入的库生成了一个会 panic 的 goroutine 怎么办?在这种情况下,开发人员无法阻止程序退出。 就像在这段代码中一样,使用延迟恢复调用一个错误的库没有帮助,因为该库正在生成一个 p
我是一名优秀的程序员,十分优秀!