【问题标题】:ANTLR v4 dynamic grammarANTLR v4 动态语法
【发布时间】:2018-02-20 14:44:28
【问题描述】:

我有这个语法:

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
  ;

如何实现为同一条目(同一行)注册评论的目标?

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

我如何告诉 antlr 解析我希望的方式,或者这是我最好告诉用户不要在他的 cmets 中使用空格的限制?

【问题讨论】:

    标签: parsing antlr grammar antlr4


    【解决方案1】:

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

    TEXT: ALPHA | DIGIT;
    TEXTS : TEXT*;
    
    COMMENT
      : '--' TEXTS
      ;
    

    类似的东西可以确保您的 -- 评论 + 混合文本被用作评论。

    【讨论】:

    • 明天回到工作场所后,我会更新语法。
    • 我用完整的语法和我现在尝试的其他内容编辑了我的问题。
    • -- 与 HYPHEN HYPHEN 在词法分析器规则中没有区别。
    【解决方案2】:

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

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

    【讨论】:

    • 如果我尝试一下,我会收到 gradle 错误消息:error(134): ProcedureHeaderLanguage.g4:150:20: rule reference EOF is not currently supported in a set。但是删除 EOF 将使其工作,但我无法检索评论文本。我必须能够访问访问者中的文本。
    【解决方案3】:

    由于我刚开始使用 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
    

    【讨论】:

    • 当单行注释是最后一个没有尾随新行的输入标记(这是我上面的 EOF 标记正在解决的问题)时,检查这是否也有效。
    • 但正如我所评论的,EOF 是无效的规则参考。当我使用你的解决方案时,我无法编译。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多