mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			290 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			290 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright 2011 The Go Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package syntax
 | |
| 
 | |
| import "unicode"
 | |
| 
 | |
| // A patchList is a list of instruction pointers that need to be filled in (patched).
 | |
| // Because the pointers haven't been filled in yet, we can reuse their storage
 | |
| // to hold the list. It's kind of sleazy, but works well in practice.
 | |
| // See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
 | |
| //
 | |
| // These aren't really pointers: they're integers, so we can reinterpret them
 | |
| // this way without using package unsafe. A value l denotes
 | |
| // p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
 | |
| // l == 0 denotes the empty list, okay because we start every program
 | |
| // with a fail instruction, so we'll never want to point at its output link.
 | |
| type patchList uint32
 | |
| 
 | |
| func (l patchList) next(p *Prog) patchList {
 | |
| 	i := &p.Inst[l>>1]
 | |
| 	if l&1 == 0 {
 | |
| 		return patchList(i.Out)
 | |
| 	}
 | |
| 	return patchList(i.Arg)
 | |
| }
 | |
| 
 | |
| func (l patchList) patch(p *Prog, val uint32) {
 | |
| 	for l != 0 {
 | |
| 		i := &p.Inst[l>>1]
 | |
| 		if l&1 == 0 {
 | |
| 			l = patchList(i.Out)
 | |
| 			i.Out = val
 | |
| 		} else {
 | |
| 			l = patchList(i.Arg)
 | |
| 			i.Arg = val
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (l1 patchList) append(p *Prog, l2 patchList) patchList {
 | |
| 	if l1 == 0 {
 | |
| 		return l2
 | |
| 	}
 | |
| 	if l2 == 0 {
 | |
| 		return l1
 | |
| 	}
 | |
| 
 | |
| 	last := l1
 | |
| 	for {
 | |
| 		next := last.next(p)
 | |
| 		if next == 0 {
 | |
| 			break
 | |
| 		}
 | |
| 		last = next
 | |
| 	}
 | |
| 
 | |
| 	i := &p.Inst[last>>1]
 | |
| 	if last&1 == 0 {
 | |
| 		i.Out = uint32(l2)
 | |
| 	} else {
 | |
| 		i.Arg = uint32(l2)
 | |
| 	}
 | |
| 	return l1
 | |
| }
 | |
| 
 | |
| // A frag represents a compiled program fragment.
 | |
| type frag struct {
 | |
| 	i   uint32    // index of first instruction
 | |
| 	out patchList // where to record end instruction
 | |
| }
 | |
| 
 | |
| type compiler struct {
 | |
| 	p *Prog
 | |
| }
 | |
| 
 | |
| // Compile compiles the regexp into a program to be executed.
 | |
| // The regexp should have been simplified already (returned from re.Simplify).
 | |
| func Compile(re *Regexp) (*Prog, error) {
 | |
| 	var c compiler
 | |
| 	c.init()
 | |
| 	f := c.compile(re)
 | |
| 	f.out.patch(c.p, c.inst(InstMatch).i)
 | |
| 	c.p.Start = int(f.i)
 | |
| 	return c.p, nil
 | |
| }
 | |
| 
 | |
| func (c *compiler) init() {
 | |
| 	c.p = new(Prog)
 | |
| 	c.p.NumCap = 2 // implicit ( and ) for whole match $0
 | |
| 	c.inst(InstFail)
 | |
| }
 | |
| 
 | |
| var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
 | |
| var anyRune = []rune{0, unicode.MaxRune}
 | |
| 
 | |
| func (c *compiler) compile(re *Regexp) frag {
 | |
| 	switch re.Op {
 | |
| 	case OpNoMatch:
 | |
| 		return c.fail()
 | |
| 	case OpEmptyMatch:
 | |
| 		return c.nop()
 | |
| 	case OpLiteral:
 | |
| 		if len(re.Rune) == 0 {
 | |
| 			return c.nop()
 | |
| 		}
 | |
| 		var f frag
 | |
| 		for j := range re.Rune {
 | |
| 			f1 := c.rune(re.Rune[j:j+1], re.Flags)
 | |
| 			if j == 0 {
 | |
| 				f = f1
 | |
| 			} else {
 | |
| 				f = c.cat(f, f1)
 | |
| 			}
 | |
| 		}
 | |
| 		return f
 | |
| 	case OpCharClass:
 | |
| 		return c.rune(re.Rune, re.Flags)
 | |
| 	case OpAnyCharNotNL:
 | |
| 		return c.rune(anyRuneNotNL, 0)
 | |
| 	case OpAnyChar:
 | |
| 		return c.rune(anyRune, 0)
 | |
| 	case OpBeginLine:
 | |
| 		return c.empty(EmptyBeginLine)
 | |
| 	case OpEndLine:
 | |
| 		return c.empty(EmptyEndLine)
 | |
| 	case OpBeginText:
 | |
| 		return c.empty(EmptyBeginText)
 | |
| 	case OpEndText:
 | |
| 		return c.empty(EmptyEndText)
 | |
| 	case OpWordBoundary:
 | |
| 		return c.empty(EmptyWordBoundary)
 | |
| 	case OpNoWordBoundary:
 | |
| 		return c.empty(EmptyNoWordBoundary)
 | |
| 	case OpCapture:
 | |
| 		bra := c.cap(uint32(re.Cap << 1))
 | |
| 		sub := c.compile(re.Sub[0])
 | |
| 		ket := c.cap(uint32(re.Cap<<1 | 1))
 | |
| 		return c.cat(c.cat(bra, sub), ket)
 | |
| 	case OpStar:
 | |
| 		return c.star(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
 | |
| 	case OpPlus:
 | |
| 		return c.plus(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
 | |
| 	case OpQuest:
 | |
| 		return c.quest(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
 | |
| 	case OpConcat:
 | |
| 		if len(re.Sub) == 0 {
 | |
| 			return c.nop()
 | |
| 		}
 | |
| 		var f frag
 | |
| 		for i, sub := range re.Sub {
 | |
| 			if i == 0 {
 | |
| 				f = c.compile(sub)
 | |
| 			} else {
 | |
| 				f = c.cat(f, c.compile(sub))
 | |
| 			}
 | |
| 		}
 | |
| 		return f
 | |
| 	case OpAlternate:
 | |
| 		var f frag
 | |
| 		for _, sub := range re.Sub {
 | |
| 			f = c.alt(f, c.compile(sub))
 | |
| 		}
 | |
| 		return f
 | |
| 	}
 | |
| 	panic("regexp: unhandled case in compile")
 | |
| }
 | |
| 
 | |
| func (c *compiler) inst(op InstOp) frag {
 | |
| 	// TODO: impose length limit
 | |
| 	f := frag{i: uint32(len(c.p.Inst))}
 | |
| 	c.p.Inst = append(c.p.Inst, Inst{Op: op})
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) nop() frag {
 | |
| 	f := c.inst(InstNop)
 | |
| 	f.out = patchList(f.i << 1)
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) fail() frag {
 | |
| 	return frag{}
 | |
| }
 | |
| 
 | |
| func (c *compiler) cap(arg uint32) frag {
 | |
| 	f := c.inst(InstCapture)
 | |
| 	f.out = patchList(f.i << 1)
 | |
| 	c.p.Inst[f.i].Arg = arg
 | |
| 
 | |
| 	if c.p.NumCap < int(arg)+1 {
 | |
| 		c.p.NumCap = int(arg) + 1
 | |
| 	}
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) cat(f1, f2 frag) frag {
 | |
| 	// concat of failure is failure
 | |
| 	if f1.i == 0 || f2.i == 0 {
 | |
| 		return frag{}
 | |
| 	}
 | |
| 
 | |
| 	// TODO: elide nop
 | |
| 
 | |
| 	f1.out.patch(c.p, f2.i)
 | |
| 	return frag{f1.i, f2.out}
 | |
| }
 | |
| 
 | |
| func (c *compiler) alt(f1, f2 frag) frag {
 | |
| 	// alt of failure is other
 | |
| 	if f1.i == 0 {
 | |
| 		return f2
 | |
| 	}
 | |
| 	if f2.i == 0 {
 | |
| 		return f1
 | |
| 	}
 | |
| 
 | |
| 	f := c.inst(InstAlt)
 | |
| 	i := &c.p.Inst[f.i]
 | |
| 	i.Out = f1.i
 | |
| 	i.Arg = f2.i
 | |
| 	f.out = f1.out.append(c.p, f2.out)
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) quest(f1 frag, nongreedy bool) frag {
 | |
| 	f := c.inst(InstAlt)
 | |
| 	i := &c.p.Inst[f.i]
 | |
| 	if nongreedy {
 | |
| 		i.Arg = f1.i
 | |
| 		f.out = patchList(f.i << 1)
 | |
| 	} else {
 | |
| 		i.Out = f1.i
 | |
| 		f.out = patchList(f.i<<1 | 1)
 | |
| 	}
 | |
| 	f.out = f.out.append(c.p, f1.out)
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) star(f1 frag, nongreedy bool) frag {
 | |
| 	f := c.inst(InstAlt)
 | |
| 	i := &c.p.Inst[f.i]
 | |
| 	if nongreedy {
 | |
| 		i.Arg = f1.i
 | |
| 		f.out = patchList(f.i << 1)
 | |
| 	} else {
 | |
| 		i.Out = f1.i
 | |
| 		f.out = patchList(f.i<<1 | 1)
 | |
| 	}
 | |
| 	f1.out.patch(c.p, f.i)
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) plus(f1 frag, nongreedy bool) frag {
 | |
| 	return frag{f1.i, c.star(f1, nongreedy).out}
 | |
| }
 | |
| 
 | |
| func (c *compiler) empty(op EmptyOp) frag {
 | |
| 	f := c.inst(InstEmptyWidth)
 | |
| 	c.p.Inst[f.i].Arg = uint32(op)
 | |
| 	f.out = patchList(f.i << 1)
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (c *compiler) rune(r []rune, flags Flags) frag {
 | |
| 	f := c.inst(InstRune)
 | |
| 	i := &c.p.Inst[f.i]
 | |
| 	i.Rune = r
 | |
| 	flags &= FoldCase // only relevant flag is FoldCase
 | |
| 	if len(r) != 1 || unicode.SimpleFold(r[0]) == r[0] {
 | |
| 		// and sometimes not even that
 | |
| 		flags &^= FoldCase
 | |
| 	}
 | |
| 	i.Arg = uint32(flags)
 | |
| 	f.out = patchList(f.i << 1)
 | |
| 
 | |
| 	// Special cases for exec machine.
 | |
| 	switch {
 | |
| 	case flags&FoldCase == 0 && (len(r) == 1 || len(r) == 2 && r[0] == r[1]):
 | |
| 		i.Op = InstRune1
 | |
| 	case len(r) == 2 && r[0] == 0 && r[1] == unicode.MaxRune:
 | |
| 		i.Op = InstRuneAny
 | |
| 	case len(r) == 4 && r[0] == 0 && r[1] == '\n'-1 && r[2] == '\n'+1 && r[3] == unicode.MaxRune:
 | |
| 		i.Op = InstRuneAnyNotNL
 | |
| 	}
 | |
| 
 | |
| 	return f
 | |
| }
 |