/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util.regex; import java.util.HashMap; import java.util.regex.Pattern.CharPredicate; import java.util.regex.CharPredicates; import static java.util.regex.ASCII.*; /** * A utility class to print out the pattern node tree. */ class PrintPattern { private static HashMap ids = new HashMap<>(); private static void print(Pattern.Node node, String text, int depth) { if (!ids.containsKey(node)) ids.put(node, ids.size()); print("%6d:%" + (depth==0? "": depth<<1) + "s<%s>", ids.get(node), "", text); if (ids.containsKey(node.next)) print(" (=>%d)", ids.get(node.next)); print("%n"); } private static void print(String s, int depth) { print(" %" + (depth==0?"":depth<<1) + "s<%s>%n", "", s); } private static void print(String fmt, Object ... args) { System.err.printf(fmt, args); } private static String toStringCPS(int[] cps) { StringBuilder sb = new StringBuilder(cps.length); for (int cp : cps) sb.append(toStringCP(cp)); return sb.toString(); } private static String toStringCP(int cp) { return (isPrint(cp) ? "" + (char)cp : "\\u" + Integer.toString(cp, 16)); } private static String toStringRange(int min, int max) { if (max == Pattern.MAX_REPS) { if (min == 0) return " * "; else if (min == 1) return " + "; return "{" + min + ", max}"; } return "{" + min + ", " + max + "}"; } private static String toStringCtype(int type) { switch(type) { case UPPER: return "ASCII.UPPER"; case LOWER: return "ASCII.LOWER"; case DIGIT: return "ASCII.DIGIT"; case SPACE: return "ASCII.SPACE"; case PUNCT: return "ASCII.PUNCT"; case CNTRL: return "ASCII.CNTRL"; case BLANK: return "ASCII.BLANK"; case UNDER: return "ASCII.UNDER"; case ASCII: return "ASCII.ASCII"; case ALPHA: return "ASCII.ALPHA"; case ALNUM: return "ASCII.ALNUM"; case GRAPH: return "ASCII.GRAPH"; case WORD: return "ASCII.WORD"; case XDIGIT: return "ASCII.XDIGIT"; default: return "ASCII ?"; } } private static String toString(Pattern.Node node) { String name = node.getClass().getName(); return name.substring(name.lastIndexOf('$') + 1); } static HashMap pmap; static { pmap = new HashMap<>(); pmap.put(Pattern.ALL, "All"); pmap.put(Pattern.DOT, "Dot"); pmap.put(Pattern.UNIXDOT, "UnixDot"); pmap.put(Pattern.VertWS, "VertWS"); pmap.put(Pattern.HorizWS, "HorizWS"); pmap.put(CharPredicates.ASCII_DIGIT, "ASCII.DIGIT"); pmap.put(CharPredicates.ASCII_WORD, "ASCII.WORD"); pmap.put(CharPredicates.ASCII_SPACE, "ASCII.SPACE"); } static void walk(Pattern.Node node, int depth) { depth++; while(node != null) { String name = toString(node); String str; if (node instanceof Pattern.Prolog) { print(node, name, depth); // print the loop here Pattern.Loop loop = ((Pattern.Prolog)node).loop; name = toString(loop); str = name + " " + toStringRange(loop.cmin, loop.cmax); print(loop, str, depth); walk(loop.body, depth); print("/" + name, depth); node = loop; } else if (node instanceof Pattern.Loop) { return; // stop here, body.next -> loop } else if (node instanceof Pattern.Curly) { Pattern.Curly c = (Pattern.Curly)node; str = "Curly " + c.type + " " + toStringRange(c.cmin, c.cmax); print(node, str, depth); walk(c.atom, depth); print("/Curly", depth); } else if (node instanceof Pattern.GroupCurly) { Pattern.GroupCurly gc = (Pattern.GroupCurly)node; str = "GroupCurly " + gc.groupIndex / 2 + ", " + gc.type + " " + toStringRange(gc.cmin, gc.cmax); print(node, str, depth); walk(gc.atom, depth); print("/GroupCurly", depth); } else if (node instanceof Pattern.GroupHead) { Pattern.GroupHead head = (Pattern.GroupHead)node; Pattern.GroupTail tail = head.tail; print(head, "Group.head " + (tail.groupIndex / 2), depth); walk(head.next, depth); print(tail, "/Group.tail " + (tail.groupIndex / 2), depth); node = tail; } else if (node instanceof Pattern.GroupTail) { return; // stopper } else if (node instanceof Pattern.Ques) { print(node, "Ques " + ((Pattern.Ques)node).type, depth); walk(((Pattern.Ques)node).atom, depth); print("/Ques", depth); } else if (node instanceof Pattern.Branch) { Pattern.Branch b = (Pattern.Branch)node; print(b, name, depth); int i = 0; while (true) { if (b.atoms[i] != null) { walk(b.atoms[i], depth); } else { print(" (accepted)", depth); } if (++i == b.size) break; print("-branch.separator-", depth); } node = b.conn; print(node, "/Branch", depth); } else if (node instanceof Pattern.BranchConn) { return; } else if (node instanceof Pattern.CharProperty) { str = pmap.get(((Pattern.CharProperty)node).predicate); if (str == null) str = toString(node); else str = "Single \"" + str + "\""; print(node, str, depth); } else if (node instanceof Pattern.SliceNode) { str = name + " \"" + toStringCPS(((Pattern.SliceNode)node).buffer) + "\""; print(node, str, depth); } else if (node instanceof Pattern.CharPropertyGreedy) { Pattern.CharPropertyGreedy gcp = (Pattern.CharPropertyGreedy)node; String pstr = pmap.get(gcp.predicate); if (pstr == null) pstr = gcp.predicate.toString(); else pstr = "Single \"" + pstr + "\""; str = name + " " + pstr + ((gcp.cmin == 0) ? "*" : "+"); print(node, str, depth); } else if (node instanceof Pattern.BackRef) { str = "GroupBackRef " + ((Pattern.BackRef)node).groupIndex / 2; print(node, str, depth); } else if (node instanceof Pattern.LastNode) { print(node, "END", depth); } else if (node == Pattern.accept) { return; } else { print(node, name, depth); } node = node.next; } } public static void main(String[] args) { Pattern p = Pattern.compile(args[0]); System.out.println(" Pattern: " + p); walk(p.root, 0); } }