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

时间:2018-08-13 13:57:20

标签: parsing antlr4 lexer

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

  • 功能
  • 变量
  • 任意文字

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

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

我基本上在三件事上有问题:

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

几个测试字符串:

  • "The length of the COMPUTER environment variable is $Length(<Env:COMPUTER>)"
  • "The last 10 chars of the COMPUTER environment is $Substring($Length(<Env:COMPUTER>)-10, $Length(<Env:COMPUTER>))"

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

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()来获取实际数据。

结果

我选择了Bart's answer

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

这里是https://github.com/IntelliSearch/FlexVersion/blob/master/IntelliSearch.FlexVersion/OutputVisitor.cs

万一链接消失,这是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:]* ;

如您所见,我还抛弃了运算符(++-/ *),因为这只应该在params中允许,但是后来我不确定那是否真的很聪明,所以我去了一种方法也是通过特定的$函数解决的。

1 个答案:

答案 0 :(得分:1)

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

我有这样的想法:

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:]* ;

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