Исправления и оптимизация

This commit is contained in:
Victor 2014-08-22 11:56:18 +03:00
parent 6ead777ba3
commit b1d8591410
30 changed files with 1194 additions and 1194 deletions

View File

@ -1,141 +1,141 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTextPane; import javax.swing.JTextPane;
import javax.swing.event.CaretEvent; import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener; import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent; 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 final class AnalyzerPanel extends JPanel {
private JLabel lineNumberLabel; private JLabel lineNumberLabel;
private JTextPane textPane; private JTextPane textPane;
private JButton analyzeButton; private JButton analyzeButton;
public AnalyzerPanel() { public AnalyzerPanel() {
lineNumberLabel = new JLabel("Line: 1"); lineNumberLabel = new JLabel("Line: 1");
initTextPane(); initTextPane();
initAnalyzeButton(); initAnalyzeButton();
setLayout(new BorderLayout(0, 0)); setLayout(new BorderLayout(0, 0));
add(lineNumberLabel, BorderLayout.NORTH); add(lineNumberLabel, BorderLayout.NORTH);
add(new JScrollPane(textPane)); add(new JScrollPane(textPane));
add(analyzeButton, BorderLayout.SOUTH); add(analyzeButton, BorderLayout.SOUTH);
} }
public AnalyzerPanel(String text) { public AnalyzerPanel(String text) {
textPane = new JTextPane(); textPane = new JTextPane();
textPane.setPreferredSize(new Dimension(300, 300)); textPane.setPreferredSize(new Dimension(300, 300));
textPane.setFont(new Font("Consolas", Font.PLAIN, 14)); textPane.setFont(new Font("Consolas", Font.PLAIN, 14));
textPane.setText(text); textPane.setText(text);
setLayout(new BorderLayout(0, 0)); setLayout(new BorderLayout(0, 0));
add(new JScrollPane(textPane)); add(new JScrollPane(textPane));
} }
private void initTextPane() { private void initTextPane() {
textPane = new JTextPane(); textPane = new JTextPane();
textPane.setPreferredSize(new Dimension(300, 350)); textPane.setPreferredSize(new Dimension(300, 350));
textPane.addCaretListener(new CaretListener() { textPane.addCaretListener(new CaretListener() {
@Override @Override
public void caretUpdate(CaretEvent caretEvent) { public void caretUpdate(CaretEvent caretEvent) {
// Âûâåñòè ïîçèöèþ êàðåòêè â lineNumberLabel. // Âûâåñòè ïîçèöèþ êàðåòêè â lineNumberLabel.
JTextComponent textComponent = (JTextComponent)caretEvent.getSource(); JTextComponent textComponent = (JTextComponent)caretEvent.getSource();
int pos = caretEvent.getDot(); int pos = caretEvent.getDot();
int rowNumber = (pos == 0) ? 1 : 0; int rowNumber = (pos == 0) ? 1 : 0;
try { try {
int offset = pos; int offset = pos;
while (offset > 0) { while (offset > 0) {
offset = Utilities.getRowStart(textComponent, offset) - 1; offset = Utilities.getRowStart(textComponent, offset) - 1;
rowNumber++; rowNumber++;
} }
} catch (BadLocationException ex) {} } catch (BadLocationException ex) {}
lineNumberLabel.setText("Line: " + rowNumber); lineNumberLabel.setText("Line: " + rowNumber);
} }
}); });
textPane.setFont(new Font("Consolas", Font.PLAIN, 14)); textPane.setFont(new Font("Consolas", Font.PLAIN, 14));
textPane.setText(getTextFromResource("/test.asm")); textPane.setText(getTextFromResource("/test.asm"));
} }
private void initAnalyzeButton() { private void initAnalyzeButton() {
analyzeButton = new JButton("Analyze"); analyzeButton = new JButton("Analyze");
analyzeButton.addActionListener(new ActionListener() { analyzeButton.addActionListener(new ActionListener() {
@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("Error", ex.getMessage(), true); showMessageBox("Error", ex.getMessage(), true);
return; return;
} }
//showMessageBox("Info","Source is correct!", false); //showMessageBox("Info","Source is correct!", false);
// Ãåíåðèðóåì ëèñòèíã. // Ãåíåðèðóåì ëèñòèíã.
ListingGenerator gen = new ListingGenerator(lex.getLexicTable(), lex.getVarTable(), lex.getLines()); ListingGenerator gen = new ListingGenerator(lex.getLexicTable(), lex.getVarTable(), lex.getLines());
String listing = gen.generate(); String listing = gen.generate();
showListing(listing); showListing(listing);
} }
}); });
} }
private void showMessageBox(String title, String text, boolean errorMessage) { private void showMessageBox(String title, String text, boolean errorMessage) {
int msgType = errorMessage ? JOptionPane.ERROR_MESSAGE : int msgType = errorMessage ? JOptionPane.ERROR_MESSAGE :
JOptionPane.INFORMATION_MESSAGE; JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showMessageDialog(this, text, title, msgType); JOptionPane.showMessageDialog(this, text, title, msgType);
} }
private void showListing(String listing) { private void showListing(String listing) {
JOptionPane.showMessageDialog(this, new AnalyzerPanel(listing), JOptionPane.showMessageDialog(this, new AnalyzerPanel(listing),
"Listing", JOptionPane.PLAIN_MESSAGE); "Listing", JOptionPane.PLAIN_MESSAGE);
} }
private String getTextFromResource(String res) { private String getTextFromResource(String res) {
try { try {
InputStream is = getClass().getResourceAsStream(res); InputStream is = getClass().getResourceAsStream(res);
BufferedReader reader = new BufferedReader(new InputStreamReader(is)); BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder text = new StringBuilder(); StringBuilder text = new StringBuilder();
String line; String line;
while( (line = reader.readLine()) != null ) { while( (line = reader.readLine()) != null ) {
text.append(line).append(System.lineSeparator()); text.append(line).append(System.lineSeparator());
} }
reader.close(); reader.close();
return text.toString(); return text.toString();
} catch (IOException ex) {} } catch (IOException ex) {}
return ""; return "";
} }
} }

View File

