我正在为一种基于markdown的语言设计语法,但没有上下文意识。
例如,我想检测像####这样的令牌。
我找到了两种不同的方法来设计规则,我不太确定哪种方法可能是最好的方法。
第一种方法:定义更复杂的令牌和一个简单的规则。
fragment
HEAD
: '#'
;
fragment
HEADING_TEXT
: (~[#]|'\#')+?
;
SUBHEADLINE
: HEAD HEAD HEADING_TEXT HEAD HEAD
;
subheadline
: SUBHEADLINE
;
由于碎片HEAD和HEADING_TEXT将到达解析器。我正在IntelliJ中进行原型设计,解析效果很好。错误消息显示了类似"缺少SUBHEADLINE"的内容,这对主应用程序来说很好(我认为我可以很容易地将这些错误更改为可读错误)。
第二种方法:解析器使用更简单的令牌和更复杂的规则。
HEAD
: '#'
;
HEADING_TEXT
: (~[#]|'\#')+?
;
subheadline
: HEAD HEAD HEADING_TEXT HEAD HEAD
;
效果也不错。这些错误更具体,可能不太适合将它们转换为人类可读的错误。
但总的来说,我不确定我应该遵循哪种方法,为什么?!在这种情况下,更复杂的令牌更容易编写,因为不会像普通编程语言那样包含任何复杂的规则。但感觉这不是正确的做法
这两种方式都有自己的行为,这取决于您需要决定使用什么。以您以前的方式定义lexer中的子标题行不允许在例如"#"之间跳过/隐藏标记,这可能是您想要的。相反,在解析器中这样做允许具有例如# /*acomment*/headline##
,这可能不是预期的行为。此外,我会把严格属于一起的东西组合成一条规则。例如,第二个变体中的HEADING_TEXT可能会匹配您希望以不同方式匹配的输入。相反,按照语言的要求定义副标题:
SUBHEADING: '##' .*? '##';
这甚至比更简单的变体更简洁,同时仍然不允许在标记之间跳过输入。