This commit is contained in:
Victor 2018-11-15 18:47:32 +02:00
commit c8fe680339
34 changed files with 2412 additions and 0 deletions

74
build.xml Normal file
View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="AsmAnalyzer" default="default" basedir=".">
<description>Builds, tests, and runs the project AsmAnalyzer.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="AsmAnalyzer-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

1411
nbproject/build-impl.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
build.xml.data.CRC32=2439a656
build.xml.script.CRC32=1475b172
build.xml.stylesheet.CRC32=28e38971@1.56.0.46
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=2439a656
nbproject/build-impl.xml.script.CRC32=44145888
nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.0.46

View File

View File

@ -0,0 +1,6 @@
compile.on.save=true
do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
user.properties.file=C:\\Users\\aNNiMON\\AppData\\Roaming\\NetBeans\\dev\\build.properties

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
</project-private>

View File

@ -0,0 +1,73 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=AsmAnalyzer
application.vendor=aNNiMON
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/AsmAnalyzer.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
includes=**
jar.compress=false
javac.classpath=
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=\
${javac.classpath}
javac.source=1.6
javac.target=1.6
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=com.annimon.asm.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project.
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
# To set system properties for unit tests define test-sys-prop.name=value:
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=windows-1251
src.dir=src
test.src.dir=test

15
nbproject/project.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>AsmAnalyzer</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
</configuration>
</project>

View File

@ -0,0 +1,111 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm;
import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Utilities;
/**
*
* @author aNNiMON
*/
public class AnalyzerPanel extends JPanel {
private JLabel lineNumberLabel;
private JTextPane textPane;
private JButton analyzeButton;
public AnalyzerPanel() {
lineNumberLabel = new JLabel("Line: 1");
initTextPane();
initAnalyzeButton();
setLayout(new BorderLayout(0, 0));
add(lineNumberLabel, BorderLayout.NORTH);
add(new JScrollPane(textPane));
add(analyzeButton, BorderLayout.SOUTH);
}
private void initTextPane() {
textPane = new JTextPane();
textPane.setPreferredSize(new Dimension(300, 300));
textPane.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent caretEvent) {
JTextComponent textComponent = (JTextComponent)caretEvent.getSource();
int pos = caretEvent.getDot();
int rowNumber = (pos == 0) ? 1 : 0;
try {
int offset = pos;
while (offset > 0) {
offset = Utilities.getRowStart(textComponent, offset) - 1;
rowNumber++;
}
} catch (BadLocationException ex) {}
lineNumberLabel.setText("Line: " + rowNumber);
}
});
textPane.setFont(new Font("Consolas", Font.PLAIN, 14));
textPane.setText(getTextFromResource("/test.asm"));
}
private void initAnalyzeButton() {
analyzeButton = new JButton("Analyze");
analyzeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
String allText = textPane.getText();
LexicalAnalyzer lex = new LexicalAnalyzer(allText);
lex.analyze();
SyntaxAnalyzer syn = new SyntaxAnalyzer(lex.getLexicTable());
try {
syn.analyze();
} catch (ExceptionWithLineNumber ex) {
System.out.println(ex.getMessage());
}
}
});
}
private String getTextFromResource(String res) {
try {
InputStream is = getClass().getResourceAsStream(res);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder text = new StringBuilder();
String line;
while( (line = reader.readLine()) != null ) {
text.append(line).append(System.lineSeparator());
}
reader.close();
return text.toString();
} catch (IOException ex) {}
return "";
}
}

View File

