Reputation: 17817
I found that there is C# antlr4 grammar. I build antlr4 parser for C# for that grammar. It works. I can walk the parse tree and see that there are some nodes that have some children.
Now I would like to generate the C# source code back from this parse tree.
Can I somehow generate (out of grammar) inverse of antlr parser that instead of parsing, when given parse tree will generate source code that would result in this parse tree?
EDIT:
My current attempt in CoffeeScript is to walk the source tree decorating it with pieces of source code using original source and start and stop positions that antlr puts in nodes, and then walk it again to print the source code. The only problem is that multiple nodes start at exactly same space in the source code. To deal with that I have some nasty logic to put source pieces only in the deepest node:
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);
What I'm trying to do is read C# source file (that comes from recompiled that botched some things) into a tree, then pass it through transformer written in OMeta (that narrows down my environment to languages that have OMeta implementation like C#, js or coffeescript, possibly others) and then write back the fixed source code.
Maybe manually walking parse tree to generate the code will be good enough for me.
Upvotes: 2
Views: 760
Reputation: 95392
Not easily; ANTLR isn't really designed to do this.
You can investigate StringTemplates, which will let you walk the tree and spit out code that is roughly right.
If you want to regenerate the source in good detail, this isn't enough. See my SO answer on How to build a prettyprinter.
Upvotes: 3