/* * JFLAP - Formal Languages and Automata Package * * * Susan H. Rodger * Computer Science Department * Duke University * August 27, 2009 * Copyright (c) 2002-2009 * All rights reserved. * JFLAP is open source software. Please see the LICENSE for terms. * */ package gui.action; import automata.Automaton; import automata.AutomatonSimulator; import automata.Configuration; import automata.NondeterminismDetector; import automata.NondeterminismDetectorFactory; import automata.SimulatorFactory; import automata.State; import grammar.Grammar; import gui.InputBox; import gui.editor.EditBlockPane; import gui.environment.Environment; import gui.environment.Universe; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import gui.sim.SimulatorPane; import gui.environment.tag.CriticalTag; import javax.swing.*; import java.awt.GridLayout; import java.awt.Component; import java.util.*; import java.io.*; import automata.graph.AutomatonDirectedGraph; import automata.mealy.MealyMachine; import automata.turing.TuringMachine; import automata.turing.TMSimulator; /** * This is the action used for the stepwise simulation of data. This method can * operate on any automaton. It uses a special exception for the two tape case. * * @author Thomas Finley */ public class SimulateAction extends AutomatonAction { private Grammar gram; /** * Instantiates a new SimulateAction. * * @param automaton * the automaton that input will be simulated on * @param environment * the environment object that we shall add our simulator pane to */ public SimulateAction(Automaton automaton, Environment environment) { super("Step...", null); if (SimulateNoClosureAction.isApplicable(automaton)) putValue(NAME, "Step with Closure..."); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, MAIN_MENU_MASK)); this.automaton = automaton; this.environment = environment; } public SimulateAction(Grammar gram, Environment environment) { super("Step...", null); if (SimulateNoClosureAction.isApplicable(automaton)) putValue(NAME, "Step with Closure..."); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, MAIN_MENU_MASK)); this.gram = gram; this.environment = environment; } /** * Returns the simulator for this automaton. * * @param automaton * the automaton to get the simulator for * @return a simulator for this automaton */ protected AutomatonSimulator getSimulator(Automaton automaton) { return SimulatorFactory.getSimulator(automaton); } /** * Given initial configurations, the simulator, and the automaton, takes any * further action that may be necessary. In the case of stepwise operation, * which is the default, an additional tab is added to the environment * * @param automaton * the automaton input is simulated on * @param simulator * the automaton simulator for this automaton * @param configurations * the initial configurations generated * @param initialInput * the object that represents the initial input; this is a String * object in most cases, but may differ for multiple tape turing * machines */ public void handleInteraction(Automaton automaton, AutomatonSimulator simulator, Configuration[] configurations, Object initialInput) { SimulatorPane simpane = new SimulatorPane(automaton, simulator, configurations, environment, false); if (initialInput instanceof String[]) initialInput = java.util.Arrays.asList((String[]) initialInput); environment.add(simpane, "Simulate: " + initialInput, new CriticalTag() { }); environment.setActive(simpane); } /** * This returns an object that encapsulates the user input for the starting * configuration. In most cases this will be a string, except in the case of * a multiple tape Turing machine. This method will probably involve some * prompt to the user. By default this method prompts the user using a * dialog box and returns the result from that dialog. * * @param component * a parent for whatever dialogs are brought up * @return the object that represents the initial input to the machine, or * null if the user elected to cancel */ protected Object initialInput(Component component, String title) { if(title.equals("")) title = "Input"; if(getObject() instanceof TuringMachine){ // Do the multitape stuff. TuringMachine tm = (TuringMachine) getObject(); int tapes = tm.tapes(); if(title.equals("Expected Result? (Accept or Reject)")){ title = "Result"; tapes = 1; } if(title.equals("Expected Output?")){ title = "Output"; } return openInputGUI(component, title, tapes); } else{ if (title.equals("")){ return openInputGUI(component, "Input?", 0); //return JOptionPane.showInputDialog(component, "Input?"); } else { return openInputGUI(component, title, 0); //return JOptionPane.showInputDialog(component, title+ "?!!!!"); } } } /** * Opens pop-up GUI for taking input. Now JFLAP can take file as an input. * @param component * @param title * @return */ private Object openInputGUI(final Component component, String title, final int tapes) { // TODO Auto-generated method stub JPanel panel; JTextField[] fields; //for FA, PDA if (tapes==0) { panel = new JPanel(new GridLayout(3, 1)); fields = new JTextField[1]; for (int i = 0; i < 1; i++) { panel.add(new JLabel(title + " ")); panel.add(fields[i] = new JTextField()); } } else { panel = new JPanel(new GridLayout(tapes*2+1, 2)); fields = new JTextField[tapes]; for (int i = 0; i < tapes; i++) { panel.add(new JLabel(title + " "+(i+1))); panel.add(fields[i] = new JTextField()); } } JButton jb=new JButton("Click to Open Input File"); jb.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub JFileChooser ourChooser=new JFileChooser (System.getProperties().getProperty("user.dir")); int retval=ourChooser.showOpenDialog(null); File f=null; if (retval==JFileChooser.APPROVE_OPTION) { f=ourChooser.getSelectedFile(); try { Scanner sc=new Scanner(f); if (tapes!=0) { String[] input = new String[tapes]; for (int i = 0; i < tapes; i++) { if (sc.hasNext()) input[i] = sc.next(); else { JOptionPane.showMessageDialog(component, "Input file does not have enough input for all tapes", "File read error" , JOptionPane.ERROR_MESSAGE); return; } } JOptionPane.getFrameForComponent(component).dispose(); handleInputFile(input); } else { String tt=sc.next(); JOptionPane.getFrameForComponent(component).dispose(); handleInputFile(tt); } } catch (FileNotFoundException e1) { // TODO Auto-generate catch block e1.printStackTrace(); } } } }); panel.add(jb); int result = JOptionPane.showOptionDialog(component, panel, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null); if (result != JOptionPane.YES_OPTION && result != JOptionPane.OK_OPTION) return null; if (tapes==0) { String input = fields[0].getText(); return input; } else { String[] input = new String[tapes]; for (int i = 0; i < tapes; i++) input[i] = fields[i].getText(); return input; } } private void handleInputFile(Object input) { Configuration[] configs = null; AutomatonSimulator simulator = getSimulator(automaton); /* if (input instanceof InputBox) { InputBox tt=(InputBox) input; if (getObject() instanceof TuringMachine) tt.addSimulator(automaton, simulator, true); else tt.addSimulator(automaton, simulator, false); return; }*/ if (input == null) return; // Get the initial configurations. if (getObject() instanceof TuringMachine) { String[] s = (String[]) input; configs = ((TMSimulator) simulator).getInitialConfigurations(s); } else { String s = (String) input; configs = simulator.getInitialConfigurations(s); } handleInteraction(automaton, simulator, configs, input); } /** * Performs the action. */ public void actionPerformed(ActionEvent e) { boolean blockEdit = false; if (environment.getActive() instanceof EditBlockPane) { EditBlockPane newPane = (EditBlockPane) environment.getActive(); automaton = newPane.getAutomaton(); blockEdit = true; } if (!automatonActionPermissible((Component) e.getSource())) return; Object input = initialInput((Component) e.getSource(), ""); Configuration[] configs = null; AutomatonSimulator simulator = getSimulator(automaton); /* if (input instanceof InputBox) { InputBox tt=(InputBox) input; if (getObject() instanceof TuringMachine) tt.addSimulator(automaton, simulator, true); else tt.addSimulator(automaton, simulator, false); return; }*/ if (input == null) return; // Get the initial configurations. if (getObject() instanceof TuringMachine) { String[] s = (String[]) input; configs = ((TMSimulator) simulator).getInitialConfigurations(s); } else { String s = (String) input; configs = simulator.getInitialConfigurations(s); } handleInteraction(automaton, simulator, configs, input); } /** * Returns whether the current automaton can legally be simulated. If not, * a dialog pops up. Will true if automaton = null. * * @param source * the source of this action * @return whether the current automaton can legally be simulated */ protected boolean automatonActionPermissible(Component source) { if (!(getObject() instanceof Automaton)) return true; if (automaton.getInitialState() == null) { JOptionPane.showMessageDialog(source, "Simulation requires an automaton\n" + "with an initial state!", "No Initial State", JOptionPane.ERROR_MESSAGE); return false; } /* * If it is a Moore or Mealy machine, don't let it start if it has * nondeterministic states. */ if(automaton instanceof MealyMachine) { NondeterminismDetector d = NondeterminismDetectorFactory.getDetector(automaton); State[] nd = d.getNondeterministicStates(automaton); if(nd.length > 0) { JOptionPane.showMessageDialog(source, "Please remove nondeterminism for simulation.\n" + "Select menu item Test : Highlight Nondeterminism\nto see nondeterministic states.", "Nondeterministic states detected", JOptionPane.ERROR_MESSAGE); return false; } } /* * If it is a Turing machine, there are transitions from the final state, and that preference * hasn't been enabled, give a warning and return. */ else if (automaton instanceof TuringMachine && !Universe.curProfile.transitionsFromTuringFinalStateAllowed()) { TuringMachine turingMachine = (TuringMachine) automaton; Object[] finalStates = turingMachine.getFinalStates(); AutomatonDirectedGraph graph = new AutomatonDirectedGraph(turingMachine); for (int i=0; i 0) { JOptionPane.showMessageDialog(source, "There are transitions from final states. Please remove them or change " + "\nthe preference in the \"Preferences\" menu in the JFLAP main menu.", "Transitions From Final States", JOptionPane.ERROR_MESSAGE); return false; } } return true; } /** * Simulate actions are applicable to every automaton which accepts a single * string of input, i.e., every automaton except for dual tape turing * machines. * * @param object * to object to test for applicability */ public static boolean isApplicable(Object object) { return object instanceof Automaton; } /** * Returns the automaton. * * @return the automaton */ protected Object getObject() { if(automaton != null)return automaton; else return gram; } /** * Returns the environment. * * @return the environment */ protected Environment getEnvironment() { return environment; } protected void setEnvironment(Environment newEnv) { environment = newEnv; } /** The automaton this simulate action runs simulations on! */ private Automaton automaton; /** The environment that the simulation pane will be put in. */ private Environment environment; }