@ -1,99 +1,99 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.directives.*; import com.annimon.asm.directives.*;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* Êîíâåðòåð äèðåêòèâ. * Êîíâåðòåð äèðåêòèâ.
* @author aNNiMON * @author aNNiMON
*/ */
public class DirectiveConverter { public final class DirectiveConverter {
private static final Directive[] DIRECTIVES = { private static final Directive[] DIRECTIVES = {
new Comma(), new Comma(),
new DB(), new DW(), new DB(), new DW(),
new InfinityValue(), new ByteValue(), new WordValue(), new InfinityValue(), new ByteValue(), new WordValue(),
new Add(), new Mul(), new Push(), new Pop(), new Idiv(), new Add(), new Mul(), new Push(), new Pop(), new Idiv(),
new ByteRegister(), new WordRegister(), new ByteRegister(), new WordRegister(),
new Variable() new Variable()
}; };
/** /**
* Êîíâåðòèðîâàòü äèðåêòèâó â å¸ èäåíòèôèêàòîð. * Êîíâåðòèðîâàòü äèðåêòèâó â å¸ èäåíòèôèêàòîð.
* @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 (Directive dir : DIRECTIVES) {
if (DIRECTIVES[i].isDirective(text)) { if (dir.isDirective(text)) {
return DIRECTIVES[i].getId(); return dir.getId();
} }
} }
return -1; return -1;
} }
/** /**
* Ïîëó÷èòü çíà÷åíèå ÷èñëà èç ñòðîêè. * Ïîëó÷èòü çíà÷åíèå ÷èñëà èç ñòðîêè.
* @param text ñòðîêà ñ ÷èñëîì. * @param text ñòðîêà ñ ÷èñëîì.
* @return Integer ÷èñëî. * @return Integer ÷èñëî.
*/ */
public static Integer parseInteger(String text) { public static Integer parseInteger(String text) {
int value; int value;
if (text.toLowerCase().endsWith("h")) { if (text.toLowerCase().endsWith("h")) {
char first = Character.toLowerCase(text.charAt(0)); char first = Character.toLowerCase(text.charAt(0));
if ( (first >= 'a') && (first <= 'f') ) { if ( (first >= 'a') && (first <= 'f') ) {
// Ïåðâûé ñèìâîë hex ÷èñëà íå äîëæåí áûòü îò a äî f // Ïåðâûé ñèìâîë hex ÷èñëà íå äîëæåí áûòü îò a äî f
return null; return null;
} }
String hex = text.substring(0, text.length() - 1); String hex = text.substring(0, text.length() - 1);
try { try {
value = Integer.parseInt(hex, 16); value = Integer.parseInt(hex, 16);
return value; return value;
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
return null; return null;
} }
} }
try { try {
value = Integer.parseInt(text); value = Integer.parseInt(text);
return value; return value;
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
return null; return null;
} }
} }
/** /**
* Ðàçáèòü ñòðîêó íà ïîäñòðîêè ñ ó÷¸òîì çàïÿòûõ. * Ðàçáèòü ñòðîêó íà ïîäñòðîêè ñ ó÷¸òîì çàïÿòûõ.
* @param text òåêñò. * @param text òåêñò.
* @return ìàññèâ ñòðîê. * @return ìàññèâ ñòðîê.
*/ */
public static String[] split(String text) { public static String[] split(String text) {
ArrayList<String> parts = new ArrayList<>(); ArrayList<String> parts = new ArrayList<>();
int length = text.length(); int length = text.length();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int ch = 0; ch < length; ch++) { for (int ch = 0; ch < length; ch++) {
int i = text.charAt(ch); int i = text.charAt(ch);
if (i == ' ') { if (i == ' ') {
if (sb.length() > 0) { if (sb.length() > 0) {
parts.add(sb.toString().trim()); parts.add(sb.toString().trim());
sb.setLength(0); sb.setLength(0);
} }
} else if (i == ',') { } else if (i == ',') {
if (sb.length() > 0) { if (sb.length() > 0) {
parts.add(sb.toString().trim()); parts.add(sb.toString().trim());
parts.add(","); parts.add(",");
sb.setLength(0); sb.setLength(0);
} }
} else { } else {
sb.append((char) i); sb.append((char) i);
} }
} }
if (sb.length() > 0) { if (sb.length() > 0) {
parts.add(sb.toString().trim()); parts.add(sb.toString().trim());
} }
String[] m = new String[parts.size()]; String[] m = new String[parts.size()];
m = parts.toArray(m); m = parts.toArray(m);
return m; return m;
} }
} }

View File

@ -1,16 +1,16 @@
package com.annimon.asm; package com.annimon.asm;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class LexicLine { public final class LexicLine {
int lineNumber; int lineNumber;
int[] line; int[] line;
public LexicLine(int lineNumber, int[] line) { public LexicLine(int lineNumber, int[] line) {
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
this.line = line; this.line = line;
} }
} }

View File

@ -1,47 +1,47 @@
package com.annimon.asm; package com.annimon.asm;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* @author aNNiMON * @author aNNiMON
*/ */
public class LexicTable { public final class LexicTable {
private ArrayList<LexicLine> lexicLines; private final ArrayList<LexicLine> lexicLines;
public LexicTable() { public LexicTable() {
lexicLines = new ArrayList<>(); lexicLines = new ArrayList<>();
} }
public void addLexicLine(int lineNumber, int[] line) { public void addLexicLine(int lineNumber, int[] line) {
lexicLines.add(new LexicLine(lineNumber, line)); lexicLines.add(new LexicLine(lineNumber, line));
} }
public int getSize() { public int getSize() {
return lexicLines.size(); return lexicLines.size();
} }
public LexicLine getLexicAt(int pos) { public LexicLine getLexicAt(int pos) {
return lexicLines.get(pos); return lexicLines.get(pos);
} }
public void updateLexicAt(int pos, LexicLine line) { public void updateLexicAt(int pos, LexicLine line) {
lexicLines.set(pos, line); lexicLines.set(pos, line);
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder text = new StringBuilder(); final StringBuilder text = new StringBuilder();
for(LexicLine lexic : lexicLines) { for(LexicLine lexic : lexicLines) {
text.append(lexic.lineNumber).append(':'); text.append(lexic.lineNumber).append(':');
int[] array = lexic.line; int[] array = lexic.line;
for (int i = 0; i < array.length; i++) { for (int i = 0; i < array.length; i++) {
text.append(" "); text.append(" ");
text.append(array[i]); text.append(array[i]);
} }
text.append(System.lineSeparator()); text.append(System.lineSeparator());
} }
return text.toString(); return text.toString();
} }
} }

View File

