1*37da2899SCharles.Forsythimplement Regex; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "regex.m"; 4*37da2899SCharles.Forsyth 5*37da2899SCharles.Forsyth# syntax 6*37da2899SCharles.Forsyth 7*37da2899SCharles.Forsyth# RE ALT regular expression 8*37da2899SCharles.Forsyth# NUL 9*37da2899SCharles.Forsyth# ALT CAT alternation 10*37da2899SCharles.Forsyth# CAT | ALT 11*37da2899SCharles.Forsyth# 12*37da2899SCharles.Forsyth# CAT DUP catenation 13*37da2899SCharles.Forsyth# DUP CAT 14*37da2899SCharles.Forsyth# 15*37da2899SCharles.Forsyth# DUP PRIM possibly duplicated primary 16*37da2899SCharles.Forsyth# PCLO 17*37da2899SCharles.Forsyth# CLO 18*37da2899SCharles.Forsyth# OPT 19*37da2899SCharles.Forsyth# 20*37da2899SCharles.Forsyth# PCLO PRIM + 1 or more 21*37da2899SCharles.Forsyth# CLO PRIM * 0 or more 22*37da2899SCharles.Forsyth# OPT PRIM ? 0 or 1 23*37da2899SCharles.Forsyth# 24*37da2899SCharles.Forsyth# PRIM ( RE ) 25*37da2899SCharles.Forsyth# () 26*37da2899SCharles.Forsyth# DOT any character 27*37da2899SCharles.Forsyth# CHAR a single character 28*37da2899SCharles.Forsyth# ESC escape sequence 29*37da2899SCharles.Forsyth# [ SET ] character set 30*37da2899SCharles.Forsyth# NUL null string 31*37da2899SCharles.Forsyth# HAT beginning of string 32*37da2899SCharles.Forsyth# DOL end of string 33*37da2899SCharles.Forsyth# 34*37da2899SCharles.Forsyth 35*37da2899SCharles.ForsythNIL : con -1; # a refRex constant 36*37da2899SCharles.ForsythNONE: con -2; # ditto, for an un-set value 37*37da2899SCharles.ForsythBAD: con 1<<16; # a non-character 38*37da2899SCharles.ForsythHUGE: con (1<<31) - 1; 39*37da2899SCharles.Forsyth 40*37da2899SCharles.Forsyth# the data structures of re.m would like to be ref-linked, but are 41*37da2899SCharles.Forsyth# circular (see fn walk), thus instead of pointers we use indexes 42*37da2899SCharles.Forsyth# into an array (arena) of nodes of the syntax tree of a regular expression. 43*37da2899SCharles.Forsyth# from a storage-allocation standpoint, this replaces many small 44*37da2899SCharles.Forsyth# allocations of one size with one big one of variable size. 45*37da2899SCharles.Forsyth 46*37da2899SCharles.ForsythReStr: adt { 47*37da2899SCharles.Forsyth s : string; 48*37da2899SCharles.Forsyth i : int; # cursor postion 49*37da2899SCharles.Forsyth n : int; # number of chars left; -1 on error 50*37da2899SCharles.Forsyth peek : fn(s: self ref ReStr): int; 51*37da2899SCharles.Forsyth next : fn(s: self ref ReStr): int; 52*37da2899SCharles.Forsyth}; 53*37da2899SCharles.Forsyth 54*37da2899SCharles.ForsythReStr.peek(s: self ref ReStr): int 55*37da2899SCharles.Forsyth{ 56*37da2899SCharles.Forsyth if(s.n <= 0) 57*37da2899SCharles.Forsyth return BAD; 58*37da2899SCharles.Forsyth return s.s[s.i]; 59*37da2899SCharles.Forsyth} 60*37da2899SCharles.Forsyth 61*37da2899SCharles.ForsythReStr.next(s: self ref ReStr): int 62*37da2899SCharles.Forsyth{ 63*37da2899SCharles.Forsyth if(s.n <= 0) 64*37da2899SCharles.Forsyth return BAD; 65*37da2899SCharles.Forsyth s.n--; 66*37da2899SCharles.Forsyth return s.s[s.i++]; 67*37da2899SCharles.Forsyth} 68*37da2899SCharles.Forsyth 69*37da2899SCharles.ForsythnewRe(kind: int, left, right: refRex, set: ref Set, ar: ref Arena, pno: int): refRex 70*37da2899SCharles.Forsyth{ 71*37da2899SCharles.Forsyth ar.rex[ar.ptr] = Rex(kind, left, right, set, pno); 72*37da2899SCharles.Forsyth return ar.ptr++; 73*37da2899SCharles.Forsyth} 74*37da2899SCharles.Forsyth 75*37da2899SCharles.Forsyth# parse a regex by recursive descent to get a syntax tree 76*37da2899SCharles.Forsyth 77*37da2899SCharles.Forsythre(s: ref ReStr, ar: ref Arena): refRex 78*37da2899SCharles.Forsyth{ 79*37da2899SCharles.Forsyth left := cat(s, ar); 80*37da2899SCharles.Forsyth if(left==NIL || s.peek()!='|') 81*37da2899SCharles.Forsyth return left; 82*37da2899SCharles.Forsyth s.next(); 83*37da2899SCharles.Forsyth right := re(s, ar); 84*37da2899SCharles.Forsyth if(right == NIL) 85*37da2899SCharles.Forsyth return NIL; 86*37da2899SCharles.Forsyth return newRe(ALT, left, right, nil, ar, 0); 87*37da2899SCharles.Forsyth} 88*37da2899SCharles.Forsyth 89*37da2899SCharles.Forsythcat(s: ref ReStr, ar: ref Arena): refRex 90*37da2899SCharles.Forsyth{ 91*37da2899SCharles.Forsyth left := dup(s, ar); 92*37da2899SCharles.Forsyth if(left == NIL) 93*37da2899SCharles.Forsyth return left; 94*37da2899SCharles.Forsyth right := cat(s, ar); 95*37da2899SCharles.Forsyth if(right == NIL) 96*37da2899SCharles.Forsyth return left; 97*37da2899SCharles.Forsyth return newRe(CAT, left, right, nil, ar, 0); 98*37da2899SCharles.Forsyth} 99*37da2899SCharles.Forsyth 100*37da2899SCharles.Forsythdup(s: ref ReStr, ar: ref Arena): refRex 101*37da2899SCharles.Forsyth{ 102*37da2899SCharles.Forsyth case s.peek() { 103*37da2899SCharles.Forsyth BAD or ')' or ']' or '|' or '?' or '*' or '+' => 104*37da2899SCharles.Forsyth return NIL; 105*37da2899SCharles.Forsyth } 106*37da2899SCharles.Forsyth prim: refRex; 107*37da2899SCharles.Forsyth case kind:=s.next() { 108*37da2899SCharles.Forsyth '(' => if(ar.pno < 0) { 109*37da2899SCharles.Forsyth if(s.peek() == ')') { 110*37da2899SCharles.Forsyth s.next(); 111*37da2899SCharles.Forsyth prim = newRe(NUL, NONE, NONE, nil, ar, 0); 112*37da2899SCharles.Forsyth } else { 113*37da2899SCharles.Forsyth prim = re(s, ar); 114*37da2899SCharles.Forsyth if(prim==NIL || s.next()!=')') 115*37da2899SCharles.Forsyth s.n = -1; 116*37da2899SCharles.Forsyth } 117*37da2899SCharles.Forsyth } else { 118*37da2899SCharles.Forsyth pno := ++ar.pno; 119*37da2899SCharles.Forsyth lp := newRe(LPN, NONE, NONE, nil, ar, pno); 120*37da2899SCharles.Forsyth rp := newRe(RPN, NONE, NONE, nil, ar, pno); 121*37da2899SCharles.Forsyth if(s.peek() == ')') { 122*37da2899SCharles.Forsyth s.next(); 123*37da2899SCharles.Forsyth prim = newRe(CAT, lp, rp, nil, ar, 0); 124*37da2899SCharles.Forsyth 125*37da2899SCharles.Forsyth } else { 126*37da2899SCharles.Forsyth prim = re(s, ar); 127*37da2899SCharles.Forsyth if(prim==NIL || s.next()!=')') 128*37da2899SCharles.Forsyth s.n = -1; 129*37da2899SCharles.Forsyth else { 130*37da2899SCharles.Forsyth prim = newRe(CAT, prim, rp, nil, ar, 0); 131*37da2899SCharles.Forsyth prim = newRe(CAT, lp, prim, nil, ar, 0); 132*37da2899SCharles.Forsyth } 133*37da2899SCharles.Forsyth } 134*37da2899SCharles.Forsyth } 135*37da2899SCharles.Forsyth '[' => prim = newRe(SET, NONE, NONE, newSet(s), ar, 0); 136*37da2899SCharles.Forsyth * => case kind { 137*37da2899SCharles.Forsyth '.' => kind = DOT; 138*37da2899SCharles.Forsyth '^' => kind = HAT; 139*37da2899SCharles.Forsyth '$' => kind = DOL; 140*37da2899SCharles.Forsyth } 141*37da2899SCharles.Forsyth prim = newRe(esc(s, kind), NONE, NONE, nil, ar, 0); 142*37da2899SCharles.Forsyth } 143*37da2899SCharles.Forsyth case s.peek() { 144*37da2899SCharles.Forsyth '*' => kind = CLO; 145*37da2899SCharles.Forsyth '+' => kind = PCLO; 146*37da2899SCharles.Forsyth '?' => kind = OPT; 147*37da2899SCharles.Forsyth * => return prim; 148*37da2899SCharles.Forsyth } 149*37da2899SCharles.Forsyth s.next(); 150*37da2899SCharles.Forsyth return newRe(kind, prim, NONE, nil, ar, 0); 151*37da2899SCharles.Forsyth} 152*37da2899SCharles.Forsyth 153*37da2899SCharles.Forsythesc(s: ref ReStr, char: int): int 154*37da2899SCharles.Forsyth{ 155*37da2899SCharles.Forsyth if(char == '\\') { 156*37da2899SCharles.Forsyth char = s.next(); 157*37da2899SCharles.Forsyth case char { 158*37da2899SCharles.Forsyth BAD => s.n = -1; 159*37da2899SCharles.Forsyth 'n' => char = '\n'; 160*37da2899SCharles.Forsyth } 161*37da2899SCharles.Forsyth } 162*37da2899SCharles.Forsyth return char; 163*37da2899SCharles.Forsyth} 164*37da2899SCharles.Forsyth 165*37da2899SCharles.Forsyth# walk the tree adjusting pointers to refer to 166*37da2899SCharles.Forsyth# next state of the finite state machine 167*37da2899SCharles.Forsyth 168*37da2899SCharles.Forsythwalk(r: refRex, succ: refRex, ar: ref Arena) 169*37da2899SCharles.Forsyth{ 170*37da2899SCharles.Forsyth if(r==NONE) 171*37da2899SCharles.Forsyth return; 172*37da2899SCharles.Forsyth rex := ar.rex[r]; 173*37da2899SCharles.Forsyth case rex.kind { 174*37da2899SCharles.Forsyth ALT => walk(rex.left, succ, ar); 175*37da2899SCharles.Forsyth walk(rex.right, succ, ar); 176*37da2899SCharles.Forsyth return; 177*37da2899SCharles.Forsyth CAT => walk(rex.left, rex.right, ar); 178*37da2899SCharles.Forsyth walk(rex.right, succ, ar); 179*37da2899SCharles.Forsyth ar.rex[r] = ar.rex[rex.left]; # optimization 180*37da2899SCharles.Forsyth return; 181*37da2899SCharles.Forsyth CLO or PCLO => 182*37da2899SCharles.Forsyth end := newRe(OPT, r, succ, nil, ar, 0); # here's the circularity 183*37da2899SCharles.Forsyth walk(rex.left, end, ar); 184*37da2899SCharles.Forsyth OPT => walk(rex.left, succ, ar); 185*37da2899SCharles.Forsyth } 186*37da2899SCharles.Forsyth ar.rex[r].right = succ; 187*37da2899SCharles.Forsyth} 188*37da2899SCharles.Forsyth 189*37da2899SCharles.Forsythcompile(e: string, flag: int): (Re, string) 190*37da2899SCharles.Forsyth{ 191*37da2899SCharles.Forsyth if(e == nil) 192*37da2899SCharles.Forsyth return (nil, "missing expression"); 193*37da2899SCharles.Forsyth s := ref ReStr(e, 0, len e); 194*37da2899SCharles.Forsyth ar := ref Arena(array[2*s.n] of Rex, 0, 0, (flag&1)-1); 195*37da2899SCharles.Forsyth start := ar.start = re(s, ar); 196*37da2899SCharles.Forsyth if(start==NIL || s.n!=0) 197*37da2899SCharles.Forsyth return (nil, "invalid regular expression"); 198*37da2899SCharles.Forsyth walk(start, NIL, ar); 199*37da2899SCharles.Forsyth if(ar.pno < 0) 200*37da2899SCharles.Forsyth ar.pno = 0; 201*37da2899SCharles.Forsyth return (ar, nil); 202*37da2899SCharles.Forsyth} 203*37da2899SCharles.Forsyth 204*37da2899SCharles.Forsyth# todo1, todo2: queues for epsilon and advancing transitions 205*37da2899SCharles.ForsythGaz: adt { 206*37da2899SCharles.Forsyth pno: int; 207*37da2899SCharles.Forsyth beg: int; 208*37da2899SCharles.Forsyth end: int; 209*37da2899SCharles.Forsyth}; 210*37da2899SCharles.ForsythTrace: adt { 211*37da2899SCharles.Forsyth cre: refRex; # cursor in Re 212*37da2899SCharles.Forsyth beg: int; # where this trace began; 213*37da2899SCharles.Forsyth gaz: list of Gaz; 214*37da2899SCharles.Forsyth}; 215*37da2899SCharles.ForsythQueue: adt { 216*37da2899SCharles.Forsyth ptr: int; 217*37da2899SCharles.Forsyth q: array of Trace; 218*37da2899SCharles.Forsyth}; 219*37da2899SCharles.Forsyth 220*37da2899SCharles.Forsythexecute(re: Re, s: string): array of (int, int) 221*37da2899SCharles.Forsyth{ 222*37da2899SCharles.Forsyth return executese(re, s, (-1,-1), 1, 1); 223*37da2899SCharles.Forsyth} 224*37da2899SCharles.Forsyth 225*37da2899SCharles.Forsythexecutese(re: Re, s: string, range: (int, int), bol: int, eol: int): array of (int,int) 226*37da2899SCharles.Forsyth{ 227*37da2899SCharles.Forsyth if(re==nil) 228*37da2899SCharles.Forsyth return nil; 229*37da2899SCharles.Forsyth (s0, s1) := range; 230*37da2899SCharles.Forsyth if(s0 < 0) 231*37da2899SCharles.Forsyth s0 = 0; 232*37da2899SCharles.Forsyth if(s1 < 0) 233*37da2899SCharles.Forsyth s1 = len s; 234*37da2899SCharles.Forsyth gaz : list of Gaz; 235*37da2899SCharles.Forsyth (beg, end) := (-1, -1); 236*37da2899SCharles.Forsyth todo1 := ref Queue(0, array[re.ptr] of Trace); 237*37da2899SCharles.Forsyth todo2 := ref Queue(0, array[re.ptr] of Trace); 238*37da2899SCharles.Forsyth for(i:=s0; i<=s1; i++) { 239*37da2899SCharles.Forsyth small2 := HUGE; # earliest possible match if advance 240*37da2899SCharles.Forsyth if(beg == -1) # no leftmost match yet 241*37da2899SCharles.Forsyth todo1.q[todo1.ptr++] = Trace(re.start, i, nil); 242*37da2899SCharles.Forsyth for(k:=0; k<todo1.ptr; k++) { 243*37da2899SCharles.Forsyth q := todo1.q[k]; 244*37da2899SCharles.Forsyth rex := re.rex[q.cre]; 245*37da2899SCharles.Forsyth next1 := next2 := NONE; 246*37da2899SCharles.Forsyth case rex.kind { 247*37da2899SCharles.Forsyth NUL => 248*37da2899SCharles.Forsyth next1 = rex.right; 249*37da2899SCharles.Forsyth DOT => 250*37da2899SCharles.Forsyth if(i<len s && s[i]!='\n') 251*37da2899SCharles.Forsyth next2 = rex.right; 252*37da2899SCharles.Forsyth HAT => 253*37da2899SCharles.Forsyth if(i == s0 && bol) 254*37da2899SCharles.Forsyth next1 = rex.right; 255*37da2899SCharles.Forsyth DOL => 256*37da2899SCharles.Forsyth if(i == s1 && eol) 257*37da2899SCharles.Forsyth next1 = rex.right; 258*37da2899SCharles.Forsyth SET => 259*37da2899SCharles.Forsyth if(i<len s && member(s[i], rex.set)) 260*37da2899SCharles.Forsyth next2 = rex.right; 261*37da2899SCharles.Forsyth CAT or 262*37da2899SCharles.Forsyth PCLO => 263*37da2899SCharles.Forsyth next1 = rex.left; 264*37da2899SCharles.Forsyth ALT or 265*37da2899SCharles.Forsyth CLO or 266*37da2899SCharles.Forsyth OPT => 267*37da2899SCharles.Forsyth next1 = rex.right; 268*37da2899SCharles.Forsyth k = insert(rex.left, q.beg, q.gaz, todo1, k); 269*37da2899SCharles.Forsyth LPN => 270*37da2899SCharles.Forsyth next1 = rex.right; 271*37da2899SCharles.Forsyth q.gaz = Gaz(rex.pno,i,-1)::q.gaz; 272*37da2899SCharles.Forsyth RPN => 273*37da2899SCharles.Forsyth next1 = rex.right; 274*37da2899SCharles.Forsyth for(r:=q.gaz; ; r=tl r) { 275*37da2899SCharles.Forsyth (pno,beg1,end1) := hd r; 276*37da2899SCharles.Forsyth if(rex.pno==pno && end1==-1) { 277*37da2899SCharles.Forsyth q.gaz = Gaz(pno,beg1,i)::q.gaz; 278*37da2899SCharles.Forsyth break; 279*37da2899SCharles.Forsyth } 280*37da2899SCharles.Forsyth } 281*37da2899SCharles.Forsyth * => 282*37da2899SCharles.Forsyth if(i<len s && rex.kind==s[i]) 283*37da2899SCharles.Forsyth next2 = rex.right; 284*37da2899SCharles.Forsyth } 285*37da2899SCharles.Forsyth if(next1 != NONE) { 286*37da2899SCharles.Forsyth if(next1 != NIL) 287*37da2899SCharles.Forsyth k =insert(next1, q.beg, q.gaz, todo1, k); 288*37da2899SCharles.Forsyth else if(better(q.beg, i, beg, end)) 289*37da2899SCharles.Forsyth (gaz, beg, end) = (q.gaz, q.beg, i); 290*37da2899SCharles.Forsyth } 291*37da2899SCharles.Forsyth if(next2 != NONE) { 292*37da2899SCharles.Forsyth if(next2 != NIL) { 293*37da2899SCharles.Forsyth if(q.beg < small2) 294*37da2899SCharles.Forsyth small2 = q.beg; 295*37da2899SCharles.Forsyth insert(next2, q.beg, q.gaz, todo2, 0); 296*37da2899SCharles.Forsyth } else if(better(q.beg, i+1, beg, end)) 297*37da2899SCharles.Forsyth (gaz, beg, end) = (q.gaz, q.beg, i+1); 298*37da2899SCharles.Forsyth } 299*37da2899SCharles.Forsyth 300*37da2899SCharles.Forsyth } 301*37da2899SCharles.Forsyth if(beg!=-1 && beg<small2) # nothing better possible 302*37da2899SCharles.Forsyth break; 303*37da2899SCharles.Forsyth (todo1,todo2) = (todo2, todo1); 304*37da2899SCharles.Forsyth todo2.ptr = 0; 305*37da2899SCharles.Forsyth } 306*37da2899SCharles.Forsyth if(beg == -1) 307*37da2899SCharles.Forsyth return nil; 308*37da2899SCharles.Forsyth result := array[re.pno+1] of { 0 => (beg,end), * => (-1,-1) }; 309*37da2899SCharles.Forsyth for( ; gaz!=nil; gaz=tl gaz) { 310*37da2899SCharles.Forsyth (pno, beg1, end1) := hd gaz; 311*37da2899SCharles.Forsyth (rbeg, nil) := result[pno]; 312*37da2899SCharles.Forsyth if(rbeg==-1 && (beg1|end1)!=-1) 313*37da2899SCharles.Forsyth result[pno] = (beg1,end1); 314*37da2899SCharles.Forsyth } 315*37da2899SCharles.Forsyth return result; 316*37da2899SCharles.Forsyth} 317*37da2899SCharles.Forsyth 318*37da2899SCharles.Forsythbetter(newbeg, newend, oldbeg, oldend: int): int 319*37da2899SCharles.Forsyth{ 320*37da2899SCharles.Forsyth return oldbeg==-1 || newbeg<oldbeg || 321*37da2899SCharles.Forsyth newbeg==oldbeg && newend>oldend; 322*37da2899SCharles.Forsyth} 323*37da2899SCharles.Forsyth 324*37da2899SCharles.Forsythinsert(next: refRex, tbeg: int, tgaz: list of Gaz, todo: ref Queue, k: int): int 325*37da2899SCharles.Forsyth{ 326*37da2899SCharles.Forsyth for(j:=0; j<todo.ptr; j++) 327*37da2899SCharles.Forsyth if(todo.q[j].cre == next) 328*37da2899SCharles.Forsyth if(todo.q[j].beg <= tbeg) 329*37da2899SCharles.Forsyth return k; 330*37da2899SCharles.Forsyth else 331*37da2899SCharles.Forsyth break; 332*37da2899SCharles.Forsyth if(j < k) 333*37da2899SCharles.Forsyth k--; 334*37da2899SCharles.Forsyth if(j < todo.ptr) 335*37da2899SCharles.Forsyth todo.ptr--; 336*37da2899SCharles.Forsyth for( ; j<todo.ptr; j++) 337*37da2899SCharles.Forsyth todo.q[j] = todo.q[j+1]; 338*37da2899SCharles.Forsyth todo.q[todo.ptr++] = Trace(next, tbeg, tgaz); 339*37da2899SCharles.Forsyth return k; 340*37da2899SCharles.Forsyth} 341*37da2899SCharles.Forsyth 342*37da2899SCharles.ForsythASCII : con 128; 343*37da2899SCharles.ForsythWORD : con 32; 344*37da2899SCharles.Forsyth 345*37da2899SCharles.Forsythmember(char: int, set: ref Set): int 346*37da2899SCharles.Forsyth{ 347*37da2899SCharles.Forsyth if(char < 128) 348*37da2899SCharles.Forsyth return ((set.ascii[char/WORD]>>char%WORD)&1)^set.neg; 349*37da2899SCharles.Forsyth for(l:=set.unicode; l!=nil; l=tl l) { 350*37da2899SCharles.Forsyth (beg, end) := hd l; 351*37da2899SCharles.Forsyth if(char>=beg && char<=end) 352*37da2899SCharles.Forsyth return !set.neg; 353*37da2899SCharles.Forsyth } 354*37da2899SCharles.Forsyth return set.neg; 355*37da2899SCharles.Forsyth} 356*37da2899SCharles.Forsyth 357*37da2899SCharles.ForsythnewSet(s: ref ReStr): ref Set 358*37da2899SCharles.Forsyth{ 359*37da2899SCharles.Forsyth set := ref Set(0, array[ASCII/WORD] of {* => 0}, nil); 360*37da2899SCharles.Forsyth if(s.peek() == '^') { 361*37da2899SCharles.Forsyth set.neg = 1; 362*37da2899SCharles.Forsyth s.next(); 363*37da2899SCharles.Forsyth } 364*37da2899SCharles.Forsyth while(s.n > 0) { 365*37da2899SCharles.Forsyth char1 := s.next(); 366*37da2899SCharles.Forsyth if(char1 == ']') 367*37da2899SCharles.Forsyth return set; 368*37da2899SCharles.Forsyth char1 = esc(s, char1); 369*37da2899SCharles.Forsyth char2 := char1; 370*37da2899SCharles.Forsyth if(s.peek() == '-') { 371*37da2899SCharles.Forsyth s.next(); 372*37da2899SCharles.Forsyth char2 = s.next(); 373*37da2899SCharles.Forsyth if(char2 == ']') 374*37da2899SCharles.Forsyth break; 375*37da2899SCharles.Forsyth char2 = esc(s, char2); 376*37da2899SCharles.Forsyth if(char2 < char1) 377*37da2899SCharles.Forsyth break; 378*37da2899SCharles.Forsyth } 379*37da2899SCharles.Forsyth for( ; char1<=char2; char1++) 380*37da2899SCharles.Forsyth if(char1 < ASCII) 381*37da2899SCharles.Forsyth set.ascii[char1/WORD] |= 1<<char1%WORD; 382*37da2899SCharles.Forsyth else { 383*37da2899SCharles.Forsyth set.unicode = (char1,char2)::set.unicode; 384*37da2899SCharles.Forsyth break; 385*37da2899SCharles.Forsyth } 386*37da2899SCharles.Forsyth } 387*37da2899SCharles.Forsyth s.n = -1; 388*37da2899SCharles.Forsyth return nil; 389*37da2899SCharles.Forsyth} 390