编写对空格敏感的解析器规则,同时从词法分析器中跳过WS

时间:2014-07-30 14:28:38

标签: antlr grammar antlr4

我在处理空白方面遇到了一些麻烦。在下面的语法摘录中,我设置了词法分析器,以便解析器跳过空格:

ENTITY_VAR
    : 'user'
    | 'resource'
    ;

INT : DIGIT+ | '-' DIGIT+ ;
ID : LETTER (LETTER | DIGIT | SPECIAL)* ;
ENTITY_ID : '__' ENTITY_VAR ('_w_' ID)?;

NEWLINE : '\r'? '\n';

WS : [ \t\r\n]+ -> skip; // skip spaces, tabs, newlines

fragment LETTER : [a-zA-Z];
fragment DIGIT : [0-9];
fragment SPECIAL : ('_' | '#' );

问题是,我想匹配ENTITY_ID形式的变量名称,以便匹配的字符串没有任何空格。将它写为lexer规则就足够了,就像我在这里做的那样,但问题是我想用解析器规则来代替它,因为我想直接访问这两个令牌ENTITY_VARID分别来自我的代码,而不是将它们整合在一个完整的令牌中ENTITY_ID

请问任何想法? 基本上任何允许我直接访问ENTITY_VARID的解决方案都适合我,将ENTITY_ID作为词法规则或将其移至解析器。

3 个答案:

答案 0 :(得分:2)

我可以想到几种方法(不是特殊的顺序):

  1. 从规则ENTITY_ID中发出几个令牌。请参阅ANTLR4: How to inject tokens获取灵感
  2. 在解析器中允许空格并随后检查
  3. 使用单个令牌并拆分代码
  4. 使用单个令牌并在将令牌流传递给解析器之前修改令牌流。即lex,修改ENTITY_ID标记并将它们拆分成其他几个标记,然后将此流传递给解析器
  5. 不要跳过空格,在处理这些“额外令牌”时,请检查它们是否在ENTITY_ID部分内(=>是错误)或不是(=>忽略错误)。
  6. 不要跳过空白并在你的语法中的任何地方添加“WS *”,允许空格(如果语法不是太大,则确定)。
  7. 在解析器规则中插入谓词,检查是否存在空格。
  8. 创建一个“陷阱”规则,如下所示:

    INVALID_ENTITY_ID : '__' WS+ ENTITY_VAR WS? ('_w_' WS? ID)?
                      | '__' WS? ENTITY_VAR WS+ ('_w_' WS? ID)?
                      | '__' WS? ENTITY_VAR WS? ('_w_' WS+ ID)
                      ;
    

    这将捕获无效的ENTITY_ID,因为它比那些也是个别令牌的部分更长。

  9. 如果它不改变“非错误”情况下的解析,我会选择2,即不允许通过允许空格来解释代码。

答案 1 :(得分:0)

据我通过浏览文档设法理解,它看起来不像是可行的。

解析器规则似乎仅适用于默认通道,因此我无法将WS发送到channel(HIDDEN),然后仅针对单个解析器规则进行恢复。

另一方面,antlr explains here的作者认为自版本4以来无法分解任何令牌。

即使我根本不喜欢它,似乎最快的方法是从词法分析器解析它(如在问题的代码中),只是为了从Java再次重新解析它字符串。

不过,我的结论还是有任何其他更好的选择或更正。

答案 2 :(得分:0)

在一个管道中挂钩两个解析器,就像你自己的回答一样,是一个健全而简单的设计/解决方案,而且我非常确定ANTLR能够帮助解决这个问题。

我不太了解ANTLR人员在流/源解析方面的工作。但是,采用两遍策略应该足够有效,因为第一遍只是使用常规语言,O(c * N)超过输入的大小c

如果您想要一张费用为O(k * N)(大k)的单一通行证,您可以考虑PEG,其中有implementations in Java(我还没试过) )。