语义谓词匹配用户定义的分隔符

本文关键字:定义 分隔符 用户 谓词 语义 | 更新日期: 2023-09-27 18:10:48

我有一个解析器,它接受两种不同类型的预定义html模板标记。一个以"end*"显式结束,另一个没有,例如:

{% for ... %}
   An explicitly-terminated tag
{% endfor %}
{% assign x = 'my implicitly-terminated tag' %}

工作得很好,但我还需要允许用户从c#代码中定义自己的标签,所以我需要Antlr4来匹配这些示例:

{% mycustomtag %}
   ...
{% endmycustomtag %}
{% myunterminatedtag %}

我试图通过使用c#语义谓词来匹配以{% [USERDEFINED] %}开头的任何内容和结束标记{% end[USERDEFINED] %},如下:

tag: // ...
    | custom_blocktag 
    | custom_tag
    // ...
// an explicitly-terminated tag
custom_blocktag:    TAGSTART custom_block_start_tag customtagblock_expr* TAGEND custom_blocktag_block TAGSTART custom_block_end_tag TAGEND { _localctx.custom_block_end_tag().GetText().Equals("end" + _localctx.custom_block_start_tag().GetText()) }?;
// an implicitly-terminated tag
custom_tag:         TAGSTART tagname customtag_expr* TAGEND ;   

不幸的是,只有在显式结束的标记之前没有隐式结束的标记时,这才能正常工作,但如果以相反的顺序出现,则会失败。

失败并报错:

{% xyz '"Test'" %}{% abc '"hello'"%}...{% endabc %}

但是,这工作得很好:

{% abc '"hello'"%}...{% endabc %}{% xyz '"Test'" %}

根据我的理解,如果我希望语义谓词阻止匹配成功(而不是匹配规则然后失败并生成错误),我将需要左侧的语义谓词。然而,如果语义谓词在左边,它将没有任何值——所以我不确定如何继续。

是否有一种方法来编写解析器规则,以便我可以定义这两种情况?

语义谓词匹配用户定义的分隔符

正如您所描述的问题,可以从任何一个标记确定的唯一语法确定性是成对集合的结束标记具有以'end'开头的名称。开始标记将出现在结束标记之前,这实际上是一种语义关联('for' -> 'endfor'关系可以用来确认这种关联,但在语法上并没有真正的帮助)。

最好的通用方法是在解析器中处理语法问题,在解析树漫步器中处理语义问题。在这里,检查每个标记并构建包含开始和结束标记关联的表的初始遍历是很容易的。

因此,只需在解析器中识别标签,而不必尝试将其限定为begin、end或singleton。

tag: TBEG 
     ( id expression  // assign etc
     | expression     // for etc
     | id             // endfor etc
     )
     TEND  // { processTag($tag); } // alternate solution
   ;
实际上,您可以在解析器中通过向标记规则添加一个操作来获得相同的结果。这个操作将创建和添加遇到的标记到标记表中。当添加一个以结尾命名的标签时,前一个标签将被标记为开始标签。

如果您打算实现其他行走器,可能需要实现标记表达式,那么最好再添加一个来预先限定标记。