This commit is contained in:
Victor 2018-11-15 18:48:02 +02:00
parent 70a61f31de
commit 8eb17d757f
20 changed files with 168 additions and 69 deletions

View File

@ -1,7 +1,3 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
@ -27,7 +23,7 @@ import javax.swing.text.JTextComponent;
import javax.swing.text.Utilities; import javax.swing.text.Utilities;
/** /**
* * Îñíîâíàÿ ïàíåëü ïðèëîæåíèÿ.
* @author aNNiMON * @author aNNiMON
*/ */
public class AnalyzerPanel extends JPanel { public class AnalyzerPanel extends JPanel {
@ -54,6 +50,7 @@ public class AnalyzerPanel extends JPanel {
@Override @Override
public void caretUpdate(CaretEvent caretEvent) { public void caretUpdate(CaretEvent caretEvent) {
// Âûâåñòè ïîçèöèþ êàðåòêè â lineNumberLabel.
JTextComponent textComponent = (JTextComponent)caretEvent.getSource(); JTextComponent textComponent = (JTextComponent)caretEvent.getSource();
int pos = caretEvent.getDot(); int pos = caretEvent.getDot();
@ -80,23 +77,28 @@ public class AnalyzerPanel extends JPanel {
@Override @Override
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
String allText = textPane.getText(); String allText = textPane.getText();
// Ëåêñè÷åñêèé àíàëèç - ïåðåâîäèì íàáîð äèðåêòèâ â êîäîâóþ òàáëèöó.
LexicalAnalyzer lex = new LexicalAnalyzer(allText); LexicalAnalyzer lex = new LexicalAnalyzer(allText);
lex.analyze(); lex.analyze();
// Ñèíòàêñè÷åñêèé àíàëèç - ïðîâåðêà ïðàâèëüíîñòè íàáîðà äèðåêòèâ.
SyntaxAnalyzer syn = new SyntaxAnalyzer(lex.getLexicTable()); SyntaxAnalyzer syn = new SyntaxAnalyzer(lex.getLexicTable());
try { try {
syn.analyze(); syn.analyze();
} catch (ExceptionWithLineNumber ex) { } catch (ExceptionWithLineNumber ex) {
showMessageBox(ex.getMessage()); showMessageBox("Error", ex.getMessage(), true);
return; return;
} }
showMessageBox("Source is correct!"); showMessageBox("Info","Source is correct!", false);
} }
}); });
} }
private void showMessageBox(String text) { private void showMessageBox(String title, String text, boolean errorMessage) {
JOptionPane.showMessageDialog(this, text); int msgType = errorMessage ? JOptionPane.ERROR_MESSAGE :
JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showMessageDialog(this, text, title, msgType);
} }
private String getTextFromResource(String res) { private String getTextFromResource(String res) {

View File

@ -3,10 +3,10 @@ package com.annimon.asm;
import com.annimon.asm.directives.*; import com.annimon.asm.directives.*;
/** /**
* * Êîíâåðòåð äèðåêòèâ.
* @author aNNiMON * @author aNNiMON
*/ */
public class DirectiveConvertor { public class DirectiveConverter {
private static final Directive[] DIRECTIVES = { private static final Directive[] DIRECTIVES = {
new Comma(), new Comma(),
@ -20,7 +20,7 @@ public class DirectiveConvertor {
/** /**
* Êîíâåðòèðîâàòü äèðåêòèâó â å¸ èäåíòèôèêàòîð. * Êîíâåðòèðîâàòü äèðåêòèâó â å¸ èäåíòèôèêàòîð.
* @param text äèðåêòèâà (dw, push, 0 è ò.ä.) * @param text äèðåêòèâà (dw, push, 0 è ò.ä.)
* @return èäåíòèôèêàòîð äèðåêòèâû * @return èäåíòèôèêàòîð äèðåêòèâû.
*/ */
public static int convert(String text) { public static int convert(String text) {
for (int i = 0; i < DIRECTIVES.length; i++) { for (int i = 0; i < DIRECTIVES.length; i++) {

View File

@ -1,7 +1,3 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm; package com.annimon.asm;
/** /**

View File

@ -1,7 +1,3 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm; package com.annimon.asm;
import java.util.ArrayList; import java.util.ArrayList;
@ -29,8 +25,8 @@ public class LexicTable {
return lexicLines.get(pos); return lexicLines.get(pos);
} }
public void updateLexicAt(LexicLine lexic, int pos) { public void updateLexicAt(int pos, LexicLine line) {
lexicLines.set(pos, lexic); lexicLines.set(pos, line);
} }
@Override @Override

View File

@ -1,48 +1,109 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.directives.ID;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* * Ëåêñè÷åñêèé àíàëèçàòîð.
* @author aNNiMON * @author aNNiMON
*/ */
public class LexicalAnalyzer { public class LexicalAnalyzer {
private String[] lines; private String[] lines;
private LexicTable lexicTable; private LexicTable lexicTable;
private VarTable varTable;
public LexicalAnalyzer(String text) { public LexicalAnalyzer(String text) {
lines = text.split(System.lineSeparator()); lines = text.split(System.lineSeparator());
lexicTable = new LexicTable(); lexicTable = new LexicTable();
varTable = new VarTable();
} }
public LexicTable getLexicTable() { public LexicTable getLexicTable() {
return lexicTable; return lexicTable;
} }
public VarTable getVarTable() {
return varTable;
}
public void analyze() { public void analyze() {
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
analyzeLine(i); analyzeLine(i);
} }
analyzeVariables();
System.out.println(lexicTable.toString()); System.out.println(lexicTable.toString());
} }
private void analyzeLine(int lineNumber) { private void analyzeLine(int lineNumber) {
String line = lines[lineNumber]; String line = lines[lineNumber];
if(line.isEmpty()) return; // Åñëè ñòðîêà íå ñîäåðæèò êîìàíä - ïðîïóñêàåì.
if (line.isEmpty()) return;
String[] parts = split(line); String[] parts = split(line);
// Êîíâåðòèðóåì äèðåêòèâû â ñîîòâåòñòâóþùèå èì èäåíòèôèêàòîðû.
int length = parts.length; int length = parts.length;
int[] lexicIds = new int[length]; int[] lexicIds = new int[length];
for (int i = 0; i < length; i++) { 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); 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) { private String[] split(String text) {
ArrayList<String> parts = new ArrayList<String>(); ArrayList<String> parts = new ArrayList<String>();
int length = text.length(); int length = text.length();

View File

@ -9,7 +9,7 @@ import com.annimon.asm.directives.Variable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
/** /**
* * روٍْـيّو<EFBFBD>مّيوى ـٍـًوهـَِْ.
* @author aNNiMON * @author aNNiMON
*/ */
public class SyntaxAnalyzer { public class SyntaxAnalyzer {
@ -19,7 +19,6 @@ public class SyntaxAnalyzer {
new Variable() new Variable()
}; };
private LexicTable lexicTable; private LexicTable lexicTable;
public SyntaxAnalyzer(LexicTable lexicTable) { public SyntaxAnalyzer(LexicTable lexicTable) {

View File

@ -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;
}
}

View File

@ -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<Var> variables;
public VarTable() {
variables = new ArrayList<Var>();
}
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;
}
}

View File

@ -31,12 +31,14 @@ public class Add extends Directive implements SyntaxChecker {
ID.REGISTER_WORD, ID.REGISTER_BYTE, ID.REGISTER_WORD, ID.REGISTER_BYTE,
// Ðåãèñòð - Ïàìÿòü // Ðåãèñòð - Ïàìÿòü
ID.REGISTER_BYTE, ID.VAR, ID.REGISTER_BYTE, ID.VAR_BYTE,
ID.REGISTER_WORD, ID.VAR, ID.REGISTER_WORD, ID.VAR_WORD,
ID.REGISTER_WORD, ID.VAR_BYTE,
// Ïàìÿòü - Ðåãèñòð // Ïàìÿòü - Ðåãèñòð
ID.VAR, ID.REGISTER_BYTE, ID.VAR_BYTE, ID.REGISTER_BYTE,
ID.VAR, ID.REGISTER_WORD, ID.VAR_WORD, ID.REGISTER_WORD,
ID.VAR_WORD, ID.REGISTER_BYTE,
// Ðåãèñòð - Çíà÷åíèå // Ðåãèñòð - Çíà÷åíèå
ID.REGISTER_BYTE, ID.NUMBER_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.REGISTER_WORD, ID.NUMBER_BYTE,
// Ïàìÿòü - Çíà÷åíèå // Ïàìÿòü - Çíà÷åíèå
ID.VAR, ID.NUMBER_BYTE, ID.VAR_BYTE, ID.NUMBER_BYTE,
ID.VAR, ID.NUMBER_WORD, ID.VAR_WORD, ID.NUMBER_WORD,
ID.VAR_WORD, ID.NUMBER_BYTE,
}; };
boolean correct = false; boolean correct = false;

View File

@ -1,7 +1,7 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
/** /**
* * Базовый класс директив.
* @author aNNiMON * @author aNNiMON
*/ */
public abstract class Directive { public abstract class Directive {
@ -22,7 +22,11 @@ public abstract class Directive {
return id; return id;
} }
/**
* Проверка на соответствие директиву тексту.
* @param text строка директивы, которую нужно проверить.
* @return результат совпадения.
*/
public boolean isDirective(String text) { public boolean isDirective(String text) {
return text.equalsIgnoreCase(name); return text.equalsIgnoreCase(name);
} }

View File

@ -1,10 +1,10 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
/** /**
* * Ñïèñîê èäåíòèôèêàòîðîâ äèðåêòèâ.
* @author aNNiMON * @author aNNiMON
*/ */
public class ID { public interface ID {
public static final int public static final int
NULL = -1, NULL = -1,

View File

@ -22,7 +22,7 @@ public class Mul extends Directive implements SyntaxChecker {
else if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1); else if (ids.length > 2) throw new TooManyArgumentsException(lineNumber, 1);
if ( (ids[1] != ID.REGISTER_BYTE) && (ids[1] != ID.REGISTER_WORD) && 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); throw new WrongArgumentException(lineNumber);
} }
return true; return true;

View File

@ -20,7 +20,7 @@ public class Pop extends Directive implements SyntaxChecker {
if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1);
for (int i = 1; i < ids.length; i++) { for (int i = 1; i < ids.length; i++) {
if ( (ids[i] != ID.REGISTER_WORD) && if ( (ids[i] != ID.REGISTER_WORD) &&
(ids[i] != ID.VAR)) { (ids[i] != ID.VAR_WORD)) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
} }

View File

@ -20,7 +20,7 @@ public class Push extends Directive implements SyntaxChecker {
if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1);
for (int i = 1; i < ids.length; i++) { for (int i = 1; i < ids.length; i++) {
if ( (ids[i] != ID.REGISTER_WORD) && if ( (ids[i] != ID.REGISTER_WORD) &&
(ids[i] != ID.VAR)) { (ids[i] != ID.VAR_WORD)) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
} }

View File

@ -18,7 +18,7 @@ public class Variable extends Directive implements SyntaxChecker {
@Override @Override
public boolean isDirective(String text) { 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 true;
} }
return false; return false;

View File

@ -1,11 +1,7 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* * Класс ошибки пропущенной запятой.
* @author aNNiMON * @author aNNiMON
*/ */
public class CommaExpectedException extends ExceptionWithLineNumber { public class CommaExpectedException extends ExceptionWithLineNumber {

View File

@ -1,11 +1,7 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* * Базовый класс для ошибок с отображением номера ошибочной строки.
* @author aNNiMON * @author aNNiMON
*/ */
public abstract class ExceptionWithLineNumber extends Exception { public abstract class ExceptionWithLineNumber extends Exception {

View File

@ -1,11 +1,7 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* * Класс ошибки, когда указано слишком мало аргументов команды, нежели ожидалось.
* @author aNNiMON * @author aNNiMON
*/ */
public class FewArgumentsException extends ExceptionWithLineNumber { public class FewArgumentsException extends ExceptionWithLineNumber {

View File

@ -1,11 +1,7 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* * Класс ошибки для превышенного количества аргументов команды.
* @author aNNiMON * @author aNNiMON
*/ */
public class TooManyArgumentsException extends ExceptionWithLineNumber { public class TooManyArgumentsException extends ExceptionWithLineNumber {

View File

@ -1,11 +1,7 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* * Класс ошибки неверного аргумента, когда не совпадает ожидаемый тип.
* @author aNNiMON * @author aNNiMON
*/ */
public class WrongArgumentException extends ExceptionWithLineNumber { public class WrongArgumentException extends ExceptionWithLineNumber {