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

时间:2015-09-01 18:15:06

标签: c# antlr antlr4

我有一个解析器,它接受两种不同类型的预定义HTML模板标记。一个明确地以“结束*”结束,一个不是例如:

{% 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\" %}

据我了解,如果我希望语义谓词阻止匹配成功(而不是匹配规则,那么失败并生成错误)我需要左侧的语义谓词。但是,语义谓词如果在左侧则没有任何值 - 所以我不确定如何继续。

有没有办法编写解析器规则,以便我可以定义这两种情况?

1 个答案:

答案 0 :(得分:1)

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

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

因此,只需识别解析器中的标签,而不必尝试限定为开始,结束或单身。

tag: TBEG 
     ( id expression  // assign etc
     | expression     // for etc
     | id             // endfor etc
     )
     TEND  // { processTag($tag); } // alternate solution
   ;

实际上,您可以通过向标记规则添加操作来纯粹在解析器中实现相同的结果。此操作将创建标记表并将其添加到标记表中。添加带有末尾名称的标记时,先前的标记将被标记为开始标记。

如果您要实现其他步行器,可能需要实现标签表达式,那么首选添加一个以预先标识标签将是首选。