1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util.regex; 27 28 import java.util.HashMap; 29 import java.util.regex.Pattern.CharPredicate; 30 import static java.util.regex.ASCII.*; 31 32 /** 33 * A utility class to print out the pattern node tree. 34 */ 35 36 class PrintPattern { 37 38 private static HashMap<Pattern.Node, Integer> ids = new HashMap<>(); 39 40 private static void print(Pattern.Node node, String text, int depth) { 41 if (!ids.containsKey(node)) 42 ids.put(node, ids.size()); 43 print("%6d:%" + (depth==0? "": depth<<1) + "s<%s>", ids.get(node), "", text); 44 if (ids.containsKey(node.next)) 45 print(" (=>%d)", ids.get(node.next)); 46 print("%n"); 47 } 48 49 private static void print(String s, int depth) { 50 print(" %" + (depth==0?"":depth<<1) + "s<%s>%n", "", s); 51 } 52 53 private static void print(String fmt, Object ... args) { 54 System.err.printf(fmt, args); 55 } 56 57 private static String toStringCPS(int[] cps) { 58 StringBuilder sb = new StringBuilder(cps.length); 59 for (int cp : cps) 60 sb.append(toStringCP(cp)); 61 return sb.toString(); 62 } 63 64 private static String toStringCP(int cp) { 65 return (isPrint(cp) ? "" + (char)cp 66 : "\\u" + Integer.toString(cp, 16)); 67 } 68 69 private static String toStringRange(int min, int max) { 70 if (max == Pattern.MAX_REPS) { 71 if (min == 0) 72 return " * "; 73 else if (min == 1) 74 return " + "; 75 return "{" + min + ", max}"; 76 } 77 return "{" + min + ", " + max + "}"; 78 } 79 80 private static String toStringCtype(int type) { 81 switch(type) { 82 case UPPER: return "ASCII.UPPER"; 83 case LOWER: return "ASCII.LOWER"; 84 case DIGIT: return "ASCII.DIGIT"; 85 case SPACE: return "ASCII.SPACE"; 86 case PUNCT: return "ASCII.PUNCT"; 87 case CNTRL: return "ASCII.CNTRL"; 88 case BLANK: return "ASCII.BLANK"; 89 case UNDER: return "ASCII.UNDER"; 90 case ASCII: return "ASCII.ASCII"; 91 case ALPHA: return "ASCII.ALPHA"; 92 case ALNUM: return "ASCII.ALNUM"; 93 case GRAPH: return "ASCII.GRAPH"; 94 case WORD: return "ASCII.WORD"; 95 case XDIGIT: return "ASCII.XDIGIT"; 96 default: return "ASCII ?"; 97 } 98 } 99 100 private static String toString(Pattern.Node node) { 101 String name = node.getClass().getName(); 102 return name.substring(name.lastIndexOf('$') + 1); 103 } 104 105 static HashMap<CharPredicate, String> pmap; 106 static { 107 pmap = new HashMap<>(); 108 pmap.put(Pattern.ALL(), "All"); 109 pmap.put(Pattern.DOT(), "Dot"); 110 pmap.put(Pattern.UNIXDOT(), "UnixDot"); 111 pmap.put(Pattern.VertWS(), "VertWS"); 112 pmap.put(Pattern.HorizWS(), "HorizWS"); 113 114 pmap.put(CharPredicates.ASCII_DIGIT(), "ASCII.DIGIT"); 115 pmap.put(CharPredicates.ASCII_WORD(), "ASCII.WORD"); 116 pmap.put(CharPredicates.ASCII_SPACE(), "ASCII.SPACE"); 117 } 118 119 static void walk(Pattern.Node node, int depth) { 120 depth++; 121 while(node != null) { 122 String name = toString(node); 123 String str; 124 if (node instanceof Pattern.Prolog) { 125 print(node, name, depth); 126 // print the loop here 127 Pattern.Loop loop = ((Pattern.Prolog)node).loop; 128 name = toString(loop); 129 str = name + " " + toStringRange(loop.cmin, loop.cmax); 130 print(loop, str, depth); 131 walk(loop.body, depth); 132 print("/" + name, depth); 133 node = loop; 134 } else if (node instanceof Pattern.Loop) { 135 return; // stop here, body.next -> loop 136 } else if (node instanceof Pattern.Curly) { 137 Pattern.Curly c = (Pattern.Curly)node; 138 str = "Curly " + c.type + " " + toStringRange(c.cmin, c.cmax); 139 print(node, str, depth); 140 walk(c.atom, depth); 141 print("/Curly", depth); 142 } else if (node instanceof Pattern.GroupCurly) { 143 Pattern.GroupCurly gc = (Pattern.GroupCurly)node; 144 str = "GroupCurly " + gc.groupIndex / 2 + 145 ", " + gc.type + " " + toStringRange(gc.cmin, gc.cmax); 146 print(node, str, depth); 147 walk(gc.atom, depth); 148 print("/GroupCurly", depth); 149 } else if (node instanceof Pattern.GroupHead) { 150 Pattern.GroupHead head = (Pattern.GroupHead)node; 151 Pattern.GroupTail tail = head.tail; 152 print(head, "Group.head " + (tail.groupIndex / 2), depth); 153 walk(head.next, depth); 154 print(tail, "/Group.tail " + (tail.groupIndex / 2), depth); 155 node = tail; 156 } else if (node instanceof Pattern.GroupTail) { 157 return; // stopper 158 } else if (node instanceof Pattern.Ques) { 159 print(node, "Ques " + ((Pattern.Ques)node).type, depth); 160 walk(((Pattern.Ques)node).atom, depth); 161 print("/Ques", depth); 162 } else if (node instanceof Pattern.Branch) { 163 Pattern.Branch b = (Pattern.Branch)node; 164 print(b, name, depth); 165 int i = 0; 166 while (true) { 167 if (b.atoms[i] != null) { 168 walk(b.atoms[i], depth); 169 } else { 170 print(" (accepted)", depth); 171 } 172 if (++i == b.size) 173 break; 174 print("-branch.separator-", depth); 175 } 176 node = b.conn; 177 print(node, "/Branch", depth); 178 } else if (node instanceof Pattern.BranchConn) { 179 return; 180 } else if (node instanceof Pattern.CharProperty) { 181 str = pmap.get(((Pattern.CharProperty)node).predicate); 182 if (str == null) 183 str = toString(node); 184 else 185 str = "Single \"" + str + "\""; 186 print(node, str, depth); 187 } else if (node instanceof Pattern.SliceNode) { 188 str = name + " \"" + 189 toStringCPS(((Pattern.SliceNode)node).buffer) + "\""; 190 print(node, str, depth); 191 } else if (node instanceof Pattern.CharPropertyGreedy) { 192 Pattern.CharPropertyGreedy gcp = (Pattern.CharPropertyGreedy)node; 193 String pstr = pmap.get(gcp.predicate); 194 if (pstr == null) 195 pstr = gcp.predicate.toString(); 196 else 197 pstr = "Single \"" + pstr + "\""; 198 str = name + " " + pstr + ((gcp.cmin == 0) ? "*" : "+"); 199 print(node, str, depth); 200 } else if (node instanceof Pattern.BackRef) { 201 str = "GroupBackRef " + ((Pattern.BackRef)node).groupIndex / 2; 202 print(node, str, depth); 203 } else if (node instanceof Pattern.LastNode) { 204 print(node, "END", depth); 205 } else if (node == Pattern.accept) { 206 return; 207 } else { 208 print(node, name, depth); 209 } 210 node = node.next; 211 } 212 } 213 214 public static void main(String[] args) { 215 Pattern p = Pattern.compile(args[0]); 216 System.out.println(" Pattern: " + p); 217 walk(p.root, 0); 218 } 219 }