@ -1,112 +1,112 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.directives.ID; import com.annimon.asm.directives.ID;
/** /**
* Ëåêñè÷åñêèé àíàëèçàòîð. * Ëåêñè÷åñêèé àíàëèçàòîð.
* @author aNNiMON * @author aNNiMON
*/ */
public class LexicalAnalyzer { public final class LexicalAnalyzer {
private String[] lines; private final String[] lines;
private LexicTable lexicTable; private final LexicTable lexicTable;
private VarTable varTable; private final 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(); varTable = new VarTable();
} }
public LexicTable getLexicTable() { public LexicTable getLexicTable() {
return lexicTable; return lexicTable;
} }
public VarTable getVarTable() { public VarTable getVarTable() {
return varTable; return varTable;
} }
public String[] getLines() { public String[] getLines() {
return lines; return lines;
} }
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(); 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]; final String line = lines[lineNumber];
// Åñëè ñòðîêà íå ñîäåðæèò êîìàíä - ïðîïóñêàåì. // Åñëè ñòðîêà íå ñîäåðæèò êîìàíä - ïðîïóñêàåì.
if (line.isEmpty()) return; if (line.isEmpty()) return;
String[] parts = DirectiveConverter.split(line); String[] parts = DirectiveConverter.split(line);
// Êîíâåðòèðóåì äèðåêòèâû â ñîîòâåòñòâóþùèå èì èäåíòèôèêàòîðû. // Êîíâåðòèðóåì äèðåêòèâû â ñîîòâåòñòâóþùèå èì èäåíòèôèêàòîðû.
int length = parts.length; final int length = parts.length;
int[] lexicIds = new int[length]; final int[] lexicIds = new int[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
lexicIds[i] = DirectiveConverter.convert(parts[i].trim()); lexicIds[i] = DirectiveConverter.convert(parts[i].trim());
} }
// Äîáàâëÿåì ïîëó÷åííóþ ñòðîêó â òàáëèöó. // Äîáàâëÿåì ïîëó÷åííóþ ñòðîêó â òàáëèöó.
lexicTable.addLexicLine(lineNumber+1, lexicIds); lexicTable.addLexicLine(lineNumber+1, lexicIds);
} }
private void analyzeVariables() { private void analyzeVariables() {
// Äîáàâëÿåì ïåðåìåííûå â òàáëèöó. // Äîáàâëÿåì ïåðåìåííûå â òàáëèöó.
for (int i = 0; i < lexicTable.getSize(); i++) { for (int i = 0; i < lexicTable.getSize(); i++) {
LexicLine line = lexicTable.getLexicAt(i); LexicLine line = lexicTable.getLexicAt(i);
addVariableToTable(line); addVariableToTable(line);
} }
// Ñîïîñòàâëÿåì òèïû ïåðåìåííûõ. // Ñîïîñòàâëÿåì òèïû ïåðåìåííûõ.
for (int i = 0; i < lexicTable.getSize(); i++) { for (int i = 0; i < lexicTable.getSize(); i++) {
LexicLine line = lexicTable.getLexicAt(i); LexicLine line = lexicTable.getLexicAt(i);
line = assignVariableTypes(line); line = assignVariableTypes(line);
lexicTable.updateLexicAt(i, line); lexicTable.updateLexicAt(i, line);
} }
} }
private void addVariableToTable(LexicLine lexicLine) { private void addVariableToTable(LexicLine lexicLine) {
if (lexicLine.line[0] != ID.VAR) return; if (lexicLine.line[0] != ID.VAR) return;
if (lexicLine.line.length != 3) return; if (lexicLine.line.length != 3) return;
String line = lines[lexicLine.lineNumber - 1]; String line = lines[lexicLine.lineNumber - 1];
// Åñëè ñòðîêà íå ñîäåðæèò êîìàíä - ïðîïóñêàåì. // Åñëè ñòðîêà íå ñîäåðæèò êîìàíä - ïðîïóñêàåì.
if (line.isEmpty()) return; if (line.isEmpty()) return;
String[] parts = DirectiveConverter.split(line); String[] parts = DirectiveConverter.split(line);
if (parts.length != 3) return; if (parts.length != 3) return;
String varName = parts[0].trim(); String varName = parts[0].trim();
int typeId = lexicLine.line[1]; int typeId = lexicLine.line[1];
String value = parts[2].trim(); String value = parts[2].trim();
varTable.addVariable(varName, typeId, value); varTable.addVariable(varName, typeId, value);
} }
private LexicLine assignVariableTypes(LexicLine lexicLine) { private LexicLine assignVariableTypes(LexicLine lexicLine) {
// Äëÿ ïåðåìåííûõ íàçíà÷àåì èõ òèï. // Äëÿ ïåðåìåííûõ íàçíà÷àåì èõ òèï.
int[] lexicIds = lexicLine.line; int[] lexicIds = lexicLine.line;
for (int i = 0; i < lexicIds.length; i++) { for (int i = 0; i < lexicIds.length; i++) {
if (lexicIds[i] == ID.VAR) { if (lexicIds[i] == ID.VAR) {
// Íàçíà÷àåì òèï èç òàáëèöû ïåðåìåííûõ. // Íàçíà÷àåì òèï èç òàáëèöû ïåðåìåííûõ.
String line = lines[lexicLine.lineNumber - 1]; String line = lines[lexicLine.lineNumber - 1];
if (line.isEmpty()) continue; if (line.isEmpty()) continue;
String[] parts = DirectiveConverter.split(line); String[] parts = DirectiveConverter.split(line);
if (parts.length != lexicIds.length) continue; if (parts.length != lexicIds.length) continue;
lexicIds[i] = varTable.getTypeOfVariable(parts[i]); lexicIds[i] = varTable.getTypeOfVariable(parts[i]);
} }
} }
lexicLine.line = lexicIds; lexicLine.line = lexicIds;
return lexicLine; return lexicLine;
} }
} }

View File

@ -1,107 +1,107 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.directives.ID; import com.annimon.asm.directives.ID;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class ListingGenerateHelper { public final class ListingGenerateHelper {
private static final String[] SEGMENT_REGISTERS = { private static final String[] SEGMENT_REGISTERS = {
"es", "cs", "ss", "ds" "es", "cs", "ss", "ds"
}; };
/** /**
* Êîíâåðòèðîâàòü ÷èñëî â ñòðîêó â HEX ôîðìàòå. * Êîíâåðòèðîâàòü ÷èñëî â ñòðîêó â HEX ôîðìàòå.
* @param value ÷èñëî * @param value ÷èñëî
* @return ñòðîêîâîå çíà÷åíèå ÷èñëà â HEX. * @return ñòðîêîâîå çíà÷åíèå ÷èñëà â HEX.
*/ */
public static String toHexString(int value) { public static String toHexString(int value) {
String str = Integer.toString(value, 16).toUpperCase(); String str = Integer.toString(value, 16).toUpperCase();
if (str.length() == 1) str = "0" + str; if (str.length() == 1) str = "0" + str;
else if (str.length() == 3) str = "0" + str; else if (str.length() == 3) str = "0" + str;
return str; return str;
} }
/** /**
* Çàïèñàòü ñëîâî â Little Endian ôîðìàòå. * Çàïèñàòü ñëîâî â Little Endian ôîðìàòå.
* @param value ÷èñëî 2 áàéòà. * @param value ÷èñëî 2 áàéòà.
* @return ñòðîêà "LL HH" * @return ñòðîêà "LL HH"
*/ */
public static String toLittleEndianString(short value) { public static String toLittleEndianString(short value) {
return toHexString(value & 0xFF) + " " + return toHexString(value & 0xFF) + " " +
toHexString((value >> 8) & 0xFF); toHexString((value >> 8) & 0xFF);
} }
/** /**
* Ñêîíâåðòèðîâàòü òåêñò â ñëîâî è çàïèñàòü åãî â Little Endian ôîðìàòå. * Ñêîíâåðòèðîâàòü òåêñò â ñëîâî è çàïèñàòü åãî â Little Endian ôîðìàòå.
* @param text ñòðîêà ñ ÷èñëîì. * @param text ñòðîêà ñ ÷èñëîì.
* @return ñòðîêà "LL HH" ëèáî "XX" â çàâèñèìîñòè îò ðàçìåðà. * @return ñòðîêà "LL HH" ëèáî "XX" â çàâèñèìîñòè îò ðàçìåðà.
*/ */
public static String toLittleEndianString(String text) { public static String toLittleEndianString(String text) {
Integer value = DirectiveConverter.parseInteger(text); final Integer value = DirectiveConverter.parseInteger(text);
if (value == null) return ""; if (value == null) return "";
if ( (-128 <= value.intValue()) && (value.intValue() <= 255) ) { if ( (-128 <= value) && (value <= 255) ) {
return toHexString(value); return toHexString(value);
} }
return toLittleEndianString(value.shortValue()); return toLittleEndianString(value.shortValue());
} }
/** /**
* Ïðîâåðêà, ÿâëÿåòñÿ ëè îïåðàíä ðåãèñòðîì èëè ïàìÿòüþ (r/m). * Ïðîâåðêà, ÿâëÿåòñÿ ëè îïåðàíä ðåãèñòðîì èëè ïàìÿòüþ (r/m).
* @param id òèï îïåðàíäà. * @param id òèï îïåðàíäà.
* @return true - îïåðàíä ðåãèñòð èëè ïàìÿòü. * @return true - îïåðàíä ðåãèñòð èëè ïàìÿòü.
*/ */
public static boolean isRegisterOrMemory(int id) { public static boolean isRegisterOrMemory(int id) {
boolean isMemory = ( (id == ID.VAR_BYTE) || (id == ID.VAR_WORD) ); boolean isMemory = ( (id == ID.VAR_BYTE) || (id == ID.VAR_WORD) );
return (isRegister(id) || isMemory); return (isRegister(id) || isMemory);
} }
/** /**
* Ïðîâåðêà, ÿâëÿåòñÿ ëè îïåðàíä ðåãèñòðîì. * Ïðîâåðêà, ÿâëÿåòñÿ ëè îïåðàíä ðåãèñòðîì.
* @param id òèï îïåðàíäà. * @param id òèï îïåðàíäà.
* @return true - îïåðàíä ðåãèñòð. * @return true - îïåðàíä ðåãèñòð.
*/ */
public static boolean isRegister(int id) { public static boolean isRegister(int id) {
return ( (id == ID.REGISTER_BYTE) || (id == ID.REGISTER_WORD) ); return ( (id == ID.REGISTER_BYTE) || (id == ID.REGISTER_WORD) );
} }
/** /**
* Ïîëó÷èòü êîä ðåãèñòðà. * Ïîëó÷èòü êîä ðåãèñòðà.
* @param register ñòðîêîâîå çíà÷åíèå ðåãèñòðà. * @param register ñòðîêîâîå çíà÷åíèå ðåãèñòðà.
* @return êîä ðåãèñòðà (3 áèòà). * @return êîä ðåãèñòðà (3 áèòà).
*/ */
public static byte getRegisterCode(String register) { public static byte getRegisterCode(String register) {
String reg = register.toLowerCase(); final String reg = register.toLowerCase();
switch (reg) { switch (reg) {
case "ax": case "al": return 0b000; case "ax": case "al": return 0b000;
case "cx": case "cl": return 0b001; case "cx": case "cl": return 0b001;
case "dx": case "dl": return 0b010; case "dx": case "dl": return 0b010;
case "bx": case "bl": return 0b011; case "bx": case "bl": return 0b011;
case "sp": case "ah": return 0b100; case "sp": case "ah": return 0b100;
case "bp": case "ch": return 0b101; case "bp": case "ch": return 0b101;
case "si": case "dh": return 0b110; case "si": case "dh": return 0b110;
case "di": case "bh": return 0b111; case "di": case "bh": return 0b111;
} }
return 0; return 0;
} }
/** /**
* Ïîëó÷èòü êîä ñåãìåíòíîãî ðåãèñòðà. * Ïîëó÷èòü êîä ñåãìåíòíîãî ðåãèñòðà.
* @param register ñòðîêîâîå çíà÷åíèå ðåãèñòðà. * @param register ñòðîêîâîå çíà÷åíèå ðåãèñòðà.
* @return êîä ñåãìåíòíîãî ðåãèñòðà, ëèáî -1, åñëè ðåãèñòð íå ñåãìåíòíûé. * @return êîä ñåãìåíòíîãî ðåãèñòðà, ëèáî -1, åñëè ðåãèñòð íå ñåãìåíòíûé.
*/ */
public static byte getSegmentRegisterCode(String register) { public static byte getSegmentRegisterCode(String register) {
String reg = register.toLowerCase(); final String reg = register.toLowerCase();
for (byte i = 0; i < SEGMENT_REGISTERS.length; i++) { for (byte i = 0; i < SEGMENT_REGISTERS.length; i++) {
if (reg.equals(SEGMENT_REGISTERS[i])) return i; if (reg.equals(SEGMENT_REGISTERS[i])) return i;
} }
return -1; return -1;
} }
} }

