/* * Copyright (c) 2009, IETR/INSA of Rennes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.frontend.schedule; import java.util.Stack; import net.sf.orcc.cal.cal.RegExp; import net.sf.orcc.cal.cal.RegExpBinary; import net.sf.orcc.cal.cal.RegExpTag; import net.sf.orcc.cal.cal.RegExpUnary; import net.sf.orcc.cal.cal.util.CalSwitch; import net.sf.orcc.df.DfFactory; import net.sf.orcc.df.Tag; public class ThompsonBuilder extends CalSwitch<Void> { /** * epsNFA stands for epsilon Nondeterministic Finite Automaton */ private Automaton eNFA; /** * An index for state labeling */ private int index; /** * A stack to store the initial and final states of the subexpressions. */ private Stack<Integer> recursionStack; public ThompsonBuilder() { eNFA = new Automaton(SimpleEdge.class); recursionStack = new Stack<Integer>(); index = 0; } public Automaton build(RegExp regexp) { doSwitch(regexp); int initialGlobal = recursionStack.pop(); int finalGlobal = recursionStack.pop(); eNFA.setInitialState(initialGlobal); eNFA.addFinalState(finalGlobal); return eNFA; } private void caseAlternation(RegExpBinary regexp) { int initialCurrent = index++; eNFA.addVertex(initialCurrent); doSwitch(regexp.getLeft()); int initialLeft = recursionStack.pop(); int finalLeft = recursionStack.pop(); doSwitch(regexp.getRight()); int initialRight = recursionStack.pop(); int finalRight = recursionStack.pop(); int finalCurrent = index++; eNFA.addVertex(finalCurrent); eNFA.addEdge(initialCurrent, initialLeft, NewEpsilon()); eNFA.addEdge(initialCurrent, initialRight, NewEpsilon()); eNFA.addEdge(finalLeft, finalCurrent, NewEpsilon()); eNFA.addEdge(finalRight, finalCurrent, NewEpsilon()); recursionStack.push(finalCurrent); recursionStack.push(initialCurrent); } private void caseConcatenation(RegExpBinary regexp) { doSwitch(regexp.getLeft()); int initialLeft = recursionStack.pop(); int finalLeft = recursionStack.pop(); doSwitch(regexp.getRight()); int initialRight = recursionStack.pop(); int finalRight = recursionStack.pop(); // Simply add an epsilon transition between the two sub automata eNFA.addEdge(finalLeft, initialRight, NewEpsilon()); recursionStack.push(finalRight); recursionStack.push(initialLeft); } @Override public Void caseRegExpBinary(RegExpBinary regexp) { if (regexp.getOperator() == null) { caseConcatenation(regexp); } else { caseAlternation(regexp); } return null; } @Override public Void caseRegExpTag(RegExpTag term) { int initialCurrent = index; int finalCurrent = index + 1; index = index + 2; eNFA.addVertex(initialCurrent); eNFA.addVertex(finalCurrent); Tag label = DfFactory.eINSTANCE.createTag(term.getTag() .getIdentifiers()); eNFA.registerLetter(label); eNFA.addEdge(initialCurrent, finalCurrent, new SimpleEdge(label)); recursionStack.push(finalCurrent); recursionStack.push(initialCurrent); return null; } @Override public Void caseRegExpUnary(RegExpUnary regexp) { if (regexp.getUnaryOperator().equals("*")) { caseStar(regexp); } else { caseZeroOrOne(regexp); } return null; } private void caseStar(RegExpUnary regexp) { int initialCurrent = index++; eNFA.addVertex(initialCurrent); doSwitch(regexp.getChild()); int initialChild = recursionStack.pop(); int finalChild = recursionStack.pop(); int finalCurrent = index++; eNFA.addVertex(finalCurrent); // epsilon transition for 0 occurrences. eNFA.addEdge(initialCurrent, finalCurrent, NewEpsilon()); // entering child regexp eNFA.addEdge(initialCurrent, initialChild, NewEpsilon()); // returning to the beginning of the child regexp eNFA.addEdge(finalChild, initialChild, NewEpsilon()); // exiting child regexp eNFA.addEdge(finalChild, finalCurrent, NewEpsilon()); recursionStack.push(finalCurrent); recursionStack.push(initialCurrent); } private void caseZeroOrOne(RegExpUnary regexp) { // Match 0 or 1 element // Similar to Kleene Star but with no loop back. int initialCurrent = index++; eNFA.addVertex(initialCurrent); doSwitch(regexp.getChild()); int initialChild = recursionStack.pop(); int finalChild = recursionStack.pop(); int finalCurrent = index++; eNFA.addVertex(finalCurrent); // epsilon transition for 0 occurrences. eNFA.addEdge(initialCurrent, finalCurrent, NewEpsilon()); // entering child regexp eNFA.addEdge(initialCurrent, initialChild, NewEpsilon()); // exiting child regexp eNFA.addEdge(finalChild, finalCurrent, NewEpsilon()); recursionStack.push(finalCurrent); recursionStack.push(initialCurrent); } /** * Returns a new epsilon transition. * * @return a new epsilon transition */ private SimpleEdge NewEpsilon() { return new SimpleEdge(null); } }