static Producer javaTokC_onReader(final Reader r) { final class X implements Producer { new StringBuilder buf; // stores from "i" char c, d, e = 'x'; // just not '\0' *() { // fill c, d and e nc(); nc(); nc(); } // get next character(s) into c, d and e void nc() ctex { c = d; d = e; if (e == '\0') ret; int i = r.read(); e = i < 0 ? '\0' : (char) i; } void ncSave() { if (c != '\0') { buf.append(c); nc(); } } public S next() { // scan for whitespace while (c != '\0') { if (c == ' ' || c == '\t' || c == '\r' || c == '\n') nc(); else if (c == '/' && d == '*') { do nc(); while (c != '\0' && !(c == '*' && d == '/')); nc(); nc(); } else if (c == '/' && d == '/') { do nc(); while (c != '\0' && "\r\n".indexOf(c) < 0); } else break; } if (c == '\0') ret null; // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ncSave(); while (c != '\0') { if (c == opener || c == '\n') { // end at \n to not propagate unclosed string literal errors ncSave(); break; } else if (c == '\\') { ncSave(); ncSave(); } else ncSave(); } } else if (Character.isJavaIdentifierStart(c)) do ncSave(); while (Character.isJavaIdentifierPart(c) || c == '\''); // for stuff like "don't" else if (Character.isDigit(c)) { do ncSave(); while (Character.isDigit(c)); if (c == 'L') ncSave(); // Long constants like 1L } else if (c == '[' && d == '[') { do ncSave(); while (c != '\0' && !(c == ']' && d == ']')); ncSave(); ncSave(); } else if (c == '[' && d == '=' && e == '[') { do ncSave(); while (c != '\0' && !(c == ']' && d == '=' && e == ']')); ncSave(); ncSave(); ncSave(); } else ncSave(); S t = buf.toString(); buf.setLength(0); ret t; } } ret new X; }