Parsing 将括号解析为ANTLR
我正在尝试匹配平衡括号,这样,如果匹配,就会创建一个Parsing 将括号解析为ANTLR,parsing,antlr,grammar,expression,Parsing,Antlr,Grammar,Expression,我正在尝试匹配平衡括号,这样,如果匹配,就会创建一个PARAMS树,否则LPARAM和RPARAM标记将作为原子添加到树中 tokens { LIST; PARAMS; } start : list -> ^(LIST list); list : (expr|atom)+; expr : LPARAM list? RPARAM -> ^(PARAMS list?); atom : INT | LPARAM | RPARAM; INT :
PARAMS
树,否则LPARAM和RPARAM标记将作为原子添加到树中
tokens
{
LIST;
PARAMS;
}
start : list -> ^(LIST list);
list : (expr|atom)+;
expr : LPARAM list? RPARAM -> ^(PARAMS list?);
atom : INT | LPARAM | RPARAM;
INT : '0'..'9'+;
LPARAM : '(';
RPARAM : ')';
目前,它永远不会创建PARAMS
树,因为在规则表达式中,它总是将endRPARAM
视为一个原子,而不是该规则的结束标记
因此目前,类似于1235
的内容被添加到列表
树中,作为令牌的平面列表,而不是所需的分组
我以前曾处理过将令牌作为原子添加到树中,但它们从未能够启动另一条规则,就像这里的LPARAM
所做的那样
这里需要某种语法/语义谓词吗?这里有一个简单的方法,有几个约束。我认为这些符合你在评论中提到的预期行为
- 子列表中永远不会出现不匹配的
LPARAM
- 子列表中永远不会出现不匹配的
RPARAM
start : root+ EOF -> ^(LIST root+ );
root : expr
| LPARAM
| RPARAM
;
expr : list
| atom
;
list : LPARAM expr+ RPARAM -> ^(LIST expr+)
;
atom : INT
;
规则root
匹配不匹配的LPARAM
s和RPARAM
s。规则list
和atom
只关心它们自己
此解决方案相对脆弱,因为规则root
要求在LPARAM
和RPARAM
之前列出expr
。即便如此,也许这足以解决你的问题
测试用例1:没有列表
输入:123
输出:
测试用例2:一个列表
输入:1(2)3
输出:
测试用例3:两个列表
输入:(1)2(3)
输出:
测试用例4:没有列表,左边不匹配
输入:((1 2 3
输出:
测试用例5:两个列表,不匹配的左
输入:((1(2)(3)
输出:
测试用例6:没有列表,权限不匹配
输入:1 2 3))
输出:
测试用例7:两个列表,不匹配的权限
输入:(1)(2)3))
输出:
测试用例8:两个列表,混合不匹配的左
输入:((1(2)((3)
输出:
测试用例9:两个列表,混合不匹配的权限
输入:(1))(2)3))
输出:
这里有一个稍微复杂一些的语法,它对
[]
和()
对进行操作。我认为,当你添加对时,解决方案会变得越来越糟糕,但是,嘿,这很有趣!您可能也遇到了语法驱动的AST构建的局限性
start : root+ EOF -> ^(LIST root+ )
;
root : expr
| LPARAM
| RPARAM
| LSQB
| RSQB
;
expr : plist
| slist
| atom
;
plist : LPARAM pexpr* RPARAM -> ^(LIST pexpr*)
;
pexpr : slist
| atom
| LSQB
| RSQB
;
slist : LSQB sexpr* RSQB -> ^(LIST sexpr*)
;
sexpr : plist
| atom
| LPARAM
| RPARAM
;
atom : INT;
INT : ('0'..'9')+;
LPARAM : '(';
RPARAM : ')';
LSQB : '[';
RSQB : ']';
LPARAM
和RPARAM
实际上是原子还是表示列表开头和结尾的语法标记?有没有一种情况下,您希望将一个视为原子,而另一种情况下,它应该是标记?是的,LPARAM和RPARAM能够单独显示在树中。它们不仅仅是语法标记。我希望它们被视为标记,只有当它能够真正匹配括号中的表达式时。所以在“12(3)”中,(3)应该是一个带括号的表达式,结果树应该是^(列表12^(参数3))。而不成功的匹配,如1 2)3)应该变成^(列表1 2)3)。我明白了。语法应该如何处理“1(2)3”这样的输入?那应该是“1^(列表2)3”还是“1^(列表2”)3”?那么“1(2)3”呢?那是“^(列表)(“2)3
”还是“”(“1^(列表2)3
”?第二个。只要字符串的任何部分都能通过一个开放和闭括号成功地平衡,那么它就会被创建为PARAMS树,否则它失败,lpram/RPARAM应该只是作为原子添加。谢谢你花时间帮助我解决我的问题。我非常感谢你添加的所有额外测试用例。我只是changed expr+到expr*,以允许使用空括号。非常感谢:)您好,很抱歉再次询问,但我正在尝试将您的答案应用到我的语法中。现在,LPARAM和RPARAM由两个名为openOp和closeOp的规则表示。openOp对应于诸如“(”、“{”、“|”之类的起始运算符,closeOp对应于诸如“)、”之类的关闭运算符“,”|“。规则还返回一个名为“op”的字符串,其中包含匹配标记的文本。我是否可以使用语义谓词检查这两个运算符是否可以相互匹配?列表:l=openOp expr*r=closeOp{canBalance($l.op,$r.op)}?->^(列表expr*)@DavidJamesBall这是一个困难的问题。在我上面的语法中,expr
表示可以包含在列表中的任何内容。它排除不匹配的位,因为它们由root
管理。允许一种类型的不匹配成为有效匹配(例如([1)
->^(列表[1)
)使用这种方法并不容易,但我会仔细考虑一下。我已经隔离了这个问题。您的规则工作得很好。问题是我的规则…list:l=openOp expr*r=closeOp{canBalance($l.op,$r.op)}?->^(list expr*)。那么$l.op和$r.op总是空的。如果我传入$l.text,我可以看到openOp工作正常。如果我删除谓词,那么$l.op和$r.op就不再是空的。在规则末尾使用语义谓词有什么微妙之处,我不知道。它似乎是先执行的。我想这是因为backtraCKK:语义谓词依赖于规则中触发的动作,但这些动作不会被命中,因为解析器正在回溯。如果openOp
和closeOp
每个选项只引用一个令牌,则可以使用$l.start
获取令牌。否则,使用{$op=$WHATEVER}
在规则中强制执行操作,即使在回溯过程中也是如此。