使用ANTLR解析JavaDoc注释

时间:2010-10-01 02:13:24

标签: javascript javadoc antlr antlr3

我正在尝试在我的JavaScript文件中解析一个特定的(本地增长的)JavaDoc标记,而我正在努力理解如何实现这一点。 Antlr抱怨如下:

jsDocComment 
    : '/**' (importJsDocCommand | ~('*/'))* '*/' <== See note 1
    ;

importJsDocCommand
    : '@import' gav
    ;

gav
    :  gavGroup ':' gavArtifact
    -> ^(IMPORT gavGroup gavArtifact)
    ;

gavGroup 
    : gavIdentifier
    ;

gavArtifact
    : gavIdentifier
    ;

gavIdentifier 
    : ('a'..'z'|'A'..'Z') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-'|'.')* <== See note 2
    ;
  • 注1:永远无法匹配以下备选方案:1

  • 注2:决策可以匹配输入,例如“'_'..'。'”使用多个替代方案:1,2结果,替代方案2被禁用该输入

以下是我要解析的内容:

/** a */
/** @something */
/** @import com.jquery:jquery */

所有行都应解析好,只需在名为“IMPORT”的AST树元素下创建的@import语句(及其Maven组:工件值)。

感谢您的协助。

2 个答案:

答案 0 :(得分:2)

  

Christopher Hunt写道:

     
      
  • 注1:永远不能匹配以下替代方案:1
  •   

~('*/')不正确:你只能在词法规则中否定单个字符(!)。在您的代码段中,您试图在解析器规则中否定某些内容。在解析器规则中,您不是否定字符,而是标记令牌。例如:

parse : ~A;
foo   : .;
A     : 'A';
B     : 'B';
C     : 'C';

parse规则将匹配除'A'之外的任何字符,但匹配'B''C'。并且foo 匹配任何字符,但匹配任何标记(或词法分析器规则)。

  

Christopher Hunt写道:

     
      
  • 注2:决策可以匹配输入,例如“'_'..'。'”使用多个替代方案:1,2因此,替代方案2被禁用该输入
  •   

两个问题:

  1. 你发表了整个语法吗?
  2. 您是在尝试解析整个JS文件,还是只是“过滤”JS文件并删除JavaDoc注释?
  3. 如果是后者,使用ANTLR可以更容易地做到这一点(如果是这种情况可以给出解释)。

    修改

    最简单的方法是在lexer上添加一个新的DocComment规则,并将其放在(现有的)Comment规则之上:

    DocComment
      :  '/**' (options {greedy=false;} : .)* '*/'
      ;
    
    Comment
      :  '/*' (options {greedy=false;} : .)* '*/' {$channel=HIDDEN;}
      ;
    

答案 1 :(得分:0)

我对这个问题的解决方案是使用没有解析器的ANTLR的Lexer并过滤掉我不感兴趣的东西。这就是我想出的东西(它还寻找全局定义的变量以及导入):

lexer grammar ECMAScriptLexer;

options {filter=true;}

@lexer::header {
    package com.classactionpl.mojo.javascript;
}

@members {
    int scopeLevel = 0;
}

IMPORTDOC
    :   '/**' .* IMPORT .* (IMPORT)* '*/'
    ;

fragment 
IMPORT
    :   '@import' WS groupId=GAVID ':' artifactId=GAVID
        {System.out.println("found import: " + $groupId.text + ":" + $artifactId.text);}
    ;

fragment
GAVID  
    :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'-'|'0'..'9'|'.')*
    ;

COMMENT
    :   '/*' .* '*/'
    ;

SL_COMMENT
    :   '//' .* '\n' 
    ;

ENTER_SCOPE
    :   '{' {++scopeLevel;}
    ;

EXIT_SCOPE
    :   '}' {--scopeLevel;}
    ;

WINDOW_VAR
    :   'window.' name=ID WS? value=(';' | '=') ~('=')
        {
            System.out.println("found window var " + $name.text + " = " + ($value == ';'));
        }
    ;

GLOBAL_VAR
    :   'var' WS name=ID WS? value=(';' | '=') ~('=')
        {
            if (scopeLevel == 0) {
                System.out.println("found global var " + $name.text + " = " + ($value == ';'));
            }
        }
    ;

fragment
ID  :   ('a'..'z'|'A'..'Z'|'$'|'_') ('a'..'z'|'A'..'Z'|'$'|'_'|'0'..'9')*
    ;

fragment
WS  :   (' '|'\t'|'\n')+
    ;