xref: /inferno-os/appl/lib/regex.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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