如何获取带注释的语法树?

时间:2017-09-10 10:20:01

标签: python antlr antlr4

我正在尝试为多种语言创建文档生成器。为此,我需要一个AST,以便知道,例如,这个注释是针对一个类而且这个是针对这个类的方法。

我开始编写这个简单的Python代码,通过递归查看它来显示树:

import sys
import antlr4
from ECMAScriptLexer import ECMAScriptLexer
from ECMAScriptParser import ECMAScriptParser

def handleTree(tree, lvl=0):
    for child in tree.getChildren():
        if isinstance(child, antlr4.tree.Tree.TerminalNode):
            print(lvl*'│ ' + '└─', child)
        else:
            handleTree(child, lvl+1)

input = antlr4.FileStream(sys.argv[1])
lexer = ECMAScriptLexer(input)
stream = antlr4.CommonTokenStream(lexer)
parser = ECMAScriptParser(stream)
tree = parser.program()
handleTree(tree)

并尝试使用antlr EcmaScript grammar解析此Javascript代码:

var i = 52; // inline comment

function foo() {
  /** The foo documentation */
  console.log('hey');
}

输出:

│ │ │ │ └─ var
│ │ │ │ │ │ └─ i
│ │ │ │ │ │ │ └─ =
│ │ │ │ │ │ │ │ │ │ └─ 52
│ │ │ │ │ └─ ;
│ │ │ └─ function
│ │ │ └─ foo
│ │ │ └─ (
│ │ │ └─ )
│ │ │ └─ {
│ │ │ │ │ │ │ │ │ │ │ │ └─ console
│ │ │ │ │ │ │ │ │ │ │ └─ .
│ │ │ │ │ │ │ │ │ │ │ │ └─ log
│ │ │ │ │ │ │ │ │ │ │ └─ (
│ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ 'hey'
│ │ │ │ │ │ │ │ │ │ │ └─ )
│ │ │ │ │ │ │ │ │ └─ ;
│ │ │ └─ }
└─ <EOF>

所有评论都会被忽略,可能是由于channel(HIDDEN) in the grammar的存在。

经过一些谷歌搜索后,我找到了this这个答案:

  

除非你有非常令人信服的理由将评论放在解析器中(我想听到),否则你应该把它放在词法分析器中。

那么,为什么评论不应该包含在解析器中以及如何获取包含注释的树?

1 个答案:

答案 0 :(得分:3)

  

那么,为什么评论不应该包含在解析器中以及如何获取包含注释的树?

如果您从规则MultiLineComment

中删除MultiLineComment : '/*' .*? '*/' -> channel(HIDDEN) ;
MultiLineComment

然后arrayLiteral将最终出现在解析器中。但是,每个解析器规则都需要包含允许它们使用的这些令牌。

例如,采用/// ArrayLiteral : /// [ Elision? ] /// [ ElementList ] /// [ ElementList , Elision? ] arrayLiteral : '[' elementList? ','? elision? ']' ; 解析器规则:

[/* ... */ 1, 2 /* ... */ , 3 /* ... */ /* ... */]

因为这是JavaScript中的有效数组文字:

MultiLineComment

这意味着您需要使用/// ArrayLiteral : /// [ Elision? ] /// [ ElementList ] /// [ ElementList , Elision? ] arrayLiteral : '[' MultiLineComment* elementList? MultiLineComment* ','? MultiLineComment* elision? MultiLineComment* ']' ; 代码来解决所有解析器规则:

BufferedTokenStream#getHiddenTokensToLeft

这将成为一个大混乱。

修改

来自评论:

  

因此无法使用antlr生成包含注释的树?是否有一些黑客或其他图书馆可以做到这一点?

GRosenberg的回答:

  

Antlr为此任务提供了一种便捷方法:BufferedTokenStream#getHiddenTokensToRight。在遍历解析树时,访问流以获取节点关联的注释(如果有)。使用 // Make a call to the REST api to create the payment return actions.payment.create({ payment: { transactions: [ { amount: { total: '<?= $amount / 100 ?>', currency: 'EUR' }, description: {'The payment transaction description.'} } ] } }); }, 获取任何结尾评论。