/* * * Copyright 2012 lexergen. * This file is part of lexergen. * * lexergen is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * lexergen is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with lexergen. If not, see <http://www.gnu.org/licenses/>. * * lexergen: * A tool to chunk source code into tokens for further processing in a compiler chain. * * Projectgroup: bi, bii * * Authors: Johannes Dahlke * * Module: Softwareprojekt Übersetzerbau 2012 * * Created: Apr. 2012 * Version: 1.0 * */ package de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.Stack; import java.util.concurrent.ArrayBlockingQueue; import de.fuberlin.bii.regextodfaconverter.directconverter.AutomatEventHandler; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.ItemAutomat; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.ItemAutomatException; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.Lr0ItemAutomat; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.ReduceEventHandler; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.Slr1ItemAutomat; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.ShiftEventHandler; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.ContextFreeGrammar; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.EmptyString; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.Grammar; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.Nonterminal; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.ProductionRule; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.ProductionSet; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.RuleElement; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.Symbol; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.Terminal; import de.fuberlin.bii.regextodfaconverter.directconverter.lrparser.grammar.TerminalSet; import de.fuberlin.bii.regextodfaconverter.directconverter.regex.operatortree.OperatorType; import de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree.node.InnerNode; import de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree.node.Leaf; import de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree.node.NewNodeEventHandler; import de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree.node.NumberedTreeNode; import de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree.node.ScalableInnerNode; import de.fuberlin.bii.regextodfaconverter.directconverter.syntaxtree.node.TreeNode; import de.fuberlin.bii.utils.Notification; import de.fuberlin.bii.utils.Test; /** * Stellt einen konkreten Syntaxbaum dar. * * @author Johannes Dahlke * */ @SuppressWarnings("rawtypes") public class ConcreteSyntaxTree<ExpressionElement extends Symbol> implements Tree, Cloneable { private ArrayList<ExpressionElement> inputElements = null; private Stack<NumberedTreeNode> nodeStack = null; private HashMap<Integer, Stack> stackSnapshots = new HashMap<Integer, Stack>(); /** * Handler für das Ereignis der Erzeugung eines neuen Knoten. */ public NewNodeEventHandler onNewNodeEvent = null; private TreeNode rootNode = null; private Grammar grammar; public ConcreteSyntaxTree( ContextFreeGrammar grammar, ExpressionElement[] expression) throws Exception { this( grammar, expression, null); } public ConcreteSyntaxTree( ContextFreeGrammar grammar, ExpressionElement[] expression, NewNodeEventHandler newNodeEventHandler) throws Exception { this( grammar, expression, newNodeEventHandler, true); } public ConcreteSyntaxTree( ContextFreeGrammar grammar, ExpressionElement[] expression, NewNodeEventHandler newNodeEventHandler, Boolean directBuild) throws Exception { super(); this.grammar = grammar; this.onNewNodeEvent = newNodeEventHandler; initTreeSkeleton(); preprocessInput( expression); if ( directBuild) buildTree(); } protected Stack<NumberedTreeNode> getNodeStack() { return nodeStack; } @SuppressWarnings("static-method") protected ItemAutomat<ExpressionElement> getNewItemAutomat( final Grammar grammar) { return new Slr1ItemAutomat<ExpressionElement>( (ContextFreeGrammar) grammar); } protected void buildTree() throws ItemAutomatException { ItemAutomat<ExpressionElement> itemAutomat = getNewItemAutomat( grammar); itemAutomat.setReduceEventHandler( getReduceEventHandler()); itemAutomat.setShiftEventHandler( getShiftEventHandler()); // Notification.printDebugInfoMessage( "isSLR1 = " + itemAutomat.isReduceConflictFree()); //Notification.printDebugInfoMessage( itemAutomat); itemAutomat.match( inputElements); rootNode = nodeStack.peek().getTreeNode(); } private static PrintHandler getNodePrintHandler() { return new PrintHandler() { public String print( Object... params) { String result = ""; for ( Object obj : params) { if ( obj instanceof ProductionRule) { ProductionRule reduceRule = (ProductionRule) obj; if ( !result.isEmpty()) result += "~"; result += reduceRule.getLeftRuleSide().toString(); } else if ( obj instanceof Terminal) { if ( !result.isEmpty()) result += "~"; result += ((Terminal)obj).toString(); break; } } return result; } }; } protected ReduceEventHandler getReduceEventHandler() { return new ReduceEventHandler() { public Object handle( Object sender, ProductionRule reduceRule, int sequenceNumber) throws Exception { updateStackBySequenceNumber( sequenceNumber); // create new inner node InnerNode<ProductionRule> newInnerNode = new ScalableInnerNode<ProductionRule>( reduceRule); newInnerNode.setPrintHandler( getNodePrintHandler()); if ( Test.isAssigned( onNewNodeEvent)) onNewNodeEvent.doOnEvent( this, newInnerNode); // add childs to the new inner node int countOfReducedElements = reduceRule.getRightRuleSide().size(); for ( int i = countOfReducedElements; i > 0; i--) { if ( reduceRule.getRightRuleSide().get( i-1) instanceof EmptyString) continue; // get child from stack TreeNode childNode = getNodeStack().pop().getTreeNode(); // insert child into parent node newInnerNode.insertChild( childNode, 0); } // push the inner node onto stack NumberedTreeNode newNumberedNode = new NumberedTreeNode<ProductionRule>( newInnerNode, sequenceNumber); nodeStack.push( newNumberedNode); snapshotCurrentStackWithSequenceNumber( sequenceNumber); return null; } }; } protected ShiftEventHandler getShiftEventHandler() { return new ShiftEventHandler() { public Object handle( Object sender, Terminal shiftedTerminal, int sequenceNumber) throws Exception { updateStackBySequenceNumber( sequenceNumber); Leaf<RuleElement> newLeaf = new Leaf<RuleElement>( shiftedTerminal); newLeaf.setPrintHandler( getNodePrintHandler()); if ( Test.isAssigned( onNewNodeEvent)) onNewNodeEvent.doOnEvent( this, newLeaf); NumberedTreeNode newNumberedLeaf = new NumberedTreeNode<RuleElement>( newLeaf, sequenceNumber); nodeStack.push( newNumberedLeaf); snapshotCurrentStackWithSequenceNumber( sequenceNumber); return null; } }; } @SuppressWarnings("unchecked") protected void updateStackBySequenceNumber( int sequenceNumber) { // clear overhang int recentSerial = -1; Set<Integer> keys = new HashSet<Integer>( stackSnapshots.keySet()); for ( Integer stackSerial : keys) { if ( stackSerial >= sequenceNumber) { stackSnapshots.remove( stackSerial); } else recentSerial = Math.max( recentSerial, stackSerial); } // update stack; if ( recentSerial > -1) { nodeStack = (Stack<NumberedTreeNode>) stackSnapshots.get( recentSerial).clone(); } else { nodeStack.clear(); } } @SuppressWarnings("unchecked") protected void snapshotCurrentStackWithSequenceNumber( int sequenceNumber) { stackSnapshots.put( sequenceNumber, (Stack<NumberedTreeNode>) nodeStack.clone()); } private void initTreeSkeleton() { nodeStack = new Stack<NumberedTreeNode>(); } private void preprocessInput( ExpressionElement[] expression) { inputElements = new ArrayList<ExpressionElement>(); for ( ExpressionElement element : expression) { inputElements.add( element); } } public Iterator<TreeNode> iterator() { return new TreeIterator( this); } public TreeNode getRoot() { return rootNode; } @SuppressWarnings("unchecked") @Override public Object clone() throws CloneNotSupportedException { ConcreteSyntaxTree clonedTree = (ConcreteSyntaxTree) super.clone(); clonedTree.grammar = this.grammar; clonedTree.rootNode = (TreeNode) this.rootNode.clone(); clonedTree.onNewNodeEvent = this.onNewNodeEvent; return clonedTree; } /** * Kompremiert den Syntaxbaum. * @param originalTree * @return */ @SuppressWarnings("unchecked") public static ConcreteSyntaxTree compress( ConcreteSyntaxTree originalTree) { // we work on a copy ConcreteSyntaxTree clonedTree; try { clonedTree = (ConcreteSyntaxTree) originalTree.clone(); } catch ( CloneNotSupportedException e) { Notification.printDebugException( e); return null; } // determine all nodes that can be skipped ArrayList<InnerNode> nodesToSkip = new ArrayList<InnerNode>(); for ( TreeNode treeNode : clonedTree) { if ( treeNode instanceof InnerNode) { InnerNode innerTreeNode = (InnerNode) treeNode; if ( innerTreeNode.childCount() == 1 && Test.isAssigned( innerTreeNode.getParentNode()) && innerTreeNode.getParentNode() instanceof InnerNode) { nodesToSkip.add( innerTreeNode); } } } // remove singles for ( InnerNode innerTreeNode : nodesToSkip) { InnerNode innerTreeNodeParent = (InnerNode) innerTreeNode.getParentNode(); int parentIndex = innerTreeNodeParent.getIndexOf( innerTreeNode); TreeNode childNode = innerTreeNode.getNodeWithIndex( 0); childNode.insertValues( 0, innerTreeNode.getValues()); childNode.setParentNode( innerTreeNodeParent, parentIndex); innerTreeNode.setParentNode( null); } return clonedTree; } @Override public String toString() { return Test.isAssigned( rootNode) ? ( ( rootNode instanceof InnerNode) ? ( (InnerNode) rootNode).toFullString() : rootNode.toString()) : super.toString(); } public Grammar getGrammar() { return grammar; } public Collection<Leaf> getLeafSet() { Collection<Leaf> leafSet = new HashSet<Leaf>(); for ( TreeNode node : this) { if ( Test.isAssigned( node) && node instanceof Leaf) { leafSet.add( (Leaf) node); } } return leafSet; } }