diff --git a/src/com/annimon/asm/AnalyzerPanel.java b/src/com/annimon/asm/AnalyzerPanel.java index 8d0f05b..2b2426b 100644 --- a/src/com/annimon/asm/AnalyzerPanel.java +++ b/src/com/annimon/asm/AnalyzerPanel.java @@ -1,141 +1,137 @@ -package com.annimon.asm; - -import com.annimon.asm.exceptions.ExceptionWithLineNumber; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextPane; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.JTextComponent; -import javax.swing.text.Utilities; - -/** - * Основная панель приложения. - * @author aNNiMON - */ -public final class AnalyzerPanel extends JPanel { - - private JLabel lineNumberLabel; - private JTextPane textPane; - private JButton analyzeButton; - - public AnalyzerPanel() { - lineNumberLabel = new JLabel("Line: 1"); - initTextPane(); - initAnalyzeButton(); - - setLayout(new BorderLayout(0, 0)); - add(lineNumberLabel, BorderLayout.NORTH); - add(new JScrollPane(textPane)); - add(analyzeButton, BorderLayout.SOUTH); - } - - public AnalyzerPanel(String text) { - textPane = new JTextPane(); - textPane.setPreferredSize(new Dimension(300, 300)); - textPane.setFont(new Font("Consolas", Font.PLAIN, 14)); - textPane.setText(text); - - setLayout(new BorderLayout(0, 0)); - add(new JScrollPane(textPane)); - } - - private void initTextPane() { - textPane = new JTextPane(); - textPane.setPreferredSize(new Dimension(300, 350)); - textPane.addCaretListener(new CaretListener() { - - @Override - public void caretUpdate(CaretEvent caretEvent) { - // Вывести позицию каретки в lineNumberLabel. - JTextComponent textComponent = (JTextComponent)caretEvent.getSource(); - - int pos = caretEvent.getDot(); - int rowNumber = (pos == 0) ? 1 : 0; - try { - int offset = pos; - while (offset > 0) { - offset = Utilities.getRowStart(textComponent, offset) - 1; - rowNumber++; - } - } catch (BadLocationException ex) {} - - lineNumberLabel.setText("Line: " + rowNumber); - } - }); - textPane.setFont(new Font("Consolas", Font.PLAIN, 14)); - textPane.setText(getTextFromResource("/test.asm")); - } - - private void initAnalyzeButton() { - analyzeButton = new JButton("Analyze"); - analyzeButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent actionEvent) { - String allText = textPane.getText(); - - // Лексический анализ - переводим набор директив в кодовую таблицу. - LexicalAnalyzer lex = new LexicalAnalyzer(allText); - lex.analyze(); - - // Синтаксический анализ - проверка правильности набора директив. - SyntaxAnalyzer syn = new SyntaxAnalyzer(lex.getLexicTable()); - try { - syn.analyze(); - } catch (ExceptionWithLineNumber ex) { - showMessageBox("Error", ex.getMessage(), true); - return; - } - - //showMessageBox("Info","Source is correct!", false); - // Генерируем листинг. - ListingGenerator gen = new ListingGenerator(lex.getLexicTable(), lex.getVarTable(), lex.getLines()); - String listing = gen.generate(); - - showListing(listing); - } - }); - } - - private void showMessageBox(String title, String text, boolean errorMessage) { - int msgType = errorMessage ? JOptionPane.ERROR_MESSAGE : - JOptionPane.INFORMATION_MESSAGE; - JOptionPane.showMessageDialog(this, text, title, msgType); - } - - private void showListing(String listing) { - JOptionPane.showMessageDialog(this, new AnalyzerPanel(listing), - "Listing", JOptionPane.PLAIN_MESSAGE); - } - - private String getTextFromResource(String res) { - try { - InputStream is = getClass().getResourceAsStream(res); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - - StringBuilder text = new StringBuilder(); - String line; - while( (line = reader.readLine()) != null ) { - text.append(line).append(System.lineSeparator()); - } - - reader.close(); - return text.toString(); - } catch (IOException ex) {} - return ""; - } -} +package com.annimon.asm; + +import com.annimon.asm.exceptions.ExceptionWithLineNumber; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.JTextComponent; +import javax.swing.text.Utilities; + +/** + * Основная панель приложения. + * @author aNNiMON + */ +public final class AnalyzerPanel extends JPanel { + + private JLabel lineNumberLabel; + private JTextPane textPane; + private JButton analyzeButton; + + public AnalyzerPanel() { + lineNumberLabel = new JLabel("Line: 1"); + initTextPane(); + initAnalyzeButton(); + + setLayout(new BorderLayout(0, 0)); + add(lineNumberLabel, BorderLayout.NORTH); + add(new JScrollPane(textPane)); + add(analyzeButton, BorderLayout.SOUTH); + } + + public AnalyzerPanel(String text) { + textPane = new JTextPane(); + textPane.setPreferredSize(new Dimension(300, 300)); + textPane.setFont(new Font("Consolas", Font.PLAIN, 14)); + textPane.setText(text); + + setLayout(new BorderLayout(0, 0)); + add(new JScrollPane(textPane)); + } + + private void initTextPane() { + textPane = new JTextPane(); + textPane.setPreferredSize(new Dimension(300, 350)); + textPane.addCaretListener(new CaretListener() { + + @Override + public void caretUpdate(CaretEvent caretEvent) { + // Вывести позицию каретки в lineNumberLabel. + JTextComponent textComponent = (JTextComponent)caretEvent.getSource(); + + int pos = caretEvent.getDot(); + int rowNumber = (pos == 0) ? 1 : 0; + try { + int offset = pos; + while (offset > 0) { + offset = Utilities.getRowStart(textComponent, offset) - 1; + rowNumber++; + } + } catch (BadLocationException ex) {} + + lineNumberLabel.setText("Line: " + rowNumber); + } + }); + textPane.setFont(new Font("Consolas", Font.PLAIN, 14)); + textPane.setText(getTextFromResource("/test.asm")); + } + + private void initAnalyzeButton() { + analyzeButton = new JButton("Analyze"); + analyzeButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent actionEvent) { + String allText = textPane.getText(); + + // Лексический анализ - переводим набор директив в кодовую таблицу. + LexicalAnalyzer lex = new LexicalAnalyzer(allText); + lex.analyze(); + + // Синтаксический анализ - проверка правильности набора директив. + SyntaxAnalyzer syn = new SyntaxAnalyzer(lex.getLexicTable()); + try { + syn.analyze(); + } catch (ExceptionWithLineNumber ex) { + showMessageBox("Error", ex.getMessage(), true); + return; + } + + //showMessageBox("Info","Source is correct!", false); + // Генерируем листинг. + ListingGenerator gen = new ListingGenerator(lex.getLexicTable(), lex.getVarTable(), lex.getLines()); + String listing = gen.generate(); + + showListing(listing); + } + }); + } + + private void showMessageBox(String title, String text, boolean errorMessage) { + int msgType = errorMessage ? JOptionPane.ERROR_MESSAGE : + JOptionPane.INFORMATION_MESSAGE; + JOptionPane.showMessageDialog(this, text, title, msgType); + } + + private void showListing(String listing) { + JOptionPane.showMessageDialog(this, new AnalyzerPanel(listing), + "Listing", JOptionPane.PLAIN_MESSAGE); + } + + private String getTextFromResource(String res) { + final StringBuilder text = new StringBuilder(); + try (InputStream is = getClass().getResourceAsStream(res)) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + String line; + while ( (line = reader.readLine()) != null ) { + text.append(line).append(System.lineSeparator()); + } + } + } catch (IOException ex) {} + return text.toString(); + } +} diff --git a/src/com/annimon/asm/DirectiveConverter.java b/src/com/annimon/asm/DirectiveConverter.java index 750d790..336b395 100644 --- a/src/com/annimon/asm/DirectiveConverter.java +++ b/src/com/annimon/asm/DirectiveConverter.java @@ -2,6 +2,8 @@ package com.annimon.asm; import com.annimon.asm.directives.*; import java.util.ArrayList; +import java.util.List; +import java.util.Locale; /** * Конвертер директив. @@ -39,8 +41,7 @@ public final class DirectiveConverter { * @return Integer число. */ public static Integer parseInteger(String text) { - int value; - if (text.toLowerCase().endsWith("h")) { + if (text.toLowerCase(Locale.ENGLISH).endsWith("h")) { char first = Character.toLowerCase(text.charAt(0)); if ( (first >= 'a') && (first <= 'f') ) { // Первый символ hex числа не должен быть от a до f @@ -49,15 +50,13 @@ public final class DirectiveConverter { String hex = text.substring(0, text.length() - 1); try { - value = Integer.parseInt(hex, 16); - return value; + return Integer.parseInt(hex, 16); } catch (NumberFormatException nfe) { return null; } } try { - value = Integer.parseInt(text); - return value; + return Integer.parseInt(text); } catch (NumberFormatException nfe) { return null; } @@ -69,28 +68,28 @@ public final class DirectiveConverter { * @return массив строк. */ public static String[] split(String text) { - ArrayList parts = new ArrayList<>(); - int length = text.length(); - StringBuilder sb = new StringBuilder(); + final List parts = new ArrayList<>(); + final int length = text.length(); + final StringBuilder word = new StringBuilder(); for (int ch = 0; ch < length; ch++) { - int i = text.charAt(ch); - if (i == ' ') { - if (sb.length() > 0) { - parts.add(sb.toString().trim()); - sb.setLength(0); + final int currentChar = text.charAt(ch); + if (currentChar == ' ') { + if (word.length() > 0) { + parts.add(word.toString().trim()); + word.setLength(0); } - } else if (i == ',') { - if (sb.length() > 0) { - parts.add(sb.toString().trim()); + } else if (currentChar == ',') { + if (word.length() > 0) { + parts.add(word.toString().trim()); parts.add(","); - sb.setLength(0); + word.setLength(0); } } else { - sb.append((char) i); + word.append((char) currentChar); } } - if (sb.length() > 0) { - parts.add(sb.toString().trim()); + if (word.length() > 0) { + parts.add(word.toString().trim()); } String[] m = new String[parts.size()]; m = parts.toArray(m); diff --git a/src/com/annimon/asm/LexicLine.java b/src/com/annimon/asm/LexicLine.java index 218e11e..644265c 100644 --- a/src/com/annimon/asm/LexicLine.java +++ b/src/com/annimon/asm/LexicLine.java @@ -1,5 +1,7 @@ package com.annimon.asm; +import java.util.Arrays; + /** * * @author aNNiMON @@ -11,6 +13,6 @@ public final class LexicLine { public LexicLine(int lineNumber, int[] line) { this.lineNumber = lineNumber; - this.line = line; + this.line = Arrays.copyOf(line, line.length); } } diff --git a/src/com/annimon/asm/LexicalAnalyzer.java b/src/com/annimon/asm/LexicalAnalyzer.java index 7e6701f..45f2c15 100644 --- a/src/com/annimon/asm/LexicalAnalyzer.java +++ b/src/com/annimon/asm/LexicalAnalyzer.java @@ -1,6 +1,7 @@ package com.annimon.asm; import com.annimon.asm.directives.ID; +import java.util.Arrays; /** * Лексический анализатор. @@ -28,7 +29,7 @@ public final class LexicalAnalyzer { } public String[] getLines() { - return lines; + return Arrays.copyOf(lines, lines.length); } public void analyze() { diff --git a/src/com/annimon/asm/ListingGenerateHelper.java b/src/com/annimon/asm/ListingGenerateHelper.java index cd4dc45..0e15252 100644 --- a/src/com/annimon/asm/ListingGenerateHelper.java +++ b/src/com/annimon/asm/ListingGenerateHelper.java @@ -1,6 +1,7 @@ package com.annimon.asm; import com.annimon.asm.directives.ID; +import java.util.Locale; /** * @@ -18,9 +19,10 @@ public final class ListingGenerateHelper { * @return строковое значение числа в HEX. */ public static String toHexString(int value) { - String str = Integer.toString(value, 16).toUpperCase(); - if (str.length() == 1) str = "0" + str; - else if (str.length() == 3) str = "0" + str; + String str = Integer.toString(value, 16).toUpperCase(Locale.ENGLISH); + if ( (str.length() == 1) || (str.length() == 3) ) { + return "0" + str; + } return str; } @@ -75,7 +77,7 @@ public final class ListingGenerateHelper { * @return код регистра (3 бита). */ public static byte getRegisterCode(String register) { - final String reg = register.toLowerCase(); + final String reg = register.toLowerCase(Locale.ENGLISH); switch (reg) { case "ax": case "al": return 0b000; @@ -97,7 +99,7 @@ public final class ListingGenerateHelper { * @return код сегментного регистра, либо -1, если регистр не сегментный. */ public static byte getSegmentRegisterCode(String register) { - final String reg = register.toLowerCase(); + final String reg = register.toLowerCase(Locale.ENGLISH); for (byte i = 0; i < SEGMENT_REGISTERS.length; i++) { if (reg.equals(SEGMENT_REGISTERS[i])) return i; } diff --git a/src/com/annimon/asm/directives/Add.java b/src/com/annimon/asm/directives/Add.java index 3c90813..43acd43 100644 --- a/src/com/annimon/asm/directives/Add.java +++ b/src/com/annimon/asm/directives/Add.java @@ -7,6 +7,7 @@ import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.FewArgumentsException; import com.annimon.asm.exceptions.TooManyArgumentsException; import com.annimon.asm.exceptions.WrongArgumentException; +import java.util.Locale; /** * @@ -18,45 +19,45 @@ public final class Add extends Directive implements ISyntaxChecker, IListingGene super("add", ID.ADD); } + private static final int[] PAIRS = { + // Регистр - Регистр + ID.REGISTER_BYTE, ID.REGISTER_BYTE, + ID.REGISTER_WORD, ID.REGISTER_WORD, + ID.REGISTER_WORD, ID.REGISTER_BYTE, + + // Регистр - Память + ID.REGISTER_BYTE, ID.VAR_BYTE, + ID.REGISTER_WORD, ID.VAR_WORD, + ID.REGISTER_WORD, ID.VAR_BYTE, + + // Память - Регистр + ID.VAR_BYTE, ID.REGISTER_BYTE, + ID.VAR_WORD, ID.REGISTER_WORD, + ID.VAR_WORD, ID.REGISTER_BYTE, + + // Регистр - Значение + ID.REGISTER_BYTE, ID.NUMBER_BYTE, + ID.REGISTER_WORD, ID.NUMBER_WORD, + ID.REGISTER_WORD, ID.NUMBER_BYTE, + + // Память - Значение + ID.VAR_BYTE, ID.NUMBER_BYTE, + ID.VAR_WORD, ID.NUMBER_WORD, + ID.VAR_WORD, ID.NUMBER_BYTE, + }; + @Override public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber { if (ids[0] != getId()) return false; if (ids.length < 4) throw new FewArgumentsException(lineNumber); - else if (ids.length > 4) throw new TooManyArgumentsException(lineNumber); + if (ids.length > 4) throw new TooManyArgumentsException(lineNumber); if (ids[2] != ID.COMMA) throw new CommaExpectedException(lineNumber); - int[] pairs = new int[] { - // Регистр - Регистр - ID.REGISTER_BYTE, ID.REGISTER_BYTE, - ID.REGISTER_WORD, ID.REGISTER_WORD, - ID.REGISTER_WORD, ID.REGISTER_BYTE, - - // Регистр - Память - ID.REGISTER_BYTE, ID.VAR_BYTE, - ID.REGISTER_WORD, ID.VAR_WORD, - ID.REGISTER_WORD, ID.VAR_BYTE, - - // Память - Регистр - ID.VAR_BYTE, ID.REGISTER_BYTE, - ID.VAR_WORD, ID.REGISTER_WORD, - ID.VAR_WORD, ID.REGISTER_BYTE, - - // Регистр - Значение - ID.REGISTER_BYTE, ID.NUMBER_BYTE, - ID.REGISTER_WORD, ID.NUMBER_WORD, - ID.REGISTER_WORD, ID.NUMBER_BYTE, - - // Память - Значение - ID.VAR_BYTE, ID.NUMBER_BYTE, - ID.VAR_WORD, ID.NUMBER_WORD, - ID.VAR_WORD, ID.NUMBER_BYTE, - }; - boolean correct = false; - for(int i = 0; i < pairs.length; i += 2) { - if ( (ids[1] == pairs[i]) && (ids[3] == pairs[i+1]) ) { + for (int i = 0; i < PAIRS.length; i += 2) { + if ( (ids[1] == PAIRS[i]) && (ids[3] == PAIRS[i+1]) ) { correct = true; break; } @@ -103,8 +104,8 @@ public final class Add extends Directive implements ISyntaxChecker, IListingGene modreg <<= 6; // r/m - if (strs[1].toLowerCase().contains("si")) modreg |= 0b100; - else if (strs[1].toLowerCase().contains("di")) modreg |= 0b101; + if (strs[1].toLowerCase(Locale.ENGLISH).contains("si")) modreg |= 0b100; + else if (strs[1].toLowerCase(Locale.ENGLISH).contains("di")) modreg |= 0b101; else modreg |= 0b110; sb.append(ListingGenerateHelper.toHexString(val)) diff --git a/src/com/annimon/asm/directives/Idiv.java b/src/com/annimon/asm/directives/Idiv.java index 37ec5b2..3d4c433 100644 --- a/src/com/annimon/asm/directives/Idiv.java +++ b/src/com/annimon/asm/directives/Idiv.java @@ -22,7 +22,7 @@ public final class Idiv extends Directive implements ISyntaxChecker, IListingGen if (ids[0] != getId()) return false; if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); - else if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1); + if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1); if ( (ids[1] != ID.REGISTER_BYTE) && (ids[1] != ID.REGISTER_WORD) && (ids[1] != ID.VAR_BYTE) && (ids[1] != ID.VAR_WORD) ) { diff --git a/src/com/annimon/asm/directives/Mul.java b/src/com/annimon/asm/directives/Mul.java index fcaa71c..f27eef6 100644 --- a/src/com/annimon/asm/directives/Mul.java +++ b/src/com/annimon/asm/directives/Mul.java @@ -22,7 +22,7 @@ public final class Mul extends Directive implements ISyntaxChecker, IListingGene if (ids[0] != getId()) return false; if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); - else if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1); + if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1); if ( (ids[1] != ID.REGISTER_BYTE) && (ids[1] != ID.REGISTER_WORD) && (ids[1] != ID.VAR_BYTE) && (ids[1] != ID.VAR_WORD) ) { diff --git a/src/com/annimon/asm/directives/Push.java b/src/com/annimon/asm/directives/Push.java index 26dd408..97a28c2 100644 --- a/src/com/annimon/asm/directives/Push.java +++ b/src/com/annimon/asm/directives/Push.java @@ -28,7 +28,6 @@ public final class Push extends Directive implements ISyntaxChecker, IListingGen } } return true; - } @Override diff --git a/src/com/annimon/asm/directives/Variable.java b/src/com/annimon/asm/directives/Variable.java index dcf1c20..9eb39f8 100644 --- a/src/com/annimon/asm/directives/Variable.java +++ b/src/com/annimon/asm/directives/Variable.java @@ -31,7 +31,7 @@ public final class Variable extends Directive implements ISyntaxChecker, IListin if (ids[0] != getId()) return false; if (ids.length < 3) throw new FewArgumentsException(lineNumber, 2); - else if (ids.length > 3) throw new TooManyArgumentsException(lineNumber, 2); + if (ids.length > 3) throw new TooManyArgumentsException(lineNumber, 2); boolean db = ( (ids[1] == ID.DB) && ((ids[2] == ID.NUMBER_BYTE) || (ids[2] == ID.NUMBER_INFINITY)) );