1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
import java.io.*; import java.lang.Character; // import java.util.HashMap; import javax.swing.*; public class Cog extends JFrame { public static String[] defName = new String[1000]; public static int[] defLine = new int[1000]; public static int defCount = 0; public static String[] varVal = new String[1000]; public static String[] varName = new String[1000]; public static int varCount = 0; public static int curLine; public static String[] strScript; public static int globI = 0; public static void main(String args[]) { try { BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Which file to open? (Case-sensitive)\n"); FileInputStream fr = new FileInputStream(new File(br.readLine())); DataInputStream ds = new DataInputStream(new BufferedInputStream(fr)); System.out.println(ds.available()); String tmp = ""; for (int i2 = ds.available(); i2 > 0; i2--) { if (ds.available() != 0) { tmp += ds.readLine() + "\n"; } } strScript = tmp.split("\n"); getDefs(); if (getDef("start") > -1) { globI = getDef("start"); System.out.println("Found start on " + getDef("start")); } else if (getDef("main") > -1) { globI = getDef("main"); System.out.println("Found main on " + getDef("main")); } else { System.out.println("Failed to start"); } for (globI = globI; globI < strScript.length; globI++) { try { analyzeLine(strScript[globI]); curLine++; } catch (Exception e2) { e2.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } } public static void analyzeLine(String s) { if (!s.startsWith("#")) { if (s.trim().startsWith("@")) { String[] tmp = s.split("="); for (int i = 0; i < tmp.length; i++) { String[] tmp2 = tmp[i].split("@"); if (tmp2.length > 1) { if (tmp2[1].equalsIgnoreCase("author")) { System.out.println("Written by " + tmp[i + 1]); } else if (tmp2[1].equalsIgnoreCase("name")) { System.out.println("Script name " + tmp[i + 1]); } } } /* } else if (s.trim().startsWith("def")) { String[] tmp = s.split(" "); for (int i = 0; i < tmp.length; i++) { if (tmp[i].endsWith("{")) { setDef(left(tmp[i].length() - 1, tmp[i]), curLine); } } */ } else if (s.trim().startsWith("goto")) { String tmp = between(s.trim(), "(", ")"); globI = getDef(tmp); } else if (s.trim().startsWith("var")) { String[] t = s.split("var"); String[] tmp = t[1].split(";"); for (int i = 0; i < tmp.length; i++) { String[] tmp2 = tmp[i].split("="); for (int i2 = 0; i2 < tmp2.length - 1; i2++) { if (tmp2[i2 + 1].contains("}")) { setVar(tmp2[i2], left(tmp2[i2 + 1].length() - 1, tmp2[i2 + 1])); } else if (tmp2[i2].contains("{")) { setVar(right(1, tmp2[i2]), tmp2[i2 + 1]); } else { setVar(tmp2[i2], tmp2[i2 + 1]); } } } } else if (s.trim().startsWith("log")) { // String tmp = right(4, s.trim()); // String tmp2 = left(tmp.length() - 1, tmp); System.out.println(between(s.trim(), "(", ")")); } else if (s.trim().startsWith("for")) { String tmp = between(s.trim(), "for(", ")"); String[] tmp2 = tmp.split("="); String[] tmp3 = tmp2[1].split(":"); int intFinish = 0; for (int i = curLine; i < strScript.length; i++) { if (strScript[i].trim().startsWith("next")) { intFinish = i; } } int iStart = Integer.valueOf(tmp3[0].trim()).intValue(); int iEnd = Integer.valueOf(tmp3[1].trim()).intValue(); int tmpi = globI + iEnd; int tmp2z = globI + 1; // JOptionPane.showMessageDialog(null, Integer.toString(globI) + ":" + Integer.toString(intFinish)); curLine = globI; for (int i = iStart; i < iEnd; i++) { // run how many times for (int i2 = curLine + 1; i2 < intFinish; i2++) { // what to run analyzeLine(strScript[i2]); globI++; curLine++; } // JOptionPane.showMessageDialog(null, "i: " + Integer.toString(i)); curLine = globI - iEnd; globI = curLine; System.out.println(i); } curLine = globI; // curLine = tmp2z; } else if (s.trim().startsWith("when")) { String tmp = between(s.trim(), "(", ")"); System.out.println(s); String[] tmp2 = tmp.split(";"); System.out.println("Going to " + tmp2[1] + " when " + tmp2[0]); if (tmp.contains("=>")) { String[] tmp3 = tmp2[0].split(">="); if (Integer.valueOf(getVar(tmp3[0].trim())).intValue() >= Integer.valueOf(tmp3[1].trim()).intValue()) { globI = getDef(tmp2[1]); } } else if (tmp.contains("<=")) { String[] tmp3 = tmp2[0].split("<="); if (Integer.valueOf(getVar(tmp3[0].trim())).intValue() <= Integer.valueOf(tmp3[1].trim()).intValue()) { globI = getDef(tmp2[1]); } } else if (tmp.contains("!=")) { String[] tmp3 = tmp2[0].split("!="); if (Integer.valueOf(getVar(tmp3[0].trim())).intValue() != Integer.valueOf(tmp3[1].trim()).intValue()) { globI = getDef(tmp2[1]); } } else if (tmp.contains("<")) { String[] tmp3 = tmp2[0].split("<"); if (Integer.valueOf(getVar(tmp3[0].trim())).intValue() < Integer.valueOf(tmp3[1].trim()).intValue()) { globI = getDef(tmp2[1]); } } else if (tmp.contains(">")) { String[] tmp3 = tmp2[0].split(">"); if (Integer.valueOf(getVar(tmp3[0].trim())).intValue() > Integer.valueOf(tmp3[1].trim()).intValue()) { globI = getDef(tmp2[1]); } } else if (tmp.contains("=")) { String[] tmp3 = tmp2[0].split("="); String tmo = getVar(tmp3[0].trim()); if (tmo.equals(tmp3[1].trim())) { globI = getDef(tmp2[1]); } } } else if (s.trim().startsWith("if")) { String tmp = between(s.trim(), "(", ")"); String[] tmp2 = new String[] { tmp}; if (tmp.contains(">=")) { tmp2 = tmp.split(">="); } else if (tmp.contains("<=")) { tmp2 = tmp.split("<="); } else if (tmp.contains("!=")) { tmp2 = tmp.split("!="); if (tmp2[0].trim() != tmp2[1].trim()) { System.out.println( tmp2[0].trim() + " does not equal " + tmp2[1].trim()); } } else if (tmp.contains("<")) { tmp2 = tmp.split("<"); } else if (tmp.contains(">")) { tmp2 = tmp.split(">"); } else if (tmp.contains("=")) { tmp2 = tmp.split("="); if (tmp2[1].trim().equals(getVar(tmp2[0].trim()))) { System.out.println( "" + tmp2[0].trim() + " equals " + tmp2[1].trim()); } } } else { for (int i = 0; i < varCount; i++) { if (s.trim().startsWith(varName[i])) { String tmp = s.trim(); String[] tmp2; if (tmp.contains("+")) { tmp2 = tmp.split("+"); } else if (tmp.contains("-")) { tmp2 = tmp.split("-"); } else if (tmp.contains("=")) { tmp2 = tmp.split("="); System.out.println( "Now " + tmp2[0].trim() + " equals " + tmp2[1].trim()); } } } } } } public static void setDef(String dName, int dLine) { defLine[defCount] = dLine; defName[defCount] = dName.trim(); defCount++; } public static int getDef(String dName) { for (int i = 0; i < defCount; i++) { if (dName.equals(defName[i])) { return defLine[i]; } } return -1; } public static void getDefs() { for (int i = 0; i < strScript.length; i++) { if (strScript[i].trim().startsWith("def")) { String[] tmp = strScript[i].split(" "); for (int i2 = 0; i2 < tmp.length; i2++) { if (tmp[i2].endsWith("{")) { setDef(left(tmp[i2].length() - 1, tmp[i2]), i); } } } } } public static void setVar(String vName, String vVal) { /* boolean inUse = false; for (int i = 0; i < varCount; i++) { System.out.println(varName[i]); if (varName[i] == vName) { inUse = true; } } if (inUse = false) {*/ varVal[varCount] = vVal.trim(); varName[varCount] = vName.trim(); varCount++; /* } else { System.out.println(vName + " is already defined"); }*/ } public static String getVar(String vName) { for (int i = 0; i < varCount; i++) { if (vName.equals(varName[i])) { return varVal[i]; } } return null; } public static String between(String e, String s1, String s2) { return mid(e.indexOf(s1) + 1, e.indexOf(s2) - e.indexOf(s1) - 1, e); } public static String mid(int offset, int toread, String s) { String tmp = ""; char[] ch = s.toCharArray(); for (int i = offset; i < offset + toread; i++) { tmp = tmp + ch[i]; } return tmp; } public static String left(int offset, String s) { String tmp = ""; char[] ch = s.toCharArray(); for (int i = 0; i < offset; i++) { tmp = tmp + ch[i]; } return tmp; } public static String right(int offset, String s) { String tmp = ""; char[] ch = s.toCharArray(); for (int i = offset; i < s.length(); i++) { tmp = tmp + ch[i]; } return tmp; } } [THIS IS THE DEMO SCRIPT YOU SHOULD TEST WITH!] @name=Demo @author=PPL var{Username = PPL;Password = Demo;invFull = true} def start{ for(i = 0:2) log(LOL) log(LOOL) log(LOOOL) next } def main{ obj_rock = findObject(rockType) if(obj_rock != null) log(Mining...) endif }
Refactorings
No refactoring yet !
Chris Jester-Young
June 23, 2008, June 23, 2008 09:18, permalink
I don't have a code refactoring for you at the moment, however, it looks like you're trying to do your own language parsing, which is not easy to do by hand. A much easier way to do parsing is to use a parser generator, such as JavaCC (https://javacc.dev.java.net/), to make a parser for you.
Given the amount of time you have (surely) spent on it, I would suggest spending just a little more time on how to turn your language into a grammar that JavaCC can use. The JavaCC site has extensive documentation on how you can write this grammar. All the best!
pewpew.lazer
June 25, 2008, June 25, 2008 08:54, permalink
Thanks for the help. I have spent many months working on various types of interpreters in numerous languages. This was my first attempt at a single file interpreter, which is not meant to be very complex.
I may use JavaCC in a later project, as for now I can't. Like I said, it's to be converted into a script, to then run a simpler script using my custom language.
Again, thanks for the help though.
Mike K
June 26, 2008, June 26, 2008 20:33, permalink
Well, I guess the biggest thing I see is the a serious lack of dynamics and generics. Granted, I don't know your use case, but I think it would make your code a lot easier to read if you use generic lists/maps/sets. This way you don't have to create huge arrays (and if someone goes over your current limit, the program will not crash).
Also, I dabbled with my own language once. From that experience, I cannot recommend HIGHLY enough the help Regular Expressions were for me. Try them out if you have the time, they will greatly reduce the number of LOC (not to mention make it easier to understand and work with).
Below are the variables I would use along with some sample code. (this is just a quick edit, I'll be back for a longer explanation and more thorough review if you would like; do not expect code to work plug'n'play).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
import java.io.*; import java.lang.Character; // import java.util.HashMap; import javax.swing.*; import java.util.regex; public class Cog extends JFrame { //public static String[] defName = new String[1000]; -- use defs //public static int[] defLine = new int[1000]; -- use defs public static HashMap<String,Integer> defs; //public static int defCount = 0; -- use defs.size() //public static String[] varVal = new String[1000]; -- use vars //public static String[] varName = new String[1000]; -- use vars public static Hashmap<String, String> vars; //-- vars<varName,varVal> //public static int varCount = 0; -- use vars.size() public static int curLine; public static String[] strScript; public static int globI = 0; //replace getDef with defs.get("item"); public static void getDefs() { for (int i = 0; i < strScript.length; i++) { String line = strScript[i].trim(); Matcher match = Pattern.compile("def(.*){").matcher(line); if(match.matches()) defs.put(match.group(1).trim(),i); //groups start at 1... group 0 is the whole matched expression } } }
pewpew.lazer
June 26, 2008, June 26, 2008 23:14, permalink
Thanks a lot, I was definately planning on working with hashmaps, hence the "// import java.util.HashMap;".
That helps a lot, thank you :)
giann
July 4, 2008, July 04, 2008 11:35, permalink
The main problem for me is that your code is made of chained 'if else'. You need to write an automate (don't know the word in english) with states. The classic way of doing it is to use lex/yacc (which uses regexp).
pewpew.lazer
July 5, 2008, July 05, 2008 18:40, permalink
I'm not sure I understand, care to elaborate?
giann
July 5, 2008, July 05, 2008 19:02, permalink
See http://memphis.compilertools.net/interpreter.html for an example of a simple interpreter written with Lex and Yacc.
pewpew.lazer
July 5, 2008, July 05, 2008 20:32, permalink
Ah ok, I get what you mean now.
The only problem is that I can't include external files. It needs to be one single file.
I'm very interested in Lex + YACC for future projects though.
So I was trying to condense a multi file interpreter (for a custom language) into a single file to run as a script inside another program.
Hoping I could get some help cleaning it up a bit.
Sorry for lots of the debug output.