1 19 20 package org.netbeans.editor.ext; 21 22 import java.util.Arrays ; 23 import java.util.ArrayList ; 24 import java.util.HashMap ; 25 import java.util.StringTokenizer ; 26 import java.util.NoSuchElementException ; 27 import java.io.IOException ; 28 import java.io.File ; 29 import java.io.Reader ; 30 import java.io.FileReader ; 31 32 39 40 public class KeywordMatchGenerator { 41 42 private static final String USAGE 43 = "Usage: java org.netbeans.editor.ext.KeywordMatchGenerator [options]" + " keyword-file [match-function-name]\n\n" + "Options:\n" + " -i Ignore case in matching\n" + " -s Input is in 'input' String or StringBuffer instead of char buffer\n" + "\nGenerator of method that matches" + " the keywords provided in the file.\n" + "Keywords in the file must be separated by spaces or new-lines" + " and they don't need to be sorted.\n"; 53 private static final String UNKNOWN_OPTION = " is unknown option.\n"; 55 public static final String IGNORE_CASE = "-i"; 57 public static final String USE_STRING = "-s"; 59 private static final String DEFAULT_METHOD_NAME = "match"; 61 private static final String [] OPTION_LIST = { IGNORE_CASE, USE_STRING }; 62 63 64 private String kwds[]; 65 66 67 private int maxKwdLen; 68 69 70 private HashMap options = new HashMap (); 71 72 private HashMap kwdConstants = new HashMap (); 73 74 75 private String indent(int cnt) { 76 StringBuffer sb = new StringBuffer (); 77 78 while(cnt-- > 0) { 79 sb.append(" "); } 81 return sb.toString(); 82 } 83 84 protected void initScan(String methodName) { 85 86 if (methodName == null) { 87 methodName = DEFAULT_METHOD_NAME; 88 } 89 90 appendString("\n"); for (int i = 0; i < kwds.length; i++) { 93 appendString(indent(1) + "public static final int " + kwdConstants.get(kwds[i]) + " = " + i + ";\n"); } 96 appendString("\n"); 98 appendString(indent(1) + "public static int "); appendString(methodName); 101 if (options.get(USE_STRING) != null) { 102 appendString("(String buffer, int offset, int len) {\n"); } else { 104 appendString("(char[] buffer, int offset, int len) {\n"); } 106 appendString(indent(2) + "if (len > " + maxKwdLen + ")\n"); appendString(indent(3) + "return -1;\n"); } 109 110 public void scan() { 111 scan(0, kwds.length, 0, 2, 0); 112 } 113 114 protected void finishScan() { 115 appendString(indent(1) + "}\n\n"); } 117 118 public void addOption(String option) { 119 options.put(option, option); 120 } 121 122 protected String getKwdConstantPrefix() { 123 return ""; } 125 126 protected String getKwdConstant(String kwd) { 127 return (String )kwdConstants.get(kwd); 128 } 129 130 protected boolean upperCaseKeyConstants() { 131 return true; 132 } 133 134 135 private void parseKeywords(String s) { 136 ArrayList keyList = new ArrayList (); 137 StringTokenizer strTok = new StringTokenizer (s); 138 139 try { 140 while(true) { 141 String key = strTok.nextToken(); 142 int keyLen = key.length(); 143 maxKwdLen = Math.max(maxKwdLen, keyLen); 144 keyList.add(key); 145 kwdConstants.put(key, getKwdConstantPrefix() 146 + (upperCaseKeyConstants() ? key.toUpperCase() : key)); 147 } 148 } catch(NoSuchElementException e) { 149 } 151 152 kwds = new String [keyList.size()]; 153 keyList.toArray(kwds); 154 Arrays.sort(kwds); 155 } 156 157 protected String getCurrentChar() { 158 boolean useString = (options.get(USE_STRING) != null); 159 boolean ignoreCase = (options.get(IGNORE_CASE) != null); 160 161 if(useString) { 162 return ignoreCase ? "Character.toLowerCase(buffer.charAt(offset++))" : "buffer.charAt(offset++)"; } else { 165 return ignoreCase ? "Character.toLowerCase(buffer[offset++])" : "buffer[offset++]"; } 168 } 169 170 private void appendCheckedReturn(String kwd, int offset, int indent) { 171 appendString(indent(indent) + "return (len == " + kwd.length()); 173 174 int kwdLenM1 = kwd.length() - 1; 175 for(int k = offset; k <= kwdLenM1; k++) { 176 appendString("\n" + indent(indent + 1) + "&& "); appendString(getCurrentChar() + " == '" + kwd.charAt(k) + "'"); } 179 180 appendString(")\n" + indent(indent + 2) + "? " + getKwdConstant(kwd) + " : -1;\n"); } 182 183 protected void appendString(String s) { 184 System.out.print(s); 185 } 186 187 196 private void scan(int indFrom, int indTo, int offset, int indent, int minKwdLen) { 197 int maxLen = 0; 199 for (int i = indFrom; i < indTo; i++) { 200 maxLen = Math.max(maxLen, kwds[i].length()); 201 } 202 203 int same; 204 int minLen; 205 do { 206 minLen = Integer.MAX_VALUE; 207 for (int i = indFrom; i < indTo; i++) { 209 minLen = Math.min(minLen, kwds[i].length()); 210 } 211 212 if (minLen > minKwdLen) { 214 appendString(indent(indent) + "if (len <= " + (minLen - 1) + ")\n"); appendString(indent(indent + 1) + "return -1;\n"); } 217 218 same = 0; 221 boolean stop = false; 222 for (int i = offset; i < minLen; i++) { 223 char c = kwds[indFrom].charAt(i); 224 for (int j = indFrom + 1; j < indTo; j++) { 225 if (kwds[j].charAt(i) != c) { 226 stop = true; 227 break; 228 } 229 } 230 if (stop) { 231 break; 232 } 233 same++; 234 } 235 236 238 if (same > 0) { 240 appendString(indent(indent) + "if ("); for (int i = 0; i < same; i++) { 242 if (i > 0) { 243 appendString(indent(indent + 1) + "|| "); } 245 appendString(getCurrentChar() + " != '" + kwds[indFrom].charAt(offset + i) + "'"); if (i < same - 1) { 247 appendString("\n"); } 249 } 250 appendString(")\n" + indent(indent + 2) + "return -1;\n"); 252 } 253 254 offset += same; 256 257 if (offset == kwds[indFrom].length()) { 260 appendString(indent(indent) + "if (len == " + offset + ")\n"); appendString(indent(indent + 1) + "return " + getKwdConstant(kwds[indFrom]) + ";\n"); indFrom++; if (offset >= minLen) { 265 minLen = offset + 1; 266 } 267 } 268 269 minKwdLen = minLen; 271 } while (same > 0 && indFrom < indTo); 272 273 if (offset < maxLen) { 276 appendString(indent(indent) + "switch (" + getCurrentChar() + ") {\n"); 278 int i = indFrom; 280 while(i < indTo) { 281 char actChar = kwds[i].charAt(offset); 283 appendString(indent(indent + 1) + "case '" + actChar + "':\n"); 285 int subGroupEndInd = i + 1; 287 while(subGroupEndInd < indTo 288 && kwds[subGroupEndInd].length() > offset 289 && kwds[subGroupEndInd].charAt(offset) == actChar 290 ) { 291 subGroupEndInd++; 292 } 293 294 if(subGroupEndInd > i + 1) { scan(i, subGroupEndInd, offset + 1, indent + 2, minLen); 296 } else { appendCheckedReturn(kwds[i], offset + 1, indent + 2); 298 } 299 300 i = subGroupEndInd; 302 } 303 304 appendString(indent(indent + 1) + "default:\n"); appendString(indent(indent + 2) + "return -1;\n"); appendString(indent(indent) + "}\n"); } else { appendString(indent(indent) + "return -1;\n"); } 310 311 } 312 313 314 public static void main(String args[]) { 315 KeywordMatchGenerator km = new KeywordMatchGenerator(); 316 317 int argShift; 319 for (argShift = 0; argShift < args.length; argShift++) { 320 int j; 321 if (args[argShift].charAt(0) != '-') { 322 break; } 324 for (j = 0; j < OPTION_LIST.length; j++) { 325 if (args[argShift].equals(OPTION_LIST[j])) { 326 km.addOption(OPTION_LIST[j]); 327 break; 328 } 329 } 330 if (j == OPTION_LIST.length) { 331 System.err.println("'" + args[argShift] + "'" + UNKNOWN_OPTION); System.err.println(USAGE); 333 return; 334 } 335 } 336 337 if (args.length - argShift < 1) { 339 System.err.println(USAGE); 340 return; 341 } 342 343 String kwds = null; 345 try { 346 File f = new File (args[argShift]); 347 if (!f.exists()) { 348 System.err.println("Non-existent file '" + args[argShift] + "'"); return; 350 } 351 char arr[] = new char[(int)f.length()]; 352 Reader isr = new FileReader (f); 353 354 int n = 0; 355 while (n < f.length()) { 356 int count = isr.read(arr, n, (int)f.length() - n); 357 if (count < 0) 358 break; 359 n += count; 360 } 361 362 kwds = new String (arr); 363 } catch(IOException e) { 364 System.err.println("Cannot read from keyword file '" + args[argShift] + "'"); return; 367 } 368 369 String methodName = null; 371 if (args.length - argShift >= 2) { 372 methodName = args[argShift + 1]; 373 } 374 375 km.parseKeywords(kwds); 377 km.initScan(methodName); 378 km.scan(); 379 km.finishScan(); 380 381 } 382 383 384 } 385 | Popular Tags |