| 1 | /* |
| 2 | ** $Id: lpprint.c,v 1.10 2016/09/13 16:06:03 roberto Exp $ |
| 3 | ** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) |
| 4 | */ |
| 5 | |
| 6 | #include <ctype.h> |
| 7 | #include <limits.h> |
| 8 | #include <stdio.h> |
| 9 | |
| 10 | |
| 11 | #include "lptypes.h" |
| 12 | #include "lpprint.h" |
| 13 | #include "lpcode.h" |
| 14 | |
| 15 | |
| 16 | #if defined(LPEG_DEBUG) |
| 17 | |
| 18 | /* |
| 19 | ** {====================================================== |
| 20 | ** Printing patterns (for debugging) |
| 21 | ** ======================================================= |
| 22 | */ |
| 23 | |
| 24 | |
| 25 | void printcharset (const byte *st) { |
| 26 | int i; |
| 27 | printf("[" ); |
| 28 | for (i = 0; i <= UCHAR_MAX; i++) { |
| 29 | int first = i; |
| 30 | while (testchar(st, i) && i <= UCHAR_MAX) i++; |
| 31 | if (i - 1 == first) /* unary range? */ |
| 32 | printf("(%02x)" , first); |
| 33 | else if (i - 1 > first) /* non-empty range? */ |
| 34 | printf("(%02x-%02x)" , first, i - 1); |
| 35 | } |
| 36 | printf("]" ); |
| 37 | } |
| 38 | |
| 39 | |
| 40 | static const char *capkind (int kind) { |
| 41 | const char *const modes[] = { |
| 42 | "close" , "position" , "constant" , "backref" , |
| 43 | "argument" , "simple" , "table" , "function" , |
| 44 | "query" , "string" , "num" , "substitution" , "fold" , |
| 45 | "runtime" , "group" }; |
| 46 | return modes[kind]; |
| 47 | } |
| 48 | |
| 49 | |
| 50 | static void printjmp (const Instruction *op, const Instruction *p) { |
| 51 | printf("-> %d" , (int)(p + (p + 1)->offset - op)); |
| 52 | } |
| 53 | |
| 54 | |
| 55 | void printinst (const Instruction *op, const Instruction *p) { |
| 56 | const char *const names[] = { |
| 57 | "any" , "char" , "set" , |
| 58 | "testany" , "testchar" , "testset" , |
| 59 | "span" , "behind" , |
| 60 | "ret" , "end" , |
| 61 | "choice" , "jmp" , "call" , "open_call" , |
| 62 | "commit" , "partial_commit" , "back_commit" , "failtwice" , "fail" , "giveup" , |
| 63 | "fullcapture" , "opencapture" , "closecapture" , "closeruntime" |
| 64 | }; |
| 65 | printf("%02ld: %s " , (long)(p - op), names[p->i.code]); |
| 66 | switch ((Opcode)p->i.code) { |
| 67 | case IChar: { |
| 68 | printf("'%c'" , p->i.aux); |
| 69 | break; |
| 70 | } |
| 71 | case ITestChar: { |
| 72 | printf("'%c'" , p->i.aux); printjmp(op, p); |
| 73 | break; |
| 74 | } |
| 75 | case IFullCapture: { |
| 76 | printf("%s (size = %d) (idx = %d)" , |
| 77 | capkind(getkind(p)), getoff(p), p->i.key); |
| 78 | break; |
| 79 | } |
| 80 | case IOpenCapture: { |
| 81 | printf("%s (idx = %d)" , capkind(getkind(p)), p->i.key); |
| 82 | break; |
| 83 | } |
| 84 | case ISet: { |
| 85 | printcharset((p+1)->buff); |
| 86 | break; |
| 87 | } |
| 88 | case ITestSet: { |
| 89 | printcharset((p+2)->buff); printjmp(op, p); |
| 90 | break; |
| 91 | } |
| 92 | case ISpan: { |
| 93 | printcharset((p+1)->buff); |
| 94 | break; |
| 95 | } |
| 96 | case IOpenCall: { |
| 97 | printf("-> %d" , (p + 1)->offset); |
| 98 | break; |
| 99 | } |
| 100 | case IBehind: { |
| 101 | printf("%d" , p->i.aux); |
| 102 | break; |
| 103 | } |
| 104 | case IJmp: case ICall: case ICommit: case IChoice: |
| 105 | case IPartialCommit: case IBackCommit: case ITestAny: { |
| 106 | printjmp(op, p); |
| 107 | break; |
| 108 | } |
| 109 | default: break; |
| 110 | } |
| 111 | printf("\n" ); |
| 112 | } |
| 113 | |
| 114 | |
| 115 | void printpatt (Instruction *p, int n) { |
| 116 | Instruction *op = p; |
| 117 | while (p < op + n) { |
| 118 | printinst(op, p); |
| 119 | p += sizei(p); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | |
| 124 | #if defined(LPEG_DEBUG) |
| 125 | static void printcap (Capture *cap) { |
| 126 | printf("%s (idx: %d - size: %d) -> %p\n" , |
| 127 | capkind(cap->kind), cap->idx, cap->siz, cap->s); |
| 128 | } |
| 129 | |
| 130 | |
| 131 | void printcaplist (Capture *cap, Capture *limit) { |
| 132 | printf(">======\n" ); |
| 133 | for (; cap->s && (limit == NULL || cap < limit); cap++) |
| 134 | printcap(cap); |
| 135 | printf("=======\n" ); |
| 136 | } |
| 137 | #endif |
| 138 | |
| 139 | /* }====================================================== */ |
| 140 | |
| 141 | |
| 142 | /* |
| 143 | ** {====================================================== |
| 144 | ** Printing trees (for debugging) |
| 145 | ** ======================================================= |
| 146 | */ |
| 147 | |
| 148 | static const char *tagnames[] = { |
| 149 | "char" , "set" , "any" , |
| 150 | "true" , "false" , |
| 151 | "rep" , |
| 152 | "seq" , "choice" , |
| 153 | "not" , "and" , |
| 154 | "call" , "opencall" , "rule" , "grammar" , |
| 155 | "behind" , |
| 156 | "capture" , "run-time" |
| 157 | }; |
| 158 | |
| 159 | |
| 160 | void printtree (TTree *tree, int ident) { |
| 161 | int i; |
| 162 | for (i = 0; i < ident; i++) printf(" " ); |
| 163 | printf("%s" , tagnames[tree->tag]); |
| 164 | switch (tree->tag) { |
| 165 | case TChar: { |
| 166 | int c = tree->u.n; |
| 167 | if (isprint(c)) |
| 168 | printf(" '%c'\n" , c); |
| 169 | else |
| 170 | printf(" (%02X)\n" , c); |
| 171 | break; |
| 172 | } |
| 173 | case TSet: { |
| 174 | printcharset(treebuffer(tree)); |
| 175 | printf("\n" ); |
| 176 | break; |
| 177 | } |
| 178 | case TOpenCall: case TCall: { |
| 179 | assert(sib2(tree)->tag == TRule); |
| 180 | printf(" key: %d (rule: %d)\n" , tree->key, sib2(tree)->cap); |
| 181 | break; |
| 182 | } |
| 183 | case TBehind: { |
| 184 | printf(" %d\n" , tree->u.n); |
| 185 | printtree(sib1(tree), ident + 2); |
| 186 | break; |
| 187 | } |
| 188 | case TCapture: { |
| 189 | printf(" kind: '%s' key: %d\n" , capkind(tree->cap), tree->key); |
| 190 | printtree(sib1(tree), ident + 2); |
| 191 | break; |
| 192 | } |
| 193 | case TRule: { |
| 194 | printf(" n: %d key: %d\n" , tree->cap, tree->key); |
| 195 | printtree(sib1(tree), ident + 2); |
| 196 | break; /* do not print next rule as a sibling */ |
| 197 | } |
| 198 | case TGrammar: { |
| 199 | TTree *rule = sib1(tree); |
| 200 | printf(" %d\n" , tree->u.n); /* number of rules */ |
| 201 | for (i = 0; i < tree->u.n; i++) { |
| 202 | printtree(rule, ident + 2); |
| 203 | rule = sib2(rule); |
| 204 | } |
| 205 | assert(rule->tag == TTrue); /* sentinel */ |
| 206 | break; |
| 207 | } |
| 208 | default: { |
| 209 | int sibs = numsiblings[tree->tag]; |
| 210 | printf("\n" ); |
| 211 | if (sibs >= 1) { |
| 212 | printtree(sib1(tree), ident + 2); |
| 213 | if (sibs >= 2) |
| 214 | printtree(sib2(tree), ident + 2); |
| 215 | } |
| 216 | break; |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | |
| 222 | void printktable (lua_State *L, int idx) { |
| 223 | int n, i; |
| 224 | lua_getuservalue(L, idx); |
| 225 | if (lua_isnil(L, -1)) /* no ktable? */ |
| 226 | return; |
| 227 | n = lua_rawlen(L, -1); |
| 228 | printf("[" ); |
| 229 | for (i = 1; i <= n; i++) { |
| 230 | printf("%d = " , i); |
| 231 | lua_rawgeti(L, -1, i); |
| 232 | if (lua_isstring(L, -1)) |
| 233 | printf("%s " , lua_tostring(L, -1)); |
| 234 | else |
| 235 | printf("%s " , lua_typename(L, lua_type(L, -1))); |
| 236 | lua_pop(L, 1); |
| 237 | } |
| 238 | printf("]\n" ); |
| 239 | /* leave ktable at the stack */ |
| 240 | } |
| 241 | |
| 242 | /* }====================================================== */ |
| 243 | |
| 244 | #endif |
| 245 | |