View File

@ -1,63 +1,63 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.directives.Add; import com.annimon.asm.directives.Add;
import com.annimon.asm.directives.ID; import com.annimon.asm.directives.ID;
import com.annimon.asm.directives.IListingGenerator; import com.annimon.asm.directives.IListingGenerator;
import com.annimon.asm.directives.Idiv; import com.annimon.asm.directives.Idiv;
import com.annimon.asm.directives.Mul; import com.annimon.asm.directives.Mul;
import com.annimon.asm.directives.Pop; import com.annimon.asm.directives.Pop;
import com.annimon.asm.directives.Push; import com.annimon.asm.directives.Push;
import com.annimon.asm.directives.Variable; import com.annimon.asm.directives.Variable;
/** /**
* Ãåíåðèðîâàíèå ëèñòèíãà. * Ãåíåðèðîâàíèå ëèñòèíãà.
* @author aNNiMON * @author aNNiMON
*/ */
public class ListingGenerator { public final class ListingGenerator {
private static final IListingGenerator[] DIRECTIVES = { private static final IListingGenerator[] DIRECTIVES = {
new Variable(), new Variable(),
new Add(), new Mul(), new Pop(), new Push(), new Idiv() new Add(), new Mul(), new Pop(), new Push(), new Idiv()
}; };
private LexicTable lexicTable; private final LexicTable lexicTable;
private VarTable varTable; private final VarTable varTable;
private String[] lines; private final String[] lines;
public ListingGenerator(LexicTable lexicTable, VarTable varTable, String[] lines) { public ListingGenerator(LexicTable lexicTable, VarTable varTable, String[] lines) {
this.lexicTable = lexicTable; this.lexicTable = lexicTable;
this.varTable = varTable; this.varTable = varTable;
this.lines = lines; this.lines = lines;
} }
public String generate() { public String generate() {
StringBuilder text = new StringBuilder(); final StringBuilder text = new StringBuilder();
short offset = VarTable.getOffset(); short offset = VarTable.getOffset();
for (int i = 0; i < lexicTable.getSize(); i++) { for (int i = 0; i < lexicTable.getSize(); i++) {
LexicLine line = lexicTable.getLexicAt(i); LexicLine line = lexicTable.getLexicAt(i);
String[] parts = DirectiveConverter.split(lines[line.lineNumber - 1]); String[] parts = DirectiveConverter.split(lines[line.lineNumber - 1]);
String strLine = generateLine(line.lineNumber, line.line, parts).trim(); String strLine = generateLine(line.lineNumber, line.line, parts).trim();
// Âûâîä àäðåñà äëÿ âñåõ äèðåêòèâ, êðîìå ïåðåìåííûõ. // Âûâîä àäðåñà äëÿ âñåõ äèðåêòèâ, êðîìå ïåðåìåííûõ.
if ( (line.line[0] != ID.VAR_BYTE) && (line.line[0] != ID.VAR_WORD) ) { if ( (line.line[0] != ID.VAR_BYTE) && (line.line[0] != ID.VAR_WORD) ) {
text.append(ListingGenerateHelper.toHexString(offset)).append(" "); text.append(ListingGenerateHelper.toHexString(offset)).append(" ");
int lineSize = strLine.split(" ").length; int lineSize = strLine.split(" ").length;
offset += lineSize; offset += lineSize;
} }
text.append(strLine); text.append(strLine);
text.append(System.lineSeparator()); text.append(System.lineSeparator());
} }
return text.toString(); return text.toString();
} }
private String generateLine(int lineNumber, int[] lexic, String[] parts) { private String generateLine(int lineNumber, int[] lexic, String[] parts) {
for (int i = 0; i < DIRECTIVES.length; i++) { for (IListingGenerator dir : DIRECTIVES) {
String text = DIRECTIVES[i].generate(lineNumber, lexic, parts, varTable); String text = dir.generate(lineNumber, lexic, parts, varTable);
if (!text.isEmpty()) return text; if (!text.isEmpty()) return text;
} }
return ""; return "";
} }
} }