@ -0,0 +1,34 @@
package com.annimon.asm;
import com.annimon.asm.directives.*;
/**
*
* @author aNNiMON
*/
public class DirectiveConvertor {
private static final Directive[] DIRECTIVES = {
new Comma(),
new DB(), new DW(),
new InfinityValue(), new ByteValue(), new WordValue(),
new Add(), new Mul(), new Push(), new Pop(),
new ByteRegister(), new WordRegister(),
new Variable()
};
/**
* Êîíâåðòèðîâàòü äèðåêòèâó â å¸ èäåíòèôèêàòîð.
* @param text äèðåêòèâà (dw, push, 0 è ò.ä.)
* @return èäåíòèôèêàòîð äèðåêòèâû
*/
public static int convert(String text) {
for (int i = 0; i < DIRECTIVES.length; i++) {
if (DIRECTIVES[i].isDirective(text)) {
return DIRECTIVES[i].getId();
}
}
return -1;
}
}

View File

@ -0,0 +1,20 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm;
/**
*
* @author aNNiMON
*/
public class LexicLine {
int lineNumber;
int[] line;
public LexicLine(int lineNumber, int[] line) {
this.lineNumber = lineNumber;
this.line = line;
}
}

View File

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

View File

@ -0,0 +1,75 @@
package com.annimon.asm;
import com.annimon.asm.exceptions.ExceptionWithLineNumber;
import java.util.ArrayList;
/**
*
* @author aNNiMON
*/
public class LexicalAnalyzer {
private String[] lines;
private LexicTable lexicTable;
public LexicalAnalyzer(String text) {
lines = text.split(System.lineSeparator());
lexicTable = new LexicTable();
}
public LexicTable getLexicTable() {
return lexicTable;
}
public void analyze() {
for (int i = 0; i < lines.length; i++) {
analyzeLine(i);
}
System.out.println(lexicTable.toString());
}
private void analyzeLine(int lineNumber) {
String line = lines[lineNumber];
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());
}
lexicTable.addLexicLine(lineNumber+1, lexicIds);
}
private String[] split(String text) {
ArrayList<String> parts = new ArrayList<String>();
int length = text.length();
StringBuilder sb = new StringBuilder();
for (int ch = 0; ch < length; ch++) {
int i = text.charAt(ch);
if (i == ' ') {
if (sb.length() > 0) {
parts.add(sb.toString().trim());
sb.setLength(0);
}
} else if (i == ',') {
if (sb.length() > 0) {
parts.add(sb.toString().trim());
parts.add(",");
sb.setLength(0);
}
} else {
sb.append((char) i);
}
}
if (sb.length() > 0) {
parts.add(sb.toString().trim());
}
String[] m = new String[parts.size()];
m = parts.toArray(m);
return m;
}
}

View File

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

View File

