gitweb on Svarog
projekti pod git sistemom za održavanje verzija -- projects under the git version control systemdiff --git a/src/asm2wsl.java b/src/asm2wsl.java
--- /dev/null
+++ b/src/asm2wsl.java
@@ -0,0 +1,746 @@
+\r
+/* \r
+Copyright 2012,2018 Doni Pracner\r
+\r
+This program is free software: you can redistribute it\r
+and/or modify it under the terms of the GNU General Public\r
+License as published by the Free Software Foundation, either\r
+version 3 of the License, or (at your option) any later\r
+version.\r
+\r
+This program is distributed in the hope that it will be\r
+useful, but WITHOUT ANY WARRANTY; without even the implied\r
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
+PURPOSE. See the GNU General Public License for more\r
+details.\r
+\r
+You should have received a copy of the GNU General Public\r
+License along with this program. If not, see\r
+<http://www.gnu.org/licenses/>.\r
+\r
+*/\r
+import java.io.*;\r
+import java.util.*;\r
+\r
+/**\r
+ * This program converts files from assembly x86 to WSL language which is a part\r
+ * of the FermaT Transformation system.<br />\r
+ * Currently it works only on a very limited subset of x86, and has a number of\r
+ * predefined macro names it uses for translation. It works with 16 bit\r
+ * registers (ax,bx, etc) and presumes that the rest of the variables are 8bit\r
+ * if not applied to a 16bit reg. Check the documentation for more details.\r
+ *\r
+ * @author Doni Pracner, http://perun.dmi.rs/pracner http://quemaster.com\r
+ */\r
+public class asm2wsl {\r
+\r
+ private static final String PROCEDURE_INTERNAL_SYS = "procedure_internal_sys";\r
+\r
+ /** translation processing switch */\r
+ public boolean originalInComments = false, translateComments = true,\r
+ addMemoryDump = false, translateToPopPush = true;\r
+\r
+ int mode = MODE_0, nUnknownC = 0, nUnknownD = 0, nKnownC = 0;\r
+\r
+ boolean labelfound = false;\r
+\r
+ public static final String versionN = "0.81";\r
+\r
+ // regular comments from the original file\r
+ // OC when original code is inserted in the file, next to the translations\r
+ // SPEC special messages from the translator\r
+ // ERR error messages from the translator\r
+ public static final char C_REG = ' ', C_OC = '#', C_SPEC = '&', C_ERR = '!';\r
+\r
+ public static final int MODE_0 = 0, MODE_CODE = 1, MODE_DATA = 2,\r
+ MODE_STACK = 3, N_MODES = 4;\r
+\r
+ public static final String CODE_SEG_START = "SKIP;\n ACTIONS A_S_start:\n A_S_start ==",\r
+ CODE_SEG_END = "CALL Z;\nSKIP END\nENDACTIONS;\n",\r
+ DATA_SEG_START = "VAR< ", DATA_SEG_END = " \tskipvar := 0 \n>:\n",\r
+ fixl = "\n%x := (%x DIV 256) * 256 + t_e_m_p;",\r
+ fixh = "\n%x := (%x MOD 256) + t_e_m_p * 256;";\r
+\r
+ public String getStandardStart() {\r
+ String ret = "C:\" This file automatically converted from assembler\";\n"\r
+ + "C:\" with asm2wsl v " + versionN + "\";\n";\r
+ ret += "VAR < ax := 0, bx := 0, cx := 0, dx := 0,\n"\r
+ + " si := 0, di := 0, bp := 0, sp := 0, \n"\r
+ + " ss := 0, ds := 0, cs := 0, es := 0,\n"\r
+ + " flag_o := 0, flag_d := 0, flag_i := 0, flag_t := 0,\n"\r
+ + " flag_z := 0, flag_s := 0, flag_p := 0, flag_a := 0,\n"\r
+ + " flag_c := 0, overflow := 256, stack := < >, t_e_m_p := 0 > :\n";\r
+ if (addMemoryDump)\r
+ ret += "BEGIN\n";\r
+ return ret;\r
+ }\r
+\r
+ public String getStandardEnd() {\r
+ String ret = "ENDVAR;\n";\r
+ if (addMemoryDump) {\r
+ ret += "C:\" end original program. testing features following\";\n"\r
+ + "WHERE\n" + "PROC memdump(VAR) ==\n"\r
+ + " PRINT(\"'memory' dump: \");\n"\r
+ + " PRINT(\"ax \",ax,\" bx \",bx,\" cx \",cx,\" dx \",dx);\n"\r
+ + " PRINT(\"flags:\");\n" + " PRINT(\"ODITSZAPC\");\n"\r
+ + " PRINT(flag_o,flag_d,flag_i,flag_t,flag_s,flag_z,flag_a,flag_p,flag_c)\n"\r
+ + "END\n" + "END\n";\r
+ }\r
+ ret += "\nENDVAR";\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * When the param works with array addressing, this should reformat it so\r
+ * that it works as intended. An important thing to remember is that there\r
+ * is a[0] element in WSL, all arrays start with a[1].\r
+ */\r
+ public String arrayFix(String str) {\r
+ String param = str.substring(str.indexOf('[') + 1, str.indexOf(']'));\r
+ return str.replace(param + "]", formatParam(param) + "+1]");\r
+ }\r
+\r
+ /**\r
+ * Transforms an asembler source parameter as need so that it can be used in\r
+ * WSL. Among other things it converts Hex numbers to decimal, fixes array\r
+ * access indexes and the high/low parts of registers.\r
+ */\r
+ public String formatParam(String str) {\r
+ str = str.toLowerCase();\r
+ if (str.contains("["))\r
+ str = arrayFix(str);\r
+ try {\r
+ if (str.matches("[0-9][0-9a-f]*h"))\r
+ return "" + Integer.parseInt(str.substring(0, str.length() - 1),\r
+ 16);\r
+ } catch (Exception e) {\r
+ System.err.println("error in hex param procesing");\r
+ e.printStackTrace();\r
+ }\r
+ if (str.compareTo("al") == 0)\r
+ return "(ax MOD 256)";\r
+ else if (str.compareTo("ah") == 0)\r
+ return "(ax DIV 256)";\r
+ else if (str.compareTo("bl") == 0)\r
+ return "(bx MOD 256)";\r
+ else if (str.compareTo("bh") == 0)\r
+ return "(bx DIV 256)";\r
+ else if (str.compareTo("cl") == 0)\r
+ return "(cx MOD 256)";\r
+ else if (str.compareTo("ch") == 0)\r
+ return "(cx DIV 256)";\r
+ else if (str.compareTo("dl") == 0)\r
+ return "(dx MOD 256)";\r
+ else if (str.compareTo("dh") == 0)\r
+ return "(dx DIV 256)";\r
+ else\r
+ // for undefined variables\r
+ if (str.compareTo("(?)") == 0)\r
+ return "\" \"";\r
+ else\r
+\r
+ return str;\r
+ }\r
+\r
+ /**\r
+ * Transforms an asembler destination parameter as need so that it can be\r
+ * used in WSL. Among other things it fixes array access indexes and the\r
+ * high/low parts of registers.\r
+ */\r
+ public String formatDst(String str) {\r
+ if (str.contains("["))\r
+ str = arrayFix(str);\r
+ str = str.toLowerCase();\r
+ if (str.length() == 2 && str.charAt(0) >= 'a' && str.charAt(0) <= 'd'\r
+ && (str.charAt(1) == 'l' || str.charAt(1) == 'h'))\r
+ return "t_e_m_p";\r
+ else\r
+ return str;\r
+ }\r
+\r
+ /**\r
+ * Used for fixing low/high register access. The given param should be the\r
+ * dst operand of an assembler command.\r
+ */\r
+ public String getXRegisterFix(String str) {\r
+ str = str.toLowerCase();\r
+ if (str.length() == 2 && str.charAt(0) >= 'a' && str.charAt(0) <= 'd') {\r
+ char c = str.charAt(0);\r
+ if (str.charAt(1) == 'l')\r
+ return fixl.replace('%', c);\r
+ if (str.charAt(1) == 'h')\r
+ return fixh.replace('%', c);\r
+ }\r
+ return "";\r
+ }\r
+\r
+ /**\r
+ * Creates a WSL comment with care to quote chars.\r
+ */\r
+ public static String createComment(String str) {\r
+ return createComment(str, C_REG);\r
+ }\r
+\r
+ /**\r
+ * Creates a WSL comment with care to quote chars, of the given type. Types\r
+ * are given as char constants. They can be default comments, comments that\r
+ * contain the original code in them, or additional comments regarding the\r
+ * translation process.\r
+ */\r
+ public static String createComment(String str, char type) {\r
+ return "C:\"" + type + str.replace("\"", "''") + "\";";\r
+ }\r
+\r
+ /**\r
+ * Creates a wsl statement that modifies the overflow limit based on the\r
+ * input string that should be the parameter of a command.\r
+ */\r
+ public String getOverflow(String str) {\r
+ int over = 256;\r
+ str = str.toLowerCase();\r
+ if (str.length() == 2) {\r
+ if ((str.charAt(1) == 'x' && str.charAt(0) >= 'a'\r
+ && str.charAt(0) <= 'd')\r
+ || (str.compareTo("si") == 0 || str.compareTo("bp") == 0))\r
+ over = 65536;\r
+ }\r
+ return "overflow := " + over + "; ";\r
+ }\r
+\r
+ private void debugPrint(ArrayList<String> com) {\r
+ System.out.println();\r
+ for (int i = 0; i < com.size(); i++) {\r
+ System.out.print(com.get(i));\r
+ System.out.print("||");\r
+ }\r
+ }\r
+\r
+ private boolean inMacro = false;\r
+\r
+ // internal state, if a procedure body is being translated currently\r
+ private boolean inProcedure = false;\r
+\r
+ // the name of the procedure currently translated, if there is one\r
+ private String currentProcName = "";\r
+\r
+ /**\r
+ * Takes a single assembler line and returns the translated WSL line(s). It\r
+ * also changes the translator modes (data, code etc).\r
+ */\r
+ public String processLine(String str) {\r
+ /* Most of the logic is here, some parts could be split off */\r
+ if (str.length() == 0)\r
+ return "";\r
+ String[] split = str.split(";", 2);\r
+ String rez = split[0];\r
+ String comment = "";\r
+ // removes the comments\r
+ if (translateComments && split.length > 1)\r
+ comment = createComment(split[1]);\r
+ if (rez.compareTo("") != 0) {\r
+ // if there is a non-comment part\r
+ String[] parts = rez.split("[\t ,]");\r
+ // separators are whitespace: tab, space and comma\r
+ ArrayList<String> com = new ArrayList<String>();\r
+ for (String s : parts)\r
+ if (s.compareTo("") != 0 && s != null)\r
+ com.add(s);\r
+ rez = "";\r
+ String a, b;\r
+ // special case, we are processing lines in a macro definition\r
+ if (inMacro) {\r
+ Iterator<String> it = com.iterator();\r
+ while (it.hasNext())\r
+ if (it.next().compareTo("endm") == 0)\r
+ inMacro = false;\r
+ return createComment(str, C_SPEC) + "\n";\r
+ }\r
+ // by this time, all the real words should be in the com array\r
+ int i = 0;\r
+ boolean work = true;\r
+ // debugPrint(com);\r
+ while (i < com.size() && work) {\r
+ String s = com.get(i).toLowerCase();\r
+ if (s.endsWith(":")) { // should represent a label\r
+ s = s.substring(0, s.length() - 1);\r
+ rez += "CALL " + s + "\n END\n";\r
+ rez += s + " == ";\r
+ // labelfound = true;\r
+ } else\r
+ // ------------------------------------------------------------\r
+ // procedures, calls and similar activities\r
+ if (s.compareTo("proc") == 0) {\r
+ // if (labelfound)\r
+ rez += "CALL Z; SKIP END \n";\r
+ a = com.get(i - 1);\r
+ rez += a + " == ";\r
+ b = PROCEDURE_INTERNAL_SYS;\r
+ rez += "\nACTIONS " + b + ": \n";\r
+ rez += b + " == ";\r
+ inProcedure = true;\r
+ currentProcName = a;\r
+ } else if (s.compareTo("endp") == 0) {\r
+ rez += " SKIP END\n ENDACTIONS\n END\n dummy" + nKnownC\r
+ + " == ";\r
+ inProcedure = false;\r
+ } else if (s.compareTo("ret") == 0) {\r
+ rez += " CALL Z;";\r
+ } else if (s.compareTo("call") == 0) {\r
+ a = com.get(++i);\r
+ // check for recursive calls, don't do outside of current \r
+ // action system\r
+ if (inProcedure && currentProcName.equals(a))\r
+ a = PROCEDURE_INTERNAL_SYS;\r
+ rez += "CALL " + a + ";";\r
+ } else\r
+ // segments and other special assembler directives\r
+ if (s.charAt(0) == '.') { //\r
+ if (s.compareTo(".code") == 0) {\r
+ rez = CODE_SEG_START;\r
+ mode = MODE_CODE;\r
+ } else if (s.compareTo(".data") == 0) {\r
+ rez = " ";\r
+ mode = MODE_DATA;\r
+ } else if (s.compareTo(".stack") == 0) {\r
+ rez = " ";\r
+ mode = MODE_STACK;\r
+ } else if (s.startsWith(".model")) {\r
+ if (!s.toLowerCase().endsWith("small")) {\r
+ rez += createComment(\r
+ "other models than small not supported :: "\r
+ + split[0],\r
+ C_SPEC);\r
+ nUnknownD++;\r
+ mode = MODE_0;\r
+ }\r
+ } else {\r
+ rez += createComment(\r
+ "directive not supported :: " + split[0],\r
+ C_SPEC);\r
+ nUnknownD++;\r
+ mode = MODE_0;\r
+ }\r
+ work = false;\r
+ } else if (s.compareTo("assume") == 0) {\r
+ rez += createComment(\r
+ "ASSUME commands not supported :: " + split[0],\r
+ C_SPEC);\r
+ nUnknownD++;\r
+ work = false;\r
+ } else if (s.compareTo("segment") == 0) {\r
+ String segn = com.get(i - 1).toLowerCase();\r
+ if (segn.compareTo("cseg") == 0\r
+ || segn.compareTo("code") == 0\r
+ || segn.compareTo("code_seg") == 0) {\r
+ rez += CODE_SEG_START;\r
+ mode = MODE_CODE;\r
+ } else if (segn.compareTo("dseg") == 0\r
+ || segn.compareTo("data_seg") == 0\r
+ || segn.compareTo("data") == 0) {\r
+ rez += " ";\r
+ mode = MODE_DATA;\r
+ } else if (segn.compareTo("sseg") == 0\r
+ || segn.compareTo("stack_seg") == 0\r
+ || segn.compareTo("stack") == 0) {\r
+ rez += " ";\r
+ mode = MODE_STACK;\r
+ } else {\r
+ rez += createComment(\r
+ "unsuported segment type :: " + split[0],\r
+ C_SPEC);\r
+ nUnknownD++;\r
+ mode = MODE_0;\r
+ }\r
+ work = false;\r
+ } else if (s.compareTo("ends") == 0) { // segment end\r
+ if (i > 0) {\r
+ String segn = com.get(i - 1).toLowerCase();\r
+ if (segn.compareTo("cseg") == 0\r
+ || segn.compareTo("code_seg") == 0\r
+ || segn.compareTo("code") == 0\r
+ || segn.compareTo("dseg") == 0\r
+ || segn.compareTo("data") == 0\r
+ || segn.compareTo("data_seg") == 0\r
+ || segn.compareTo("sseg") == 0\r
+ || segn.compareTo("stack") == 0\r
+ || segn.compareTo("stack_seg") == 0) {\r
+ rez += createComment("end of segment " + segn,\r
+ C_SPEC);\r
+ mode = MODE_0;\r
+ } else {\r
+ rez += createComment(\r
+ "unsuported segment type :: " + split[0],\r
+ C_SPEC);\r
+ nUnknownD++;\r
+ }\r
+ } else {\r
+ rez += createComment("end of segment", C_SPEC);\r
+ mode = MODE_0;\r
+ }\r
+ work = false;\r
+ } else\r
+ // macro ideas ----\r
+ if (s.compareTo("macro") == 0) {\r
+ rez += createComment(\r
+ "found macro definition - macros unsuported",\r
+ C_ERR);\r
+ nUnknownC++;\r
+ inMacro = true;\r
+ work = false;\r
+ } else if (s.compareTo("endm") == 0) {\r
+ rez += createComment(\r
+ "found macro definition end - macros unsuported",\r
+ C_ERR);\r
+ nUnknownC++;\r
+ work = false;\r
+ } else\r
+\r
+ /*\r
+ * ------------------------------\r
+ * \r
+ * special macro names translated directly\r
+ */\r
+ if ((s.compareTo("print_str") == 0\r
+ || s.compareTo("print_num") == 0\r
+ || s.compareTo("print_char") == 0)\r
+ && com.get(i + 1).compareTo("macro") != 0) { \r
+ rez += "PRINFLUSH(" + com.get(i + 1) + ");";\r
+\r
+ work = false;\r
+ } else if (s.compareTo("print_new_line") == 0\r
+ && (com.size() <= i + 1\r
+ || com.get(i + 1).compareTo("macro") != 0)) { \r
+ rez += "PRINT(\"\");";\r
+\r
+ work = false;\r
+ } else if (s.compareTo("read_str") == 0\r
+ && com.get(i + 1).compareTo("macro") != 0) { \r
+ rez += "@Read_Line_Proc(VAR " + com.get(i + 1)\r
+ + ", Standard_Input_Port);";\r
+\r
+ work = false;\r
+ } else if (s.compareTo("read_num") == 0\r
+ && com.get(i + 1).compareTo("macro") != 0) { \r
+ rez += "@Read_Line_Proc(VAR t_e_m_p, Standard_Input_Port);\n";\r
+ rez += com.get(i + 1) + " := @String_To_Num(t_e_m_p);";\r
+\r
+ work = false;\r
+ } else if (s.compareTo("end_execution") == 0\r
+ && (com.size() <= i + 1\r
+ || com.get(i + 1).compareTo("macro") != 0)) { \r
+ rez += "CALL Z;";\r
+\r
+ work = false;\r
+ } else\r
+\r
+ // ---------------------------------------\r
+ // operators and similar commands\r
+ if (s.compareTo("mov") == 0) {\r
+ a = com.get(i + 1);\r
+ b = com.get(i + 2).toLowerCase();\r
+ if ((b.compareTo("@data") == 0)\r
+ || (b.compareTo("dseg") == 0)) {\r
+ rez += createComment("unneeded DATA segment fixes",\r
+ C_SPEC);\r
+ work = false;\r
+ } else {// rez += getOverflow(a);\r
+ rez += formatDst(a) + " := " + formatParam(b) + ";";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ }\r
+ } else if (s.compareTo("add") == 0 || s.compareTo("adc") == 0) {\r
+ a = com.get(i + 1);\r
+ b = com.get(i + 2);\r
+ rez += getOverflow(a);\r
+ rez += formatDst(a) + " := " + formatParam(a) + " + "\r
+ + formatParam(b) + ";\n";\r
+ if (s.compareTo("adc") == 0)\r
+ rez += formatDst(a) + " := " + formatParam(a) + " + "\r
+ + " + flag_c;\n";\r
+ rez += "IF " + formatDst(a) + " >= overflow THEN "\r
+ + formatDst(a) + " := " + formatDst(a)\r
+ + " MOD overflow; flag_o :=1; flag_c := 1; ELSE flag_o :=0; flag_c := 0; FI;";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ } else if (s.compareTo("sub") == 0 || s.compareTo("cmp") == 0) {\r
+ a = com.get(i + 1);\r
+ b = com.get(i + 2);\r
+ // rez += getOverflow(a);\r
+ rez += "IF " + formatParam(a) + " = " + formatParam(b)\r
+ + " THEN\n\t flag_z := 1\n ELSE\n\t flag_z := 0\n FI; ";\r
+ rez += "IF " + formatParam(a) + " < " + formatParam(b)\r
+ + " THEN\n\t flag_c := 1\n ELSE\n\t flag_c := 0\n FI; ";\r
+ if (s.compareTo("sub") == 0)\r
+ rez += formatDst(a) + " := " + formatParam(a) + " - "\r
+ + formatParam(b) + ";";\r
+ work = false;\r
+ } else if (s.compareTo("inc") == 0) {\r
+ a = com.get(i + 1);\r
+ rez += getOverflow(a);\r
+ rez += formatDst(a) + " := " + formatParam(a) + " + 1;";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ } else if (s.compareTo("dec") == 0) {\r
+ a = com.get(i + 1);\r
+ rez += getOverflow(a);\r
+ rez += formatDst(a) + " := " + formatParam(a) + " - 1;";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ } else if (s.compareTo("shr") == 0) {\r
+ a = com.get(i + 1);\r
+ // rez += getOverflow(a);\r
+ rez += "IF " + formatParam(a) + " MOD 2 = 1 THEN "\r
+ + " flag_c := 1; ELSE flag_c := 0; FI;";\r
+ rez += formatDst(a) + " := " + formatParam(a) + " DIV 2;";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ } else if (s.compareTo("shl") == 0) {\r
+ a = com.get(i + 1);\r
+ rez += getOverflow(a);\r
+ rez += formatDst(a) + " := " + formatParam(a) + " * 2;";\r
+ rez += "IF " + formatDst(a) + " >= overflow THEN "\r
+ + formatDst(a) + " := " + formatDst(a)\r
+ + " MOD overflow; flag_o :=1; flag_c := 1; ELSE flag_o :=0; flag_c := 0; FI;";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ } else if (s.compareTo("xchg") == 0) {\r
+ a = com.get(i + 1);\r
+ b = com.get(i + 2);\r
+ rez += "< " + formatDst(a) + " := " + formatParam(b) + ", "\r
+ + formatDst(b) + " := " + formatParam(a) + " >;";\r
+ rez += getXRegisterFix(a);\r
+ work = false;\r
+ } else\r
+ // logical exp\r
+ if (s.compareTo("and") == 0) {\r
+ // rez += com.get(i+1)+" := "+com.get(i+1)+" AND\r
+ // "+formatParam(com.get(i+2))+";";\r
+ rez += createComment(\r
+ "and not implemented yet :: " + split[0], C_ERR);\r
+ nUnknownC++;\r
+ work = false;\r
+ } else if (s.compareTo("xor") == 0) {\r
+ a = com.get(i + 1);\r
+ b = formatParam(com.get(i + 2));\r
+ if (a.compareTo(b) == 0)\r
+ rez += a + " := 0;";\r
+ else {\r
+ rez += createComment(\r
+ "xor not implemnted yet :: " + split[0], C_ERR);\r
+ // a+" := ("+a+" AND NOT "+b+") OR (NOT "+a+" AND "+b+"\r
+ // );");\r
+ nUnknownC++;\r
+ }\r
+ work = false;\r
+ } else if (s.compareTo("not") == 0) {\r
+ // rez += com.get(i+1)+" := NOT "+com.get(i+1)+";";\r
+ rez += createComment(\r
+ "NOT not implemented yet :: " + split[0], C_ERR);\r
+ nUnknownC++;\r
+ work = false;\r
+ } else\r
+ // jumps\r
+ if (s.compareTo("jmp") == 0) {\r
+ rez += "CALL " + com.get(i + 1) + ";";\r
+ work = false;\r
+ } else if (s.compareTo("je") == 0 || s.compareTo("jz") == 0) {\r
+ rez += "IF flag_z = 1 THEN CALL " + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("jne") == 0 || s.compareTo("jnz") == 0) {\r
+ rez += "IF flag_z = 0 THEN CALL " + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("ja") == 0) {\r
+ rez += "IF flag_z = 0 AND flag_c = 0 THEN CALL "\r
+ + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("jae") == 0 || s.compareTo("jnc") == 0) {\r
+ rez += "IF flag_c = 0 THEN CALL " + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("jb") == 0) {\r
+ rez += "IF flag_c = 1 THEN CALL " + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("jcxz") == 0) {\r
+ rez += "IF cx = 0 THEN CALL " + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("jo") == 0) {\r
+ rez += "IF flag_o = 1 THEN CALL " + com.get(i + 1) + " FI;";\r
+ work = false;\r
+ } else if (s.compareTo("loop") == 0) {\r
+ rez += "cx := cx - 1;\n";\r
+ rez += "IF cx>0 THEN CALL " + com.get(i + 1)\r
+ + " ELSE CALL dummy" + nKnownC + " FI\n";\r
+ rez += "END\ndummy" + nKnownC + " ==";\r
+ work = false;\r
+ } else\r
+\r
+ // end and other\r
+ if (s.compareTo("end") == 0) {\r
+ // TODO parse the optional entry label that comes with end\r
+ rez += createComment("program end");\r
+ work = false;\r
+ } else if (s.compareTo("nop") == 0) {\r
+ rez += "SKIP;";\r
+ work = false;\r
+ } else\r
+\r
+ // stack\r
+ if (s.compareTo("pop") == 0) {\r
+ if (translateToPopPush) {\r
+ rez += "POP(" + formatDst(com.get(i + 1)) + ", stack);";\r
+ } else {\r
+ rez += formatDst(com.get(i + 1)) + " := HEAD(stack);\n";\r
+ rez += "stack := TAIL(stack);";\r
+ }\r
+ rez += getXRegisterFix(com.get(i + 1));\r
+ work = false;\r
+ } else if (s.compareTo("push") == 0) {\r
+ if (translateToPopPush) {\r
+ rez += "PUSH(stack, " + formatParam(com.get(i + 1))\r
+ + ");";\r
+ } else {\r
+ rez += "stack := < " + formatParam(com.get(i + 1))\r
+ + " > ++ stack;";\r
+ }\r
+ work = false;\r
+ } else\r
+ // var definitions\r
+ if (s.compareTo("db") == 0 || s.compareTo("dw") == 0) {\r
+ if (mode == MODE_DATA) {\r
+ if (com.size() == i + 2) {\r
+ rez += "\t " + com.get(i - 1) + " := "\r
+ + formatParam(com.get(i + 1)) + ",";\r
+ } else {// array\r
+ rez += "\t " + com.get(i - 1) + " := < "\r
+ + formatParam(com.get(i + 1));\r
+ for (int j = i + 2; j < com.size(); j++)\r
+ rez += "," + formatParam(com.get(j));\r
+ rez += " >,";\r
+ }\r
+ } else {\r
+\r
+ }\r
+ }\r
+ i++;\r
+ }\r
+ if (rez.compareTo("") == 0 && com.size() > 0) {\r
+ rez = createComment(" unkown command:" + split[0], C_ERR);\r
+ nUnknownC++;\r
+ } else\r
+ nKnownC++; // this now counts the directives too...\r
+ }\r
+ return rez + " " + comment + "\n";\r
+\r
+ }\r
+\r
+ /**\r
+ * Converts an asm file to a wsl file. It also prints out the number of\r
+ * unsupported commands.\r
+ */\r
+ public void convertAFile(File f) {\r
+ try {\r
+ BufferedReader in = new BufferedReader(\r
+ new InputStreamReader(new FileInputStream(f)));\r
+ String str = in.readLine(), rez = f.getPath();\r
+ if (rez.toLowerCase().endsWith(".asm"))\r
+ rez = rez.substring(0, rez.length() - 4);\r
+ PrintWriter out = new PrintWriter(\r
+ new OutputStreamWriter(new FileOutputStream(rez + ".wsl")));\r
+ nUnknownD = 0;\r
+ nUnknownC = 0;\r
+ nKnownC = 0;\r
+ StringBuilder[] sbs = new StringBuilder[N_MODES];\r
+ for (int i = 0; i < N_MODES; i++)\r
+ sbs[i] = new StringBuilder();\r
+ while (str != null) {\r
+ rez = processLine(str);\r
+ if (originalInComments)\r
+ sbs[mode].append(createComment(str, C_OC) + "\n");\r
+ sbs[mode].append(rez);\r
+ str = in.readLine();\r
+ }\r
+ sbs[MODE_CODE].append(CODE_SEG_END);\r
+ if (addMemoryDump)\r
+ sbs[MODE_CODE].append("memdump();");\r
+ sbs[MODE_DATA].append(DATA_SEG_END);\r
+ // remove comments from dataseg\r
+ String datastr = sbs[MODE_DATA].toString()\r
+ .replaceAll("C:\"(.*?)\";\n?", "");\r
+ in.close();\r
+ out.print(getStandardStart());\r
+ out.print(sbs[MODE_0]);\r
+ out.print(DATA_SEG_START);\r
+ out.print(datastr); // out.print(sbs[MODE_DATA]);\r
+ out.print(sbs[MODE_CODE]);\r
+ out.print(getStandardEnd());\r
+ out.close();\r
+ if (nUnknownD > 0)\r
+ System.out.println("warning: " + nUnknownD\r
+ + " unkown/unsuported directives were found");\r
+ if (nUnknownC > 0)\r
+ System.out.println("errors : " + nUnknownC\r
+ + " unkown/unsuported commands were found");\r
+ System.out.println(nKnownC + " commands translated");\r
+ } catch (Exception e) {\r
+ System.err.println("error in conversion:");\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ public void run(String[] args) {\r
+ if (args.length == 0) {\r
+ System.out.println("Assembler to WSL converter. v " + versionN\r
+ + ", by Doni Pracner");\r
+ System.out.println("usage:\n\t asm2wsl {-option[ +-]} filename");\r
+ System.out.println("options: (def value in parenthesis)");\r
+ System.out.println("\t -oc : orignal code in comments ("\r
+ + (originalInComments ? "+" : "-") + ")");\r
+ System.out.println("\t -c : translate comments ("\r
+ + (translateComments ? "+" : "-") + ")");\r
+ System.out.println("\t -dump : add memory dump commands to end ("\r
+ + (addMemoryDump ? "+" : "-") + ")");\r
+ } else {\r
+ if (args[0].compareTo("-h") == 0\r
+ || args[0].compareTo("--help") == 0) {\r
+ run(new String[0]);\r
+ return;\r
+ }\r
+ int i = 0;\r
+ while (i < args.length && args[i].charAt(0) == '-') {\r
+ if (args[i].startsWith("-oc")) {\r
+ if (args[i].length() == 4)\r
+ originalInComments = args[i].charAt(3) == '+';\r
+ else\r
+ originalInComments = true;\r
+ } else if (args[i].startsWith("-c")) {\r
+ if (args[i].length() == 3)\r
+ translateComments = args[i].charAt(2) == '+';\r
+ else\r
+ translateComments = true;\r
+ } else if (args[i].startsWith("-dump")) {\r
+ addMemoryDump = true;\r
+ if (args[i].length() == 6 && args[i].charAt(5) == '-')\r
+ addMemoryDump = false;\r
+ }\r
+ i++;\r
+ }\r
+\r
+ if (i >= args.length) {\r
+ System.out.println("no filename supplied");\r
+ System.exit(2);\r
+ }\r
+ File f = new File(args[i]);\r
+ if (f.exists()) {\r
+ Calendar now = Calendar.getInstance();\r
+ convertAFile(f);\r
+ long mili = Calendar.getInstance().getTimeInMillis()\r
+ - now.getTimeInMillis();\r
+ System.out.println("conversion time:" + mili + " ms");\r
+ } else\r
+ System.out.println("file does not exist");\r
+ }\r
+ }\r
+\r
+ public static void main(String[] args) {\r
+ new asm2wsl().run(args);\r
+ }\r
+}\r