设计规则的两种不同方法(像## <text> ##一样检测标记)

时间:2016-06-02 20:54:12

标签: antlr4

我为基于降价的语言设计语法但没有语境感知。

例如,我想检测像## ##。

这样的标记

我找到了两种不同的设计规则的方法,而且我不太确定哪种方式可能是最好的方法。

第一种方式:定义更复杂的令牌和简单的规则。

fragment
HEAD
    : '#'
    ;

fragment
HEADING_TEXT
    : (~[#]|'\\#')+?
    ;

SUBHEADLINE
    : HEAD HEAD HEADING_TEXT HEAD HEAD
    ;
subheadline
    : SUBHEADLINE
    ;

由于片段HEAD和HEADING_TEXT会进入解析器。我在IntelliJ中进行原型设计,解析效果很好。并且错误消息显示类似于&#34;缺少SUBHEADLINE&#34;什么对主要应用程序有用(我认为我可以轻松地将这些错误更改为人类可读的错误)。

第二种方法:更简单的令牌和更复杂的解析器规则。

HEAD
    : '#'
    ;

HEADING_TEXT
    : (~[#]|'\\#')+?
    ;
subheadline
    : HEAD HEAD HEADING_TEXT HEAD HEAD
    ;

工作正常。错误更具体,可能不太适合将它们转换为人类可读的错误。

但我总体上不确定应遵循哪种方法,为什么?!在这种情况下,更复杂的令牌更容易编写,因为不会像普通编程语言那样包含任何复杂的规则。但它并不觉得这是正确的做法。

1 个答案:

答案 0 :(得分:1)

两种方式都有自己的行为,这取决于你需要决定使用什么。以你的方式在词法分析器中定义子头部不允许在例如两者之间跳过/隐藏标记。 '#',这可能就是你想要的。在解析器中执行此操作可以允许例如# /*acomment*/headline##这可能不是预期的行为。我也会把严格属于一起的东西组合成一条规则。例如,第二个变体中的HEADING_TEXT可能会匹配您想要以不同方式匹配的输入。而是完全按照语言规定定义子标题:

SUBHEADING: '##' .*? '##';

这比简单的变体更加简洁,但仍然不允许在标记之间跳过输入。