代码之家  ›  专栏  ›  技术社区  ›  Christopher Hunt

使用antlr解析javadoc注释

  •  2
  • Christopher Hunt  · 技术社区  · 14 年前

    我正试图在我的javascript文件中解析一个特定的(国产的)javadoc标记,我正在努力理解如何实现这一点。安特尔的投诉记录如下:

    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 */
    

    所有行都应该解析OK,只需在名为“import”的ast树元素下创建@import语句(及其maven group:artifact值)。

    谢谢你的帮助。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Bart Kiers    14 年前

    克里斯托弗·亨特写道:

    • 注1:以下选项永远无法匹配:1

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

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

    这个 parse 规则将 匹配除 'A' ,但两者都匹配 'B' 'C' . 和 foo 匹配任何字符,但匹配任何令牌(或lexer规则)。

    克里斯托弗·亨特写道:

    • 注2:决策可以使用多个备选方案来匹配输入,如“'…”:1,2因此,该输入的备选方案2被禁用。

    两个问题:

    1. 你把整个语法都贴出来了吗?
    2. 您是在尝试解析整个JS文件,还是只是“过滤”JS文件并拉出JavaDoc注释?

    如果是后者,使用antlr可以更容易地做到这一点(如果是这样的话,也可以给出解释)。

    编辑

    只需添加一个新的 DocComment 统治凌志者并将其置于(现有的) Comment 规则:

    DocComment
      :  '/**' (options {greedy=false;} : .)* '*/'
      ;
    
    Comment
      :  '/*' (options {greedy=false;} : .)* '*/' {$channel=HIDDEN;}
      ;
    
        2
  •  0
  •   Christopher Hunt    14 年前

    我解决这个问题的方法是在没有解析器的情况下使用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')+
        ;