在a previous question with a simple grammar中,我学会了处理可以包含关键字列表中的关键字的ID . 我的实际语法稍微复杂一些:在不同类型的句子中有几个关键词列表 . 这是我尝试一种讲述故事的简单语法:
grammar Hello;
file : ( fixedSentence )* EOF ;
sentence : KEYWORD1 ID+ KEYWORD2 ID+ PERIOD
| KEYWORD3 ID+ KEYWORD4 ID+ PERIOD;
KEYWORD1 : 'hello' | 'howdy' | 'hi' ;
KEYWORD2 : 'bye' | 'goodbye' | 'adios' ;
KEYWORD3 : 'dear' | 'dearest' ;
KEYWORD4 : 'love' | 'yours' ;
PERIOD : '.' ;
ID : [a-z]+ ;
WS : [ \t\r\n]+ -> skip ;
所以我想要匹配的句子是,例如:
hello snickers bar goodbye mars bar.
dear peter this is fun yours james.
这很有效 . 但我还想匹配包含不希望终止ID块的关键字的句子 . 例如
hello hello kitty goodbye my dearest raggedy ann and andy.
hello
拳头显示为 KEYWORD1
,然后仅作为第一个ID的一部分 . 按照上述链接问题的示例,我可以像这样解决:
// ugly solution:
fixedSentence : KEYWORD1 a=(ID|KEYWORD1|KEYWORD3|KEYWORD4)+ KEYWORD2 b=(ID|KEYWORD1|KEYWORD2|KEYWORD3|KEYWORD4)+ PERIOD
| KEYWORD3 a=(ID|KEYWORD1|KEYWORD2|KEYWORD3)+ KEYWORD4 b=(ID|KEYWORD1|KEYWORD2|KEYWORD3|KEYWORD4)+ PERIOD;
这工作,并完全符合我的要求 . 在我的真实语言中,我有数百个关键字列表,用于不同类型的句子,所以如果我尝试这种方法,我肯定会犯这样的错误,当我用我的语言创建新结构时,我必须回去编辑所有其他人 .
根据ANTLR4书中的评论示例,从列表中进行非贪婪匹配会更好 . 所以我尝试了这个
// non-greedy matching concept:
KEYWORD : KEYWORD1 | KEYWORD2 | KEYWORD3 | KEYWORD4 ;
niceID : ( ID | KEYWORD ) ;
niceSentence : KEYWORD1 niceID+? KEYWORD2 niceID+? PERIOD
| KEYWORD2 niceID+? KEYWORD3 niceID+? PERIOD;
我认为遵循评论模型(例如,在本书的第81页给出):
COMMENT : '/*' .*? '*/' -> skip ;
通过使用 ?
建议非贪婪 . (虽然这个例子是词法规则,这会改变这里的含义吗?) fixedSentence
有效,但 niceSentence
是失败的 . 我从哪里开始?
具体来说,解析上面的hello kitty测试句中报告的错误是,
测试规则 sentence
:
line 1:6 extraneous input 'hello' expecting ID
line 1:29 extraneous input 'dearest' expecting {'.', ID}
测试规则 fixedSentence
:没有错误 .
测试规则 niceSentence
:
line 1:6 extraneous input 'hello' expecting {ID, KEYWORD}
line 1:29 extraneous input 'dearest' expecting {KEYWORD2, ID, KEYWORD}
line 1:57 extraneous input '.' expecting {KEYWORD2, ID, KEYWORD}
如果它有助于查看解析树,here they are .
1 回答
认识到解析器非常适合处理语法,即结构,而不是语义区别 . 关键字在一个上下文中是否为
ID
终止符而在另一个上下文中是否在语法上是等价的,本质上是语义的 .处理语义模糊的典型ANTLR方法是创建一个尽可能多地识别多个结构区别的解析树,然后走树分析每个节点相对于周围节点(在这种情况下)以解决模糊 .
如果这解析为你的解析器
那么你的句子基本上是自由形式的 . 更合适的工具可能是NLP库 - 斯坦福有一个很好的工具 .
Additional
如果将词法规则定义为
词法分析器将永远不会发出
KEYWORD
令牌 - 'hello'被消耗并作为KEYWORD1发出,并且永远不会评估KEYWORD
规则 . 由于解析树无法识别令牌的类型(显然),因此它不是很有启发性 . 转储令牌流以查看词法分析器实际执行的操作如果将
KEYWORD
规则放在其他规则之前,则词法分析器将仅发出KEYWORD
标记 .更改为解析器规则
将允许这个非常有限的例子工作 .