解析字符串时如何处理 Antlr 空格

How to handle Antlr whitespace when parsing a string

我有一个需要解析的字符串,它对于正则表达式来说太重了。正则表达式不太擅长找到平衡的匹配项......不过这个任务相当简单,因为每个字符串可以包含三种类型的信息:

我需要插入字符串,以便我可以用我的程序生成的内容替换变量和函数,但要保留任意文本(包括空格)。

我发现这是学习 ANTLR 的绝佳机会,但我正在努力让它发挥作用。

我基本上在三件事上遇到问题:

  1. 我需要保留空格,因为任意文本都不会丢失。
  2. 我希望函数中的参数不关心空格
  3. 我不确定如何匹配任意文本。我尝试了几种不同的选择,但 none 对我有用。包括例如 .+.+?~[$<].

几个测试字符串:

到目前为止,这是我的代码:

grammar Output;     

start
    :  (expr)* ; 

expr 
    : expr expr 
    | VAR 
    | FUNC '(' commaexpr ')' 
    ; 

commaexpr
    : expr
    | commaexpr ',' commaexpr
    ;


FUNC: '$' ID ; 
VAR : '<' ID '>' ;
fragment ID : [a-zA-Z] | [a-zA-Z][a-zA-Z0-9:]+ ; 
WS : [\r\n]+ -> skip ; 

编辑:

我已经能够在这方面取得一些进展。好像我有一个解决方案,有点。不确定我的解决方案是否是最佳选择:

grammar Output;     

start
    :  (expr)* ; 

expr 
    : expr expr 
    | variable
    | function
    | text
    ;

variable
    : VAR
    ;

function
    : FUNC '(' commaexpr ')' 
    ;

commaexpr
    : WS? expr WS?
    | commaexpr ',' commaexpr
    ;

text: TEXT+ ;

FUNC: '$' ID ; 
VAR : '<' ID '>' ;
fragment ID : [a-zA-Z] | [a-zA-Z][a-zA-Z0-9:]+ ; 
TEXT: .+?;
NL : [\r\n]+ -> skip ; 
WS: [ ]+ ;

这样做有什么陷阱吗?我看到 text 表达式是一个字符列表而不是字符串,但这对我有用,因为我可以在访问者中对它们使用 GetText() 来获取实际数据。

结果

我选择了 的变体。

最终代码,ANTLR 代码以及与此相关的访问者在这里:https://github.com/IntelliSearch/FlexVersion/tree/master/IntelliSearch.FlexVersion.OutputParser

还有这里的 OutputVisitor:https://github.com/IntelliSearch/FlexVersion/blob/master/IntelliSearch.FlexVersion/OutputVisitor.cs

以防 link 在一个阶段死亡,这里是 ANTLR g4 文件:

grammar Output;

start
  : expr* EOF
  ;

expr
 : function
 | variable
 | text
 ;

function
 : FUNC '(' params ')';

variable
 : VAR;

params
 : expr+ ( ',' expr+ )*
 ;

text
 : OTHER+
 ;

FUNC      : '$' ID;
VAR       : '<' ID '>';
OPEN_PAR  : '(';
CLOSE_PAR : ')';
COMMA     : ',';
OTHER     : . ;

fragment ID : [a-zA-Z] [a-zA-Z0-9:]* ;

如您所见,我也放弃了运算符 (++-/*),因为这只应该在参数中允许,但后来我不确定这是否真的明智,所以改为我采用了一种方法,该方法也可以通过特定的 $functions 解决。

在词法分析器中,.+? 将始终使用单个字符,因此请注意删除 +? 部分。

我有这样的想法:

grammar Output;

start
  : expr* EOF
  ;

expr
 : FUNC '(' params ')'
 | expr ( MULT | DIV ) expr
 | expr ( PLUS | MINUS ) expr
 | VAR
 | ignore
 ;

params
 : expr+ ( ',' expr+ )*
 ;

ignore
 : OTHER+
 ;

FUNC      : '$' ID;
VAR       : '<' ID '>';
OPEN_PAR  : '(';
CLOSE_PAR : ')';
MULT      : '*';
DIV       : '/';
MINUS     : '-';
PLUS      : '+';
OTHER     : . ;

fragment ID : [a-zA-Z] [a-zA-Z0-9:]* ;

我刚刚看到了您自己的解决方案,但如果它按您希望的方式工作,那很好。