From 8eb17d757ff9c654ad6336b13d0297c8481389bf Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 15 Nov 2018 18:48:02 +0200 Subject: [PATCH] 3 --- src/com/annimon/asm/AnalyzerPanel.java | 20 +++--- ...Convertor.java => DirectiveConverter.java} | 8 +-- src/com/annimon/asm/LexicLine.java | 6 +- src/com/annimon/asm/LexicTable.java | 8 +-- src/com/annimon/asm/LexicalAnalyzer.java | 69 +++++++++++++++++-- src/com/annimon/asm/SyntaxAnalyzer.java | 3 +- src/com/annimon/asm/Var.java | 27 ++++++++ src/com/annimon/asm/VarTable.java | 31 +++++++++ src/com/annimon/asm/directives/Add.java | 15 ++-- src/com/annimon/asm/directives/Directive.java | 8 ++- src/com/annimon/asm/directives/ID.java | 4 +- src/com/annimon/asm/directives/Mul.java | 2 +- src/com/annimon/asm/directives/Pop.java | 2 +- src/com/annimon/asm/directives/Push.java | 2 +- src/com/annimon/asm/directives/Variable.java | 2 +- .../exceptions/CommaExpectedException.java | 6 +- .../exceptions/ExceptionWithLineNumber.java | 6 +- .../asm/exceptions/FewArgumentsException.java | 6 +- .../exceptions/TooManyArgumentsException.java | 6 +- .../exceptions/WrongArgumentException.java | 6 +- 20 files changed, 168 insertions(+), 69 deletions(-) rename src/com/annimon/asm/{DirectiveConvertor.java => DirectiveConverter.java} (88%) create mode 100644 src/com/annimon/asm/Var.java create mode 100644 src/com/annimon/asm/VarTable.java diff --git a/src/com/annimon/asm/AnalyzerPanel.java b/src/com/annimon/asm/AnalyzerPanel.java index 62ebc16..f6cf06a 100644 --- a/src/com/annimon/asm/AnalyzerPanel.java +++ b/src/com/annimon/asm/AnalyzerPanel.java @@ -1,7 +1,3 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm; import com.annimon.asm.exceptions.ExceptionWithLineNumber; @@ -27,7 +23,7 @@ import javax.swing.text.JTextComponent; import javax.swing.text.Utilities; /** - * + * Основная панель приложения. * @author aNNiMON */ public class AnalyzerPanel extends JPanel { @@ -54,6 +50,7 @@ public class AnalyzerPanel extends JPanel { @Override public void caretUpdate(CaretEvent caretEvent) { + // Вывести позицию каретки в lineNumberLabel. JTextComponent textComponent = (JTextComponent)caretEvent.getSource(); int pos = caretEvent.getDot(); @@ -80,23 +77,28 @@ public class AnalyzerPanel extends JPanel { @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(ex.getMessage()); + showMessageBox("Error", ex.getMessage(), true); return; } - showMessageBox("Source is correct!"); + showMessageBox("Info","Source is correct!", false); } }); } - private void showMessageBox(String text) { - JOptionPane.showMessageDialog(this, text); + 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 String getTextFromResource(String res) { diff --git a/src/com/annimon/asm/DirectiveConvertor.java b/src/com/annimon/asm/DirectiveConverter.java similarity index 88% rename from src/com/annimon/asm/DirectiveConvertor.java rename to src/com/annimon/asm/DirectiveConverter.java index e583dc7..d97409d 100644 --- a/src/com/annimon/asm/DirectiveConvertor.java +++ b/src/com/annimon/asm/DirectiveConverter.java @@ -3,10 +3,10 @@ package com.annimon.asm; import com.annimon.asm.directives.*; /** - * + * Конвертер директив. * @author aNNiMON */ -public class DirectiveConvertor { +public class DirectiveConverter { private static final Directive[] DIRECTIVES = { new Comma(), @@ -20,7 +20,7 @@ public class DirectiveConvertor { /** * Конвертировать директиву в её идентификатор. * @param text директива (dw, push, 0 и т.д.) - * @return идентификатор директивы + * @return идентификатор директивы. */ public static int convert(String text) { for (int i = 0; i < DIRECTIVES.length; i++) { @@ -30,5 +30,5 @@ public class DirectiveConvertor { } return -1; - } + } } diff --git a/src/com/annimon/asm/LexicLine.java b/src/com/annimon/asm/LexicLine.java index 36949f7..b7d907b 100644 --- a/src/com/annimon/asm/LexicLine.java +++ b/src/com/annimon/asm/LexicLine.java @@ -1,11 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm; /** - * + * * @author aNNiMON */ public class LexicLine { diff --git a/src/com/annimon/asm/LexicTable.java b/src/com/annimon/asm/LexicTable.java index 3d7d946..4410ffa 100644 --- a/src/com/annimon/asm/LexicTable.java +++ b/src/com/annimon/asm/LexicTable.java @@ -1,7 +1,3 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm; import java.util.ArrayList; @@ -29,8 +25,8 @@ public class LexicTable { return lexicLines.get(pos); } - public void updateLexicAt(LexicLine lexic, int pos) { - lexicLines.set(pos, lexic); + public void updateLexicAt(int pos, LexicLine line) { + lexicLines.set(pos, line); } @Override diff --git a/src/com/annimon/asm/LexicalAnalyzer.java b/src/com/annimon/asm/LexicalAnalyzer.java index 427f49f..45d79ae 100644 --- a/src/com/annimon/asm/LexicalAnalyzer.java +++ b/src/com/annimon/asm/LexicalAnalyzer.java @@ -1,48 +1,109 @@ package com.annimon.asm; -import com.annimon.asm.exceptions.ExceptionWithLineNumber; +import com.annimon.asm.directives.ID; import java.util.ArrayList; /** - * + * Лексический анализатор. * @author aNNiMON */ public class LexicalAnalyzer { private String[] lines; private LexicTable lexicTable; + private VarTable varTable; public LexicalAnalyzer(String text) { lines = text.split(System.lineSeparator()); lexicTable = new LexicTable(); + varTable = new VarTable(); } public LexicTable getLexicTable() { return lexicTable; } + public VarTable getVarTable() { + return varTable; + } + public void analyze() { for (int i = 0; i < lines.length; i++) { analyzeLine(i); } + analyzeVariables(); System.out.println(lexicTable.toString()); } private void analyzeLine(int lineNumber) { String line = lines[lineNumber]; - if(line.isEmpty()) return; + // Если строка не содержит команд - пропускаем. + if (line.isEmpty()) return; String[] parts = split(line); + // Конвертируем директивы в соответствующие им идентификаторы. int length = parts.length; int[] lexicIds = new int[length]; for (int i = 0; i < length; i++) { - lexicIds[i] = DirectiveConvertor.convert(parts[i].trim()); + lexicIds[i] = DirectiveConverter.convert(parts[i].trim()); } + // Добавляем полученную строку в таблицу. lexicTable.addLexicLine(lineNumber+1, lexicIds); } + private void analyzeVariables() { + // Добавляем переменные в таблицу. + for (int i = 0; i < lexicTable.getSize(); i++) { + LexicLine line = lexicTable.getLexicAt(i); + addVariableToTable(line); + } + // Сопоставляем типы переменных. + for (int i = 0; i < lexicTable.getSize(); i++) { + LexicLine line = lexicTable.getLexicAt(i); + line = assignVariableTypes(line); + lexicTable.updateLexicAt(i, line); + } + } + + private void addVariableToTable(LexicLine lexicLine) { + if (lexicLine.line[0] != ID.VAR) return; + if (lexicLine.line.length != 3) return; + + String line = lines[lexicLine.lineNumber - 1]; + // Если строка не содержит команд - пропускаем. + if (line.isEmpty()) return; + String[] parts = split(line); + if (parts.length != 3) return; + + String varName = parts[0].trim(); + int typeId = lexicLine.line[1]; + String value = parts[2].trim(); + + varTable.addVariable(varName, typeId, value); + } + + private LexicLine assignVariableTypes(LexicLine lexicLine) { + // Для переменных назначаем их тип. + int[] lexicIds = lexicLine.line; + + for (int i = 0; i < lexicIds.length; i++) { + if (lexicIds[i] == ID.VAR) { + // Назначаем тип из таблицы переменных. + String line = lines[lexicLine.lineNumber - 1]; + if (line.isEmpty()) continue; + String[] parts = split(line); + if (parts.length != lexicIds.length) continue; + + lexicIds[i] = varTable.getTypeOfVariable(parts[i]); + } + } + lexicLine.line = lexicIds; + + return lexicLine; + } + private String[] split(String text) { ArrayList parts = new ArrayList(); int length = text.length(); diff --git a/src/com/annimon/asm/SyntaxAnalyzer.java b/src/com/annimon/asm/SyntaxAnalyzer.java index 91d78b6..83e0528 100644 --- a/src/com/annimon/asm/SyntaxAnalyzer.java +++ b/src/com/annimon/asm/SyntaxAnalyzer.java @@ -9,7 +9,7 @@ import com.annimon.asm.directives.Variable; import com.annimon.asm.exceptions.ExceptionWithLineNumber; /** - * + * Синтаксический анализатор. * @author aNNiMON */ public class SyntaxAnalyzer { @@ -19,7 +19,6 @@ public class SyntaxAnalyzer { new Variable() }; - private LexicTable lexicTable; public SyntaxAnalyzer(LexicTable lexicTable) { diff --git a/src/com/annimon/asm/Var.java b/src/com/annimon/asm/Var.java new file mode 100644 index 0000000..45f8113 --- /dev/null +++ b/src/com/annimon/asm/Var.java @@ -0,0 +1,27 @@ +package com.annimon.asm; + +/** + * Класс переменной. + * @author aNNiMON + */ +public class Var { + + String name; + int type; + String value; + + public Var(String name, int type, String value) { + this.name = name; + this.type = type; + this.value = value; + } + + public String getName() { + return name; + } + + public void setValue(String value) { + this.value = value; + } + +} diff --git a/src/com/annimon/asm/VarTable.java b/src/com/annimon/asm/VarTable.java new file mode 100644 index 0000000..2b1c80b --- /dev/null +++ b/src/com/annimon/asm/VarTable.java @@ -0,0 +1,31 @@ +package com.annimon.asm; + +import com.annimon.asm.directives.ID; +import java.util.ArrayList; + +/** + * Таблица переменных. + * @author aNNiMON + */ +public class VarTable { + + private ArrayList variables; + + public VarTable() { + variables = new ArrayList(); + } + + public void addVariable(String name, int type, String value) { + variables.add(new Var(name, type, value)); + } + + public int getTypeOfVariable(String name) { + for (Var var : variables) { + if (var.name.equalsIgnoreCase(name)) { + if (var.type == ID.DB) return ID.VAR_BYTE; + else if (var.type == ID.DW) return ID.VAR_WORD; + } + } + return ID.VAR; + } +} diff --git a/src/com/annimon/asm/directives/Add.java b/src/com/annimon/asm/directives/Add.java index 2d12bc5..b47d518 100644 --- a/src/com/annimon/asm/directives/Add.java +++ b/src/com/annimon/asm/directives/Add.java @@ -31,12 +31,14 @@ public class Add extends Directive implements SyntaxChecker { ID.REGISTER_WORD, ID.REGISTER_BYTE, // Регистр - Память - ID.REGISTER_BYTE, ID.VAR, - ID.REGISTER_WORD, ID.VAR, + ID.REGISTER_BYTE, ID.VAR_BYTE, + ID.REGISTER_WORD, ID.VAR_WORD, + ID.REGISTER_WORD, ID.VAR_BYTE, // Память - Регистр - ID.VAR, ID.REGISTER_BYTE, - ID.VAR, ID.REGISTER_WORD, + ID.VAR_BYTE, ID.REGISTER_BYTE, + ID.VAR_WORD, ID.REGISTER_WORD, + ID.VAR_WORD, ID.REGISTER_BYTE, // Регистр - Значение ID.REGISTER_BYTE, ID.NUMBER_BYTE, @@ -44,8 +46,9 @@ public class Add extends Directive implements SyntaxChecker { ID.REGISTER_WORD, ID.NUMBER_BYTE, // Память - Значение - ID.VAR, ID.NUMBER_BYTE, - ID.VAR, ID.NUMBER_WORD, + ID.VAR_BYTE, ID.NUMBER_BYTE, + ID.VAR_WORD, ID.NUMBER_WORD, + ID.VAR_WORD, ID.NUMBER_BYTE, }; boolean correct = false; diff --git a/src/com/annimon/asm/directives/Directive.java b/src/com/annimon/asm/directives/Directive.java index bb9c56b..bfba657 100644 --- a/src/com/annimon/asm/directives/Directive.java +++ b/src/com/annimon/asm/directives/Directive.java @@ -1,7 +1,7 @@ package com.annimon.asm.directives; /** - * + * Базовый класс директив. * @author aNNiMON */ public abstract class Directive { @@ -22,7 +22,11 @@ public abstract class Directive { return id; } - + /** + * Проверка на соответствие директиву тексту. + * @param text строка директивы, которую нужно проверить. + * @return результат совпадения. + */ public boolean isDirective(String text) { return text.equalsIgnoreCase(name); } diff --git a/src/com/annimon/asm/directives/ID.java b/src/com/annimon/asm/directives/ID.java index de360a5..d6d3724 100644 --- a/src/com/annimon/asm/directives/ID.java +++ b/src/com/annimon/asm/directives/ID.java @@ -1,10 +1,10 @@ package com.annimon.asm.directives; /** - * + * Список идентификаторов директив. * @author aNNiMON */ -public class ID { +public interface ID { public static final int NULL = -1, diff --git a/src/com/annimon/asm/directives/Mul.java b/src/com/annimon/asm/directives/Mul.java index 3a64c6a..ab2004b 100644 --- a/src/com/annimon/asm/directives/Mul.java +++ b/src/com/annimon/asm/directives/Mul.java @@ -22,7 +22,7 @@ public class Mul extends Directive implements SyntaxChecker { else if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1); if ( (ids[1] != ID.REGISTER_BYTE) && (ids[1] != ID.REGISTER_WORD) && - (ids[1] != ID.VAR)) { + (ids[1] != ID.VAR_BYTE) && (ids[1] != ID.VAR_WORD) ) { throw new WrongArgumentException(lineNumber); } return true; diff --git a/src/com/annimon/asm/directives/Pop.java b/src/com/annimon/asm/directives/Pop.java index 092d2ab..5a7edf3 100644 --- a/src/com/annimon/asm/directives/Pop.java +++ b/src/com/annimon/asm/directives/Pop.java @@ -20,7 +20,7 @@ public class Pop extends Directive implements SyntaxChecker { if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); for (int i = 1; i < ids.length; i++) { if ( (ids[i] != ID.REGISTER_WORD) && - (ids[i] != ID.VAR)) { + (ids[i] != ID.VAR_WORD)) { throw new WrongArgumentException(lineNumber); } } diff --git a/src/com/annimon/asm/directives/Push.java b/src/com/annimon/asm/directives/Push.java index 57b372e..2ad84ed 100644 --- a/src/com/annimon/asm/directives/Push.java +++ b/src/com/annimon/asm/directives/Push.java @@ -20,7 +20,7 @@ public class Push extends Directive implements SyntaxChecker { if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); for (int i = 1; i < ids.length; i++) { if ( (ids[i] != ID.REGISTER_WORD) && - (ids[i] != ID.VAR)) { + (ids[i] != ID.VAR_WORD)) { throw new WrongArgumentException(lineNumber); } } diff --git a/src/com/annimon/asm/directives/Variable.java b/src/com/annimon/asm/directives/Variable.java index 1d1cc34..77f2032 100644 --- a/src/com/annimon/asm/directives/Variable.java +++ b/src/com/annimon/asm/directives/Variable.java @@ -18,7 +18,7 @@ public class Variable extends Directive implements SyntaxChecker { @Override public boolean isDirective(String text) { - if (Pattern.matches(Pattern.compile("^[^1-9]+[\\w.@_$]").pattern(), text)) { + if (Pattern.matches(Pattern.compile("^[^0-9]*[\\w.@_$]").pattern(), text)) { return true; } return false; diff --git a/src/com/annimon/asm/exceptions/CommaExpectedException.java b/src/com/annimon/asm/exceptions/CommaExpectedException.java index 1ea5ebc..402c197 100644 --- a/src/com/annimon/asm/exceptions/CommaExpectedException.java +++ b/src/com/annimon/asm/exceptions/CommaExpectedException.java @@ -1,11 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm.exceptions; /** - * + * Класс ошибки пропущенной запятой. * @author aNNiMON */ public class CommaExpectedException extends ExceptionWithLineNumber { diff --git a/src/com/annimon/asm/exceptions/ExceptionWithLineNumber.java b/src/com/annimon/asm/exceptions/ExceptionWithLineNumber.java index 927abd8..76ecddb 100644 --- a/src/com/annimon/asm/exceptions/ExceptionWithLineNumber.java +++ b/src/com/annimon/asm/exceptions/ExceptionWithLineNumber.java @@ -1,11 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm.exceptions; /** - * + * Базовый класс для ошибок с отображением номера ошибочной строки. * @author aNNiMON */ public abstract class ExceptionWithLineNumber extends Exception { diff --git a/src/com/annimon/asm/exceptions/FewArgumentsException.java b/src/com/annimon/asm/exceptions/FewArgumentsException.java index b368a51..59b44ad 100644 --- a/src/com/annimon/asm/exceptions/FewArgumentsException.java +++ b/src/com/annimon/asm/exceptions/FewArgumentsException.java @@ -1,11 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm.exceptions; /** - * + * Класс ошибки, когда указано слишком мало аргументов команды, нежели ожидалось. * @author aNNiMON */ public class FewArgumentsException extends ExceptionWithLineNumber { diff --git a/src/com/annimon/asm/exceptions/TooManyArgumentsException.java b/src/com/annimon/asm/exceptions/TooManyArgumentsException.java index b14091f..bc82c42 100644 --- a/src/com/annimon/asm/exceptions/TooManyArgumentsException.java +++ b/src/com/annimon/asm/exceptions/TooManyArgumentsException.java @@ -1,11 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm.exceptions; /** - * + * Класс ошибки для превышенного количества аргументов команды. * @author aNNiMON */ public class TooManyArgumentsException extends ExceptionWithLineNumber { diff --git a/src/com/annimon/asm/exceptions/WrongArgumentException.java b/src/com/annimon/asm/exceptions/WrongArgumentException.java index 25484cf..5d7702a 100644 --- a/src/com/annimon/asm/exceptions/WrongArgumentException.java +++ b/src/com/annimon/asm/exceptions/WrongArgumentException.java @@ -1,11 +1,7 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package com.annimon.asm.exceptions; /** - * + * Класс ошибки неверного аргумента, когда не совпадает ожидаемый тип. * @author aNNiMON */ public class WrongArgumentException extends ExceptionWithLineNumber {