/* * Copyright (c) 2006 David Holroyd */ package uk.co.badgersinfoil.metaas.impl.antlr; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Writer; import java.util.IdentityHashMap; import java.util.Map; import org.antlr.runtime.Token; import org.asdt.core.internal.antlr.AS3Parser; /** * A little hack to create a 'dot' file representing the structure of the * given LinkedListTree, suitable to visualisation using the graphviz.org * 'dot' tool. */ public class ASTDot { private PrintWriter out; private Map doneTokens = new IdentityHashMap(); public ASTDot(Writer writer) { out = new PrintWriter(writer); } public ASTDot(OutputStream stream) { out = new PrintWriter(stream); } public static void dump(LinkedListTree ast) { new ASTDot(System.err).dotify(ast); } public void dotify(LinkedListTree ast) { println("digraph ast_diagram {"); println(" node [fontsize=12];"); nodeSubGraph(ast); tokenSubGraph(ast); startStopTokenEdges(ast); println("}"); out.flush(); } private void nodeSubGraph(LinkedListTree ast) { println(" subgraph tree {"); treeNodes(ast); println(" }"); } private void treeNodes(LinkedListTree ast) { println(" "+nodeName(ast)+" [label="+label(ast)+",shape=invhouse];"); for (int i=0; i<ast.getChildCount(); i++) { LinkedListTree child = (LinkedListTree)ast.getChild(i); println(" "+nodeName(ast)+" -> "+nodeName(child)+" [weight=10,style=bold];"); treeNodes(child); } } private String label(LinkedListTree ast) { return label(AS3Parser.tokenNames[ast.getType()]); } private String nodeName(LinkedListTree ast) { return "ast_0x"+Integer.toHexString(System.identityHashCode(ast)); } private void tokenSubGraph(LinkedListTree ast) { println(" subgraph cluster_tokens {"); println(" rankdir=LR;"); tokenNodes(ast); println(" }"); } private void tokenNodes(LinkedListTree ast) { for (LinkedListToken tok = ast.getStartToken(); tok!=null; tok=tok.getNext()) { tokenNode(tok); } for (int i=0; i<ast.getChildCount(); i++) { LinkedListTree child = (LinkedListTree)ast.getChild(i); tokenNodes(child); } } private int runSeq = 0; private void tokenNode(LinkedListToken tok) { if (doneTokens.containsKey(tok)) { return; } Integer runId = new Integer(runSeq++); out.print(" tok_"+runId+" [label=\""); for (; tok!=null; tok=tok.getNext()) { out.print("<"+fieldName(tok)+"> "+label(tok)); doneTokens.put(tok, runId); if (tok.getNext() != null) { out.print("|"); } } out.println("\",shape=record];"); } private String label(LinkedListToken tok) { if (tok.getType() == Token.EOF) { return "EOF"; } if (tok.getType() == AS3Parser.VIRTUAL_PLACEHOLDER) { return "PLACEHOLD"; } String txt = tok.getText(); if (txt.length() > 10) { txt = txt.substring(0, 7) + "..."; } return "\\\""+txt.replaceAll("\\|", "\\\\|") .replaceAll("\"", "\\\\\"") .replaceAll("\\{", "\\\\{") .replaceAll("\\}", "\\\\}") .replaceAll("<", "\\\\<") .replaceAll(">", "\\\\>") .replaceAll("\n", "\\\\\\\\n") .replaceAll("\t", "\\\\\\\\t")+"\\\""; } private String nodeName(LinkedListToken tok) { return "tok_"+doneTokens.get(tok)+":"+fieldName(tok); } private String fieldName(LinkedListToken tok) { return "f"+Integer.toHexString(System.identityHashCode(tok)); } private void startStopTokenEdges(LinkedListTree ast) { if (ast.getStartToken() != null) { println(" "+nodeName(ast)+" -> "+nodeName(ast.getStartToken())+" [minlen=2,color=green,tailport=w];"); } if (ast.getStopToken() != null) { println(" "+nodeName(ast)+" -> "+nodeName(ast.getStopToken())+" [minlen=2,color=red,tailport=e];"); } for (int i=0; i<ast.getChildCount(); i++) { LinkedListTree child = (LinkedListTree)ast.getChild(i); startStopTokenEdges(child); } } private String label(String str) { if (str.length() > 15) { str = str.substring(0, 15); } StringBuffer res = new StringBuffer("\""); for (int i=0; i<str.length(); i++) { char c = str.charAt(i); switch (c) { case '\n': res.append("\\\\n"); break; case '\r': res.append("\\\\r"); break; case '\t': res.append("\\\\t"); break; case '"': res.append("\\\\\\\""); break; default: res.append(c); } } res.append("\""); return res.toString(); } private void println(String txt) { out.println(txt); } }