如何解析C#代码,然后将其序列化回文本文件

时间:2015-05-15 13:45:42

标签: javascript c# antlr grammar antlr4

我发现有C#antlr4语法。我为该语法为C#构建了antlr4解析器。有用。我可以走遍解析树,看看有些节点有一些孩子。

现在我想从这个解析树中生成C#源代码。

我可以以某种方式生成(语法之外)antlr解析器的逆,而不是解析,当给定解析树将生成将导致此解析树的源代码?

编辑:

我目前在CoffeeScript中的尝试是使用原始源以及antlr放入节点的开始和停止位置,使用源代码片段来处理源代码树,然后再次遍历以打印源代码。唯一的问题是多个节点从源代码中的完全相同的空间开始。为了解决这个问题,我有一些令人讨厌的逻辑,只将源代码放在最深的节点中:

antlr = require 'antlr4'
{CSharp4Parser} = require './CSharp4Parser'
{CSharp4Lexer} = require './CSharp4Lexer'

input = "namespace A { class B {}; class C {} }"

cstream = new antlr.InputStream(input)
lexer = new CSharp4Lexer(cstream)
tstream = new antlr.CommonTokenStream(lexer)
parser = new CSharp4Parser(tstream)
parser.buildParseTrees = true ;

tree = parser.compilation_unit();

decorateWithSource = new antlr.tree.ParseTreeListener();

start =
  prev: null

stop =
  prev: null

o = (msg) -> process.stdout.write(msg)

decorateWithSource.enterEveryRule = (a) ->
  if start.prev
    start.prev.before = input.substr(start.prev.start.start, a.start.start - start.prev.start.start)

  if stop.prev
    stop.prev.after = input.substr(stop.prev.stop.start, a.start.start - stop.prev.stop.start)

  start.prev = a
  stop.prev = null

decorateWithSource.exitEveryRule = (a) ->
  if start.prev
    start.prev.before = input.substr(start.prev.start.start, a.stop.start - start.prev.start.start)

  if stop.prev
    stop.prev.after = input.substr(stop.prev.stop.start, a.stop.start - stop.prev.stop.start)

  start.prev = null
  stop.prev = a

walker = new antlr.tree.ParseTreeWalker();
walker.walk(decorateWithSource, tree);
stop.prev.after = input.substr(stop.prev.stop.start)

printOut = new antlr.tree.ParseTreeListener();
printOut.enterEveryRule = (a) ->
  o (a.before || ''), ' -> '+parser.ruleNames[a.ruleIndex]
printOut.exitEveryRule = (a) ->
  o (a.after || ''), ' < '+parser.ruleNames[a.ruleIndex]
walker.walk(printOut, tree);

我想要做的是将C#源文件(来自重新编译的一些东西)读入树中,然后通过OMeta编写的变换器(将我的环境缩小到具有OMeta实现的语言) C#,js或coffeescript,可能是其他人)然后回写固定的源代码。

也许手动行走解析树来生成代码对我来说已经足够了。

1 个答案:

答案 0 :(得分:3)

不容易; ANTLR实际上并不是为此而设计的。

您可以调查StringTemplates,它可以让您遍历树并吐出大致正确的代码。

如果您想要更详细地重新生成源,这还不够。在How to build a prettyprinter上查看我的答案。