ANTLR v4 动态文法

ANTLR v4 dynamic grammar

我有这个语法:

grammar ProcedureHeaderLanguage ;

@header
{
  package com.company.generated.antlr.atr;
}

fragment DIGIT
  : '0'..'9'
  ;

fragment A
  : [aA]
  ;

fragment B
  : [bB]
  ;

fragment C
  : [cC]
  ;

fragment D
  : [dD]
  ;

fragment E
  : [eE]
  ;

fragment F
  : [fF]
  ;

fragment G
  : [gG]
  ;

fragment H
  : [hH]
  ;

fragment I
  : [iI]
  ;

fragment J
  : [jJ]
  ;

fragment K
  : [kK]
  ;

fragment L
  : [lL]
  ;

fragment M
  : [mM]
  ;

fragment N
  : [nN]
  ;

fragment O
  : [oO]
  ;

fragment P
  : [pP]
  ;

fragment Q
  : [qQ]
  ;

fragment R
  : [rR]
  ;

fragment S
  : [sS]
  ;

fragment T
  : [tT]
  ;

fragment U
  : [uU]
  ;

fragment V
  : [vV]
  ;

fragment W
  : [wW]
  ;

fragment X
  : [xX]
  ;

fragment Y
  : [yY]
  ;

fragment Z
  : [zZ]
  ;

fragment DIGIT_PAIR
  : DIGIT DIGIT
  ;

fragment ALPHA
  : 'a'..'z'
  | 'A'..'Z'
  ;

SEMICOLON
  : ';'
  ;

HYPHEN
  : '-'
  ;

PROCEDURE_IDENTIFIER
  : P R O C E D U R E
  ;

COMMA
  : ','
  ;

LEFT_PARENTHESIS
  : '('
  ;

RIGHT_PARENTHESIS
  : ')'
  ;

dataField
  : IDENTIFIER
  ;

nameField
  : dataField
  ;

parameterNameField
  : dataField
  ;

dataTypeField
  : dataField
  ;

IN
  : I N
  ;

WS
  : (' ' | '\t' | '\r' | '\n')+ -> skip
  ;

IDENTIFIER
  : (ALPHA | '_') (ALPHA | DIGIT | '_')*
  ;

COMMENT
  : HYPHEN HYPHEN
  ;

parameterPair
  : parameterNameField IN dataTypeField
  ;

procedureName
  : PROCEDURE_IDENTIFIER nameField
  ;

procedureParameter
  : LEFT_PARENTHESIS parameterPair (COMMA parameterPair)* RIGHT_PARENTHESIS
  ;

procedure
  : procedureName procedureParameter SEMICOLON
  ;

procedures
  : procedure (procedure)*
  ;

能够解析下面的例子:

sorten_COBB_SEK in number,
sorten_COBB_VORG in number,

然而,解析文件将不仅包含此类数据。 它还将存储一些可选而非强制性的信息。 我知道我可以简单地告诉他们使用 ? 是可选的,但这并不那么简单。

我还有这个例子:

sorten_FEUCHTE_MIN in number,
sorten_FEUCHTE_MAX in number,
sorten_FEUCHTE_SPERR in number,
sorten_LEIMUNG in varchar2, -- J or N
sorten_BEMERKUNG in varchar2

其中 -- J or N 与条目 sorten_LEIMUNG 关联,我想获取该条目的信息。问题是分隔符 COMMA 在我要解析的评论之前。

所以像这样的一些语法是行不通的:

parameterPair
  : parameterNameField IN dataTypeField COMMA? COMMENT? dataField?
  ;

procedureParameter
  : LEFT_PARENTHESIS parameterPair (parameterPair)* RIGHT_PARENTHESIS
  ;

我怎样才能实现同时为同一条目(同一行)注册评论的目标?

EDIT: 如上所述,上面的语法将正确解析第一个示例。但是第二个会坏掉。它会将 or 检测为新的 parameterName。 通过第二个语法更改,我能够解析 -- J,而其余部分将被检测为新的 parameterName。

我如何告诉 antlr 按我的意愿解析,或者这是一个限制,我最好告诉用户不要在他的评论中使用空格?

没有你完整的语法,我无法进行真正的测试,但我会尽力为你提出建议。由于您的评论标识符 -- 必须是连续的,因此我将该规则编码为:

TEXT: ALPHA | DIGIT;
TEXTS : TEXT*;

COMMENT
  : '--' TEXTS
  ;

类似的东西可以确保您的 -- 评论 + 混合文本被词法化为评论。

您的 COMMENT 规则不完整。它只包含评论介绍者,但没有任何内容应该与该行的其余部分相匹配。一个典型的做法是:

SINGLE_LINE_COMMENT: '--' ~([\r\n] | EOF)*;

因为我刚开始使用 ANTLR 我不知道这是否是最好的解决方案,但语法规则:

SINGLE_LINE_COMMENT
  : '--' (.)*? '\r'? '\n'
  ;

parameterPair
  : parameterNameField IN dataTypeField COMMA? SINGLE_LINE_COMMENT?
  ;

然后我可以在自定义访问者中执行此操作:

/**
     * Filters out the needed informations of the antlr parser context and 
     * creates the POJO {@link SqlParameter} with it.
     *
     * @param parameterPair the parameter pair
     * @return the sql parameter
     */
    private SqlParameter createParameter( ParameterPairContext parameterPair )
    {
      final String parameterName = parameterPair.parameterNameField().getText();
      final String dataType = parameterPair.dataTypeField().getText();
      Optional<String> comment = Optional.empty();
      if ( parameterPair.SINGLE_LINE_COMMENT() != null )
      {
        comment = Optional.ofNullable( parameterPair.SINGLE_LINE_COMMENT().getText().trim() );
      }

      return new SqlParameter( parameterName, dataType, comment );
    }

这并不是在所有情况下都实用,但现在应该可以解决问题。将其注销会得到我需要的结果:

StringBuilder log = new StringBuilder();
log.append( "Parameter: " );
log.append( parameter.getParameterName() );
log.append( " with type: " );
log.append( parameter.getParameterType() );
parameter.getComment().ifPresent( comment -> log.append( " with comment: " ).append( comment ) );
>>>>>>>>>>>>>>>>>>>>>>>>>>>
Parameter: sorten_FEUCHTE_SPERR with type: number
Parameter: sorten_LEIMUNG with type: varchar2 with comment: -- J or N
Parameter: sorten_BEMERKUNG with type: varchar2