@@ -14,60 +14,86 @@ public class JohnnyScript {
1414
1515 private static final String OUTPUT_EXTENSION = ".ram" ;
1616 private static final String LINE_COMMENT_DELIMITER = "//" ;
17+ private static final String JUMP_POINT_DELIMITER = ":" ;
18+ private static final String VARIABLE_DELIMITER = "#" ;
1719
1820 public static void main (String [] args ) throws IOException {
1921
2022 Path source = getFilename (args );
2123 List <String > code = Files .readAllLines (source );
22- writeOutFile (source .getFileName ().toString (), compileCode (code ));
24+ try {
25+ writeOutFile (source .getFileName ().toString (), compileCode (code ));
26+ } catch (Exception e ) {
27+ throw new CompilerHaltException ("Compiler halted due to erroneous code!\n " , e );
28+ }
2329
2430 }
2531
2632 /**
27- * Generates the ram code consisting from 1000 lines of compiled JohnnyScript and "000" for empty lines
33+ * Generates ram code using RamCode object
2834 *
29- * @param sourceLines {@link java.util. List} of String objects containing lines of JohnnyScript code
35+ * @param sourceLines {@link List} of String objects containing lines of JohnnyScript code
3036 * @return compiled numeric code for .ram file
3137 */
32- private static List <String > compileCode (List <String > sourceLines ) {
33- List <String > compiled = new ArrayList <>();
34-
35- for (int i = 0 ; i <= 999 ; i ++) {
36- if (i < sourceLines .size ()) {
37- try {
38- String compiledLine = compile (sourceLines .get (i ));
39- if (compiledLine != null ) {
40- compiled .add (compiledLine );
41- } else {
42- sourceLines .remove (i ); // Remove comment line from source
43- i --; // Reduce index to continue at next line without skipping
44- }
45- } catch (InvalidScriptException e ) {
46- throw new CompilerHaltException ("Invalid code at line " + i , e );
38+ private static List <String > compileCode (List <String > sourceLines ) throws InvalidScriptException , DuplicateVariableException , VariableNotInitializedException , DuplicateJumpPointException {
39+ RamCode code = new RamCode ();
40+ int lineNumber = 0 ;
41+ for (String line :sourceLines ) {
42+ line = decomment (line );
43+ if (line == null ) {
44+ continue ;
45+ }
46+ if (line .contains (VARIABLE_DELIMITER )) {
47+ String [] parts = line .split (VARIABLE_DELIMITER + "| " );
48+ if (parts [0 ].length () == 0 ) {
49+ // variable declaration (# at start of line)
50+ if (parts .length != 3 ) {
51+ throw new InvalidScriptException ("Syntax error at line " + lineNumber + ": " + line + " (variable declaration: #varname [int])" );
52+ } else code .addVar (parts [1 ],Integer .valueOf (parts [2 ]));
53+ } else {
54+ // reference to variable
55+ if (parts .length != 3 ) {
56+ throw new InvalidScriptException ("Syntax error at line " + lineNumber + ": " + line + " (variable declaration: #varname [int])" );
57+ } else code .addCodeWithVar (encode (parts [0 ], false ),parts [2 ]);
4758 }
48- } else compiled .add ("000" );
59+ } else {
60+ if (line .contains (JUMP_POINT_DELIMITER )) {
61+ String jpName = line .replace (":" , "" );
62+ code .addJumpPoint (jpName );
63+ } else {
64+ String [] parts = line .split (" " );
65+ if (Codes .valueOf (parts [0 ].toUpperCase ()).codeOrdinal == Codes .JMP .codeOrdinal ) {
66+ code .addJump (parts [1 ]);
67+ } else code .addCode (encode (line , true ));
68+ }
69+
70+ }
71+ lineNumber ++;
72+
4973 }
5074
51- return compiled ;
75+ try {
76+ return code .getCode ();
77+ } catch (InvalidJumpsException e ) {
78+ throw new CompilerHaltException ("Compiler halted due to erroneous code!\n " , e );
79+ }
5280 }
5381
5482 /**
55- * Handles compiling of specific lines depending on the type of code.
83+ * Removes comments from line and trims excess whitespace
5684 *
5785 * @param line Line of JohnnyScript code
5886 * @return compiled line of .ram code or null if line is a comment
59- * @throws InvalidScriptException on invalid JohnnyScript code
6087 */
61- private static String compile (String line ) throws InvalidScriptException {
88+ private static String decomment (String line ) {
6289 if (line .contains (LINE_COMMENT_DELIMITER )) {
6390 /* Separate code from comment */
6491 int commentStart = line .indexOf (LINE_COMMENT_DELIMITER );
6592 String nonComment = line .substring (0 , commentStart );
6693 if (!nonComment .equals ("" ))
67- return encode ( nonComment );
94+ return nonComment . trim ( );
6895 else return null ;
69- } else
70- return encode (line );
96+ } else return line .trim ();
7197 }
7298
7399 /**
@@ -77,17 +103,19 @@ private static String compile(String line) throws InvalidScriptException {
77103 * @return numeric line for instruction
78104 * @throws InvalidScriptException on invalid JohnnyScript code
79105 */
80- private static String encode (String line ) throws InvalidScriptException {
81- String [] parts = line .trim (). split (" " );
82- if (parts .length > 2 ) throw new InvalidScriptException ("InvalidJohnnyScript (too many parts): " + line );
106+ private static String encode (String line , boolean appendLow ) throws InvalidScriptException {
107+ String [] parts = line .split (" " );
108+ if (parts .length > 2 ) throw new InvalidScriptException ("Syntax error (too many parts): " + line );
83109 if (parts .length == 1 ) {
84- return String .format ("%03d" , Integer .parseInt (parts [0 ]));
110+ String output = Codes .valueOf (parts [0 ].toUpperCase ()).getCode ();
111+ if (appendLow ) output = output + "000" ;
112+ return output ;
113+ } else {
114+ String code = parts [0 ].toUpperCase ();
115+ String hi = Codes .valueOf (code ).getCode ();
116+ String lo = String .format ("%03d" , Integer .parseInt (parts [1 ]));
117+ return hi + lo ;
85118 }
86- // else there are two parts
87- String code = parts [0 ].toUpperCase ();
88- String lo = String .format ("%03d" , Integer .parseInt (parts [1 ]));
89- String hi = Codes .valueOf (code ).getCode ();
90- return hi + lo ;
91119
92120 }
93121
@@ -160,7 +188,6 @@ public String getCode() {
160188class RamCode {
161189
162190 private static final int MAX_LINES = 999 ;
163- private static final String JUMP_POINT_DELIMITER = ":" ;
164191
165192 private static int writeIndex ;
166193
@@ -191,16 +218,12 @@ void addVar(String name, int value) throws DuplicateVariableException {
191218 }
192219 }
193220
194- void addCodeWithVar (String input ) throws VariableNotInitializedException {
195- assert input .contains ("#" );
196- String [] parts = input .split ("#" );
197- assert parts .length == 2 ;
198- String var = parts [1 ];
221+ void addCodeWithVar (String commandOrdinal , String var ) throws VariableNotInitializedException {
199222 if (!variables .containsKey (var )) {
200223 throw new VariableNotInitializedException ("Variable has not been initialized: " + var );
201224 } else {
202225 int line = varLoc .get (var );
203- code .add (parts [ 0 ]. trim () + String .format ("%03d" , line ));
226+ code .add (commandOrdinal + String .format ("%03d" , line ));
204227 }
205228 }
206229
@@ -232,7 +255,7 @@ private List<String> initializeZeros(List<String> code) {
232255 return code ;
233256 }
234257
235- List getCode () throws InvalidJumpsException {
258+ List < String > getCode () throws InvalidJumpsException {
236259 List <String > output = new ArrayList <>();
237260 initializeZeros (output );
238261
@@ -248,7 +271,7 @@ List getCode() throws InvalidJumpsException {
248271
249272 for (String loc : code
250273 ) {
251- output .add (writeIndex , loc );
274+ output .set (writeIndex , loc );
252275 writeIndex ++;
253276 }
254277
@@ -261,7 +284,7 @@ List getCode() throws InvalidJumpsException {
261284 for (int line :jumpList ) {
262285 line = 1 + variables .size () + line ;
263286 assert output .get (line ).equals (jpName + ":" );
264- output .set (line , JohnnyScript .Codes .JMP .codeOrdinal + String .format ("%03d" , line ));
287+ output .set (line , JohnnyScript .Codes .JMP .codeOrdinal + String .format ("%03d" , 1 + variables . size ()+ jumpPoints . get ( jpName ) ));
265288 }
266289 }
267290 });
0 commit comments