这是一个带有几个约束的简单方法。我认为这些符合您在评论中提到的预期行为。
- 不匹配的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 和RPARAMs。规则list,atom只关心自己。
该解决方案相对脆弱,因为 ruleroot需要在和expr之前列出。即便如此,也许这足以解决您的问题。LPARAMRPARAM
测试用例 1:没有列表
输入:1 2 3
输出:

测试用例 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    : ']';