如何在Antlr4 Lexer的\p{..}Unicode集合中排除特定字符
Antlr4 Lexer 实现自定义操作符标识符的问题解决
问题描述
我正在定义一门语言,希望自定义操作符标识符属于Unicode类别S、P、Me(符号、标点、封闭标记),但需要排除括号类字符(()、{}、[])与逗号。尝试的代码中,用NO_OP引用实现排除时报错“rule reference NO_OP is not currently supported in a set”;直接在集合中添加排除字符又提示“chars used multiple times”,想知道Antlr4 Lexer里实现这个需求的可行方式。
原代码示例
// Punctuation L_PAREN : '('; R_PAREN : ')'; L_CURLY : '{'; R_CURLY : '}'; L_BRACKET : '['; R_BRACKET : ']'; COMMA : ','; // Operator Identifiers NO_OP : (L_PAREN | R_PAREN | L_BRACKET | R_BRACKET | L_CURLY | R_CURLY | COMMA); IDENT_OP_LIKE : (UNICODE_OPISH ~NO_OP)+; fragment UNICODE_OPISH : [\p{S}\p{P}\p{Me}];
可行解决方案
方法1:直接在字符集中显式排除目标字符
Antlr4的字符集支持用~和交集操作&&来精准筛选字符,同时要把单独的标点规则放在操作符规则之前,让Antlr优先匹配单个标点,避免冲突。
修改后的代码:
// Punctuation(必须放在IDENT_OP_LIKE之前) L_PAREN : '('; R_PAREN : ')'; L_CURLY : '{'; R_CURLY : '}'; L_BRACKET : '['; R_BRACKET : ']'; COMMA : ','; // Operator Identifiers IDENT_OP_LIKE : [\p{S}\p{P}\p{Me}&&[^(){}[],]]+;
说明:[\p{S}\p{P}\p{Me}&&[^(){}[],]]表示取Unicode类别S、P、Me的字符,同时排除()、{}、[]和逗号。提前定义的单个标点规则会优先匹配这些字符,剩余符合条件的字符序列则会被识别为IDENT_OP_LIKE。
方法2:使用语义谓词过滤
如果需要更灵活的排除逻辑,可以在匹配后通过语义谓词过滤掉包含禁用字符的序列:
// Punctuation L_PAREN : '('; R_PAREN : ')'; L_CURLY : '{'; R_CURLY : '}'; L_BRACKET : '['; R_BRACKET : ']'; COMMA : ','; // Operator Identifiers IDENT_OP_LIKE : (UNICODE_OPISH)+ { String text = getText(); for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); // 检查字符是否属于排除列表 if (c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || c == ',') { skip(); // 跳过包含禁用字符的匹配 return; } } }; fragment UNICODE_OPISH : [\p{S}\p{P}\p{Me}];
说明:当匹配到UNICODE_OPISH序列后,遍历每个字符,若发现禁用字符则跳过当前匹配,Antlr会自动尝试匹配其他规则(比如单独的标点规则)。
内容的提问来源于stack exchange,提问作者meta_leap
相关产品推荐
相关产品推荐

