PageRenderTime 359ms CodeModel.GetById 56ms app.highlight 251ms RepoModel.GetById 13ms app.codeStats 1ms

/src/ikj/main/org/jregex/Term.java

https://github.com/olabini/ioke
Java | 2184 lines | 1768 code | 216 blank | 200 comment | 145 complexity | 15c7d248b934c305aaa85190dc8ee590 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * Copyright (c) 2001, Sergey A. Samokhodkin
   3 * All rights reserved.
   4 *
   5 * Redistribution and use in source and binary forms, with or without modification,
   6 * are permitted provided that the following conditions are met:
   7 *
   8 * - Redistributions of source code must retain the above copyright notice,
   9 * this list of conditions and the following disclaimer.
  10 * - Redistributions in binary form
  11 * must reproduce the above copyright notice, this list of conditions and the following
  12 * disclaimer in the documentation and/or other materials provided with the distribution.
  13 * - Neither the name of jregex nor the names of its contributors may be used
  14 * to endorse or promote products derived from this software without specific prior
  15 * written permission.
  16 *
  17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20 * IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  25 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26 *
  27 * @version 1.2_01
  28 */
  29
  30package org.jregex;
  31
  32import java.util.*;
  33
  34class Term implements REFlags{
  35   public enum TermType {
  36       //runtime Term types
  37       CHAR, BITSET, BITSET2, ANY_CHAR, ANY_CHAR_NE,
  38
  39       REG, REG_I, FIND, FINDREG, SUCCESS,
  40
  41       /*optimization-transparent types*/
  42       BOUNDARY, DIRECTION, UBOUNDARY, UDIRECTION,
  43
  44       GROUP_IN, GROUP_OUT, VOID,
  45
  46       START, END, END_EOL, LINE_START, LINE_END, LAST_MATCH_END,
  47
  48       CNT_SET_0, CNT_INC, CNT_GT_EQ, READ_CNT_LT,
  49
  50       // CTSTORE_CRINC: store on 'actual' search entry
  51       CRSTORE_CRINC, CR_SET_0, CR_LT, CR_GT_EQ,
  52
  53       /*optimization-nontransparent types*/
  54       BRANCH, BRANCH_STORE_CNT, BRANCH_STORE_CNT_AUX1,
  55
  56       // INDEPENDENT_IN: functionally the same as NLOOKAHEAD_IN
  57       PLOOKAHEAD_IN, PLOOKAHEAD_OUT, NLOOKAHEAD_IN, NLOOKAHEAD_OUT, PLOOKBEHIND_IN,
  58       PLOOKBEHIND_OUT, NLOOKBEHIND_IN, NLOOKBEHIND_OUT, INDEPENDENT_IN, INDEPENDENT_OUT,
  59
  60       REPEAT_0_INF, REPEAT_MIN_INF, REPEAT_MIN_MAX, REPEAT_REG_MIN_INF, REPEAT_REG_MIN_MAX,
  61
  62       BACKTRACK_0, BACKTRACK_MIN, BACKTRACK_FIND_MIN, BACKTRACK_FINDREG_MIN, BACKTRACK_REG_MIN,
  63
  64       MEMREG_CONDITION, LOOKAHEAD_CONDITION_IN, LOOKAHEAD_CONDITION_OUT, LOOKBEHIND_CONDITION_IN,
  65       LOOKBEHIND_CONDITION_OUT
  66   }
  67
  68   // compiletime: length of vars[] (see makeTree())
  69   static final int VARS_LENGTH=4;
  70
  71   // compiletime variable indicies:
  72   private static final int MEMREG_COUNT=0;    //refers current memreg index
  73   private static final int CNTREG_COUNT=1;   //refers current counters number
  74   private static final int DEPTH=2;      //refers current depth: (((depth=3)))
  75   private static final int LOOKAHEAD_COUNT=3;    //refers current memreg index
  76
  77   private static final int LIMITS_LENGTH=3;
  78   private static final int LIMITS_PARSE_RESULT_INDEX=2;
  79   private static final int LIMITS_OK=1;
  80   private static final int LIMITS_FAILURE=2;
  81
  82   //static CustomParser[] customParsers=new CustomParser[256];
  83
  84   // **** CONTROL FLOW ****
  85
  86   // next-to-execute and next-if-failed commands;
  87   Term next,failNext;
  88
  89   // **** TYPES ****
  90
  91   TermType type=TermType.VOID;
  92   boolean inverse;
  93
  94   // used with type=CHAR
  95   char c;
  96
  97   // used with type=FIND
  98   int distance;
  99   boolean eat;
 100
 101   // used with type=BITSET(2);
 102   boolean[] bitset;
 103   boolean[][] bitset2;
 104   boolean[] categoryBitset;  //types(unicode categories)
 105
 106   // used with type=BALANCE;
 107   char[] brackets;
 108
 109   // used for optimization with type=BITSET,BITSET2
 110   int weight;
 111
 112   // **** MEMORISATION ****
 113
 114   // memory slot, used with type=REG,GROUP_IN,GROUP_OUT
 115   int memreg=-1;
 116
 117
 118   // **** COUNTERS ****
 119
 120   // max|min number of iterations
 121   // used with CNT_GT_EQ ,REPEAT_* etc.;
 122   int minCount,maxCount;
 123
 124   // used with REPEAT_*,REPEAT_REG_*;
 125   Term target;
 126
 127   // a counter slot to increment & compare with maxCount (CNT_INC etc.);
 128   int cntreg=0;
 129
 130   // lookahead group id;
 131   int lookaheadId;
 132
 133   // **** COMPILE HELPERS ****
 134
 135   protected Term prev,in,out,out1,first,current;
 136
 137   //new!!
 138   protected Term branchOut;
 139
 140   //protected  boolean newBranch=false,closed=false;
 141   //protected  boolean newBranch=false;
 142
 143   //for debugging
 144   static int instances;
 145   int instanceNum;
 146
 147   Term(){
 148      //for debugging
 149      instanceNum=instances;
 150      instances++;
 151      in=out=this;
 152   }
 153
 154   Term(TermType type){
 155      this();
 156      this.type=type;
 157   }
 158
 159   static void makeTree(String s, int flags,Pattern re) throws PatternSyntaxException{
 160      char[] data=s.toCharArray();
 161      makeTree(data,0,data.length,flags,re);
 162   }
 163
 164   static void makeTree(char[] data,int offset,int end,
 165         int flags,Pattern re) throws PatternSyntaxException{
 166      // memreg,counter,depth,lookahead
 167      int[] vars={1,0,0,0}; //don't use counters[0]
 168
 169      //collect iterators for subsequent optimization
 170      List iterators=new ArrayList();
 171      Map groupNames=new LinkedHashMap();
 172
 173      Pretokenizer t=new Pretokenizer(data,offset,end);
 174      Term term=makeTree(t,data,vars,flags,new Group(),iterators,groupNames);
 175      // term=(0-...-0)
 176
 177      // convert closing outer bracket into success term
 178      term.out.type=TermType.SUCCESS;
 179      // term=(0-...-!!!
 180
 181      //throw out opening bracket
 182      Term first=term.next;
 183      // term=...-!!!
 184
 185      // Optimisation:
 186      Term optimized=first;
 187      Optimizer opt=Optimizer.find(first);
 188      if(opt!=null) optimized=opt.makeFirst(first);
 189
 190      java.util.Iterator en=iterators.iterator();
 191      while(en.hasNext()){
 192         Iterator i=(Iterator)en.next();
 193         i.optimize();
 194      }
 195      // ===
 196
 197      re.root=optimized;
 198      re.root0=first;
 199      re.memregs=vars[MEMREG_COUNT];
 200      re.counters=vars[CNTREG_COUNT];
 201      re.lookaheads=vars[LOOKAHEAD_COUNT];
 202      re.namedGroupMap=groupNames;
 203   }
 204
 205   private static Term makeTree(Pretokenizer t,char[] data,int[] vars,
 206         int flags,Term term,List iterators,Map groupNames) throws PatternSyntaxException{
 207//System.out.println("Term.makeTree(): flags="+flags);
 208      if(vars.length!=VARS_LENGTH) throw new IllegalArgumentException("vars.length should be "+VARS_LENGTH+", not "+vars.length);
 209      //Term term=new Term(isMemReg? vars[MEMREG_COUNT]: -1);
 210      // use memreg 0 as unsignificant
 211      //Term term=new Group(isMemReg? vars[MEMREG_COUNT]: 0);
 212      while(true){
 213         t.next();
 214         term.append(t.tOffset,t.tOutside,data,vars,flags,iterators,groupNames);
 215         switch(t.ttype){
 216            case Pretokenizer.FLAGS:
 217               flags=t.flags(flags);
 218               continue;
 219            case Pretokenizer.CLASS_GROUP:
 220               t.next();
 221               Term clg=new Term();
 222               CharacterClass.parseGroup(data,t.tOffset,t.tOutside,clg,
 223                               (flags&IGNORE_CASE)>0, (flags&IGNORE_SPACES)>0,
 224                               (flags&UNICODE)>0, (flags&XML_SCHEMA)>0);
 225               term.append(clg);
 226               continue;
 227            case Pretokenizer.PLAIN_GROUP:
 228               vars[DEPTH]++;
 229//System.out.println("PLAIN_GROUP, t.tOffset="+t.tOffset+", t.tOutside="+t.tOutside+", t.flags("+flags+")="+t.flags(flags));
 230               term.append(makeTree(t,data,vars,t.flags(flags),new Group(),iterators,groupNames));
 231               break;
 232            case Pretokenizer.NAMED_GROUP:
 233               String gname=t.groupName;
 234               int id;
 235               if(Character.isDigit(gname.charAt(0))){
 236                  try{
 237                     id=Integer.parseInt(gname);
 238                  }
 239                  catch(NumberFormatException e){
 240                     throw new PatternSyntaxException("group name starts with digit but is not a number");
 241                  }
 242                  if(groupNames.containsValue(new Integer(id))){
 243                     if(t.groupDeclared) throw new PatternSyntaxException("group redeclaration: "+gname+"; use ({=id}...) for multiple group assignments");
 244                  }
 245                  if(vars[MEMREG_COUNT]<=id)vars[MEMREG_COUNT]=id+1;
 246               }
 247               else{
 248                  Integer no=(Integer)groupNames.get(gname);
 249                  if(no==null){
 250                     id=vars[MEMREG_COUNT]++;
 251                     groupNames.put(t.groupName,new Integer(id));
 252                  }
 253                  else{
 254                     if(t.groupDeclared) throw new PatternSyntaxException("group redeclaration "+gname+"; use ({=name}...) for group reassignments");
 255                     id=no.intValue();
 256                  }
 257               }
 258               vars[DEPTH]++;
 259               term.append(makeTree(t,data,vars,flags,new Group(id),iterators,groupNames));
 260               break;
 261            case '(':
 262               vars[DEPTH]++;
 263               term.append(makeTree(t,data,vars,flags,new Group(vars[MEMREG_COUNT]++),iterators,groupNames));
 264               break;
 265            case Pretokenizer.POS_LOOKAHEAD:
 266               vars[DEPTH]++;
 267               term.append(makeTree(t,data,vars,flags,new Lookahead(vars[LOOKAHEAD_COUNT]++,true),iterators,groupNames));
 268               break;
 269            case Pretokenizer.NEG_LOOKAHEAD:
 270               vars[DEPTH]++;
 271               term.append(makeTree(t,data,vars,flags,new Lookahead(vars[LOOKAHEAD_COUNT]++,false),iterators,groupNames));
 272               break;
 273            case Pretokenizer.POS_LOOKBEHIND:
 274               vars[DEPTH]++;
 275               term.append(makeTree(t,data,vars,flags,new Lookbehind(vars[LOOKAHEAD_COUNT]++,true),iterators,groupNames));
 276               break;
 277            case Pretokenizer.NEG_LOOKBEHIND:
 278               vars[DEPTH]++;
 279               term.append(makeTree(t,data,vars,flags,new Lookbehind(vars[LOOKAHEAD_COUNT]++,false),iterators,groupNames));
 280               break;
 281            case Pretokenizer.INDEPENDENT_REGEX:
 282               vars[DEPTH]++;
 283               term.append(makeTree(t,data,vars,flags,new IndependentGroup(vars[LOOKAHEAD_COUNT]++),iterators,groupNames));
 284               break;
 285            case Pretokenizer.CONDITIONAL_GROUP:
 286               vars[DEPTH]++;
 287               t.next();
 288               Term fork=null;
 289               boolean positive=true;
 290               switch(t.ttype){
 291                  case Pretokenizer.NEG_LOOKAHEAD:
 292                     positive=false;
 293                  case Pretokenizer.POS_LOOKAHEAD:
 294                     vars[DEPTH]++;
 295                     Lookahead la=new Lookahead(vars[LOOKAHEAD_COUNT]++,positive);
 296                     makeTree(t,data,vars,flags,la,iterators,groupNames);
 297                     fork=new ConditionalExpr(la);
 298                     break;
 299                  case Pretokenizer.NEG_LOOKBEHIND:
 300                     positive=false;
 301                  case Pretokenizer.POS_LOOKBEHIND:
 302                     vars[DEPTH]++;
 303                     Lookbehind lb=new Lookbehind(vars[LOOKAHEAD_COUNT]++,positive);
 304                     makeTree(t,data,vars,flags,lb,iterators,groupNames);
 305                     fork=new ConditionalExpr(lb);
 306                     break;
 307                  case '(':
 308                     t.next();
 309                     if(t.ttype!=')') throw new PatternSyntaxException("malformed condition");
 310                     int memregNo;
 311                     if(Character.isDigit(data[t.tOffset])) memregNo=makeNumber(t.tOffset,t.tOutside,data);
 312                     else{
 313                        String gn=new String(data,t.tOffset,t.tOutside-t.tOffset);
 314                        Integer gno=(Integer)groupNames.get(gn);
 315                        if(gno==null) throw new PatternSyntaxException("unknown group name in conditional expr.: "+gn);
 316                        memregNo=gno.intValue();
 317                     }
 318                     fork=new ConditionalExpr(memregNo);
 319                     break;
 320                  default:
 321                     throw new PatternSyntaxException("malformed conditional expression: "+t.ttype+" '"+(char)t.ttype+"'");
 322               }
 323               term.append(makeTree(t,data,vars,flags,fork,iterators,groupNames));
 324               break;
 325            case '|':
 326               term.newBranch();
 327               break;
 328            case Pretokenizer.END:
 329               if(vars[DEPTH]>0) throw new PatternSyntaxException("unbalanced parenthesis");
 330               term.close();
 331               return term;
 332            case ')':
 333               if(vars[DEPTH]<=0) throw new PatternSyntaxException("unbalanced parenthesis");
 334               term.close();
 335               vars[DEPTH]--;
 336               return term;
 337            case Pretokenizer.COMMENT:
 338               while(t.ttype!=')') t.next();
 339               continue;
 340            default:
 341               throw new PatternSyntaxException("unknown token type: "+t.ttype);
 342         }
 343      }
 344   }
 345
 346   static int makeNumber(int off, int out, char[] data){
 347      int n=0;
 348      for(int i=off;i<out;i++){
 349         int d=data[i]-'0';
 350         if(d<0 || d>9) return -1;
 351         n*=10;
 352         n+=d;
 353      }
 354      return n;
 355   }
 356
 357   protected void append(int offset,int end,char[] data,
 358         int[] vars,int flags,List iterators,Map gmap) throws PatternSyntaxException{
 359//System.out.println("append("+new String(data,offset,end-offset)+")");
 360//System.out.println("current="+this.current);
 361      int[] limits=new int[3];
 362      int i=offset;
 363      Term tmp,current=this.current;
 364      while(i<end){
 365         char c=data[i];
 366         boolean greedy=true;
 367         switch(c){
 368            //operations
 369            case '*':
 370               if(current==null) throw new PatternSyntaxException("missing term before *");
 371               i++;
 372               if(i<end){
 373                   switch(data[i]) {
 374                   case '?':
 375                       greedy^=true;
 376                       i++;
 377                       break;
 378                   case '*':
 379                   case '+':
 380                       throw new PatternSyntaxException("nested *?+ in regexp");
 381                   }
 382               }
 383               tmp=greedy? makeGreedyStar(vars,current,iterators):
 384                             makeLazyStar(vars,current);
 385               current=replaceCurrent(tmp);
 386               break;
 387
 388            case '+':
 389               if(current==null) throw new PatternSyntaxException("missing term before +");
 390               i++;
 391               if(i<end){
 392                   switch(data[i]) {
 393                   case '?':
 394                       greedy^=true;
 395                       i++;
 396                       break;
 397                   case '*':
 398                   case '+':
 399                       throw new PatternSyntaxException("nested *?+ in regexp");
 400                   }
 401               }
 402               tmp=greedy? makeGreedyPlus(vars,current,iterators):
 403                               makeLazyPlus(vars,current);
 404               current=replaceCurrent(tmp);
 405               break;
 406
 407            case '?':
 408               if(current==null) throw new PatternSyntaxException("missing term before ?");
 409               i++;
 410               if(i<end){
 411                   switch(data[i]) {
 412                   case '?':
 413                       greedy^=true;
 414                       i++;
 415                       break;
 416                   case '*':
 417                   case '+':
 418                       throw new PatternSyntaxException("nested *?+ in regexp");
 419                   }
 420               }
 421
 422               tmp=greedy? makeGreedyQMark(vars,current):
 423                               makeLazyQMark(vars,current);
 424               current=replaceCurrent(tmp);
 425               break;
 426
 427            case '{':
 428               limits[0]=0;
 429               limits[1]=-1;
 430               int le=parseLimits(i+1,end,data,limits);
 431               if(limits[LIMITS_PARSE_RESULT_INDEX]==LIMITS_OK){ //parse ok
 432                  if(current==null) throw new PatternSyntaxException("missing term before {}");
 433                  i=le;
 434                  if(i<end && data[i]=='?'){
 435                     greedy^=true;
 436                     i++;
 437                  }
 438                  tmp=greedy? makeGreedyLimits(vars,current,limits,iterators):
 439                              makeLazyLimits(vars,current,limits);
 440                  current=replaceCurrent(tmp);
 441                  break;
 442               }
 443               else{ //unicode class or named backreference
 444                  if(data[i+1]=='\\'){ //'{\name}' - backreference
 445                     int p=i+2;
 446                     if(p==end) throw new PatternSyntaxException("'group_id' expected");
 447                     while(Character.isWhitespace(data[p])){
 448                        p++;
 449                        if(p==end) throw new PatternSyntaxException("'group_id' expected");
 450                     }
 451                     BackReference br=new BackReference(-1,(flags&IGNORE_CASE)>0);
 452                     i=parseGroupId(data,p,end,br,gmap);
 453                     current=append(br);
 454                     continue;
 455                  }
 456                  else{
 457                     Term t=new Term();
 458                     i=CharacterClass.parseName(data,i,end,t,false,(flags&IGNORE_SPACES)>0);
 459                     current=append(t);
 460                     continue;
 461                  }
 462               }
 463
 464            case ' ':
 465            case '\t':
 466            case '\r':
 467            case '\n':
 468               if((flags&IGNORE_SPACES)>0){
 469                  i++;
 470                  continue;
 471               }
 472               //else go on as default
 473
 474            //symbolic items
 475            default:
 476               tmp=new Term();
 477               i=parseTerm(data,i,end,tmp,flags);
 478
 479               if(tmp.type==TermType.END && i<end){
 480                   if((flags&IGNORE_SPACES)>0) {
 481                       i++;
 482                       while(i<end) {
 483                           c=data[i];
 484                           switch(c){
 485                           case ' ':
 486                           case '\t':
 487                           case '\r':
 488                           case '\n':
 489                               i++;
 490                               continue;
 491                           default:
 492                               throw new PatternSyntaxException("'$' is not a last term in the group: <"+new String(data,offset,end-offset)+">");
 493                           }
 494                       }
 495                   } else {
 496                       throw new PatternSyntaxException("'$' is not a last term in the group: <"+new String(data,offset,end-offset)+">");
 497                   }
 498               }
 499               //"\A"
 500               //if(tmp.type==START && i>(offset+1)){
 501               //   throw new PatternSyntaxException("'^' is not a first term in the group: <"+new String(data,offset,end-offset)+">");
 502               //}
 503               current=append(tmp);
 504               break;
 505         }
 506//System.out.println("next term: "+next);
 507//System.out.println("  next.out="+next.out);
 508//System.out.println("  next.out1="+next.out1);
 509//System.out.println("  next.branchOut="+next.branchOut);
 510      }
 511//System.out.println(in.toStringAll());
 512//System.out.println("current="+current);
 513//System.out.println();
 514   }
 515
 516
 517   private static int parseGroupId(char[] data, int i, int end, Term term, Map gmap) throws PatternSyntaxException{
 518      int id;
 519      int nstart=i;
 520      if(Character.isDigit(data[i])){
 521         while(Character.isDigit(data[i])){
 522            i++;
 523            if(i==end) throw new PatternSyntaxException("group_id expected");
 524         }
 525         id=makeNumber(nstart,i,data);
 526      }
 527      else{
 528         while(Character.isJavaIdentifierPart(data[i])){
 529            i++;
 530            if(i==end) throw new PatternSyntaxException("group_id expected");
 531         }
 532         String s=new String(data,nstart,i-nstart);
 533         Integer no=(Integer)gmap.get(s);
 534         if(no==null)throw new PatternSyntaxException("backreference to unknown group: "+s);
 535         id=no.intValue();
 536      }
 537      while(Character.isWhitespace(data[i])){
 538         i++;
 539         if(i==end) throw new PatternSyntaxException("'}' expected");
 540      }
 541
 542      int c=data[i++];
 543
 544      if(c!='}') throw new PatternSyntaxException("'}' expected");
 545
 546      term.memreg=id;
 547      return i;
 548   }
 549
 550   protected Term append(Term term) throws PatternSyntaxException{
 551//System.out.println("append("+term.toStringAll()+"), this="+toStringAll());
 552      //Term prev=this.prev;
 553      Term current=this.current;
 554      if(current==null){
 555//System.out.println("2");
 556//System.out.println("  term="+term);
 557//System.out.println("  term.in="+term.in);
 558         in.next=term;
 559         term.prev=in;
 560         this.current=term;
 561//System.out.println("  result: "+in.toStringAll()+"\r\n");
 562         return term;
 563      }
 564//System.out.println("3");
 565      link(current,term);
 566      //this.prev=current;
 567      this.current=term;
 568//System.out.println(in.toStringAll());
 569//System.out.println("current="+this.current);
 570//System.out.println();
 571      return term;
 572   }
 573
 574   protected Term replaceCurrent(Term term) throws PatternSyntaxException{
 575//System.out.println("replaceCurrent("+term+"), current="+current+", current.prev="+current.prev);
 576      //Term prev=this.prev;
 577      Term prev=current.prev;
 578      if(prev!=null){
 579         Term in=this.in;
 580         if(prev==in){
 581            //in.next=term;
 582            //term.prev=in;
 583            in.next=term.in;
 584            term.in.prev=in;
 585         }
 586         else link(prev,term);
 587      }
 588      this.current=term;
 589//System.out.println("   new current="+this.current);
 590      return term;
 591   }
 592
 593
 594   protected void newBranch() throws PatternSyntaxException{
 595//System.out.println("newBranch()");
 596      close();
 597      startNewBranch();
 598//System.out.println(in.toStringAll());
 599//System.out.println("current="+current);
 600//System.out.println();
 601   }
 602
 603
 604   protected void close() throws PatternSyntaxException{
 605//System.out.println("close(), current="+current+", this="+toStringAll());
 606//System.out.println();
 607//System.out.println("close()");
 608//System.out.println("current="+this.current);
 609//System.out.println("prev="+this.prev);
 610//System.out.println();
 611      /*
 612      Term prev=this.prev;
 613      if(prev!=null){
 614         Term current=this.current;
 615         if(current!=null){
 616            link(prev,current);
 617            prev=current;
 618            this.current=null;
 619         }
 620         link(prev,out);
 621         this.prev=null;
 622      }
 623      */
 624      Term current=this.current;
 625      if(current!=null) linkd(current,out);
 626      else in.next=out;
 627//System.out.println(in.toStringAll());
 628//System.out.println("current="+this.current);
 629//System.out.println("prev="+this.prev);
 630//System.out.println();
 631   }
 632
 633   private final static void link(Term term,Term next){
 634      linkd(term,next.in);
 635      next.prev=term;
 636   }
 637
 638   private final static void linkd(Term term,Term next){
 639//System.out.println("linkDirectly(\""+term+"\" -> \""+next+"\")");
 640      Term prev_out=term.out;
 641      if(prev_out!=null){
 642//System.out.println("   prev_out="+prev_out);
 643         prev_out.next=next;
 644      }
 645      Term prev_out1=term.out1;
 646      if(prev_out1!=null){
 647//System.out.println("   prev_out1="+prev_out1);
 648         prev_out1.next=next;
 649      }
 650      Term prev_branch=term.branchOut;
 651      if(prev_branch!=null){
 652//System.out.println("   prev_branch="+prev_branch);
 653         prev_branch.failNext=next;
 654      }
 655   }
 656
 657   protected void startNewBranch() throws PatternSyntaxException{
 658//System.out.println("newBranch()");
 659//System.out.println("before startNewBranch(), this="+toStringAll());
 660//System.out.println();
 661      Term tmp=in.next;
 662      Term b=new Branch();
 663      in.next=b;
 664      b.next=tmp;
 665      b.in=null;
 666      b.out=null;
 667      b.out1=null;
 668      b.branchOut=b;
 669      current=b;
 670//System.out.println("startNewBranch(), this="+toStringAll());
 671//System.out.println();
 672   }
 673
 674   private final static Term makeGreedyStar(int[] vars,Term term,List iterators) throws PatternSyntaxException{
 675      //vars[STACK_SIZE]++;
 676      switch(term.type){
 677         case REPEAT_0_INF:
 678         case REPEAT_MIN_INF:
 679         case REPEAT_MIN_MAX:
 680         case REPEAT_REG_MIN_INF:
 681         case REPEAT_REG_MIN_MAX:
 682         case INDEPENDENT_IN:
 683         case GROUP_IN:{
 684            Term b=new Branch();
 685            b.next=term.in;
 686            term.out.next=b;
 687
 688            b.in=b;
 689            b.out=null;
 690            b.out1=null;
 691            b.branchOut=b;
 692
 693            return b;
 694         }
 695         default:{
 696            Iterator i=new Iterator(term,0,-1,iterators);
 697            return i;
 698         }
 699      }
 700   }
 701
 702   private final static Term makeLazyStar(int[] vars,Term term){
 703      //vars[STACK_SIZE]++;
 704      switch(term.type){
 705         case REPEAT_0_INF:
 706         case REPEAT_MIN_INF:
 707         case REPEAT_MIN_MAX:
 708         case REPEAT_REG_MIN_INF:
 709         case REPEAT_REG_MIN_MAX:
 710         case GROUP_IN:{
 711            Term b=new Branch();
 712            b.failNext=term.in;
 713            term.out.next=b;
 714
 715            b.in=b;
 716            b.out=b;
 717            b.out1=null;
 718            b.branchOut=null;
 719
 720            return b;
 721         }
 722         default:{
 723            Term b=new Branch();
 724            b.failNext=term;
 725            term.next=b;
 726
 727            b.in=b;
 728            b.out=b;
 729            b.out1=null;
 730            b.branchOut=null;
 731
 732            return b;
 733         }
 734      }
 735   }
 736
 737   private final static Term makeGreedyPlus(int[] vars,Term term,List iterators) throws PatternSyntaxException{
 738      //vars[STACK_SIZE]++;
 739      switch(term.type){
 740         case REPEAT_0_INF:
 741         case REPEAT_MIN_INF:
 742         case REPEAT_MIN_MAX:
 743         case REPEAT_REG_MIN_INF:
 744         case REPEAT_REG_MIN_MAX:
 745         case INDEPENDENT_IN://?
 746         case GROUP_IN:{
 747//System.out.println("makeGreedyPlus():");
 748//System.out.println("   in="+term.in);
 749//System.out.println("   out="+term.out);
 750            Term b=new Branch();
 751            b.next=term.in;
 752            term.out.next=b;
 753
 754            b.in=term.in;
 755            b.out=null;
 756            b.out1=null;
 757            b.branchOut=b;
 758
 759//System.out.println("   returning "+b.in);
 760
 761            return b;
 762         }
 763         default:{
 764            return new Iterator(term,1,-1,iterators);
 765         }
 766      }
 767   }
 768
 769   private final static Term makeLazyPlus(int[] vars,Term term){
 770      //vars[STACK_SIZE]++;
 771      switch(term.type){
 772         case REPEAT_0_INF:
 773         case REPEAT_MIN_INF:
 774         case REPEAT_MIN_MAX:
 775         case REPEAT_REG_MIN_INF:
 776         case REPEAT_REG_MIN_MAX:
 777         case GROUP_IN:{
 778            Term b=new Branch();
 779            term.out.next=b;
 780            b.failNext=term.in;
 781
 782            b.in=term.in;
 783            b.out=b;
 784            b.out1=null;
 785            b.branchOut=null;
 786
 787            return b;
 788         }
 789         case REG:
 790         default:{
 791            Term b=new Branch();
 792            term.next=b;
 793            b.failNext=term;
 794
 795            b.in=term;
 796            b.out=b;
 797            b.out1=null;
 798            b.branchOut=null;
 799
 800            return b;
 801         }
 802      }
 803   }
 804
 805   private final static Term makeGreedyQMark(int[] vars,Term term){
 806      //vars[STACK_SIZE]++;
 807      switch(term.type){
 808         case REPEAT_0_INF:
 809         case REPEAT_MIN_INF:
 810         case REPEAT_MIN_MAX:
 811         case REPEAT_REG_MIN_INF:
 812         case REPEAT_REG_MIN_MAX:
 813         case GROUP_IN:{
 814            Term b=new Branch();
 815            b.next=term.in;
 816
 817            b.in=b;
 818            b.out=term.out;
 819            b.out1=null;
 820            b.branchOut=b;
 821
 822            return b;
 823         }
 824         case REG:
 825         default:{
 826            Term b=new Branch();
 827            b.next=term;
 828
 829            b.in=b;
 830            b.out=term;
 831            b.out1=null;
 832            b.branchOut=b;
 833
 834            return b;
 835         }
 836      }
 837   }
 838
 839   private final static Term makeLazyQMark(int[] vars,Term term){
 840      //vars[STACK_SIZE]++;
 841      switch(term.type){
 842         case REPEAT_0_INF:
 843         case REPEAT_MIN_INF:
 844         case REPEAT_MIN_MAX:
 845         case REPEAT_REG_MIN_INF:
 846         case REPEAT_REG_MIN_MAX:
 847         case GROUP_IN:{
 848            Term b=new Branch();
 849            b.failNext=term.in;
 850
 851            b.in=b;
 852            b.out=b;
 853            b.out1=term.out;
 854            b.branchOut=null;
 855
 856            return b;
 857         }
 858         case REG:
 859         default:{
 860            Term b=new Branch();
 861            b.failNext=term;
 862
 863            b.in=b;
 864            b.out=b;
 865            b.out1=term;
 866            b.branchOut=null;
 867
 868            return b;
 869         }
 870      }
 871   }
 872
 873   private final static Term makeGreedyLimits(int[] vars,Term term,int[] limits,List iterators) throws PatternSyntaxException{
 874      //vars[STACK_SIZE]++;
 875      int m=limits[0];
 876      int n=limits[1];
 877      switch(term.type){
 878         case REPEAT_0_INF:
 879         case REPEAT_MIN_INF:
 880         case REPEAT_MIN_MAX:
 881         case REPEAT_REG_MIN_INF:
 882         case REPEAT_REG_MIN_MAX:
 883         case GROUP_IN:{
 884            int cntreg=vars[CNTREG_COUNT]++;
 885            Term reset=new Term(TermType.CR_SET_0);
 886               reset.cntreg=cntreg;
 887            Term b=new Term(TermType.BRANCH);
 888
 889            Term inc=new Term(TermType.CRSTORE_CRINC);
 890               inc.cntreg=cntreg;
 891
 892            reset.next=b;
 893
 894            if(n>=0){
 895               Term lt=new Term(TermType.CR_LT);
 896                  lt.cntreg=cntreg;
 897                  lt.maxCount=n;
 898               b.next=lt;
 899               lt.next=term.in;
 900            }
 901            else{
 902               b.next=term.in;
 903            }
 904            term.out.next=inc;
 905            inc.next=b;
 906
 907            if(m>=0){
 908               Term gt=new Term(TermType.CR_GT_EQ);
 909                  gt.cntreg=cntreg;
 910                  gt.maxCount=m;
 911               b.failNext=gt;
 912
 913               reset.in=reset;
 914               reset.out=gt;
 915               reset.out1=null;
 916               reset.branchOut=null;
 917            }
 918            else{
 919               reset.in=reset;
 920               reset.out=null;
 921               reset.out1=null;
 922               reset.branchOut=b;
 923            }
 924            return reset;
 925         }
 926         default:{
 927            return new Iterator(term,limits[0],limits[1],iterators);
 928         }
 929      }
 930   }
 931
 932   private final static Term makeLazyLimits(int[] vars,Term term,int[] limits){
 933      //vars[STACK_SIZE]++;
 934      int m=limits[0];
 935      int n=limits[1];
 936      switch(term.type){
 937         case REPEAT_0_INF:
 938         case REPEAT_MIN_INF:
 939         case REPEAT_MIN_MAX:
 940         case REPEAT_REG_MIN_INF:
 941         case REPEAT_REG_MIN_MAX:
 942         case GROUP_IN:{
 943            int cntreg=vars[CNTREG_COUNT]++;
 944            Term reset=new Term(TermType.CR_SET_0);
 945               reset.cntreg=cntreg;
 946            Term b=new Term(TermType.BRANCH);
 947            Term inc=new Term(TermType.CRSTORE_CRINC);
 948               inc.cntreg=cntreg;
 949
 950            reset.next=b;
 951
 952            if(n>=0){
 953               Term lt=new Term(TermType.CR_LT);
 954                  lt.cntreg=cntreg;
 955                  lt.maxCount=n;
 956               b.failNext=lt;
 957               lt.next=term.in;
 958            }
 959            else{
 960               b.failNext=term.in;
 961            }
 962            term.out.next=inc;
 963            inc.next=b;
 964
 965            if(m>=0){
 966               Term gt=new Term(TermType.CR_GT_EQ);
 967                  gt.cntreg=cntreg;
 968                  gt.maxCount=m;
 969               b.next=gt;
 970
 971               reset.in=reset;
 972               reset.out=gt;
 973               reset.out1=null;
 974               reset.branchOut=null;
 975
 976               return reset;
 977            }
 978            else{
 979            	  reset.in=reset;
 980               reset.out=b;
 981               reset.out1=null;
 982               reset.branchOut=null;
 983
 984               return reset;
 985            }
 986         }
 987         case REG:
 988         default:{
 989            Term reset=new Term(TermType.CNT_SET_0);
 990            Term b=new Branch(TermType.BRANCH_STORE_CNT);
 991            Term inc=new Term(TermType.CNT_INC);
 992
 993            reset.next=b;
 994
 995            if(n>=0){
 996               Term lt=new Term(TermType.READ_CNT_LT);
 997                  lt.maxCount=n;
 998               b.failNext=lt;
 999               lt.next=term;
1000               term.next=inc;
1001               inc.next=b;
1002            }
1003            else{
1004               b.next=term;
1005               term.next=inc;
1006               inc.next=term;
1007            }
1008
1009            if(m>=0){
1010               Term gt=new Term(TermType.CNT_GT_EQ);
1011                  gt.maxCount=m;
1012               b.next=gt;
1013
1014               reset.in=reset;
1015               reset.out=gt;
1016               reset.out1=null;
1017               reset.branchOut=null;
1018
1019               return reset;
1020            }
1021            else{
1022               reset.in=reset;
1023               reset.out=b;
1024               reset.out1=null;
1025               reset.branchOut=null;
1026
1027               return reset;
1028            }
1029         }
1030      }
1031   }
1032
1033
1034   private final int parseTerm(char[] data, int i, int out, Term term,
1035              int flags) throws PatternSyntaxException{
1036      char c=data[i++];
1037      boolean inv=false;
1038      switch(c){
1039         case '[':
1040            return CharacterClass.parseClass(data,i,out,term,(flags&IGNORE_CASE)>0,(flags&IGNORE_SPACES)>0,(flags&UNICODE)>0,(flags&XML_SCHEMA)>0);
1041
1042         case '.':
1043            term.type=(flags&DOTALL)>0? TermType.ANY_CHAR: TermType.ANY_CHAR_NE;
1044            break;
1045
1046         case '$':
1047            //term.type=mods[MULTILINE_IND]? LINE_END: END; //??
1048            term.type=(flags&MULTILINE)>0? TermType.LINE_END: TermType.END_EOL;
1049            break;
1050
1051         case '^':
1052            term.type=(flags&MULTILINE)>0? TermType.LINE_START: TermType.START;
1053            break;
1054
1055         case '\\':
1056            if(i>=out) throw new PatternSyntaxException("Escape without a character");
1057            c=data[i++];
1058            esc: switch(c){
1059               case 'f':
1060                  c='\f'; // form feed
1061                  break;
1062
1063               case 'n':
1064                  c='\n'; // new line
1065                  break;
1066
1067               case 'r':
1068                  c='\r'; // carriage return
1069                  break;
1070
1071               case 't':
1072                  c='\t'; // tab
1073                  break;
1074
1075               case '\\':
1076                  c='\\';
1077                  break;
1078
1079               case 'u':
1080                   if(i+4 >= out) throw new PatternSyntaxException("To few characters for u-escape");
1081
1082                  c=(char)((CharacterClass.toHexDigit(data[i++])<<12)+
1083                          (CharacterClass.toHexDigit(data[i++])<<8)+
1084                          (CharacterClass.toHexDigit(data[i++])<<4)+
1085                           CharacterClass.toHexDigit(data[i++]));
1086                  break;
1087
1088               case 'v':
1089                   if(i+6 >= out) throw new PatternSyntaxException("To few characters for u-escape");
1090                  c=(char)((CharacterClass.toHexDigit(data[i++])<<24)+
1091                          (CharacterClass.toHexDigit(data[i++])<<16)+
1092                          (CharacterClass.toHexDigit(data[i++])<<12)+
1093                          (CharacterClass.toHexDigit(data[i++])<<8)+
1094                          (CharacterClass.toHexDigit(data[i++])<<4)+
1095                           CharacterClass.toHexDigit(data[i++]));
1096                  break;
1097
1098               case 'x':{   // hex 2-digit number -> char
1099                   if(i >= out) throw new PatternSyntaxException("To few characters for x-escape");
1100                  int hex=0;
1101                  char d;
1102	               if((d=data[i++])=='{'){
1103	                  while(i<out && (d=data[i++])!='}'){
1104	                     hex=(hex<<4)+CharacterClass.toHexDigit(d);
1105	                     if(hex>0xffff) throw new PatternSyntaxException("\\x{<out of range>}");
1106	                  }
1107	               }
1108	               else{
1109                       if(i >= out) throw new PatternSyntaxException("To few characters for x-escape");
1110                     hex=(CharacterClass.toHexDigit(d)<<4)+
1111                          CharacterClass.toHexDigit(data[i++]);
1112	               }
1113                  c=(char)hex;
1114                  break;
1115               }
1116               case '0':
1117               case 'o':   // oct 2- or 3-digit number -> char
1118                  int oct=0;
1119                  for(;;){
1120                     char d=data[i];
1121                     if(d>='0' && d<='7'){
1122                         i++;
1123                         oct*=8;
1124                         oct+=d-'0';
1125                         if(oct>0xffff) break;
1126                         if(i>=out) break;
1127                     }
1128                     else break;
1129                  }
1130                  c=(char)oct;
1131                  break;
1132
1133               case 'm':   // decimal number -> char
1134                  int dec=0;
1135                  for(;;){
1136                     char d=data[i++];
1137                     if(d>='0' && d<='9'){
1138                        dec*=10;
1139                        dec+=d-'0';
1140                        if(dec>0xffff) break;
1141                        if(i>=out) break;
1142                     }
1143                     else break;
1144                  }
1145                  i--;
1146                  c=(char)dec;
1147                  break;
1148
1149               case 'c':   // ctrl-char
1150                  c=(char)(data[i++]&0x1f);
1151                  break;
1152
1153               case 'D':   // non-digit
1154                  inv=true;
1155                  // go on
1156               case 'd':   // digit
1157                  CharacterClass.makeDigit(term,inv,(flags&UNICODE)>0);
1158                  return i;
1159
1160               case 'S':   // non-space
1161                  inv=true;
1162                  // go on
1163               case 's':   // space
1164                  CharacterClass.makeSpace(term,inv,(flags&UNICODE)>0);
1165                  return i;
1166
1167               case 'W':   // non-letter
1168                  inv=true;
1169                  // go on
1170               case 'w':   // letter
1171                  CharacterClass.makeWordChar(term,inv,(flags&UNICODE)>0);
1172                  return i;
1173
1174               case 'B':   // non-(word boundary)
1175                  inv=true;
1176                  // go on
1177               case 'b':   // word boundary
1178                  CharacterClass.makeWordBoundary(term,inv,(flags&UNICODE)>0);
1179                  return i;
1180               case '<':   // non-(word boundary)
1181                  CharacterClass.makeWordStart(term,(flags&UNICODE)>0);
1182                  return i;
1183
1184               case '>':   // word boundary
1185                  CharacterClass.makeWordEnd(term,(flags&UNICODE)>0);
1186                  return i;
1187               case 'A':   // text beginning
1188                  term.type=TermType.START;
1189                  return i;
1190
1191               case 'Z':   // text end
1192                  term.type=TermType.END_EOL;
1193                  return i;
1194
1195               case 'z':   // text end
1196                  term.type=TermType.END;
1197                  return i;
1198
1199               case 'G':   // end of last match
1200                  term.type=TermType.LAST_MATCH_END;
1201                  return i;
1202
1203               case 'P':   // \\P{..}
1204                  inv=true;
1205               case 'p':   // \\p{..}
1206                  i=CharacterClass.parseName(data,i,out,term,inv,(flags&IGNORE_SPACES)>0);
1207                  return i;
1208
1209               default:
1210                  if(c>='1' && c<='9'){
1211                     int n=c-'0';
1212                     while((i<out) && (c=data[i])>='0' && c<='9'){
1213                        n=(n*10)+c-'0';
1214                        i++;
1215                     }
1216                     term.type=(flags&IGNORE_CASE)>0? TermType.REG_I: TermType.REG;
1217                     term.memreg=n;
1218                     return i;
1219                  }
1220                  /*
1221                  if(c<256){
1222                     CustomParser termp=customParsers[c];
1223                     if(termp!=null){
1224                        i=termp.parse(i,data,term);
1225                        return i;
1226                     }
1227                  }
1228                  */
1229            }
1230            term.type=TermType.CHAR;
1231            term.c=c;
1232            break;
1233
1234         default:
1235            if((flags&IGNORE_CASE)==0){
1236               term.type=TermType.CHAR;
1237               term.c=c;
1238            }
1239            else{
1240               CharacterClass.makeICase(term,c);
1241            }
1242            break;
1243      }
1244      return i;
1245   }
1246
1247
1248   // one of {n},{n,},{,n},{n1,n2}
1249   protected static final int parseLimits(int i,int end,char[] data,int[] limits) throws PatternSyntaxException{
1250      if(limits.length!=LIMITS_LENGTH) throw new IllegalArgumentException("maxTimess.length="+limits.length+", should be 2");
1251      limits[LIMITS_PARSE_RESULT_INDEX]=LIMITS_OK;
1252      int ind=0;
1253      int v=0;
1254      char c;
1255      while(i<end){
1256         c=data[i++];
1257         switch(c){
1258            case ' ':
1259               continue;
1260
1261            case ',':
1262               if(ind>0) throw new PatternSyntaxException("illegal construction: {.. , , ..}");
1263               limits[ind++]=v;
1264               v=-1;
1265               continue;
1266
1267            case '}':
1268               limits[ind]=v;
1269               if(ind==0) limits[1]=v;
1270               return i;
1271
1272            default:
1273               if(c>'9' || c<'0'){
1274                  //throw new PatternSyntaxException("illegal symbol in iterator: '{"+c+"}'");
1275                  limits[LIMITS_PARSE_RESULT_INDEX]=LIMITS_FAILURE;
1276                  return i;
1277               }
1278               if(v<0) v=0;
1279               v= v*10 + (c-'0');
1280         }
1281      }
1282      throw new PatternSyntaxException("malformed quantifier");
1283   }
1284
1285   public String toString(){
1286      StringBuffer b=new StringBuffer(100);
1287      b.append(instanceNum);
1288      b.append(": ");
1289      if(inverse) b.append('^');
1290      switch(type){
1291         case VOID:
1292            b.append("[]");
1293            b.append(" , ");
1294            break;
1295         case CHAR:
1296            b.append(CharacterClass.stringValue(c));
1297            b.append(" , ");
1298            break;
1299         case ANY_CHAR:
1300            b.append("dotall, ");
1301            break;
1302         case ANY_CHAR_NE:
1303            b.append("dot-eols, ");
1304            break;
1305         case BITSET:
1306            b.append('[');
1307            b.append(CharacterClass.stringValue0(bitset));
1308            b.append(']');
1309            b.append(" , weight=");
1310            b.append(weight);
1311            b.append(" , ");
1312            break;
1313         case BITSET2:
1314            b.append('[');
1315            b.append(CharacterClass.stringValue2(bitset2));
1316            b.append(']');
1317            b.append(" , weight=");
1318            b.append(weight);
1319            b.append(" , ");
1320            break;
1321         case START:
1322            b.append("abs.start");
1323            break;
1324         case END:
1325            b.append("abs.end");
1326            break;
1327         case END_EOL:
1328            b.append("abs.end-eol");
1329            break;
1330         case LINE_START:
1331            b.append("line start");
1332            break;
1333         case LINE_END:
1334            b.append("line end");
1335            break;
1336         case LAST_MATCH_END:
1337            if(inverse)b.append("non-");
1338            b.append("BOUNDARY");
1339            break;
1340         case BOUNDARY:
1341            if(inverse)b.append("non-");
1342            b.append("BOUNDARY");
1343            break;
1344         case UBOUNDARY:
1345            if(inverse)b.append("non-");
1346            b.append("UBOUNDARY");
1347            break;
1348         case DIRECTION:
1349            b.append("DIRECTION");
1350            break;
1351         case UDIRECTION:
1352            b.append("UDIRECTION");
1353            break;
1354         case FIND:
1355            b.append(">>>{");
1356            b.append(target);
1357            b.append("}, <<");
1358            b.append(distance);
1359            if(eat){
1360               b.append(",eat");
1361            }
1362            b.append(", ");
1363            break;
1364         case REPEAT_0_INF:
1365            b.append("rpt{");
1366            b.append(target);
1367            b.append(",0,inf}");
1368            if(failNext!=null){
1369               b.append(", =>");
1370               b.append(failNext.instanceNum);
1371               b.append(", ");
1372            }
1373            break;
1374         case REPEAT_MIN_INF:
1375            b.append("rpt{");
1376            b.append(target);
1377            b.append(",");
1378            b.append(minCount);
1379            b.append(",inf}");
1380            if(failNext!=null){
1381               b.append(", =>");
1382               b.append(failNext.instanceNum);
1383               b.append(", ");
1384            }
1385            break;
1386         case REPEAT_MIN_MAX:
1387            b.append("rpt{");
1388            b.append(target);
1389            b.append(",");
1390            b.append(minCount);
1391            b.append(",");
1392            b.append(maxCount);
1393            b.append("}");
1394            if(failNext!=null){
1395               b.append(", =>");
1396               b.append(failNext.instanceNum);
1397               b.append(", ");
1398            }
1399            break;
1400         case REPEAT_REG_MIN_INF:
1401            b.append("rpt{$");
1402            b.append(memreg);
1403            b.append(',');
1404            b.append(minCount);
1405            b.append(",inf}");
1406            if(failNext!=null){
1407               b.append(", =>");
1408               b.append(failNext.instanceNum);
1409               b.append(", ");
1410            }
1411            break;
1412         case REPEAT_REG_MIN_MAX:
1413            b.append("rpt{$");
1414            b.append(memreg);
1415            b.append(',');
1416            b.append(minCount);
1417            b.append(',');
1418            b.append(maxCount);
1419            b.append("}");
1420            if(failNext!=null){
1421               b.append(", =>");
1422               b.append(failNext.instanceNum);
1423               b.append(", ");
1424            }
1425            break;
1426         case BACKTRACK_0:
1427            b.append("back(0)");
1428            break;
1429         case BACKTRACK_MIN:
1430            b.append("back(");
1431            b.append(minCount);
1432            b.append(")");
1433            break;
1434         case BACKTRACK_REG_MIN:
1435            b.append("back");
1436            b.append("_$");
1437            b.append(memreg);
1438            b.append("(");
1439            b.append(minCount);
1440            b.append(")");
1441            break;
1442         case GROUP_IN:
1443            b.append('(');
1444            if(memreg>0)b.append(memreg);
1445            b.append('-');
1446            b.append(" , ");
1447            break;
1448         case GROUP_OUT:
1449            b.append('-');
1450            if(memreg>0)b.append(memreg);
1451            b.append(')');
1452            b.append(" , ");
1453            break;
1454         case PLOOKAHEAD_IN:
1455            b.append('(');
1456            b.append("=");
1457            b.append(lookaheadId);
1458            b.append(" , ");
1459            break;
1460         case PLOOKAHEAD_OUT:
1461            b.append('=');
1462            b.append(lookaheadId);
1463            b.append(')');
1464            b.append(" , ");
1465            break;
1466         case NLOOKAHEAD_IN:
1467            b.append("(!");
1468            b.append(lookaheadId);
1469            b.append(" , ");
1470            if(failNext!=null){
1471               b.append(", =>");
1472               b.append(failNext.instanceNum);
1473               b.append(", ");
1474            }
1475            break;
1476         case NLOOKAHEAD_OUT:
1477            b.append('!');
1478            b.append(lookaheadId);
1479            b.append(')');
1480            b.append(" , ");
1481            break;
1482         case PLOOKBEHIND_IN:
1483            b.append('(');
1484            b.append("<=");
1485            b.append(lookaheadId);
1486            b.append(" , dist=");
1487            b.append(distance);
1488            b.append(" , ");
1489            break;
1490         case PLOOKBEHIND_OUT:
1491            b.append("<=");
1492            b.append(lookaheadId);
1493            b.append(')');
1494            b.append(" , ");
1495            break;
1496         case NLOOKBEHIND_IN:
1497            b.append("(<!");
1498            b.append(lookaheadId);
1499            b.append(" , dist=");
1500            b.append(distance);
1501            b.append(" , ");
1502            if(failNext!=null){
1503               b.append(", =>");
1504               b.append(failNext.instanceNum);
1505               b.append(", ");
1506            }
1507            break;
1508         case NLOOKBEHIND_OUT:
1509            b.append("<!");
1510            b.append(lookaheadId);
1511            b.append(')');
1512            b.append(" , ");
1513            break;
1514         case MEMREG_CONDITION:
1515            b.append("(reg");
1516            b.append(memreg);
1517            b.append("?)");
1518            if(failNext!=null){
1519               b.append(", =>");
1520               b.append(failNext.instanceNum);
1521               b.append(", ");
1522            }
1523            break;
1524         case LOOKAHEAD_CONDITION_IN:
1525            b.append("(cond");
1526            b.append(lookaheadId);
1527            b.append(((Lookahead)this).isPositive? '=': '!');
1528            b.append(" , ");
1529            if(failNext!=null){
1530               b.append(", =>");
1531               b.append(failNext.instanceNum);
1532               b.append(", ");
1533            }
1534            break;
1535         case LOOKAHEAD_CONDITION_OUT:
1536            b.append("cond");
1537            b.append(lookaheadId);
1538            b.append(")");
1539            if(failNext!=null){
1540               b.append(", =>");
1541               b.append(failNext.instanceNum);
1542               b.append(", ");
1543            }
1544            break;
1545         case REG:
1546            b.append("$");
1547            b.append(memreg);
1548            b.append(", ");
1549            break;
1550         case SUCCESS:
1551            b.append("END");
1552            break;
1553         case BRANCH_STORE_CNT_AUX1:
1554            b.append("(aux1)");
1555         case BRANCH_STORE_CNT:
1556            b.append("(cnt)");
1557         case BRANCH:
1558            b.append("=>");
1559            if(failNext!=null) b.append(failNext.instanceNum);
1560            else b.append("null");
1561            b.append(" , ");
1562            break;
1563         default:
1564            b.append('[');
1565            switch(type){
1566               case CNT_SET_0:
1567                  b.append("cnt=0");
1568                 

Large files files are truncated, but you can click here to view the full file