簡體   English   中英

意外的 Antlr4 解析器錯誤

[英]Unexpected Antlr4 parser errors

我在 Antlr4 中發現了一個奇怪的行為(我嘗試了 4.10 和 4.10.1 版本,結果相同)。

當我嘗試使用語法時

grammar Paths;

cfg: NL? (entry (NL | EOF))* EOF;

entry: path ':' value;

path: SEGMENT ('.' SEGMENT)*;

value: USTRING;

SEGMENT: [a-zA-Z0-9]+;

USTRING: [a-zA-Z0-9]+;

NL: [\n\r]+;

WS: [ \t]+ -> skip;

在字符串"key1:value1\nkey2.sub:value2\nkey3.sub1.sub2:value3"上,我看到錯誤消息:

line 1:5 mismatched input 'value1' expecting {':', '.'}
line 2:9 mismatched input 'value2' expecting {':', '.'}
line 3:15 mismatched input 'value3' expecting {':', '.'}

如果我用value: SEGMENT替換value definition ,一切都會按預期進行。

第一個定義有什么問題?

兩種情況下 tree 的 output 是一樣的:

(cfg (entry (path key1) : (value value1)) \n (entry (path key2 . sub) : (value value2)) \n (entry (path key3 . sub1 . sub2) : (value value3)) <EOF> <EOF>)

我試圖簡化語法:

grammar Paths;

cfg: NL? (entry (NL | EOF))* EOF;

entry: path ':' value;

path: SEGMENT;

value: USTRING;

SEGMENT: [a-zA-Z0-9]+;

USTRING: [a-zA-Z0-9]+;

NL: [\n\r]+;

WS: [ \t]+ -> skip;

在這種情況下,我有錯誤(解析的字符串是"key1:value1\nkey2:value2\nkey3:value3" ):

line 1:5 mismatched input 'value1' expecting USTRING
line 2:5 mismatched input 'value2' expecting USTRING
line 3:5 mismatched input 'value3' expecting USTRING

如果我在value定義中用SEGMENT替換USTRING ,一切都很好。 Output 是

(cfg (entry (path key1) : (value value1)) \n (entry (path key2) : (value value2)) \n (entry (path key3) : (value value3)) <EOF> <EOF>)

這是因為 ANTLR 的 Lexer 處理輸入的字符 stream 以產生令牌 stream,解析器處理令牌 stream。ANTLR 中的遞歸下降解析正在處理令牌 stream,並且對 Lexer 如何查看輸入沒有影響。

Lexer 規則SEGMENTUSTRING是相同的,因此,這兩個規則將完全匹配相同的輸入字符運行。 當發生這種情況時,ANTLR 將匹配第一個規則,因此它們都將是“SEGMENTS”標記。

如果您已經完成了標准設置(並創建了grun別名,您可以使用 `-tokens 選項運行它以獲取令牌 stream 的轉儲。這通常是驗證您的 Lexer 規則是否正在創建令牌的好主意您期望的 stream。

發生這種情況是因為 Antlr 分配給值類型 '''SEGMENT'''。 Lexer 忽略語法,如果有可以分配給不同類型的標記,lexer 將它們分配給一個隨機類型。

這段代碼幫助了我:

val lexer = PathsLexer(CharStreams.fromString("key1:value1\nkey2.sub:value2\nkey3.sub1.sub2:value3"))
val tokens = CommonTokenStream(lexer)
tokens.fill()
println(tokens.getTokens.asScala.map { token =>
  s"$token: ${token.getType} -> ${lexer.getVocabulary.getDisplayName(token.getType)}"
}.mkString("\n"))

可能我需要了解更多關於 Antlr 模式的知識。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM