diff --git a/README.md b/README.md index 5a5a474..b571095 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,6 @@ Also many functions was simplified for easier use, got more obvious names and in # How to use? Since program was designed for beginner programmers helper scripts was provided to make easier access to it's functionality. Java 12+ is required to run emulator. -On Windows double-click run.bat to run a program or debug.bat to debug a program. -On Linux/MacOS run run.sh/debug.sh in terminal to get started(remember to make it executable). \ No newline at end of file +Since version 3.1.0 graphical interface is provided. +On Windows double-click run.bat to run a program or debug.bat to debug or gui.bat to run emulator in graphical mode. +On Linux/MacOS/Windows(with bash installed) run run.sh/debug.sh/gui.sh in terminal to get started(remember to make it executable). \ No newline at end of file diff --git a/scripts/debug.sh b/scripts/debug.sh index 027a359..19def29 100644 --- a/scripts/debug.sh +++ b/scripts/debug.sh @@ -1,4 +1,6 @@ #!/bin/bash echo Specify input file: read -r InputPath -java -jar PseudoAssemblerEmulator.jar -di "$InputPath" \ No newline at end of file +java -jar PseudoAssemblerEmulator.jar -di "$InputPath" +read -n 1 -s -r -p "Press any key to continue..." +echo \ No newline at end of file diff --git a/scripts/gui.bat b/scripts/gui.bat new file mode 100644 index 0000000..14efbd0 --- /dev/null +++ b/scripts/gui.bat @@ -0,0 +1,5 @@ +@echo off +@echo on +java -jar PseudoAssemblerEmulator.jar +@echo off +pause \ No newline at end of file diff --git a/scripts/gui.sh b/scripts/gui.sh new file mode 100644 index 0000000..3d170f5 --- /dev/null +++ b/scripts/gui.sh @@ -0,0 +1,4 @@ +#!/bin/bash +java -jar PseudoAssemblerEmulator.jar +read -n 1 -s -r -p "Press any key to continue..." +echo \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh index f6107f7..368baee 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -1,4 +1,6 @@ #!/bin/bash echo Specify input file: read -r InputPath -java -jar PseudoAssemblerEmulator.jar -i "$InputPath" \ No newline at end of file +java -jar PseudoAssemblerEmulator.jar -i "$InputPath" +read -n 1 -s -r -p "Press any key to continue..." +echo \ No newline at end of file diff --git a/src/com/hermant/Main.java b/src/com/hermant/Main.java index 9e3210f..996d9f5 100644 --- a/src/com/hermant/Main.java +++ b/src/com/hermant/Main.java @@ -3,10 +3,14 @@ import com.hermant.cli.*; import com.hermant.gui.Window; import com.hermant.machine.Machine; +import com.hermant.parser.ParseException; import com.hermant.parser.Parser; import com.hermant.program.Program; +import com.hermant.serializer.SerializationException; import com.hermant.serializer.Serializer; +import java.io.IOException; + public class Main { public static void main(String[] args) { @@ -15,9 +19,21 @@ public static void main(String[] args) { Options options = ArgsParser.parse(args); if(options.version())Version.print(); if(options.help()) Help.printUsage(); - Program program = options.binary() ? - Serializer.deserializeBinary(options.input()) : Parser.parse(options.input()); - if(!options.output().isEmpty()) Serializer.serializeProgram(program, options.output()); + Program program = null; + try { + program = options.binary() ? + Serializer.deserializeBinary(options.input()) : Parser.parse(options.input()); + } catch (IOException | SerializationException | ParseException e) { + e.printStackTrace(); + System.exit(-1); + } + if(!options.output().isEmpty()) { + try { + Serializer.serializeProgram(program, options.output()); + } catch (IOException e) { + e.printStackTrace(); + } + } if(options.abandon())System.exit(0); Machine m = new Machine(options.debug(), options.unsafe()); m.loadProgram(program); diff --git a/src/com/hermant/cli/Version.java b/src/com/hermant/cli/Version.java index 43b4806..33715c6 100644 --- a/src/com/hermant/cli/Version.java +++ b/src/com/hermant/cli/Version.java @@ -3,7 +3,7 @@ public class Version { private static final int MAJOR = 3; - private static final int MINOR = 0; + private static final int MINOR = 1; private static final int REVISION = 0; private static final String PROJECT_NAME = "PseudoAssembler Emulator"; @@ -12,5 +12,8 @@ public class Version { public static void print(){ System.out.println(FULL); } + public static String getFull(){ + return FULL; + } } diff --git a/src/com/hermant/gui/Form.java b/src/com/hermant/gui/Form.java index d15e599..151c876 100644 --- a/src/com/hermant/gui/Form.java +++ b/src/com/hermant/gui/Form.java @@ -1,8 +1,10 @@ package com.hermant.gui; import com.hermant.machine.Machine; +import com.hermant.parser.ParseException; import com.hermant.parser.Parser; import com.hermant.program.Program; +import com.hermant.serializer.SerializationException; import com.hermant.serializer.Serializer; import javax.swing.*; @@ -40,6 +42,7 @@ public class Form { if(returnVal == JFileChooser.APPROVE_OPTION){ File file = inputChooser.getSelectedFile(); input.setText(file.getPath()); + input.setToolTipText(file.getPath()); } }); selectOutputFileButton.addActionListener(e -> { @@ -47,6 +50,7 @@ public class Form { if(returnVal == JFileChooser.APPROVE_OPTION){ File file = outputChooser.getSelectedFile(); output.setText(file.getPath()); + output.setToolTipText(file.getPath()); } }); sleep_slider.addChangeListener( @@ -60,18 +64,20 @@ public class Form { routine.addItem(new Combo(1, "Debug")); routine.addActionListener(e -> run_button.setText(Objects.requireNonNull(routine.getSelectedItem()).toString())); - CustomInputStream streamer = new CustomInputStream(); - terminal.addKeyListener(streamer); - System.setIn(streamer); + CustomInputStream inputStream = new CustomInputStream(); + terminal.addKeyListener(inputStream); + System.setIn(inputStream); CustomOutputStream outputStream = new CustomOutputStream(terminal); PrintStream printStream = new PrintStream(outputStream); System.setOut(printStream); + System.setErr(printStream); run_button.addActionListener(e -> { Thread t = new Thread(() -> { running = true; terminal.setText(""); outputStream.reset(); + inputStream.reset(); setControlsEnabled(false); boolean unsafe = unsafeCheckBox.isSelected(); boolean abandon = abandonCheckBox.isSelected(); @@ -80,16 +86,42 @@ public class Form { int sleep = sleep_slider.getValue() * 10; String inputFile = input.getText(); String outputFile = output.getText(); - if(debug && sleep == 0) - JOptionPane.showMessageDialog(null, "Debugging without sleep is not recommended!"); + int warning = JOptionPane.OK_OPTION; + if(!abandon && debug && sleep == 0) + warning = JOptionPane.showConfirmDialog(null, + "Debugging without sleep is not recommended!\n Continue?", + "Confirm", JOptionPane.YES_NO_OPTION); + if(warning == JOptionPane.NO_OPTION){ + setControlsEnabled(true); + running = false; + return; + } if(inputFile.isEmpty()) JOptionPane.showMessageDialog(null, "You must provide input file!"); else { - Program program = binary ? - Serializer.deserializeBinary(inputFile) : Parser.parse(inputFile); - if(!outputFile.isEmpty()) Serializer.serializeProgram(program, outputFile); + Program program; + try { + program = binary ? + Serializer.deserializeBinary(inputFile) : Parser.parse(inputFile); + } catch (IOException | SerializationException | ParseException ex) { + ex.printStackTrace(); + setControlsEnabled(true); + running = false; + return; + } + if(!outputFile.isEmpty()) { + try { + Serializer.serializeProgram(program, outputFile); + } catch (IOException ex) { + ex.printStackTrace(); + } + } Machine m = new Machine(debug, unsafe); m.loadProgram(program); - if(!abandon) m.runProgram(sleep); + if(!abandon) + try { m.runProgram(sleep); } + catch (Exception ex){ + ex.printStackTrace(); + } m.free(); } setControlsEnabled(true); @@ -185,7 +217,10 @@ static class CustomInputStream extends InputStream implements KeyListener { private StringBuilder buffer = new StringBuilder(); private int pos = 0; - CustomInputStream() { + public void reset(){ + str = ""; + pos = 0; + buffer = new StringBuilder(); } @Override diff --git a/src/com/hermant/gui/Window.java b/src/com/hermant/gui/Window.java index 947af42..d5fc790 100644 --- a/src/com/hermant/gui/Window.java +++ b/src/com/hermant/gui/Window.java @@ -1,11 +1,13 @@ package com.hermant.gui; +import com.hermant.cli.Version; + import javax.swing.*; import java.awt.*; public class Window { public Window(){ - JFrame frame = new JFrame("gui"); + JFrame frame = new JFrame(Version.getFull()); Form form = new Form(); frame.setContentPane(form.getMain()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/src/com/hermant/parser/ParseException.java b/src/com/hermant/parser/ParseException.java index a3b2470..6fcfe5f 100644 --- a/src/com/hermant/parser/ParseException.java +++ b/src/com/hermant/parser/ParseException.java @@ -1,6 +1,6 @@ package com.hermant.parser; -class ParseException extends Exception{ +public class ParseException extends Exception{ ParseException(String errorMessage, int lineNumber) { super(errorMessage + " at line " + lineNumber); } diff --git a/src/com/hermant/parser/Parser.java b/src/com/hermant/parser/Parser.java index f12278e..8d45cd3 100644 --- a/src/com/hermant/parser/Parser.java +++ b/src/com/hermant/parser/Parser.java @@ -482,15 +482,8 @@ public Declaration create(int count, String value) { public abstract Declaration create(int count, String value); } - public static Program parse(String path){ - Program program = new Program(); - try { - program = parse(path, analyzeLabels(path)); - } catch (IOException | ParseException e) { - e.printStackTrace(); - System.exit(1); - } - return program; + public static Program parse(String path) throws IOException, ParseException { + return parse(path, analyzeLabels(path)); } private static Program parse(String path, Map labelMemoryTranslation) throws ParseException, IOException { diff --git a/src/com/hermant/serializer/SerializationException.java b/src/com/hermant/serializer/SerializationException.java index d6d0caa..a2a6ab2 100644 --- a/src/com/hermant/serializer/SerializationException.java +++ b/src/com/hermant/serializer/SerializationException.java @@ -1,6 +1,6 @@ package com.hermant.serializer; -class SerializationException extends Exception { +public class SerializationException extends Exception { SerializationException(String errorMessage) { super(errorMessage); } diff --git a/src/com/hermant/serializer/Serializer.java b/src/com/hermant/serializer/Serializer.java index 63d9d44..ad69837 100644 --- a/src/com/hermant/serializer/Serializer.java +++ b/src/com/hermant/serializer/Serializer.java @@ -78,39 +78,30 @@ Declaration deserialize(ByteBuffer buffer) { abstract Declaration deserialize(ByteBuffer buffer); } - public static Program deserializeBinary(String path){ + public static Program deserializeBinary(String path) throws IOException, SerializationException, BufferUnderflowException { Program program = new Program(); - try { - byte[] bytes = Files.readAllBytes(Paths.get(path)); - ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); - if(buffer.remaining() < 2)throw new SerializationException("File is too small."); - int declarations = Short.toUnsignedInt(buffer.getShort()); - int maxDeclarationType = DeclarationType.values().length - 1; - while(declarations > 0 && buffer.hasRemaining()){ - int typeIndex = buffer.get(); - if(typeIndex > maxDeclarationType || typeIndex < 0) - throw new SerializationException("invalid internal structure"); - DeclarationType type = DeclarationType.values()[typeIndex]; - program.addDeclaration(type.deserialize(buffer)); - declarations--; - } - if(declarations > 0) throw new SerializationException("invalid internal structure"); - while(buffer.hasRemaining()){ - program.addInstruction(deserializeInstruction(buffer)); - } - } catch (IOException | SerializationException | BufferUnderflowException e) { - e.printStackTrace(); - System.exit(1); + byte[] bytes = Files.readAllBytes(Paths.get(path)); + ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + if(buffer.remaining() < 2)throw new SerializationException("File is too small."); + int declarations = Short.toUnsignedInt(buffer.getShort()); + int maxDeclarationType = DeclarationType.values().length - 1; + while(declarations > 0 && buffer.hasRemaining()){ + int typeIndex = buffer.get(); + if(typeIndex > maxDeclarationType || typeIndex < 0) + throw new SerializationException("invalid internal structure"); + DeclarationType type = DeclarationType.values()[typeIndex]; + program.addDeclaration(type.deserialize(buffer)); + declarations--; + } + if(declarations > 0) throw new SerializationException("invalid internal structure"); + while(buffer.hasRemaining()){ + program.addInstruction(deserializeInstruction(buffer)); } return program; } - public static void serializeProgram(Program program, String path){ - try { - Files.write(Paths.get(path), program.serialize()); - } catch (IOException e) { - e.printStackTrace(); - } + public static void serializeProgram(Program program, String path) throws IOException { + Files.write(Paths.get(path), program.serialize()); } private static LoadableInstruction deserializeInstruction(ByteBuffer buffer){