View File

@ -1,22 +1,22 @@
package com.annimon.asm; package com.annimon.asm;
import javax.swing.JFrame; import javax.swing.JFrame;
/** /**
* @author aNNiMON * @author aNNiMON
*/ */
public class Main extends JFrame { public final class Main extends JFrame {
public static void main(String[] args) { public static void main(String[] args) {
new Main().setVisible(true); new Main().setVisible(true);
} }
public Main() { public Main() {
super("Assembler analyzer"); super("Assembler analyzer");
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new AnalyzerPanel()); add(new AnalyzerPanel());
pack(); pack();
} }
} }

View File

@ -1,44 +1,44 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.directives.Add; import com.annimon.asm.directives.Add;
import com.annimon.asm.directives.Mul; import com.annimon.asm.directives.Mul;
import com.annimon.asm.directives.Pop; import com.annimon.asm.directives.Pop;
import com.annimon.asm.directives.Push; import com.annimon.asm.directives.Push;
import com.annimon.asm.directives.ISyntaxChecker; import com.annimon.asm.directives.ISyntaxChecker;
import com.annimon.asm.directives.Idiv; import com.annimon.asm.directives.Idiv;
import com.annimon.asm.directives.Variable; import com.annimon.asm.directives.Variable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
/** /**
* Ñèíòàêñè÷åñêèé àíàëèçàòîð. * Ñèíòàêñè÷åñêèé àíàëèçàòîð.
* @author aNNiMON * @author aNNiMON
*/ */
public class SyntaxAnalyzer { public final class SyntaxAnalyzer {
private static final ISyntaxChecker[] DIRECTIVES = { private static final ISyntaxChecker[] DIRECTIVES = {
new Add(), new Mul(), new Push(), new Pop(), new Idiv(), new Add(), new Mul(), new Push(), new Pop(), new Idiv(),
new Variable() new Variable()
}; };
private LexicTable lexicTable; private final LexicTable lexicTable;
public SyntaxAnalyzer(LexicTable lexicTable) { public SyntaxAnalyzer(LexicTable lexicTable) {
this.lexicTable = lexicTable; this.lexicTable = lexicTable;
} }
public void analyze() throws ExceptionWithLineNumber { public void analyze() throws ExceptionWithLineNumber {
for (int i = 0; i < lexicTable.getSize(); i++) { for (int i = 0; i < lexicTable.getSize(); i++) {
LexicLine line = lexicTable.getLexicAt(i); LexicLine line = lexicTable.getLexicAt(i);
analyzeLine(line.lineNumber, line.line); analyzeLine(line.lineNumber, line.line);
} }
} }
private void analyzeLine(int lineNumber, int[] lexic) throws ExceptionWithLineNumber { private void analyzeLine(int lineNumber, int[] lexic) throws ExceptionWithLineNumber {
for (int i = 0; i < DIRECTIVES.length; i++) { for (ISyntaxChecker dir : DIRECTIVES) {
if (DIRECTIVES[i].check(lineNumber, lexic)) { if (dir.check(lineNumber, lexic)) {
return; return;
} }
} }
} }
} }

View File

@ -1,25 +1,25 @@
package com.annimon.asm; package com.annimon.asm;
/** /**
* Êëàññ ïåðåìåííîé. * Êëàññ ïåðåìåííîé.
* @author aNNiMON * @author aNNiMON
*/ */
public class Var { public final class Var {
String name; String name;
int type; int type;
String value; String value;
short addr; short addr;
public Var(String name, int type, String value, short addr) { public Var(String name, int type, String value, short addr) {
this.name = name; this.name = name;
this.type = type; this.type = type;
this.value = value; this.value = value;
this.addr = addr; this.addr = addr;
} }
public short getAddress() { public short getAddress() {
return addr; return addr;
} }
} }

View File

@ -1,52 +1,52 @@
package com.annimon.asm; package com.annimon.asm;
import com.annimon.asm.directives.ID; import com.annimon.asm.directives.ID;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
* Òàáëèöà ïåðåìåííûõ. * Òàáëèöà ïåðåìåííûõ.
* @author aNNiMON * @author aNNiMON
*/ */
public class VarTable { public final class VarTable {
private ArrayList<Var> variables; private static short offset;
private static short offset; private final ArrayList<Var> variables;
public VarTable() { public VarTable() {
variables = new ArrayList<>(); variables = new ArrayList<>();
offset = 0x103; offset = 0x103;
} }
public static short getOffset() { public static short getOffset() {
return offset; return offset;
} }
public void addVariable(String name, int type, String value) { public void addVariable(String name, int type, String value) {
addVariable(name, type, value, offset); addVariable(name, type, value, offset);
int size = (type == ID.DW) ? 2 : 1; int size = (type == ID.DW) ? 2 : 1;
offset += size; offset += size;
} }
public void addVariable(String name, int type, String value, short address) { public void addVariable(String name, int type, String value, short address) {
variables.add(new Var(name, type, value, address)); variables.add(new Var(name, type, value, address));
} }
public int getTypeOfVariable(String name) { public int getTypeOfVariable(String name) {
for (Var var : variables) { for (Var var : variables) {
if (var.name.equalsIgnoreCase(name)) { if (var.name.equalsIgnoreCase(name)) {
if (var.type == ID.DB) return ID.VAR_BYTE; if (var.type == ID.DB) return ID.VAR_BYTE;
else if (var.type == ID.DW) return ID.VAR_WORD; else if (var.type == ID.DW) return ID.VAR_WORD;
} }
} }
return ID.VAR; return ID.VAR;
} }
public short getAddressOfVariable(String name) { public short getAddressOfVariable(String name) {
for (Var var : variables) { for (Var var : variables) {
if (var.name.equalsIgnoreCase(name)) { if (var.name.equalsIgnoreCase(name)) {
return var.getAddress(); return var.getAddress();
} }
} }
return ID.VAR; return ID.VAR;
} }
} }

View File

