gitweb on Svarog
projekti pod git sistemom za održavanje verzija -- projects under
the git version control system
de00850a3ad3eeb13ce776d6a484b4b00920b6fc
1 package com
.qumaster
.transformations
.mjc2wsl
;
3 Copyright (C) 2014 Doni Pracner
5 This file is part of mjc2wsl.
7 mjc2wsl is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 mjc2wsl is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with mjc2wsl. If not, see <http://www.gnu.org/licenses/>.
23 import com
.qumaster
.transformations
.TransMessages
;
26 * This program converts file from compiled MicroJava bytecode to WSL language
27 * which is a part of the FermaT Transformation system. MicroJava is a subset
28 * used in Compiler Construction courses by Hanspeter Moessenboeck, not
31 * @author Doni Pracner, http://perun.dmi.rs/pracner http://quemaster.com
34 //default version name, used if the file is not found
35 private static String versionN
= "0.1.x";
37 private String versionFile
= "version.properties";
39 private TransMessages messages
= new TransMessages();
41 private boolean genPauseAfterEachAddress
=false,
42 genPrintForEachAddress
= false,
43 genPrintEStackOnChange
= false;
45 private boolean genPopPush
=false;
47 private boolean genInlinePrint
=false;
49 /** Constant used for marking a regular comment from the original file */
50 public static final char C_REG
= ' ';
52 * Constant used for marking when original code is inserted in the file,
53 * next to the translations
55 public static final char C_OC
= '#';
56 /** Constant used for marking special messages from the translator */
57 public static final char C_SPEC
= '&';
58 /** Constant used for marking error messages from the translator */
59 public static final char C_ERR
= '!';
61 /** instruction code in MicroJava bytecode. */
62 public static final int
121 private boolean originalInComments
= false;
123 private HashMap
<Integer
,String
> opMap
= null;
125 private String opCodeFile
= "mj-bytecodes.properties";
127 private HashMap
<Integer
, String
> getOpMap() {
129 opMap
= new HashMap
<Integer
, String
>(60, 0.98f
);
131 BufferedReader in
= new BufferedReader(new InputStreamReader(
132 getClass().getResourceAsStream(opCodeFile
)));
133 String str
= in
.readLine();
134 while (str
!= null) {
135 String
[] ss
= str
.split("=");
136 opMap
.put(Integer
.parseInt(ss
[0]), ss
[1]);
140 } catch (Exception ex
) {
141 ex
.printStackTrace();
147 private Properties versionData
;
149 private String
getVersion() {
150 if (versionData
== null) {
151 versionData
= new Properties();
153 versionData
.load(getClass().getResourceAsStream(versionFile
));
154 } catch (IOException e
) {
158 String ver
= versionData
.getProperty("version");
165 public String
getOpString(int op
) {
166 return getOpMap().get(op
);
169 public String
describeOpCode(int op
) {
170 return op
+ " (" + getOpString(op
) + ")";
173 private InputStream mainIn
;
174 private PrintWriter out
= null;
175 private int counter
= -1;
177 private void pr(int i
){
181 private void pr(char i
){
185 private void pr(String i
){
189 private void prl(String i
){
198 res
= res
<< 24 >>> 24;
199 } catch (IOException ex
) {
200 ex
.printStackTrace();
207 return (get() * 256 + get()) << 16 >> 16;
211 return (get2() << 16) + (get2() << 16 >>> 16);
214 public String
createStandardStart(){
215 return createStandardStart(10);
218 public String
createStandardStart(int numWords
){
219 StringBuilder ret
= new StringBuilder(
220 "C:\" This file automatically converted from microjava bytecode\";\n"
221 +"C:\" with mjc2wsl v "+getVersion()+"\";\n");
223 ret
.append("\nBEGIN");
224 ret
.append("\nVAR <\n\t");
225 ret
.append("mjvm_locals := ARRAY(1,0),");
226 ret
.append("\n\tmjvm_statics := ARRAY("+numWords
+",0),");
227 ret
.append("\n\tmjvm_arrays := < >,");
228 ret
.append("\n\tmjvm_flag_jump := 0,");
229 ret
.append("\n\tmjvm_objects := < >,");
230 ret
.append("\n\tmjvm_estack := < >, mjvm_mstack := < > > :");
232 return ret
.toString();
235 public String
createAsciiString(){
236 StringBuilder ret
= new StringBuilder("C:\"char array for ascii code conversions\";");
237 ret
.append("\nascii := \"????????????????????????????????\"++\n");
238 ret
.append("\" !\"++Quote++\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\";\n");
240 return ret
.toString();
243 public String
createStandardEnd(){
244 StringBuilder ret
= new StringBuilder("SKIP\nENDVAR\n");
245 ret
.append("\nWHERE\n");
247 ret
.append("\nFUNCT CHR(num) ==:\n");
248 ret
.append("\t@List_To_String(< num >)\n");
251 if (!genInlinePrint
) {
252 ret
.append("\nPROC Print_MJ(val, format VAR)==\n");
253 ret
.append(createComment("print spacing", C_SPEC
));
254 ret
.append("\n\tIF format>1 THEN\n\t\tFOR i:=2 TO ");
255 ret
.append("format STEP 1 DO PRINFLUSH(\" \") OD\n");
256 ret
.append("\tFI;\n\tPRINFLUSH(val)\nEND\n");
258 ret
.append("\nPROC Print_MJ_CHAR(val, format VAR)==\n");
259 ret
.append(createComment("print spacing", C_SPEC
));
260 ret
.append("\n\tIF format>1 THEN\n\t\tFOR i:=2 TO ");
261 ret
.append("format STEP 1 DO PRINFLUSH(\" \") OD\n");
262 ret
.append("\tFI;\n\tPRINFLUSH(CHR(val))\n");
267 return ret
.toString();
270 private String
createStartVar(String
... vars
){
271 StringBuilder ret
= new StringBuilder("VAR < ");
272 ret
.append(vars
[0] + " := 0");
273 for (int i
=1; i
<vars
.length
; i
++)
274 ret
.append(", "+ vars
[i
] +" := 0");
277 return ret
.toString();
280 private String
createEndVar(){
284 private String
createLocal(int i
) {
285 // arrays start at 1 in WSL, so we need an offset
286 return "mjvm_locals[" + (i
+ 1) + "]";
289 private String
createStatic(int i
) {
290 return "mjvm_statics[" + (i
+ 1) + "]";
293 private String
createArray(int i
) {
294 return "mjvm_arrays[" + i
+ "]";
297 private String
createArray(String i
) {
298 return "mjvm_arrays[" + i
+ "]";
301 private String
createObject(String i
) {
302 return "mjvm_objects[" + i
+ "]";
306 * Creates a WSL comment with care to quote chars.
308 public static String
createComment(String str
){
309 return createComment(str
, C_REG
);
313 * Creates a WSL comment with care to quote chars, of the
314 * given type. Types are given as char constants. They can be
315 * default comments, comments that contain the original code
316 * in them, or additional comments regarding the translation
319 public static String
createComment(String str
, char type
) {
320 return "C:\"" + type
+ str
.replace("\"", "''") + "\";";
323 // generalised stack operations
325 private String
createToStack(String stack
, String var
){
327 return "PUSH("+stack
+"," + var
+ ");";
329 return stack
+ " := <" + var
+ " > ++ " + stack
+";";
332 private String
createFromStack(String stack
, String var
){
334 return "POP("+ var
+ ", "+stack
+");";
336 return var
+ ":= HEAD("+stack
+"); "+stack
+" := TAIL("+stack
+");";
340 private String
createToEStack(int i
) {
341 return createToEStack(i
+"");
344 private String
createToEStack(String i
) {
345 String res
= createToStack("mjvm_estack", i
);
346 if (genPrintEStackOnChange
)
347 res
+= "PRINT(\"eStack\",mjvm_estack);";
351 private String
createFromEStack(String st
) {
352 String res
= createFromStack("mjvm_estack",st
);
353 if (genPrintEStackOnChange
)
354 res
+= "PRINT(\"eStack\",mjvm_estack);";
358 private String
createPopEStack() {
359 String res
= "mjvm_estack := TAIL(mjvm_estack);";
360 if (genPrintEStackOnChange
)
361 res
+= "PRINT(\"eStack\",mjvm_estack);";
365 private String
createTopTwoEStack() {
366 return createFromEStack("tempa") + "\n" + createFromEStack("tempb");
369 private String
createTopEStack() {
370 return createFromEStack("tempa");
375 private String
createToMStack(int i
) {
376 return createToMStack(i
+"");
379 private String
createToMStack(String i
) {
380 return createToStack("mjvm_mstack", i
);
383 private String
createFromMStack(String st
) {
384 return createFromStack("mjvm_mstack", st
);
387 private String
getRelationFor(int opcode
) throws Exception
{
389 case jeq
: return "=";
390 case jne
: return "<>";
391 case jlt
: return "<";
392 case jle
: return "<=";
393 case jgt
: return ">";
394 case jge
: return ">=";
396 throw new Exception("Wrong opcode for a relation");
399 private boolean isJumpCode(int opcode
) {
400 return (opcode
>= jmp
) && (opcode
<= jge
);
403 public void convertStream(InputStream ins
) throws Exception
{
406 byte m
= (byte) get();
407 byte j
= (byte) get();
408 if (m
!='M' || j
!='J')
409 throw new Exception("Wrong start of bytecode file");
410 int codesize
= get4();
411 int numberOfWords
= get4();
412 int mainAdr
= get4();
414 prl(createStandardStart(numberOfWords
));
415 prl("SKIP;\n ACTIONS a" + (14 + mainAdr
) + " :");
418 prl(" a" + counter
+ " ==");
419 if (originalInComments
)
420 prl(createComment(describeOpCode(op
), C_OC
));
421 if (genPrintForEachAddress
) {
422 prl("PRINT(\"a" + counter
+ "\");");
423 if (genPauseAfterEachAddress
)
424 prl("debug_disposable_string := @Read_Line(Standard_Input_Port);");
428 prl(createToEStack(createLocal(get())));
435 prl(createStartVar("tempa"));
436 prl("tempa :="+createLocal(op
- load_0
)+";");
437 prl(createToEStack("tempa"));
442 prl(createFromEStack(createLocal(get())));
449 prl(createStartVar("tempa"));
450 prl(createFromEStack("tempa"));
451 prl(createLocal(op
- store_0
)+" := tempa;");
457 prl(createToEStack(createStatic(get2())));
461 prl(createFromEStack(createStatic(get2())));
467 prl(createStartVar("tempa"));
468 prl(createTopEStack());
469 prl(createToEStack(createObject("tempa") + "[" + (f
+ 1) + "]"));
475 prl(createStartVar("tempa", "tempb"));
476 prl(createTopTwoEStack());
477 prl(createObject("tempb") + "[" + (f
+ 1) + "]:=tempa;");
483 prl(createToEStack(get4()));
488 prl(createToEStack(-1));
498 prl(createToEStack(op
- const_0
));
503 prl(createStartVar("tempa", "tempb", "tempres"));
504 prl(createTopTwoEStack());
505 prl("tempres := tempb + tempa;");
506 prl(createToEStack("tempres"));
511 prl(createStartVar("tempa", "tempb", "tempres"));
512 prl(createTopTwoEStack());
513 prl("tempres := tempb - tempa;");
514 prl(createToEStack("tempres"));
519 prl(createStartVar("tempa", "tempb", "tempres"));
520 prl(createTopTwoEStack());
521 prl("tempres := tempb * tempa;");
522 prl(createToEStack("tempres"));
527 prl(createStartVar("tempa", "tempb", "tempres"));
528 prl(createTopTwoEStack());
529 prl("IF tempa = 0 THEN ERROR(\"division by zero\") FI;");
530 prl("tempres := tempb DIV tempa;");
531 prl(createToEStack("tempres"));
536 prl(createStartVar("tempa", "tempb", "tempres"));
537 prl(createTopTwoEStack());
538 prl("IF tempa = 0 THEN ERROR(\"division by zero\") FI;");
539 prl("tempres := tempb MOD tempa;");
540 prl(createToEStack("tempres"));
546 prl(createStartVar("tempa"));
547 prl(createTopEStack());
548 prl(createToEStack("-tempa"));
554 prl(createStartVar("tempa", "tempb"));
555 prl(createTopTwoEStack());
556 prl("VAR <tempres :=tempb, i:=1 >:");
557 prl("\tFOR i:=1 TO tempa STEP 1 DO tempres := tempres * 2 OD;");
558 prl(createToEStack("tempres"));
564 prl(createStartVar("tempa", "tempb"));
565 prl(createTopTwoEStack());
566 prl("VAR <tempres :=tempb, i:=1 >:");
567 prl("\tFOR i:=1 TO tempa STEP 1 DO tempres := tempres DIV 2 OD;");
568 prl(createToEStack("tempres"));
575 int b1
= get(), b2
= get();
576 prl(createLocal(b1
) + " := " + createLocal(b1
) + " + " + b2
+ ";");
582 // TODO maybe objects and arrays should be in the same list?
583 prl("mjvm_objects := mjvm_objects ++ < ARRAY(" + size
585 prl(createToEStack("LENGTH(mjvm_objects)"));
589 get();// 0 - bytes, 1 - words; ignore for now
590 // TODO take into consideration 0/1
591 prl(createStartVar("tempa"));
592 prl(createTopEStack());
593 prl("mjvm_arrays := mjvm_arrays ++ < ARRAY(tempa,0) >;");
594 prl(createToEStack("LENGTH(mjvm_arrays)"));
601 prl(createStartVar("tempa", "tempb"));
602 prl(createTopTwoEStack());
603 prl(createToEStack(createArray("tempb") + "[tempa+1]"));
609 prl(createStartVar("tempa", "tempb", "tempres"));
610 prl(createFromEStack("tempres"));
611 prl(createTopTwoEStack());
612 prl("mjvm_arrays[tempb][tempa+1]:=tempres;");
617 prl(createStartVar("tempa", "tempb"));
618 prl(createTopEStack());
619 prl("tempb := LENGTH("+ createArray("tempa") + ");");
620 prl(createToEStack("tempb"));
626 prl(createStartVar("tempa", "tempb"));
627 prl(createTopEStack());
628 prl(createToEStack("tempa"));
629 prl(createToEStack("tempa"));
634 prl(createStartVar("tempa", "tempb"));
635 prl(createTopTwoEStack());
636 prl(createToEStack("tempb"));
637 prl(createToEStack("tempa"));
638 prl(createToEStack("tempb"));
639 prl(createToEStack("tempa"));
645 prl(createPopEStack());
650 prl("CALL a" + (counter
+ get2()) + ";");
660 prl(createStartVar("tempa", "tempb"));
661 prl(createTopTwoEStack());
662 prl("IF tempb " + getRelationFor(op
)
663 + " tempa THEN mjvm_flag_jump := 1"
664 + " ELSE mjvm_flag_jump := 0"
667 prl("IF mjvm_flag_jump = 1 THEN CALL a"
669 + " ELSE CALL a" + (counter
+ 1)
676 prl("CALL a" + (counter
+ get2()) + ";");
681 // we let the actions return
682 // there is nothing to clean up
683 prl("SKIP\n END\n b" + counter
+ " ==");
687 int parameters
= get();
690 prl(createToMStack("mjvm_locals"));
691 prl("mjvm_locals := ARRAY(" + locals
+ ",0);");
692 for (int i
= parameters
- 1; i
>= 0; i
--)
693 prl(createFromEStack(createLocal(i
)));
697 prl(createFromMStack("mjvm_locals"));
703 // TODO make it a char for read
704 messages
.message("char is read like a number", TransMessages
.M_WAR
);
705 prl(createComment("char is read like a number", C_SPEC
));
708 prl(createStartVar("tempa"));
709 prl("tempa := @String_To_Num(@Read_Line(Standard_Input_Port));");
710 prl(createToEStack("tempa"));
717 prl(createStartVar("tempa", "tempb"));
718 prl(createTopTwoEStack());
720 prl(createComment("print spacing and transformation",C_SPEC
));
721 prl("PRINFLUSH(SUBSTR(\" \", 0, MIN(10, MAX(0,tempa-1))), @List_To_String(< tempb >));");
723 prl("Print_MJ_CHAR(tempb,tempa);");
728 // TODO printing numbers needs different lengths of spacing
729 prl(createStartVar("tempa", "tempb"));
731 prl(createTopTwoEStack());
733 prl(createComment("print spacing",C_SPEC
));
734 prl("PRINFLUSH(SUBSTR(\" \", 0, MIN(10, MAX(0, tempa-SLENGTH(@String(tempb))))), tempb);");
737 prl("Print_MJ(tempb,tempa);");
743 prl("ERROR(\"Runtime error: trap(" + get() + ")\");");
748 prl(createComment("unknown op error: " + op
, C_ERR
));
749 messages
.message("unknown op error: " + op
, TransMessages
.M_ERR
);
753 boolean wasJump
= isJumpCode(op
);
759 prl("CALL a" + counter
+ "\n END");
761 prl("SKIP\n END\nENDACTIONS;\n");
762 pr(createStandardEnd());
765 public void convertFile(File f
) {
767 convertStream(new FileInputStream(f
));
768 } catch (Exception ex
) {
769 ex
.printStackTrace();
773 public void printHelp() {
780 public void printLongHelp() {
783 System
.out
.println();
785 System
.out
.println();
786 printHelpDirectives();
787 System
.out
.println();
788 printHelpGenerating();
789 System
.out
.println();
793 public void printHelpOutput() {
794 System
.out
.println("Output options:");
795 System
.out
.println(" --screen print output to screen");
796 System
.out
.println(" -o --oc[+-] include original code in comments");
797 System
.out
.println(" -v verbose, print warning messages");
798 System
.out
.println(" -q quiet; don't print even the error messages");
799 System
.out
.println(" -d print detailed debug messages");
802 public void printHelpGenerating() {
803 System
.out
.println("Options for generating extra code for tracking code execution");
804 System
.out
.println(" --genEStackPrint generate print for all EStack changes");
805 System
.out
.println(" --genAddrPrint generate prints after every address of the original code ");
806 System
.out
.println(" --genAddrPause generate a pause after every address of the original code ");
807 System
.out
.println(" --genAddr short for --genAddrPrint and --genAddrPause");
808 System
.out
.println(" --genAll short for applying all code generation");
811 public void printHelpDirectives(){
812 System
.out
.println("Alternatives for code generation:");
813 System
.out
.println(" --genPopPush generate POP/PUSH instead of TAIL/HEAD");
814 System
.out
.println(" --genHeadTail generate TAIL/HEAD instead of POP/PUSH ");
815 System
.out
.println();
816 System
.out
.println(" --genInlinePrint generate prints directly instead of procedure calls");
817 System
.out
.println(" --genProcedurePrint generate prints as custom procedure calls");
820 public void printHelpHelp() {
821 System
.out
.println("Help and info options");
822 System
.out
.println(" -h basic help");
823 System
.out
.println(" --help print more detailed help");
824 System
.out
.println(" --version or -version print version and exit");
827 public void printUsage(){
828 System
.out
.println("usage:\n\t mjc2wsl {options} filename [outfile]");
831 public void printVersion() {
832 System
.out
.println("MicroJava bytecode to WSL converter. v " + getVersion()
833 + ", by Doni Pracner");
836 public String
makeDefaultOutName(String inname
){
838 if (inname
.endsWith(".obj"))
839 rez
= rez
.substring(0, rez
.length() - 4);
843 public void run(String
[] args
) {
844 if (args
.length
== 0) {
848 while (i
< args
.length
&& args
[i
].charAt(0) == '-') {
849 if (args
[i
].compareTo("-h") == 0) {
852 } else if (args
[i
].compareTo("--help") == 0) {
855 } else if (args
[i
].compareTo("--version") == 0
856 || args
[i
].compareTo("-version") == 0) {
859 } else if (args
[i
].compareTo("-o") == 0
860 || args
[i
].startsWith("--oc")) {
861 if (args
[i
].length() == 2)
862 originalInComments
= true;
863 else if (args
[i
].length() == 5)
864 originalInComments
= args
[i
].charAt(4) == '+';
866 originalInComments
= true;
867 } else if (args
[i
].compareTo("--screen") == 0) {
868 out
= new PrintWriter(System
.out
);
869 } else if (args
[i
].compareTo("-d") == 0) {
870 messages
.setPrintLevel(TransMessages
.M_DEB
);// print debug info
871 } else if (args
[i
].compareTo("-v") == 0) {
872 messages
.setPrintLevel(TransMessages
.M_WAR
);// print warnings
873 } else if (args
[i
].compareTo("-q") == 0) {
874 messages
.setPrintLevel(TransMessages
.M_QUIET
);// no printing
875 } else if (args
[i
].compareToIgnoreCase("--genEStackPrint") == 0) {
876 genPrintEStackOnChange
= true;
877 } else if (args
[i
].compareToIgnoreCase("--genAddrPause") == 0) {
878 genPauseAfterEachAddress
= true;
879 } else if (args
[i
].compareToIgnoreCase("--genAddrPrint") == 0) {
880 genPrintForEachAddress
= true;
881 } else if (args
[i
].compareToIgnoreCase("--genAddr") == 0) {
882 genPrintForEachAddress
= true;
883 genPauseAfterEachAddress
= true;
884 } else if (args
[i
].compareToIgnoreCase("--genAll") == 0) {
885 genPrintEStackOnChange
= true;
886 genPrintForEachAddress
= true;
887 genPauseAfterEachAddress
= true;
888 } else if (args
[i
].compareToIgnoreCase("--genPopPush") == 0) {
890 } else if (args
[i
].compareToIgnoreCase("--genInlinePrint") == 0) {
891 genInlinePrint
= true;
892 } else if (args
[i
].compareToIgnoreCase("--genHeadTail") == 0) {
894 } else if (args
[i
].compareToIgnoreCase("--genProcedurePrint") == 0) {
895 genInlinePrint
= false;
900 if (i
>= args
.length
) {
901 System
.out
.println("no filename supplied");
904 File f
= new File(args
[i
]);
906 if (i
+ 1 < args
.length
) {
908 out
= new PrintWriter(args
[i
+ 1]);
909 } catch (Exception e
) {
910 System
.err
.println("error in opening out file:");
915 // if not set to screen, or a file, make a default filename
917 out
= new PrintWriter(makeDefaultOutName(args
[i
]));
918 } catch (Exception e
) {
919 System
.err
.println("error in opening out file:");
924 Calendar now
= Calendar
.getInstance();
926 long mili
= Calendar
.getInstance().getTimeInMillis()
927 - now
.getTimeInMillis();
928 System
.out
.println("conversion time:" + mili
+ " ms");
929 messages
.printMessageCounters();
932 System
.out
.println("file does not exist");
936 public static void main(String
[] args
) {
937 new mjc2wsl().run(args
);
Svarog.pmf.uns.ac.rs/gitweb
maintanance
Doni Pracner