package de.fuberlin.projecta.parser; import de.fuberlin.commons.lexer.IToken; import de.fuberlin.commons.parser.ISyntaxTree; import de.fuberlin.projecta.utils.StringUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; public class Tree implements ISyntaxTree { private final Symbol symbol; private final ArrayList<ISyntaxTree> children = new ArrayList<ISyntaxTree>(); private final HashMap<String, Object> attributes = new HashMap<String, Object>(); private IToken token; private ISyntaxTree parent = null; /** * Creates a new empty node for non-terminals. * * @param symbol */ public Tree(Symbol symbol) { this.symbol = symbol; } @Override public void addChild(ISyntaxTree child) { if (child.getParent() == this) return; if (children.contains(child)) return; children.add(child); child.setParent(this); } @Override public int getChildrenCount() { return children.size(); } @Override public ISyntaxTree getChild(int i) { return children.get(i); } @Override public Object getAttribute(String key) { return attributes.get(key); } @Override public List<ISyntaxTree> getChildrenByName(String name) { List<ISyntaxTree> res = new LinkedList<ISyntaxTree>(); for (ISyntaxTree child : getChildren()) { if (child.getSymbol().getName().equals(name)) res.add(child); } return res; } @Override public boolean setAttribute(String key, Object value) { if (!attributes.containsKey(key)) { System.out.println("Warning, attribute not declared: " + key); return false; } attributes.put(key, value); return true; } public boolean addAttribute(String key) { if (attributes.containsKey(key)) { System.out.println("Warning: attribute already declared: " + key); return false; } attributes.put(key, null); // declare return true; } @Override public void setParent(ISyntaxTree parent) { if (getParent() == parent) { return; } if (parent != null && parent.getParent() == this) { System.out.println("Warning: Cyclic link detected."); return; } if (parent != null) { parent.addChild(this); } else { // remove this instance from old parent removeChild(this.parent, this); } this.parent = parent; } public void printTree() { printTree(0); } protected void printTree(int depth) { System.out.print(StringUtils.repeat(' ', depth)); if (getSymbol() != null) System.out.println(getSymbol()); else if (getToken() != null) { System.out.println(toString() + " (Token: " + getToken() + ")"); } else { System.out.println(toString()); } for (int i = 0; i < getChildrenCount(); ++i) { Tree tree = (Tree) getChild(i); if (tree != null) tree.printTree(depth + 2); } } @Override public List<ISyntaxTree> getChildren() { return children; } private static ISyntaxTree removeChild(ISyntaxTree tree, ISyntaxTree child) { final int index = tree.getChildren().indexOf(child); if (index < 0) return null; return tree.removeChild(index); } @Override public ISyntaxTree removeChild(int i) { ISyntaxTree child = children.remove(i); child.setParent(null); return child; } @Override public Symbol getSymbol() { return symbol; } public void setToken(IToken token) { this.token = token; } @Override public IToken getToken() { return token; } @Override public ISyntaxTree getParent() { return parent; } }