@ -12,7 +12,7 @@ import com.annimon.asm.exceptions.WrongArgumentException;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Add extends Directive implements ISyntaxChecker, IListingGenerator { public final class Add extends Directive implements ISyntaxChecker, IListingGenerator {
public Add() { public Add() {
super("add", ID.ADD); super("add", ID.ADD);

View File

@ -4,7 +4,7 @@ package com.annimon.asm.directives;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class ByteRegister extends Register { public final class ByteRegister extends Register {
@Override @Override
public int getId() { public int getId() {

View File

@ -4,7 +4,7 @@ package com.annimon.asm.directives;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class ByteValue extends NumericValue { public final class ByteValue extends NumericValue {
@Override @Override
public int getId() { public int getId() {

View File

@ -1,13 +1,13 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Comma extends Directive { public final class Comma extends Directive {
public Comma() { public Comma() {
super(",", ID.COMMA); super(",", ID.COMMA);
} }
} }

View File

@ -1,13 +1,13 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class DB extends Directive { public final class DB extends Directive {
public DB() { public DB() {
super("db", ID.DB); super("db", ID.DB);
} }
} }

View File

@ -1,13 +1,13 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class DW extends Directive { public final class DW extends Directive {
public DW() { public DW() {
super("dw", ID.DW); super("dw", ID.DW);
} }
} }

View File

@ -1,77 +1,77 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
import com.annimon.asm.ListingGenerateHelper; import com.annimon.asm.ListingGenerateHelper;
import com.annimon.asm.VarTable; import com.annimon.asm.VarTable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import com.annimon.asm.exceptions.FewArgumentsException; import com.annimon.asm.exceptions.FewArgumentsException;
import com.annimon.asm.exceptions.TooManyArgumentsException; import com.annimon.asm.exceptions.TooManyArgumentsException;
import com.annimon.asm.exceptions.WrongArgumentException; import com.annimon.asm.exceptions.WrongArgumentException;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Idiv extends Directive implements ISyntaxChecker, IListingGenerator { public final class Idiv extends Directive implements ISyntaxChecker, IListingGenerator {
public Idiv() { public Idiv() {
super("idiv", ID.IDIV); super("idiv", ID.IDIV);
} }
@Override @Override
public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber { public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber {
if (ids[0] != getId()) return false; if (ids[0] != getId()) return false;
if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1);
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_BYTE) && (ids[1] != ID.VAR_WORD) ) { (ids[1] != ID.VAR_BYTE) && (ids[1] != ID.VAR_WORD) ) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
return true; return true;
} }
@Override @Override
public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) { public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) {
if (ids[0] != getId()) return ""; if (ids[0] != getId()) return "";
// MUL r/m 1111011w | mod111r/m // MUL r/m 1111011w | mod111r/m
StringBuilder sb = new StringBuilder(); int val = 0b1111011_0;
int val = 0b1111011_0; if ( (ids[1] == ID.REGISTER_WORD) || (ids[1] == ID.VAR_WORD) ) {
if ( (ids[1] == ID.REGISTER_WORD) || (ids[1] == ID.VAR_WORD) ) { val |= 1;
val |= 1; }
}
String varaddr = " ";
String varaddr = " "; if ( (ids[1] == ID.VAR_BYTE) || (ids[1] == ID.VAR_WORD)) {
if ( (ids[1] == ID.VAR_BYTE) || (ids[1] == ID.VAR_WORD)) { short offset = vars.getAddressOfVariable(strs[1]);
short offset = vars.getAddressOfVariable(strs[1]); varaddr += ListingGenerateHelper.toLittleEndianString(offset) + " ";
varaddr += ListingGenerateHelper.toLittleEndianString(offset) + " "; }
}
// mod
// mod int modrm = 0b00;
int modrm = 0b00; if (ListingGenerateHelper.isRegister(ids[1])) {
if (ListingGenerateHelper.isRegister(ids[1])) { // Åñëè îïåðàíä - ðåãèñòð, òî mod = 11
// Åñëè îïåðàíä - ðåãèñòð, òî mod = 11 modrm |= 0b11;
modrm |= 0b11; }
} modrm <<= 6;
modrm <<= 6;
// r/m
// r/m if (modrm == 0) modrm = 0b110;
if (modrm == 0) modrm = 0b110; else {
else { // Åñëè mod != 11, òî r/m - id ðåãèñòðà.
// Åñëè mod != 11, òî r/m - id ðåãèñòðà. modrm |= ListingGenerateHelper.getRegisterCode(strs[1]);
modrm |= ListingGenerateHelper.getRegisterCode(strs[1]); }
}
// reg - 111
// reg - 111 byte regID = 0b111;
byte regID = 0b111; regID <<= 3;
regID <<= 3; modrm |= regID;
modrm |= regID;
final StringBuilder sb = new StringBuilder();
sb.append(ListingGenerateHelper.toHexString(val)) sb.append(ListingGenerateHelper.toHexString(val))
.append(' ') .append(' ')
.append(ListingGenerateHelper.toHexString(modrm)) .append(ListingGenerateHelper.toHexString(modrm))
.append(varaddr); .append(varaddr);
return sb.toString(); return sb.toString();
} }
} }

View File

@ -4,7 +4,7 @@ package com.annimon.asm.directives;
* Íåîïðåäåë¸ííîå çíà÷åíèå (?) * Íåîïðåäåë¸ííîå çíà÷åíèå (?)
* @author aNNiMON * @author aNNiMON
*/ */
public class InfinityValue extends NumericValue { public final class InfinityValue extends NumericValue {
@Override @Override
public int getId() { public int getId() {

View File

@ -1,77 +1,77 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
import com.annimon.asm.ListingGenerateHelper; import com.annimon.asm.ListingGenerateHelper;
import com.annimon.asm.VarTable; import com.annimon.asm.VarTable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import com.annimon.asm.exceptions.FewArgumentsException; import com.annimon.asm.exceptions.FewArgumentsException;
import com.annimon.asm.exceptions.TooManyArgumentsException; import com.annimon.asm.exceptions.TooManyArgumentsException;
import com.annimon.asm.exceptions.WrongArgumentException; import com.annimon.asm.exceptions.WrongArgumentException;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Mul extends Directive implements ISyntaxChecker, IListingGenerator { public final class Mul extends Directive implements ISyntaxChecker, IListingGenerator {
public Mul() { public Mul() {
super("mul", ID.MUL); super("mul", ID.MUL);
} }
@Override @Override
public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber { public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber {
if (ids[0] != getId()) return false; if (ids[0] != getId()) return false;
if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1); if (ids.length < 2) throw new FewArgumentsException(lineNumber, 1);
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_BYTE) && (ids[1] != ID.VAR_WORD) ) { (ids[1] != ID.VAR_BYTE) && (ids[1] != ID.VAR_WORD) ) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
return true; return true;
} }
@Override @Override
public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) { public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) {
if (ids[0] != getId()) return ""; if (ids[0] != getId()) return "";
// MUL r/m 1111011w | mod100r/m // MUL r/m 1111011w | mod100r/m
StringBuilder sb = new StringBuilder(); int val = 0b1111011_0;
int val = 0b1111011_0; if ( (ids[1] == ID.REGISTER_WORD) || (ids[1] == ID.VAR_WORD) ) {
if ( (ids[1] == ID.REGISTER_WORD) || (ids[1] == ID.VAR_WORD) ) { val |= 1;
val |= 1; }
}
String varaddr = " ";
String varaddr = " "; if ( (ids[1] == ID.VAR_BYTE) || (ids[1] == ID.VAR_WORD)) {
if ( (ids[1] == ID.VAR_BYTE) || (ids[1] == ID.VAR_WORD)) { short offset = vars.getAddressOfVariable(strs[1]);
short offset = vars.getAddressOfVariable(strs[1]); varaddr += ListingGenerateHelper.toLittleEndianString(offset) + " ";
varaddr += ListingGenerateHelper.toLittleEndianString(offset) + " "; }
}
// mod
// mod int modrm = 0b00;
int modrm = 0b00; if (ListingGenerateHelper.isRegister(ids[1])) {
if (ListingGenerateHelper.isRegister(ids[1])) { // Åñëè îïåðàíä - ðåãèñòð, òî mod = 11
// Åñëè îïåðàíä - ðåãèñòð, òî mod = 11 modrm |= 0b11;
modrm |= 0b11; }
} modrm <<= 6;
modrm <<= 6;
// r/m
// r/m if (modrm == 0) modrm = 0b110;
if (modrm == 0) modrm = 0b110; else {
else { // Åñëè mod != 11, òî r/m - id ðåãèñòðà.
// Åñëè mod != 11, òî r/m - id ðåãèñòðà. modrm |= ListingGenerateHelper.getRegisterCode(strs[1]);
modrm |= ListingGenerateHelper.getRegisterCode(strs[1]); }
}
// reg - 100
// reg - 100 byte regID = 0b100;
byte regID = 0b100; regID <<= 3;
regID <<= 3; modrm |= regID;
modrm |= regID;
final StringBuilder sb = new StringBuilder();
sb.append(ListingGenerateHelper.toHexString(val)) sb.append(ListingGenerateHelper.toHexString(val))
.append(' ') .append(' ')
.append(ListingGenerateHelper.toHexString(modrm)) .append(ListingGenerateHelper.toHexString(modrm))
.append(varaddr); .append(varaddr);
return sb.toString(); return sb.toString();
} }
} }

View File

@ -1,64 +1,64 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
import com.annimon.asm.ListingGenerateHelper; import com.annimon.asm.ListingGenerateHelper;
import com.annimon.asm.VarTable; import com.annimon.asm.VarTable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import com.annimon.asm.exceptions.FewArgumentsException; import com.annimon.asm.exceptions.FewArgumentsException;
import com.annimon.asm.exceptions.WrongArgumentException; import com.annimon.asm.exceptions.WrongArgumentException;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Pop extends Directive implements ISyntaxChecker, IListingGenerator { public final class Pop extends Directive implements ISyntaxChecker, IListingGenerator {
public Pop() { public Pop() {
super("pop", ID.POP); super("pop", ID.POP);
} }
@Override @Override
public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber { public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber {
if (ids[0] != getId()) return false; if (ids[0] != getId()) return false;
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_WORD)) { (ids[i] != ID.VAR_WORD)) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
} }
return true; return true;
} }
@Override @Override
public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) { public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) {
if (ids[0] != getId()) return ""; if (ids[0] != getId()) return "";
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (ids[1] == ID.REGISTER_WORD) { if (ids[1] == ID.REGISTER_WORD) {
byte segmentID = ListingGenerateHelper.getSegmentRegisterCode(strs[1]); byte segmentID = ListingGenerateHelper.getSegmentRegisterCode(strs[1]);
if (segmentID != -1) { if (segmentID != -1) {
//seg (òîëüêî cs, ds, ss, es) 00seg111 //seg (òîëüêî cs, ds, ss, es) 00seg111
byte val = (byte) (0b00_000_111 | (segmentID << 3)); byte val = (byte) (0b00_000_111 | (segmentID << 3));
sb.append(ListingGenerateHelper.toHexString(val)); sb.append(ListingGenerateHelper.toHexString(val));
} else { } else {
// reg16/32 01011reg // reg16/32 01011reg
byte regID = ListingGenerateHelper.getRegisterCode(strs[1]); byte regID = ListingGenerateHelper.getRegisterCode(strs[1]);
byte val = (byte) (0b01011_000 | regID); byte val = (byte) (0b01011_000 | regID);
sb.append(ListingGenerateHelper.toHexString(val)); sb.append(ListingGenerateHelper.toHexString(val));
} }
} else if (ids[1] == ID.VAR_WORD) { } else if (ids[1] == ID.VAR_WORD) {
//r/m16/32 10001111 | mod110r/m //r/m16/32 10001111 | mod110r/m
short offset = vars.getAddressOfVariable(strs[1]); short offset = vars.getAddressOfVariable(strs[1]);
sb.append(ListingGenerateHelper.toHexString(0b10001111)) sb.append(ListingGenerateHelper.toHexString(0b10001111))
.append(' ') .append(' ')
.append(ListingGenerateHelper.toHexString(0b00_000_110)) .append(ListingGenerateHelper.toHexString(0b00_000_110))
.append(' ') .append(' ')
.append(ListingGenerateHelper.toLittleEndianString(offset)); .append(ListingGenerateHelper.toLittleEndianString(offset));
} }
return sb.toString(); return sb.toString();
} }
} }

