package prc.makedep; import java.util.*; import java.util.regex.*; /** * A class for parsing NWScript files. * * @author Ornedan */ public class NWScript { private static enum STATES{ /** * Normal code, can switch to the other modes from here. */ NORMAL, /** * String mode. Exited by an unescaped " (technically should be ended * by a new line as well, but we assume the code is not that badly fubar'd). */ STRING, /** * Singe line comment, started by //. Exited by a newline. */ SCOMMENT, /** * Multi-line comment. */ MCOMMENT }; private static Matcher matcher = Pattern.compile("#include[ \t\u000B\f\r]*\"(.*)\"").matcher(""); /** * Parses the given source text for #include directives and returns the names of * the files included. * * @param srcText contents of a nwscript source file * @return array of String containing the names of files included by this one */ public static String[] findIncludes(CharSequence srcText){ StringBuffer wip = new StringBuffer(srcText); ArrayList list = new ArrayList(); removeComments(wip); // Parse for remaining #include statements //#include[ \t\x0B\f\r]*"(.*)" matcher.reset(wip); //String debug; while(matcher.find()){ //debug = matcher.group(1); //list.add(debug); list.add(matcher.group(1)); } return list.toArray(new String[0]); } /** * Replaces the contents of comments with spaces. * * @param sbuf Stringbuffer containing nwscript to strip comments from */ private static void removeComments(StringBuffer sbuf){ STATES state = STATES.NORMAL; char prev = '\u0000', cur; boolean evenBSlash = true; for(int i = 0; i < sbuf.length(); i++){ cur = sbuf.charAt(i); switch(state){ case NORMAL: if(prev == '/'){ if(cur == '/'){ state = STATES.SCOMMENT; sbuf.setCharAt(i - 1, ' '); sbuf.setCharAt(i, ' '); } else if(cur == '*'){ state = STATES.MCOMMENT; sbuf.setCharAt(i - 1, ' '); sbuf.setCharAt(i, ' '); // Null current so that /*/ won't get mistakenly detected as having closed cur = ' '; } } else if(cur == '\"') state = STATES.STRING; break; case STRING: if(cur == '\"'){ if(evenBSlash) state = STATES.NORMAL; } else if(cur == '\\') evenBSlash = !evenBSlash; else evenBSlash = true; break; case SCOMMENT: if(cur == '\n') state = STATES.NORMAL; else sbuf.setCharAt(i, ' '); break; case MCOMMENT: if(prev == '*' && cur == '/') state = STATES.NORMAL; sbuf.setCharAt(i, ' '); break; } prev = cur; } } /** * Test main * @param args */ public static void main(String[] args) { findIncludes( "/**\n" + " * Mof! \" \"\n" + " */\n" + "#include \"test\"\n" + "#include \"tset\"\n" + "/*/ */\n"+ "\n"+ "void main()\n"+ "{// Rar!\n"+ " florb(); /* call florb */\n"+ " /* another call */ florb();\n"+ "}\n" ); } }