|
@@ -71,522 +71,518 @@ import de.mcs.utils.jsap.SwitchOption;
|
|
|
@Command(help = "SPS Assembler \r\n usage java -jar SPSEmulator-x.x.x.jar <options>")
|
|
|
public class SPSAssembler {
|
|
|
|
|
|
- private static final String INCLUDE_FILE = ".include";
|
|
|
- private static final String END_MACRO_DEFINITION = ".endmacro";
|
|
|
- private static final String START_MACRO_DEFINITION = ".macro";
|
|
|
- private static final String DEFAULT_PACKAGE_FILTER = "de.mcs.tools.sps"; //$NON-NLS-1$
|
|
|
- private static File source;
|
|
|
- private static HARDWARE destination;
|
|
|
- private static File destinationFile;
|
|
|
- private static String outputFormat;
|
|
|
- private static File includes;
|
|
|
- private static Outputter outputter;
|
|
|
- private static String destinationStr;
|
|
|
-
|
|
|
- private int lineNumber;
|
|
|
- // private int srcLineNumber;
|
|
|
- private Map<String, Integer> labels;
|
|
|
- private boolean inBlockComment;
|
|
|
- private List<Mnemonic> mnemonics;
|
|
|
- private boolean inMacro;
|
|
|
- private Macro actualMacro;
|
|
|
- private Map<String, Macro> macros;
|
|
|
-
|
|
|
- @SwitchOption(shortKey = 'h', longKey = "help", name = "help", help = "show this help page", required = false, defaultValue = false)
|
|
|
- public static void doHelp(boolean value) {
|
|
|
- if (value) {
|
|
|
- CommandlineProcessor.showHelp();
|
|
|
- System.exit(0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @StringOption(shortKey = 'f', longKey = "format", name = "format", defaultValue = "HEX", help = "the output format. HEX: IntelHEX, TPSTXT: TPS programming text", required = false)
|
|
|
- public static void setOutputFormat(String value) {
|
|
|
- outputFormat = value.toUpperCase();
|
|
|
- }
|
|
|
-
|
|
|
- @StringOption(shortKey = 'd', longKey = "hardware", name = "hardware system", defaultValue = "HOLTEK", help = "the hardware system to compile to. Passible options are: HOLTEK, ATMEGA8, ARDUINOSPS, TINYSPS", required = false)
|
|
|
- public static void setDestinationSystem(String value) {
|
|
|
- destinationStr = value;
|
|
|
- }
|
|
|
-
|
|
|
- @FileOption(shortKey = 'i', longKey = "includes", name = "includes", defaultValue = "", help = "where to find the includes files.", required = false)
|
|
|
- public static void setDestinationSystem(File file) {
|
|
|
- if ((file != null) && !file.getName().equals("")) {
|
|
|
- includes = file;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @FileOption(index = 1, name = "source file", help = "source file to compile", required = true, mustExists = true)
|
|
|
- public static void setSourceFile(File file) {
|
|
|
- if ((file != null) && !file.getName().equals("")) {
|
|
|
- source = file;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @FileOption(index = 2, name = "destination file", help = "destination file to compile to", required = false)
|
|
|
- public static void setDestinationFile(File file) {
|
|
|
- if ((file != null) && !file.getName().equals("")) {
|
|
|
- destinationFile = file;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param args
|
|
|
- * @throws IOException
|
|
|
- */
|
|
|
- public static void main(String[] args) {
|
|
|
- try {
|
|
|
- destination = HARDWARE.HOLTEK;
|
|
|
-
|
|
|
- CommandlineProcessor.processCommandline(SPSAssembler.class, args);
|
|
|
-
|
|
|
- try {
|
|
|
- destination = HARDWARE.valueOf((destinationStr.toUpperCase()));
|
|
|
- } catch (IllegalArgumentException e) {
|
|
|
- throw new HardwareException(String.format("Hardware %s unknow for this assembler", destinationStr));
|
|
|
- }
|
|
|
-
|
|
|
- registerAllOutputter();
|
|
|
-
|
|
|
- if ((source == null) || (!source.exists())) {
|
|
|
- CommandlineProcessor.showHelp(
|
|
|
- String.format("source file null or not found. %s", (source == null) ? "" : source.getAbsolutePath()));
|
|
|
- System.exit(-1);
|
|
|
- }
|
|
|
-
|
|
|
- if (destinationFile == null) {
|
|
|
- String name = source.getName();
|
|
|
- name = name.substring(0, source.getName().lastIndexOf("."));
|
|
|
- String ext = outputter.getDefaultExtension();
|
|
|
- destinationFile = new File(source.getParentFile(), name + ext);
|
|
|
- }
|
|
|
-
|
|
|
- System.out.printf("source file: %s \r\n", source.getName());
|
|
|
- System.out.printf("destination file: %s \r\n", destinationFile.getName());
|
|
|
- System.out.printf("output format: %s \r\n", outputFormat);
|
|
|
- System.out.printf("hardware: %s \r\n", destination.name());
|
|
|
- if (includes != null) {
|
|
|
- System.out.printf("includes foldes: %s \r\n", includes.getCanonicalPath());
|
|
|
- }
|
|
|
- System.out.println();
|
|
|
-
|
|
|
- try {
|
|
|
- SPSAssembler spsAssembler = new SPSAssembler();
|
|
|
- spsAssembler.doWork(source);
|
|
|
-
|
|
|
- List<Mnemonic> mnemonics = spsAssembler.getMnemonics();
|
|
|
-
|
|
|
- outputMnemonics(mnemonics);
|
|
|
-
|
|
|
- outputLabels(spsAssembler);
|
|
|
-
|
|
|
- outputMacros(spsAssembler);
|
|
|
-
|
|
|
- outputFile(mnemonics);
|
|
|
-
|
|
|
- System.out.println("assembling succesfully");
|
|
|
- } catch (SyntaxError e) {
|
|
|
- e.printStackTrace();
|
|
|
- System.err.println(e.getMessage());
|
|
|
- System.exit(-1);
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @throws InstantiationException
|
|
|
- * @throws IllegalAccessException
|
|
|
- * @throws Exception
|
|
|
- */
|
|
|
- private static void registerAllOutputter() throws InstantiationException, IllegalAccessException, Exception {
|
|
|
- Set<Class<?>> outputClasses = searchOutputter(SPSOutputter.class);
|
|
|
- for (Class<?> outClass : outputClasses) {
|
|
|
- SPSOutputter annotation = outClass.getAnnotation(SPSOutputter.class);
|
|
|
- if (annotation.name().equalsIgnoreCase(outputFormat)) {
|
|
|
- outputter = (Outputter) outClass.newInstance();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (outputter == null) {
|
|
|
- throw new Exception(String.format("can't find outputter for format: %s", outputFormat));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private static Set<Class<?>> searchOutputter(Class<? extends Annotation> annotationClass) {
|
|
|
- ConfigurationBuilder builder = new ConfigurationBuilder();
|
|
|
- builder.addUrls(ClasspathHelper.forPackage(DEFAULT_PACKAGE_FILTER));
|
|
|
- Reflections reflections = new Reflections(builder);
|
|
|
- Set<Class<?>> classes = new HashSet<Class<?>>();
|
|
|
- classes.addAll(reflections.getTypesAnnotatedWith(annotationClass));
|
|
|
- return classes;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param mnemonics
|
|
|
- * @throws IOException
|
|
|
- * @throws FileNotFoundException
|
|
|
- */
|
|
|
- private static void outputFile(List<Mnemonic> mnemonics) throws IOException, FileNotFoundException {
|
|
|
- try (FileOutputStream output = new FileOutputStream(destinationFile)) {
|
|
|
- outputter.output(mnemonics, output);
|
|
|
- } finally {
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param spsAssembler
|
|
|
- */
|
|
|
- private static void outputMacros(SPSAssembler spsAssembler) {
|
|
|
- Map<String, Macro> macros = spsAssembler.getMacros();
|
|
|
- if ((macros != null) && (macros.size() > 0)) {
|
|
|
- System.out.println();
|
|
|
- System.out.println("macros");
|
|
|
- for (Macro macro : macros.values()) {
|
|
|
- System.out.printf("%s: %s\r\n", macro.getName(), macro.toString());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param spsAssembler
|
|
|
- */
|
|
|
- private static void outputLabels(SPSAssembler spsAssembler) {
|
|
|
- Map<String, Integer> labels = spsAssembler.getLabels();
|
|
|
- if ((labels != null) && (labels.size() > 0)) {
|
|
|
- System.out.println();
|
|
|
- System.out.println("labels");
|
|
|
- for (Entry<String, Integer> entry : labels.entrySet()) {
|
|
|
- System.out.printf("%s: 0x%03x\r\n", entry.getKey(), entry.getValue());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param mnemonics
|
|
|
- */
|
|
|
- private static void outputMnemonics(List<Mnemonic> mnemonics) {
|
|
|
- System.out.println("Mnemonics");
|
|
|
- int pos = 0;
|
|
|
- for (Iterator<Mnemonic> iterator = mnemonics.iterator(); iterator.hasNext();) {
|
|
|
- Mnemonic mnemonic = iterator.next();
|
|
|
- System.out.printf("0x%03x: %s\r\n", pos, mnemonic.toString());
|
|
|
- pos++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- *
|
|
|
- */
|
|
|
- public SPSAssembler() {
|
|
|
- lineNumber = 0;
|
|
|
- // srcLineNumber = 0;
|
|
|
- labels = new HashMap<>();
|
|
|
- inBlockComment = false;
|
|
|
- mnemonics = new ArrayList<>();
|
|
|
- inMacro = false;
|
|
|
- actualMacro = null;
|
|
|
- macros = new HashMap<>();
|
|
|
- }
|
|
|
-
|
|
|
- private void doWork(File source) throws IOException, SyntaxError {
|
|
|
- System.out.printf("start parsing file: %s\r\n", source.getName());
|
|
|
-
|
|
|
- List<String> sourceFile = Files.readAllLines(source.toPath(), Charset.forName("UTF-8"));
|
|
|
- for (int i = 0; i < sourceFile.size(); i++) {
|
|
|
- String line = sourceFile.get(i);
|
|
|
-
|
|
|
- List<String> linesToAdd;
|
|
|
- do {
|
|
|
- linesToAdd = parseLine(i, line);
|
|
|
- if (linesToAdd != null) {
|
|
|
- sourceFile.remove(i);
|
|
|
- sourceFile.addAll(i, linesToAdd);
|
|
|
- line = sourceFile.get(i);
|
|
|
- linesToAdd = parseLine(i, line);
|
|
|
- }
|
|
|
- } while (linesToAdd != null);
|
|
|
- }
|
|
|
-
|
|
|
- // Checking destination
|
|
|
- checkingHardware();
|
|
|
-
|
|
|
- calculatingJumps();
|
|
|
-
|
|
|
- paddingSubroutines();
|
|
|
-
|
|
|
- // checking size of program
|
|
|
- checkingProgramSize();
|
|
|
- }
|
|
|
-
|
|
|
- private void paddingSubroutines() throws SyntaxError {
|
|
|
- // checking location of Subroutines
|
|
|
- if (destination.equals(HARDWARE.ARDUINOSPS) || destination.equals(HARDWARE.TINYSPS)) {
|
|
|
- int position = 0;
|
|
|
- for (int i = 0; i < mnemonics.size(); i++) {
|
|
|
- Mnemonic mnemonic = mnemonics.get(i);
|
|
|
- if (mnemonic instanceof DFSB) {
|
|
|
- break;
|
|
|
- }
|
|
|
- position++;
|
|
|
- }
|
|
|
- if (position < 256) {
|
|
|
- int count = 256 - position;
|
|
|
- for (int i = 0; i < count; i++) {
|
|
|
- mnemonics.add(position, new NOP(""));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void checkingProgramSize() throws HardwareException {
|
|
|
- int prgSize = 0;
|
|
|
- for (Mnemonic mnemonic : mnemonics) {
|
|
|
- if (mnemonic instanceof DFSB) {
|
|
|
- break;
|
|
|
- }
|
|
|
- prgSize++;
|
|
|
- }
|
|
|
- int maxSize = 128;
|
|
|
- switch (destination) {
|
|
|
- case ARDUINOSPS:
|
|
|
- case TINYSPS:
|
|
|
- maxSize = 256;
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- if (prgSize > maxSize) {
|
|
|
- throw new HardwareException(
|
|
|
- String.format("Program exceeding size (%d) for hardeware %s (%d).", prgSize, destination, maxSize));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void calculatingJumps() throws SyntaxError {
|
|
|
- int address = 0;
|
|
|
- Mnemonic predecessor = null;
|
|
|
- for (Iterator<Mnemonic> iterator = mnemonics.iterator(); iterator.hasNext();) {
|
|
|
- Mnemonic mnemonic = iterator.next();
|
|
|
- if ((mnemonic instanceof JMP) || (mnemonic instanceof LOOPC) || (mnemonic instanceof LOOPD)
|
|
|
- || (mnemonic instanceof CALL)) {
|
|
|
- if (mnemonic.isLabel()) {
|
|
|
- processJMP(mnemonic, predecessor);
|
|
|
- }
|
|
|
- }
|
|
|
- if (mnemonic instanceof RJMP) {
|
|
|
- if (mnemonic.isLabel()) {
|
|
|
- processRJMP(address, mnemonic);
|
|
|
- }
|
|
|
- }
|
|
|
- address++;
|
|
|
- predecessor = mnemonic;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @throws SyntaxError
|
|
|
- */
|
|
|
- private void checkingHardware() throws SyntaxError {
|
|
|
- for (Iterator<Mnemonic> iterator = mnemonics.iterator(); iterator.hasNext();) {
|
|
|
- Mnemonic mnemonic = iterator.next();
|
|
|
- if (!mnemonic.allowedHardware().contains(destination)) {
|
|
|
- throw new SyntaxError(mnemonic.getLineNumber(),
|
|
|
- String.format("the mnemonic \"%s\" with the argument \"%s\" is not availble on the choosen hardware \"%s\"",
|
|
|
- mnemonic.getName(), mnemonic.getArgument() == null ? "" : mnemonic.getArgument(), destination.name()));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void processJMP(Mnemonic mnemonic, Mnemonic predecessor) throws SyntaxError {
|
|
|
- String label = mnemonic.getArgument();
|
|
|
- if (!labels.containsKey(label)) {
|
|
|
- throw new SyntaxError(mnemonic.getLineNumber(),
|
|
|
- String.format("used label %s on mnemonic \"%s\" is not defined.", label, mnemonic.getName()));
|
|
|
- }
|
|
|
- int lineNumber = (Integer) labels.get(label);
|
|
|
- int page = lineNumber / 16;
|
|
|
- lineNumber = lineNumber % 16;
|
|
|
- mnemonic.setArgument(Integer.toString(lineNumber));
|
|
|
- mnemonic.checkArgument();
|
|
|
- if ((predecessor != null) && (predecessor instanceof PAGE)) {
|
|
|
- PAGE pageMne = (PAGE) predecessor;
|
|
|
- if (pageMne.isCalculate()) {
|
|
|
- pageMne.setArgument(Integer.toString(page));
|
|
|
- pageMne.checkArgument();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void processRJMP(int address, Mnemonic mnemonic) throws SyntaxError {
|
|
|
- String label = mnemonic.getArgument();
|
|
|
- if (!labels.containsKey(label)) {
|
|
|
- throw new SyntaxError(mnemonic.getLineNumber(),
|
|
|
- String.format("used label %s on mnemonic \"%s\" is not defined.", label, mnemonic.getName()));
|
|
|
- }
|
|
|
- int lineNumber = (Integer) labels.get(label);
|
|
|
- lineNumber = address - lineNumber;
|
|
|
- if (lineNumber < 0) {
|
|
|
- throw new SyntaxError(mnemonic.getLineNumber(),
|
|
|
- String.format("label %s defined after mnemonic \"%s\". JMP can only step back!", label, mnemonic.getName()));
|
|
|
- }
|
|
|
- mnemonic.setArgument(Integer.toString(lineNumber));
|
|
|
- mnemonic.checkArgument();
|
|
|
- }
|
|
|
-
|
|
|
- private List<String> parseLine(int srcLineNumber, String srcLine) throws SyntaxError, IOException {
|
|
|
- String line = srcLine.trim();
|
|
|
- if (line.startsWith(".")) {
|
|
|
- // process pre compiler part
|
|
|
- String label = getLabel(line);
|
|
|
- return precompiler(srcLineNumber, label);
|
|
|
- } else {
|
|
|
- if (inMacro) {
|
|
|
- actualMacro.addLine(line);
|
|
|
- } else {
|
|
|
- if (line.startsWith(":")) {
|
|
|
- String label = getLabel(line);
|
|
|
- if (labels.containsKey(label)) {
|
|
|
- throw new SyntaxError(srcLineNumber,
|
|
|
- String.format("Label \"%s\" already definied in line %d.", label, labels.get(label)));
|
|
|
- }
|
|
|
- labels.put(label, lineNumber);
|
|
|
- } else {
|
|
|
- Mnemonic mnemonic = getMnemonic(line, srcLineNumber);
|
|
|
- if (mnemonic != null) {
|
|
|
- lineNumber++;
|
|
|
- mnemonics.add(mnemonic);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- private List<String> precompiler(int srcLineNumber, String value) throws IOException, SyntaxError {
|
|
|
- String label = value.trim().toLowerCase();
|
|
|
- String name = label;
|
|
|
- if (label.indexOf(" ") > 0) {
|
|
|
- name = label.substring(0, label.indexOf(" "));
|
|
|
- }
|
|
|
- if (INCLUDE_FILE.equals(name)) {
|
|
|
- includeFile(srcLineNumber, label);
|
|
|
- } else if (START_MACRO_DEFINITION.equals(name)) {
|
|
|
- startMacroDefinition(srcLineNumber, label);
|
|
|
- inMacro = true;
|
|
|
- } else if (END_MACRO_DEFINITION.equalsIgnoreCase(label)) {
|
|
|
- // end of macro definition
|
|
|
- inMacro = false;
|
|
|
- macros.put(actualMacro.getName(), actualMacro);
|
|
|
- } else {
|
|
|
- // seems to be a macro usage
|
|
|
- name = name.substring(1);
|
|
|
- String[] arguments = label.split(" ");
|
|
|
- if (arguments.length < 1) {
|
|
|
- throw new IllegalArgument(srcLineNumber, "Need at least one argument for the macro name.");
|
|
|
- }
|
|
|
- String[] args = null;
|
|
|
- if (arguments.length > 1) {
|
|
|
- args = Arrays.copyOfRange(arguments, 1, arguments.length);
|
|
|
- }
|
|
|
- Macro macro = macros.get(name);
|
|
|
- if (macro == null) {
|
|
|
- throw new SyntaxError(srcLineNumber, String.format("macro with name %s not define.", name));
|
|
|
- }
|
|
|
- List<String> macroMnemonics = macro.processMacro(args, srcLineNumber);
|
|
|
- return macroMnemonics;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param srcLineNumber
|
|
|
- * @param label
|
|
|
- * @throws IllegalArgument
|
|
|
- */
|
|
|
- private void startMacroDefinition(int srcLineNumber, String label) throws IllegalArgument {
|
|
|
- // macro definition
|
|
|
- String[] arguments = label.split(" ");
|
|
|
- if (arguments.length < 2) {
|
|
|
- throw new IllegalArgument(srcLineNumber, "Need at least one argument for the macro name.");
|
|
|
- }
|
|
|
- String macroName = arguments[1];
|
|
|
- String[] args = null;
|
|
|
- if (arguments.length > 2) {
|
|
|
- args = Arrays.copyOfRange(arguments, 2, arguments.length);
|
|
|
- }
|
|
|
- actualMacro = new Macro(macroName, args);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @param srcLineNumber
|
|
|
- * @param label
|
|
|
- * @throws IllegalArgument
|
|
|
- * @throws IOException
|
|
|
- * @throws SyntaxError
|
|
|
- */
|
|
|
- private void includeFile(int srcLineNumber, String label) throws IllegalArgument, IOException, SyntaxError {
|
|
|
- String[] arguments = label.split(" ");
|
|
|
- if (arguments.length < 2) {
|
|
|
- throw new IllegalArgument(srcLineNumber, "Need at least one argument for the filename to include.");
|
|
|
- }
|
|
|
- File includeFile = new File(includes, String.format("%s.tps", arguments[1]));
|
|
|
- if (!includeFile.exists()) {
|
|
|
- throw new IllegalArgument(srcLineNumber, String.format("include file not found: %s", includeFile.getName()));
|
|
|
- }
|
|
|
- System.out.println("=====");
|
|
|
- System.out.printf("include file: %s \r\n", includeFile.getName());
|
|
|
- SPSAssembler spsAssembler = new SPSAssembler();
|
|
|
- spsAssembler.doWork(includeFile);
|
|
|
- outputMnemonics(spsAssembler.getMnemonics());
|
|
|
- outputLabels(spsAssembler);
|
|
|
- outputMacros(spsAssembler);
|
|
|
- System.out.println("=====");
|
|
|
- }
|
|
|
-
|
|
|
- private Mnemonic getMnemonic(String line, int srcLineNumber) throws SyntaxError {
|
|
|
- String newLine = stripComments(line);
|
|
|
- if (StringUtils.isNotEmpty(newLine)) {
|
|
|
- Mnemonic mnemonic = MnemonicFactory.getMnemonic(newLine, srcLineNumber);
|
|
|
- return mnemonic;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- private String stripComments(String line) {
|
|
|
- if (line.indexOf("*/") >= 0) {
|
|
|
- inBlockComment = false;
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (inBlockComment) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (line.indexOf(";") >= 0) {
|
|
|
- line = line.substring(0, line.indexOf(";")).trim();
|
|
|
- return line;
|
|
|
- }
|
|
|
- if (line.startsWith("/*")) {
|
|
|
- inBlockComment = true;
|
|
|
- return null;
|
|
|
- }
|
|
|
- return line.trim();
|
|
|
- }
|
|
|
-
|
|
|
- private String getLabel(String line) {
|
|
|
- line = stripComments(line);
|
|
|
- return line;
|
|
|
- }
|
|
|
-
|
|
|
- private List<Mnemonic> getMnemonics() {
|
|
|
- return mnemonics;
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Macro> getMacros() {
|
|
|
- return macros;
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Integer> getLabels() {
|
|
|
- return labels;
|
|
|
- }
|
|
|
+ private static final String INCLUDE_FILE = ".include";
|
|
|
+ private static final String END_MACRO_DEFINITION = ".endmacro";
|
|
|
+ private static final String START_MACRO_DEFINITION = ".macro";
|
|
|
+ private static final String DEFAULT_PACKAGE_FILTER = "de.mcs.tools.sps"; //$NON-NLS-1$
|
|
|
+ private static File source;
|
|
|
+ private static HARDWARE destination;
|
|
|
+ private static File destinationFile;
|
|
|
+ private static String outputFormat;
|
|
|
+ private static File includes;
|
|
|
+ private static Outputter outputter;
|
|
|
+ private static String destinationStr;
|
|
|
+
|
|
|
+ private int lineNumber;
|
|
|
+ // private int srcLineNumber;
|
|
|
+ private Map<String, Integer> labels;
|
|
|
+ private boolean inBlockComment;
|
|
|
+ private List<Mnemonic> mnemonics;
|
|
|
+ private boolean inMacro;
|
|
|
+ private Macro actualMacro;
|
|
|
+ private Map<String, Macro> macros;
|
|
|
+
|
|
|
+ @SwitchOption(shortKey = 'h', longKey = "help", name = "help", help = "show this help page", required = false, defaultValue = false)
|
|
|
+ public static void doHelp(boolean value) {
|
|
|
+ if (value) {
|
|
|
+ CommandlineProcessor.showHelp();
|
|
|
+ System.exit(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @StringOption(shortKey = 'f', longKey = "format", name = "format", defaultValue = "HEX", help = "the output format. HEX: IntelHEX, TPSTXT: TPS programming text", required = false)
|
|
|
+ public static void setOutputFormat(String value) {
|
|
|
+ outputFormat = value.toUpperCase();
|
|
|
+ }
|
|
|
+
|
|
|
+ @StringOption(shortKey = 'd', longKey = "hardware", name = "hardware system", defaultValue = "HOLTEK", help = "the hardware system to compile to. Passible options are: HOLTEK, ATMEGA8, ARDUINOSPS, TINYSPS", required = false)
|
|
|
+ public static void setDestinationSystem(String value) {
|
|
|
+ destinationStr = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ @FileOption(shortKey = 'i', longKey = "includes", name = "includes", defaultValue = "", help = "where to find the includes files.", required = false)
|
|
|
+ public static void setDestinationSystem(File file) {
|
|
|
+ if ((file != null) && !file.getName().equals("")) {
|
|
|
+ includes = file;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @FileOption(index = 1, name = "source file", help = "source file to compile", required = true, mustExists = true)
|
|
|
+ public static void setSourceFile(File file) {
|
|
|
+ if ((file != null) && !file.getName().equals("")) {
|
|
|
+ source = file;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @FileOption(index = 2, name = "destination file", help = "destination file to compile to", required = false)
|
|
|
+ public static void setDestinationFile(File file) {
|
|
|
+ if ((file != null) && !file.getName().equals("")) {
|
|
|
+ destinationFile = file;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param args
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static void main(String[] args) {
|
|
|
+ try {
|
|
|
+ destination = HARDWARE.HOLTEK;
|
|
|
+
|
|
|
+ CommandlineProcessor.processCommandline(SPSAssembler.class, args);
|
|
|
+
|
|
|
+ try {
|
|
|
+ destination = HARDWARE.valueOf((destinationStr.toUpperCase()));
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ throw new HardwareException(String.format("Hardware %s unknow for this assembler", destinationStr));
|
|
|
+ }
|
|
|
+
|
|
|
+ registerAllOutputter();
|
|
|
+
|
|
|
+ if ((source == null) || (!source.exists())) {
|
|
|
+ CommandlineProcessor.showHelp(String.format("source file null or not found. %s", (source == null) ? "" : source.getAbsolutePath()));
|
|
|
+ System.exit(-1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (destinationFile == null) {
|
|
|
+ String name = source.getName();
|
|
|
+ name = name.substring(0, source.getName().lastIndexOf("."));
|
|
|
+ String ext = outputter.getDefaultExtension();
|
|
|
+ destinationFile = new File(source.getParentFile(), name + ext);
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.printf("source file: %s \r\n", source.getName());
|
|
|
+ System.out.printf("destination file: %s \r\n", destinationFile.getName());
|
|
|
+ System.out.printf("output format: %s \r\n", outputFormat);
|
|
|
+ System.out.printf("hardware: %s \r\n", destination.name());
|
|
|
+ if (includes != null) {
|
|
|
+ System.out.printf("includes foldes: %s \r\n", includes.getCanonicalPath());
|
|
|
+ }
|
|
|
+ System.out.println();
|
|
|
+
|
|
|
+ try {
|
|
|
+ SPSAssembler spsAssembler = new SPSAssembler();
|
|
|
+ spsAssembler.doWork(source);
|
|
|
+
|
|
|
+ List<Mnemonic> mnemonics = spsAssembler.getMnemonics();
|
|
|
+
|
|
|
+ outputMnemonics(mnemonics);
|
|
|
+
|
|
|
+ outputLabels(spsAssembler);
|
|
|
+
|
|
|
+ outputMacros(spsAssembler);
|
|
|
+
|
|
|
+ outputFile(mnemonics);
|
|
|
+
|
|
|
+ System.out.println("assembling succesfully");
|
|
|
+ } catch (SyntaxError e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ System.err.println(e.getMessage());
|
|
|
+ System.exit(-1);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @throws InstantiationException
|
|
|
+ * @throws IllegalAccessException
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private static void registerAllOutputter() throws InstantiationException, IllegalAccessException, Exception {
|
|
|
+ Set<Class<?>> outputClasses = searchOutputter(SPSOutputter.class);
|
|
|
+ for (Class<?> outClass : outputClasses) {
|
|
|
+ SPSOutputter annotation = outClass.getAnnotation(SPSOutputter.class);
|
|
|
+ if (annotation.name().equalsIgnoreCase(outputFormat)) {
|
|
|
+ outputter = (Outputter) outClass.newInstance();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (outputter == null) {
|
|
|
+ throw new Exception(String.format("can't find outputter for format: %s", outputFormat));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Set<Class<?>> searchOutputter(Class<? extends Annotation> annotationClass) {
|
|
|
+ ConfigurationBuilder builder = new ConfigurationBuilder();
|
|
|
+ builder.addUrls(ClasspathHelper.forPackage(DEFAULT_PACKAGE_FILTER));
|
|
|
+ Reflections reflections = new Reflections(builder);
|
|
|
+ Set<Class<?>> classes = new HashSet<Class<?>>();
|
|
|
+ classes.addAll(reflections.getTypesAnnotatedWith(annotationClass));
|
|
|
+ return classes;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param mnemonics
|
|
|
+ * @throws IOException
|
|
|
+ * @throws FileNotFoundException
|
|
|
+ */
|
|
|
+ private static void outputFile(List<Mnemonic> mnemonics) throws IOException, FileNotFoundException {
|
|
|
+ try (FileOutputStream output = new FileOutputStream(destinationFile)) {
|
|
|
+ outputter.output(mnemonics, output);
|
|
|
+ } finally {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param spsAssembler
|
|
|
+ */
|
|
|
+ private static void outputMacros(SPSAssembler spsAssembler) {
|
|
|
+ Map<String, Macro> macros = spsAssembler.getMacros();
|
|
|
+ if ((macros != null) && (macros.size() > 0)) {
|
|
|
+ System.out.println();
|
|
|
+ System.out.println("macros");
|
|
|
+ for (Macro macro : macros.values()) {
|
|
|
+ System.out.printf("%s: %s\r\n", macro.getName(), macro.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param spsAssembler
|
|
|
+ */
|
|
|
+ private static void outputLabels(SPSAssembler spsAssembler) {
|
|
|
+ Map<String, Integer> labels = spsAssembler.getLabels();
|
|
|
+ if ((labels != null) && (labels.size() > 0)) {
|
|
|
+ System.out.println();
|
|
|
+ System.out.println("labels");
|
|
|
+ for (Entry<String, Integer> entry : labels.entrySet()) {
|
|
|
+ System.out.printf("%s: 0x%03x\r\n", entry.getKey(), entry.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param mnemonics
|
|
|
+ */
|
|
|
+ private static void outputMnemonics(List<Mnemonic> mnemonics) {
|
|
|
+ System.out.println("Mnemonics");
|
|
|
+ int pos = 0;
|
|
|
+ for (Iterator<Mnemonic> iterator = mnemonics.iterator(); iterator.hasNext();) {
|
|
|
+ Mnemonic mnemonic = iterator.next();
|
|
|
+ System.out.printf("0x%03x: %s\r\n", pos, mnemonic.toString());
|
|
|
+ pos++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ */
|
|
|
+ public SPSAssembler() {
|
|
|
+ lineNumber = 0;
|
|
|
+ // srcLineNumber = 0;
|
|
|
+ labels = new HashMap<>();
|
|
|
+ inBlockComment = false;
|
|
|
+ mnemonics = new ArrayList<>();
|
|
|
+ inMacro = false;
|
|
|
+ actualMacro = null;
|
|
|
+ macros = new HashMap<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void doWork(File source) throws IOException, SyntaxError {
|
|
|
+ System.out.printf("start parsing file: %s\r\n", source.getName());
|
|
|
+
|
|
|
+ List<String> sourceFile = Files.readAllLines(source.toPath(), Charset.forName("UTF-8"));
|
|
|
+ for (int i = 0; i < sourceFile.size(); i++) {
|
|
|
+ String line = sourceFile.get(i);
|
|
|
+
|
|
|
+ List<String> linesToAdd;
|
|
|
+ do {
|
|
|
+ linesToAdd = parseLine(i, line);
|
|
|
+ if (linesToAdd != null) {
|
|
|
+ sourceFile.remove(i);
|
|
|
+ sourceFile.addAll(i, linesToAdd);
|
|
|
+ line = sourceFile.get(i);
|
|
|
+ linesToAdd = parseLine(i, line);
|
|
|
+ }
|
|
|
+ } while (linesToAdd != null);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Checking destination
|
|
|
+ checkingHardware();
|
|
|
+
|
|
|
+ calculatingJumps();
|
|
|
+
|
|
|
+ paddingSubroutines();
|
|
|
+
|
|
|
+ // checking size of program
|
|
|
+ checkingProgramSize();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void paddingSubroutines() throws SyntaxError {
|
|
|
+ // checking location of Subroutines
|
|
|
+ if (destination.equals(HARDWARE.ARDUINOSPS) || destination.equals(HARDWARE.TINYSPS)) {
|
|
|
+ int position = 0;
|
|
|
+ boolean foundSub = false;
|
|
|
+ for (int i = 0; i < mnemonics.size(); i++) {
|
|
|
+ Mnemonic mnemonic = mnemonics.get(i);
|
|
|
+ if (mnemonic instanceof DFSB) {
|
|
|
+ foundSub = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ position++;
|
|
|
+ }
|
|
|
+ if (foundSub && (position < 256)) {
|
|
|
+ int count = 256 - position;
|
|
|
+ for (int i = 0; i < count; i++) {
|
|
|
+ mnemonics.add(position, new NOP(""));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void checkingProgramSize() throws HardwareException {
|
|
|
+ int prgSize = 0;
|
|
|
+ for (Mnemonic mnemonic : mnemonics) {
|
|
|
+ if (mnemonic instanceof DFSB) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ prgSize++;
|
|
|
+ }
|
|
|
+ int maxSize = 128;
|
|
|
+ switch (destination) {
|
|
|
+ case ARDUINOSPS:
|
|
|
+ case TINYSPS:
|
|
|
+ maxSize = 256;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (prgSize > maxSize) {
|
|
|
+ throw new HardwareException(String.format("Program exceeding size (%d) for hardeware %s (%d).", prgSize, destination, maxSize));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void calculatingJumps() throws SyntaxError {
|
|
|
+ int address = 0;
|
|
|
+ Mnemonic predecessor = null;
|
|
|
+ for (Iterator<Mnemonic> iterator = mnemonics.iterator(); iterator.hasNext();) {
|
|
|
+ Mnemonic mnemonic = iterator.next();
|
|
|
+ if ((mnemonic instanceof JMP) || (mnemonic instanceof LOOPC) || (mnemonic instanceof LOOPD) || (mnemonic instanceof CALL)) {
|
|
|
+ if (mnemonic.isLabel()) {
|
|
|
+ processJMP(mnemonic, predecessor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (mnemonic instanceof RJMP) {
|
|
|
+ if (mnemonic.isLabel()) {
|
|
|
+ processRJMP(address, mnemonic);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ address++;
|
|
|
+ predecessor = mnemonic;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @throws SyntaxError
|
|
|
+ */
|
|
|
+ private void checkingHardware() throws SyntaxError {
|
|
|
+ for (Iterator<Mnemonic> iterator = mnemonics.iterator(); iterator.hasNext();) {
|
|
|
+ Mnemonic mnemonic = iterator.next();
|
|
|
+ if (!mnemonic.allowedHardware().contains(destination)) {
|
|
|
+ throw new SyntaxError(mnemonic.getLineNumber(),
|
|
|
+ String.format("the mnemonic \"%s\" with the argument \"%s\" is not availble on the choosen hardware \"%s\"", mnemonic.getName(),
|
|
|
+ mnemonic.getArgument() == null ? "" : mnemonic.getArgument(), destination.name()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void processJMP(Mnemonic mnemonic, Mnemonic predecessor) throws SyntaxError {
|
|
|
+ String label = mnemonic.getArgument();
|
|
|
+ if (!labels.containsKey(label)) {
|
|
|
+ throw new SyntaxError(mnemonic.getLineNumber(), String.format("used label %s on mnemonic \"%s\" is not defined.", label, mnemonic.getName()));
|
|
|
+ }
|
|
|
+ int lineNumber = (Integer) labels.get(label);
|
|
|
+ int page = lineNumber / 16;
|
|
|
+ lineNumber = lineNumber % 16;
|
|
|
+ mnemonic.setArgument(Integer.toString(lineNumber));
|
|
|
+ mnemonic.checkArgument();
|
|
|
+ if ((predecessor != null) && (predecessor instanceof PAGE)) {
|
|
|
+ PAGE pageMne = (PAGE) predecessor;
|
|
|
+ if (pageMne.isCalculate()) {
|
|
|
+ pageMne.setArgument(Integer.toString(page));
|
|
|
+ pageMne.checkArgument();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void processRJMP(int address, Mnemonic mnemonic) throws SyntaxError {
|
|
|
+ String label = mnemonic.getArgument();
|
|
|
+ if (!labels.containsKey(label)) {
|
|
|
+ throw new SyntaxError(mnemonic.getLineNumber(), String.format("used label %s on mnemonic \"%s\" is not defined.", label, mnemonic.getName()));
|
|
|
+ }
|
|
|
+ int lineNumber = (Integer) labels.get(label);
|
|
|
+ lineNumber = address - lineNumber;
|
|
|
+ if (lineNumber < 0) {
|
|
|
+ throw new SyntaxError(mnemonic.getLineNumber(),
|
|
|
+ String.format("label %s defined after mnemonic \"%s\". JMP can only step back!", label, mnemonic.getName()));
|
|
|
+ }
|
|
|
+ mnemonic.setArgument(Integer.toString(lineNumber));
|
|
|
+ mnemonic.checkArgument();
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> parseLine(int srcLineNumber, String srcLine) throws SyntaxError, IOException {
|
|
|
+ String line = srcLine.trim();
|
|
|
+ if (line.startsWith(".")) {
|
|
|
+ // process pre compiler part
|
|
|
+ String label = getLabel(line);
|
|
|
+ return precompiler(srcLineNumber, label);
|
|
|
+ } else {
|
|
|
+ if (inMacro) {
|
|
|
+ actualMacro.addLine(line);
|
|
|
+ } else {
|
|
|
+ if (line.startsWith(":")) {
|
|
|
+ String label = getLabel(line);
|
|
|
+ if (labels.containsKey(label)) {
|
|
|
+ throw new SyntaxError(srcLineNumber, String.format("Label \"%s\" already definied in line %d.", label, labels.get(label)));
|
|
|
+ }
|
|
|
+ labels.put(label, lineNumber);
|
|
|
+ } else {
|
|
|
+ Mnemonic mnemonic = getMnemonic(line, srcLineNumber);
|
|
|
+ if (mnemonic != null) {
|
|
|
+ lineNumber++;
|
|
|
+ mnemonics.add(mnemonic);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> precompiler(int srcLineNumber, String value) throws IOException, SyntaxError {
|
|
|
+ String label = value.trim().toLowerCase();
|
|
|
+ String name = label;
|
|
|
+ if (label.indexOf(" ") > 0) {
|
|
|
+ name = label.substring(0, label.indexOf(" "));
|
|
|
+ }
|
|
|
+ if (INCLUDE_FILE.equals(name)) {
|
|
|
+ includeFile(srcLineNumber, label);
|
|
|
+ } else if (START_MACRO_DEFINITION.equals(name)) {
|
|
|
+ startMacroDefinition(srcLineNumber, label);
|
|
|
+ inMacro = true;
|
|
|
+ } else if (END_MACRO_DEFINITION.equalsIgnoreCase(label)) {
|
|
|
+ // end of macro definition
|
|
|
+ inMacro = false;
|
|
|
+ macros.put(actualMacro.getName(), actualMacro);
|
|
|
+ } else {
|
|
|
+ // seems to be a macro usage
|
|
|
+ name = name.substring(1);
|
|
|
+ String[] arguments = label.split(" ");
|
|
|
+ if (arguments.length < 1) {
|
|
|
+ throw new IllegalArgument(srcLineNumber, "Need at least one argument for the macro name.");
|
|
|
+ }
|
|
|
+ String[] args = null;
|
|
|
+ if (arguments.length > 1) {
|
|
|
+ args = Arrays.copyOfRange(arguments, 1, arguments.length);
|
|
|
+ }
|
|
|
+ Macro macro = macros.get(name);
|
|
|
+ if (macro == null) {
|
|
|
+ throw new SyntaxError(srcLineNumber, String.format("macro with name %s not define.", name));
|
|
|
+ }
|
|
|
+ List<String> macroMnemonics = macro.processMacro(args, srcLineNumber);
|
|
|
+ return macroMnemonics;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param srcLineNumber
|
|
|
+ * @param label
|
|
|
+ * @throws IllegalArgument
|
|
|
+ */
|
|
|
+ private void startMacroDefinition(int srcLineNumber, String label) throws IllegalArgument {
|
|
|
+ // macro definition
|
|
|
+ String[] arguments = label.split(" ");
|
|
|
+ if (arguments.length < 2) {
|
|
|
+ throw new IllegalArgument(srcLineNumber, "Need at least one argument for the macro name.");
|
|
|
+ }
|
|
|
+ String macroName = arguments[1];
|
|
|
+ String[] args = null;
|
|
|
+ if (arguments.length > 2) {
|
|
|
+ args = Arrays.copyOfRange(arguments, 2, arguments.length);
|
|
|
+ }
|
|
|
+ actualMacro = new Macro(macroName, args);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param srcLineNumber
|
|
|
+ * @param label
|
|
|
+ * @throws IllegalArgument
|
|
|
+ * @throws IOException
|
|
|
+ * @throws SyntaxError
|
|
|
+ */
|
|
|
+ private void includeFile(int srcLineNumber, String label) throws IllegalArgument, IOException, SyntaxError {
|
|
|
+ String[] arguments = label.split(" ");
|
|
|
+ if (arguments.length < 2) {
|
|
|
+ throw new IllegalArgument(srcLineNumber, "Need at least one argument for the filename to include.");
|
|
|
+ }
|
|
|
+ File includeFile = new File(includes, String.format("%s.tps", arguments[1]));
|
|
|
+ if (!includeFile.exists()) {
|
|
|
+ throw new IllegalArgument(srcLineNumber, String.format("include file not found: %s", includeFile.getName()));
|
|
|
+ }
|
|
|
+ System.out.println("=====");
|
|
|
+ System.out.printf("include file: %s \r\n", includeFile.getName());
|
|
|
+ SPSAssembler spsAssembler = new SPSAssembler();
|
|
|
+ spsAssembler.doWork(includeFile);
|
|
|
+ outputMnemonics(spsAssembler.getMnemonics());
|
|
|
+ outputLabels(spsAssembler);
|
|
|
+ outputMacros(spsAssembler);
|
|
|
+ System.out.println("=====");
|
|
|
+ }
|
|
|
+
|
|
|
+ private Mnemonic getMnemonic(String line, int srcLineNumber) throws SyntaxError {
|
|
|
+ String newLine = stripComments(line);
|
|
|
+ if (StringUtils.isNotEmpty(newLine)) {
|
|
|
+ Mnemonic mnemonic = MnemonicFactory.getMnemonic(newLine, srcLineNumber);
|
|
|
+ return mnemonic;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String stripComments(String line) {
|
|
|
+ if (line.indexOf("*/") >= 0) {
|
|
|
+ inBlockComment = false;
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (inBlockComment) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (line.indexOf(";") >= 0) {
|
|
|
+ line = line.substring(0, line.indexOf(";")).trim();
|
|
|
+ return line;
|
|
|
+ }
|
|
|
+ if (line.startsWith("/*")) {
|
|
|
+ inBlockComment = true;
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return line.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getLabel(String line) {
|
|
|
+ line = stripComments(line);
|
|
|
+ return line;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Mnemonic> getMnemonics() {
|
|
|
+ return mnemonics;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Macro> getMacros() {
|
|
|
+ return macros;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Integer> getLabels() {
|
|
|
+ return labels;
|
|
|
+ }
|
|
|
}
|