View File

@ -1,65 +1,65 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
import com.annimon.asm.ListingGenerateHelper; import com.annimon.asm.ListingGenerateHelper;
import com.annimon.asm.VarTable; import com.annimon.asm.VarTable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import com.annimon.asm.exceptions.FewArgumentsException; import com.annimon.asm.exceptions.FewArgumentsException;
import com.annimon.asm.exceptions.WrongArgumentException; import com.annimon.asm.exceptions.WrongArgumentException;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Push extends Directive implements ISyntaxChecker, IListingGenerator { public final class Push extends Directive implements ISyntaxChecker, IListingGenerator {
public Push() { public Push() {
super("push", ID.PUSH); super("push", ID.PUSH);
} }
@Override @Override
public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber { public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber {
if (ids[0] != getId()) return false; if (ids[0] != getId()) return false;
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_WORD)) { (ids[i] != ID.VAR_WORD)) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
} }
return true; return true;
} }
@Override @Override
public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) { public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) {
if (ids[0] != getId()) return ""; if (ids[0] != getId()) return "";
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (ids[1] == ID.REGISTER_WORD) { if (ids[1] == ID.REGISTER_WORD) {
byte segmentID = ListingGenerateHelper.getSegmentRegisterCode(strs[1]); byte segmentID = ListingGenerateHelper.getSegmentRegisterCode(strs[1]);
if (segmentID != -1) { if (segmentID != -1) {
//seg (òîëüêî cs, ds, ss, es) 00seg110 //seg (òîëüêî cs, ds, ss, es) 00seg110
byte val = (byte) (0b00_000_110 | (segmentID << 3)); byte val = (byte) (0b00_000_110 | (segmentID << 3));
sb.append(ListingGenerateHelper.toHexString(val)); sb.append(ListingGenerateHelper.toHexString(val));
} else { } else {
// reg16/32 01010reg // reg16/32 01010reg
byte regID = ListingGenerateHelper.getRegisterCode(strs[1]); byte regID = ListingGenerateHelper.getRegisterCode(strs[1]);
byte val = (byte) (0b01010_000 | regID); byte val = (byte) (0b01010_000 | regID);
sb.append(ListingGenerateHelper.toHexString(val)); sb.append(ListingGenerateHelper.toHexString(val));
} }
} else if (ids[1] == ID.VAR_WORD) { } else if (ids[1] == ID.VAR_WORD) {
// r/m16/32 11111111 | mod110r/m // r/m16/32 11111111 | mod110r/m
short offset = vars.getAddressOfVariable(strs[1]); short offset = vars.getAddressOfVariable(strs[1]);
sb.append(ListingGenerateHelper.toHexString(0b11111111)) sb.append(ListingGenerateHelper.toHexString(0b11111111))
.append(' ') .append(' ')
.append(ListingGenerateHelper.toHexString(0b00_110_110)) .append(ListingGenerateHelper.toHexString(0b00_110_110))
.append(' ') .append(' ')
.append(ListingGenerateHelper.toLittleEndianString(offset)); .append(ListingGenerateHelper.toLittleEndianString(offset));
} }
return sb.toString(); return sb.toString();
} }
} }

View File