@ -0,0 +1,31 @@
package com.annimon.asm;
import com.annimon.asm.directives.ID;
import com.annimon.asm.exceptions.ExceptionWithLineNumber;
/**
*
* @author aNNiMON
*/
public class SyntaxAnalyzer {
private LexicTable lexicTable;
public SyntaxAnalyzer(LexicTable lexicTable) {
this.lexicTable = lexicTable;
}
public void analyze() throws ExceptionWithLineNumber {
for (int i = 0; i < lexicTable.getSize(); i++) {
LexicLine line = lexicTable.getLexicAt(i);
analyzeLine(line.lineNumber, line.line);
}
}
private void analyzeLine(int lineNumber, int[] lexic) throws ExceptionWithLineNumber {
if (lexic[0] == ID.VAR) {
}
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class Add extends Directive {
public Add() {
super("add", ID.ADD);
}
}

View File

@ -0,0 +1,32 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class ByteRegister extends Register {
public ByteRegister() {
super();
}
@Override
public int getId() {
return ID.REGISTER_BYTE;
}
@Override
protected String[] getRegisterNames() {
return new String[] {
"ah", "al",
"bh", "bl",
"ch", "cl",
"dh", "dl",
};
}
}

View File

@ -0,0 +1,31 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class ByteValue extends NumericValue {
public ByteValue() {
super();
}
@Override
public int getId() {
return ID.NUMBER_BYTE;
}
@Override
protected boolean checkRange(Integer value) {
if (value == null) return false;
if ( (-128 <= value.intValue()) && (value.intValue() <= 255) ) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class Comma extends Directive {
public Comma() {
super(",", ID.COMMA);
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class DB extends Directive {
public DB() {
super("db", ID.DB);
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class DW extends Directive {
public DW() {
super("dw", ID.DW);
}
}

View File

@ -0,0 +1,33 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public abstract class Directive {
protected String name;
protected int id;
protected Directive(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public boolean isDirective(String text) {
return text.equalsIgnoreCase(name);
}
}

View File

@ -0,0 +1,36 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class ID {
public static final int
NULL = -1,
DB = 0,
DW = 1,
COMMA = 5,
ADD = 10,
MUL = 11,
PUSH = 12,
POP = 13,
NUMBER_BYTE = 100,
NUMBER_WORD = 101,
NUMBER_INFINITY = 102,
REGISTER_BYTE = 200,
REGISTER_WORD = 201,
VAR = 500,
VAR_BYTE = 501,
VAR_WORD = 502;
}

View File

@ -0,0 +1,31 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
* Íåîïðåäåë¸ííîå çíà÷åíèå (?)
* @author aNNiMON
*/
public class InfinityValue extends NumericValue {
public InfinityValue() {
super();
}
@Override
public int getId() {
return ID.NUMBER_INFINITY;
}
@Override
public boolean isDirective(String text) {
return text.equals("?");
}
@Override
protected boolean checkRange(Integer value) {
return true;
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class Mul extends Directive {
public Mul() {
super("mul", ID.MUL);
}
}

View File

@ -0,0 +1,45 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public abstract class NumericValue extends Directive {
public NumericValue() {
super("", ID.NULL);
}
@Override
public boolean isDirective(String text) {
if (text == null) return false;
Integer value = parse(text);
return checkRange(value);
}
protected abstract boolean checkRange(Integer value);
private Integer parse(String text) {
int value;
if (text.toLowerCase().endsWith("h")) {
String hex = text.substring(0, text.length() - 1);
try {
value = Integer.parseInt(hex, 16);
return value;
} catch (NumberFormatException numberFormatException) {
return null;
}
}
try {
value = Integer.parseInt(text);
return value;
} catch (NumberFormatException numberFormatException) {
return null;
}
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class Pop extends Directive {
public Pop() {
super("pop", ID.POP);
}
}

View File

@ -0,0 +1,17 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class Push extends Directive {
public Push() {
super("push", ID.PUSH);
}
}

View File

@ -0,0 +1,29 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public abstract class Register extends Directive {
public Register() {
super("", ID.NULL);
}
@Override
public boolean isDirective(String text) {
String[] names = getRegisterNames();
for (int i = 0; i < names.length; i++) {
if (text.equalsIgnoreCase(names[i])) {
return true;
}
}
return false;
}
protected abstract String[] getRegisterNames();
}

View File

@ -0,0 +1,22 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class Variable extends Directive {
public Variable() {
super("", ID.VAR);
}
@Override
public boolean isDirective(String text) {
return true;
}
}

View File

@ -0,0 +1,30 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class WordRegister extends Register {
public WordRegister() {
super();
}
@Override
public int getId() {
return ID.REGISTER_WORD;
}
@Override
protected String[] getRegisterNames() {
return new String[] {
"ax", "bx", "cx", "dx",
"cs", "ds", "ss", "es"
};
}
}

View File

@ -0,0 +1,31 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.annimon.asm.directives;
/**
*
* @author aNNiMON
*/
public class WordValue extends NumericValue {
public WordValue() {
super();
}
@Override
public int getId() {
return ID.NUMBER_WORD;
}
@Override
protected boolean checkRange(Integer value) {
if (value == null) return false;
if ( (-32768 <= value.intValue()) && (value.intValue() <= 65535) ) {
return true;
}
return false;
}
}

View File

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

8
src/test.asm Normal file
View File

@ -0,0 +1,8 @@
num1 db 12
num2 dw 2000
num3 dw ?
add num1, num2
push num2
mul num1
pop ax