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;
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) {

View File

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

View File

@ -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 {

View File

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

View File

@ -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<String> parts = new ArrayList<String>();
int length = text.length();

View File

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

View File

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

View File

@ -1,10 +1,10 @@
package com.annimon.asm.directives;
/**
*
* Ñïèñîê èäåíòèôèêàòîðîâ äèðåêòèâ.
* @author aNNiMON
*/
public class ID {
public interface ID {
public static final int
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);
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;

View File

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

View File

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

View File

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

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;
/**
*
* Класс ошибки пропущенной запятой.
* @author aNNiMON
*/
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;
/**
*
* Базовый класс для ошибок с отображением номера ошибочной строки.
* @author aNNiMON
*/
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;
/**
*
* Класс ошибки, когда указано слишком мало аргументов команды, нежели ожидалось.
* @author aNNiMON
*/
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;
/**
*
* Класс ошибки для превышенного количества аргументов команды.
* @author aNNiMON
*/
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;
/**
*
* Класс ошибки неверного аргумента, когда не совпадает ожидаемый тип.
* @author aNNiMON
*/
public class WrongArgumentException extends ExceptionWithLineNumber {