@ -1,61 +1,61 @@
package com.annimon.asm.directives; package com.annimon.asm.directives;
import com.annimon.asm.ListingGenerateHelper; import com.annimon.asm.ListingGenerateHelper;
import com.annimon.asm.VarTable; import com.annimon.asm.VarTable;
import com.annimon.asm.exceptions.ExceptionWithLineNumber; import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import com.annimon.asm.exceptions.FewArgumentsException; import com.annimon.asm.exceptions.FewArgumentsException;
import com.annimon.asm.exceptions.TooManyArgumentsException; import com.annimon.asm.exceptions.TooManyArgumentsException;
import com.annimon.asm.exceptions.WrongArgumentException; import com.annimon.asm.exceptions.WrongArgumentException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class Variable extends Directive implements ISyntaxChecker, IListingGenerator { public final class Variable extends Directive implements ISyntaxChecker, IListingGenerator {
public Variable() { public Variable() {
super("", ID.VAR); super("", ID.VAR);
} }
@Override @Override
public boolean isDirective(String text) { public boolean isDirective(String text) {
if (Pattern.matches(Pattern.compile("^[^0-9]*[\\w.@_$]").pattern(), text)) { if (Pattern.matches(Pattern.compile("^[^0-9]*[\\w.@_$]").pattern(), text)) {
return true; return true;
} }
return false; return false;
} }
@Override @Override
public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber { public boolean check(int lineNumber, int[] ids) throws ExceptionWithLineNumber {
if (ids[0] != getId()) return false; if (ids[0] != getId()) return false;
if (ids.length < 3) throw new FewArgumentsException(lineNumber, 2); if (ids.length < 3) throw new FewArgumentsException(lineNumber, 2);
else if (ids.length > 3) throw new TooManyArgumentsException(lineNumber, 2); else if (ids.length > 3) throw new TooManyArgumentsException(lineNumber, 2);
boolean db = ( (ids[1] == ID.DB) && boolean db = ( (ids[1] == ID.DB) &&
((ids[2] == ID.NUMBER_BYTE) || (ids[2] == ID.NUMBER_INFINITY)) ); ((ids[2] == ID.NUMBER_BYTE) || (ids[2] == ID.NUMBER_INFINITY)) );
boolean dw = ( (ids[1] == ID.DW) && boolean dw = ( (ids[1] == ID.DW) &&
((ids[2] == ID.NUMBER_WORD) || (ids[2] == ID.NUMBER_INFINITY)) ); ((ids[2] == ID.NUMBER_WORD) || (ids[2] == ID.NUMBER_INFINITY)) );
if (!db && !dw) { if (!db && !dw) {
throw new WrongArgumentException(lineNumber); throw new WrongArgumentException(lineNumber);
} }
return true; return true;
} }
@Override @Override
public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) { public String generate(int lineNumber, int[] ids, String[] strs, VarTable vars) {
if ( (ids[0] != ID.VAR_BYTE) && (ids[0] != ID.VAR_WORD) ) return ""; if ( (ids[0] != ID.VAR_BYTE) && (ids[0] != ID.VAR_WORD) ) return "";
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int offset = vars.getAddressOfVariable(strs[0]); int offset = vars.getAddressOfVariable(strs[0]);
sb.append(ListingGenerateHelper.toHexString(offset)).append(" "); sb.append(ListingGenerateHelper.toHexString(offset)).append(" ");
if (ids[2] == ID.NUMBER_INFINITY) { if (ids[2] == ID.NUMBER_INFINITY) {
sb.append("??"); sb.append("??");
if (ids[1] == ID.DW) sb.append(" ??"); if (ids[1] == ID.DW) sb.append(" ??");
} else sb.append( ListingGenerateHelper.toLittleEndianString(strs[2]) ); } else sb.append( ListingGenerateHelper.toLittleEndianString(strs[2]) );
return sb.toString(); return sb.toString();
} }
} }

View File

@ -4,7 +4,7 @@ package com.annimon.asm.directives;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class WordRegister extends Register { public final class WordRegister extends Register {
@Override @Override
public int getId() { public int getId() {

View File

@ -4,7 +4,7 @@ package com.annimon.asm.directives;
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class WordValue extends NumericValue { public final class WordValue extends NumericValue {
@Override @Override
public int getId() { public int getId() {

View File

@ -1,12 +1,12 @@
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* Êëàññ îøèáêè ïðîïóùåííîé çàïÿòîé. * Êëàññ îøèáêè ïðîïóùåííîé çàïÿòîé.
* @author aNNiMON * @author aNNiMON
*/ */
public class CommaExpectedException extends ExceptionWithLineNumber { public final class CommaExpectedException extends ExceptionWithLineNumber {
public CommaExpectedException(int lineNumber) { public CommaExpectedException(int lineNumber) {
super("Comma expected", lineNumber); super("Comma expected", lineNumber);
} }
} }

View File

@ -1,21 +1,21 @@
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 {
private int lineNumber; private final int lineNumber;
public ExceptionWithLineNumber(String message, int lineNumber) { public ExceptionWithLineNumber(String message, int lineNumber) {
super(message); super(message);
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
} }
@Override @Override
public String getMessage() { public String getMessage() {
return super.getMessage() + " at line " + lineNumber; return super.getMessage() + " at line " + lineNumber;
} }
} }

View File

@ -1,16 +1,16 @@
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* Êëàññ îøèáêè, êîãäà óêàçàíî ñëèøêîì ìàëî àðãóìåíòîâ êîìàíäû, íåæåëè îæèäàëîñü. * Êëàññ îøèáêè, êîãäà óêàçàíî ñëèøêîì ìàëî àðãóìåíòîâ êîìàíäû, íåæåëè îæèäàëîñü.
* @author aNNiMON * @author aNNiMON
*/ */
public class FewArgumentsException extends ExceptionWithLineNumber { public final class FewArgumentsException extends ExceptionWithLineNumber {
public FewArgumentsException(int lineNumber) { public FewArgumentsException(int lineNumber) {
super("Few arguments", lineNumber); super("Few arguments", lineNumber);
} }
public FewArgumentsException(int lineNumber, int necessaryArguments) { public FewArgumentsException(int lineNumber, int necessaryArguments) {
super("Few arguments, need " + necessaryArguments + " args", lineNumber); super("Few arguments, need " + necessaryArguments + " args", lineNumber);
} }
} }

View File

@ -1,16 +1,16 @@
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* Êëàññ îøèáêè äëÿ ïðåâûøåííîãî êîëè÷åñòâà àðãóìåíòîâ êîìàíäû. * Êëàññ îøèáêè äëÿ ïðåâûøåííîãî êîëè÷åñòâà àðãóìåíòîâ êîìàíäû.
* @author aNNiMON * @author aNNiMON
*/ */
public class TooManyArgumentsException extends ExceptionWithLineNumber { public final class TooManyArgumentsException extends ExceptionWithLineNumber {
public TooManyArgumentsException(int lineNumber) { public TooManyArgumentsException(int lineNumber) {
super("Too many arguments", lineNumber); super("Too many arguments", lineNumber);
} }
public TooManyArgumentsException(int lineNumber, int necessaryArguments) { public TooManyArgumentsException(int lineNumber, int necessaryArguments) {
super("Too many arguments, need " + necessaryArguments + " args", lineNumber); super("Too many arguments, need " + necessaryArguments + " args", lineNumber);
} }
} }

View File

@ -1,12 +1,12 @@
package com.annimon.asm.exceptions; package com.annimon.asm.exceptions;
/** /**
* Êëàññ îøèáêè íåâåðíîãî àðãóìåíòà, êîãäà íå ñîâïàäàåò îæèäàåìûé òèï. * Êëàññ îøèáêè íåâåðíîãî àðãóìåíòà, êîãäà íå ñîâïàäàåò îæèäàåìûé òèï.
* @author aNNiMON * @author aNNiMON
*/ */
public class WrongArgumentException extends ExceptionWithLineNumber { public final class WrongArgumentException extends ExceptionWithLineNumber {
public WrongArgumentException(int lineNumber) { public WrongArgumentException(int lineNumber) {
super("Wrong argument", lineNumber); super("Wrong argument", lineNumber);
} }
} }