diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-12-17 06:37:06 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-12-17 06:37:06 +0000 |
commit | 47bb29b1482762f80c52debe0b9adc1ce167e126 (patch) | |
tree | b113b8918f9eb221f65ad5d9ea88ce8ec1b900cc /libgo/go/regexp | |
parent | 62a321b609629b50f5a98e8f95539af22ffa6cb8 (diff) | |
download | gcc-47bb29b1482762f80c52debe0b9adc1ce167e126.tar.gz |
Update to current master source.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167972 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/regexp')
-rw-r--r-- | libgo/go/regexp/regexp.go | 411 |
1 files changed, 159 insertions, 252 deletions
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go index d3f03ad790b..2c041cd773c 100644 --- a/libgo/go/regexp/regexp.go +++ b/libgo/go/regexp/regexp.go @@ -89,114 +89,83 @@ var ( ErrBadBackslash = Error("illegal backslash escape") ) -// An instruction executed by the NFA -type instr interface { - kind() int // the type of this instruction: _CHAR, _ANY, etc. - next() instr // the instruction to execute after this one - setNext(i instr) - index() int - setIndex(i int) - print() -} +const ( + iStart = iota // beginning of program + iEnd // end of program: success + iBOT // '^' beginning of text + iEOT // '$' end of text + iChar // 'a' regular character + iCharClass // [a-z] character class + iAny // '.' any character including newline + iNotNL // [^\n] special case: any character but newline + iBra // '(' parenthesized expression: 2*braNum for left, 2*braNum+1 for right + iAlt // '|' alternation + iNop // do nothing; makes it easy to link without patching +) -// Fields and methods common to all instructions -type common struct { - _next instr - _index int +// An instruction executed by the NFA +type instr struct { + kind int // the type of this instruction: iChar, iAny, etc. + index int // used only in debugging; could be eliminated + next *instr // the instruction to execute after this one + // Special fields valid only for some items. + char int // iChar + braNum int // iBra, iEbra + cclass *charClass // iCharClass + left *instr // iAlt, other branch +} + +func (i *instr) print() { + switch i.kind { + case iStart: + print("start") + case iEnd: + print("end") + case iBOT: + print("bot") + case iEOT: + print("eot") + case iChar: + print("char ", string(i.char)) + case iCharClass: + i.cclass.print() + case iAny: + print("any") + case iNotNL: + print("notnl") + case iBra: + if i.braNum&1 == 0 { + print("bra", i.braNum/2) + } else { + print("ebra", i.braNum/2) + } + case iAlt: + print("alt(", i.left.index, ")") + case iNop: + print("nop") + } } -func (c *common) next() instr { return c._next } -func (c *common) setNext(i instr) { c._next = i } -func (c *common) index() int { return c._index } -func (c *common) setIndex(i int) { c._index = i } - // Regexp is the representation of a compiled regular expression. // The public interface is entirely through methods. type Regexp struct { expr string // the original expression prefix string // initial plain text string prefixBytes []byte // initial plain text bytes - inst []instr - start instr // first instruction of machine - prefixStart instr // where to start if there is a prefix - nbra int // number of brackets in expression, for subexpressions -} - -const ( - _START = iota // beginning of program - _END // end of program: success - _BOT // '^' beginning of text - _EOT // '$' end of text - _CHAR // 'a' regular character - _CHARCLASS // [a-z] character class - _ANY // '.' any character including newline - _NOTNL // [^\n] special case: any character but newline - _BRA // '(' parenthesized expression - _EBRA // ')'; end of '(' parenthesized expression - _ALT // '|' alternation - _NOP // do nothing; makes it easy to link without patching -) - -// --- START start of program -type _Start struct { - common -} - -func (start *_Start) kind() int { return _START } -func (start *_Start) print() { print("start") } - -// --- END end of program -type _End struct { - common -} - -func (end *_End) kind() int { return _END } -func (end *_End) print() { print("end") } - -// --- BOT beginning of text -type _Bot struct { - common -} - -func (bot *_Bot) kind() int { return _BOT } -func (bot *_Bot) print() { print("bot") } - -// --- EOT end of text -type _Eot struct { - common -} - -func (eot *_Eot) kind() int { return _EOT } -func (eot *_Eot) print() { print("eot") } - -// --- CHAR a regular character -type _Char struct { - common - char int + inst []*instr + start *instr // first instruction of machine + prefixStart *instr // where to start if there is a prefix + nbra int // number of brackets in expression, for subexpressions } -func (char *_Char) kind() int { return _CHAR } -func (char *_Char) print() { print("char ", string(char.char)) } - -func newChar(char int) *_Char { - c := new(_Char) - c.char = char - return c -} - -// --- CHARCLASS [a-z] - -type _CharClass struct { - common +type charClass struct { negate bool // is character class negated? ([^a-z]) // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x): ranges []int cmin, cmax int } -func (cclass *_CharClass) kind() int { return _CHARCLASS } - -func (cclass *_CharClass) print() { +func (cclass *charClass) print() { print("charclass") if cclass.negate { print(" (negated)") @@ -212,7 +181,7 @@ func (cclass *_CharClass) print() { } } -func (cclass *_CharClass) addRange(a, b int) { +func (cclass *charClass) addRange(a, b int) { // range is a through b inclusive cclass.ranges = append(cclass.ranges, a, b) if a < cclass.cmin { @@ -223,7 +192,7 @@ func (cclass *_CharClass) addRange(a, b int) { } } -func (cclass *_CharClass) matches(c int) bool { +func (cclass *charClass) matches(c int) bool { if c < cclass.cmin || c > cclass.cmax { return cclass.negate } @@ -236,67 +205,17 @@ func (cclass *_CharClass) matches(c int) bool { return cclass.negate } -func newCharClass() *_CharClass { - c := new(_CharClass) - c.ranges = make([]int, 0, 4) - c.cmin = 0x10FFFF + 1 // MaxRune + 1 - c.cmax = -1 - return c -} - -// --- ANY any character -type _Any struct { - common -} - -func (any *_Any) kind() int { return _ANY } -func (any *_Any) print() { print("any") } - -// --- NOTNL any character but newline -type _NotNl struct { - common -} - -func (notnl *_NotNl) kind() int { return _NOTNL } -func (notnl *_NotNl) print() { print("notnl") } - -// --- BRA parenthesized expression -type _Bra struct { - common - n int // subexpression number -} - -func (bra *_Bra) kind() int { return _BRA } -func (bra *_Bra) print() { print("bra", bra.n) } - -// --- EBRA end of parenthesized expression -type _Ebra struct { - common - n int // subexpression number -} - -func (ebra *_Ebra) kind() int { return _EBRA } -func (ebra *_Ebra) print() { print("ebra ", ebra.n) } - -// --- ALT alternation -type _Alt struct { - common - left instr // other branch -} - -func (alt *_Alt) kind() int { return _ALT } -func (alt *_Alt) print() { print("alt(", alt.left.index(), ")") } - -// --- NOP no operation -type _Nop struct { - common +func newCharClass() *instr { + i := &instr{kind: iCharClass} + i.cclass = new(charClass) + i.cclass.ranges = make([]int, 0, 4) + i.cclass.cmin = 0x10FFFF + 1 // MaxRune + 1 + i.cclass.cmax = -1 + return i } -func (nop *_Nop) kind() int { return _NOP } -func (nop *_Nop) print() { print("nop") } - -func (re *Regexp) add(i instr) instr { - i.setIndex(len(re.inst)) +func (re *Regexp) add(i *instr) *instr { + i.index = len(re.inst) re.inst = append(re.inst, i) return i } @@ -364,8 +283,9 @@ func escape(c int) int { return -1 } -func (p *parser) charClass() instr { - cc := newCharClass() +func (p *parser) charClass() *instr { + i := newCharClass() + cc := i.cclass if p.c() == '^' { cc.negate = true p.nextc() @@ -380,18 +300,18 @@ func (p *parser) charClass() instr { // Is it [^\n]? if cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == '\n' && cc.ranges[1] == '\n' { - nl := new(_NotNl) + nl := &instr{kind: iNotNL} p.re.add(nl) return nl } // Special common case: "[a]" -> "a" if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] { - c := newChar(cc.ranges[0]) + c := &instr{kind: iChar, char: cc.ranges[0]} p.re.add(c) return c } - p.re.add(cc) - return cc + p.re.add(i) + return i case '-': // do this before backslash processing p.error(ErrBadRange) case '\\': @@ -428,7 +348,7 @@ func (p *parser) charClass() instr { return nil } -func (p *parser) term() (start, end instr) { +func (p *parser) term() (start, end *instr) { switch c := p.c(); c { case '|', endOfFile: return nil, nil @@ -443,15 +363,15 @@ func (p *parser) term() (start, end instr) { p.error(ErrUnmatchedRbkt) case '^': p.nextc() - start = p.re.add(new(_Bot)) + start = p.re.add(&instr{kind: iBOT}) return start, start case '$': p.nextc() - start = p.re.add(new(_Eot)) + start = p.re.add(&instr{kind: iEOT}) return start, start case '.': p.nextc() - start = p.re.add(new(_Any)) + start = p.re.add(&instr{kind: iAny}) return start, start case '[': p.nextc() @@ -472,12 +392,10 @@ func (p *parser) term() (start, end instr) { } p.nlpar-- p.nextc() - bra := new(_Bra) + bra := &instr{kind: iBra, braNum: 2 * nbra} p.re.add(bra) - ebra := new(_Ebra) + ebra := &instr{kind: iBra, braNum: 2*nbra + 1} p.re.add(ebra) - bra.n = nbra - ebra.n = nbra if start == nil { if end == nil { p.error(ErrInternal) @@ -485,9 +403,9 @@ func (p *parser) term() (start, end instr) { } start = ebra } else { - end.setNext(ebra) + end.next = ebra } - bra.setNext(start) + bra.next = start return bra, ebra case '\\': c = p.nextc() @@ -504,14 +422,14 @@ func (p *parser) term() (start, end instr) { fallthrough default: p.nextc() - start = newChar(c) + start = &instr{kind: iChar, char: c} p.re.add(start) return start, start } panic("unreachable") } -func (p *parser) closure() (start, end instr) { +func (p *parser) closure() (start, end *instr) { start, end = p.term() if start == nil { return @@ -519,28 +437,28 @@ func (p *parser) closure() (start, end instr) { switch p.c() { case '*': // (start,end)*: - alt := new(_Alt) + alt := &instr{kind: iAlt} p.re.add(alt) - end.setNext(alt) // after end, do alt + end.next = alt // after end, do alt alt.left = start // alternate brach: return to start start = alt // alt becomes new (start, end) end = alt case '+': // (start,end)+: - alt := new(_Alt) + alt := &instr{kind: iAlt} p.re.add(alt) - end.setNext(alt) // after end, do alt + end.next = alt // after end, do alt alt.left = start // alternate brach: return to start end = alt // start is unchanged; end is alt case '?': // (start,end)?: - alt := new(_Alt) + alt := &instr{kind: iAlt} p.re.add(alt) - nop := new(_Nop) + nop := &instr{kind: iNop} p.re.add(nop) alt.left = start // alternate branch is start - alt.setNext(nop) // follow on to nop - end.setNext(nop) // after end, go to nop + alt.next = nop // follow on to nop + end.next = nop // after end, go to nop start = alt // start is now alt end = nop // end is nop pointed to by both branches default: @@ -553,27 +471,27 @@ func (p *parser) closure() (start, end instr) { return } -func (p *parser) concatenation() (start, end instr) { +func (p *parser) concatenation() (start, end *instr) { for { nstart, nend := p.closure() switch { case nstart == nil: // end of this concatenation if start == nil { // this is the empty string - nop := p.re.add(new(_Nop)) + nop := p.re.add(&instr{kind: iNop}) return nop, nop } return case start == nil: // this is first element of concatenation start, end = nstart, nend default: - end.setNext(nstart) + end.next = nstart end = nend } } panic("unreachable") } -func (p *parser) regexp() (start, end instr) { +func (p *parser) regexp() (start, end *instr) { start, end = p.concatenation() for { switch p.c() { @@ -582,36 +500,35 @@ func (p *parser) regexp() (start, end instr) { case '|': p.nextc() nstart, nend := p.concatenation() - alt := new(_Alt) + alt := &instr{kind: iAlt} p.re.add(alt) alt.left = start - alt.setNext(nstart) - nop := new(_Nop) + alt.next = nstart + nop := &instr{kind: iNop} p.re.add(nop) - end.setNext(nop) - nend.setNext(nop) + end.next = nop + nend.next = nop start, end = alt, nop } } panic("unreachable") } -func unNop(i instr) instr { - for i.kind() == _NOP { - i = i.next() +func unNop(i *instr) *instr { + for i.kind == iNop { + i = i.next } return i } func (re *Regexp) eliminateNops() { for _, inst := range re.inst { - if inst.kind() == _END { + if inst.kind == iEnd { continue } - inst.setNext(unNop(inst.next())) - if inst.kind() == _ALT { - alt := inst.(*_Alt) - alt.left = unNop(alt.left) + inst.next = unNop(inst.next) + if inst.kind == iAlt { + inst.left = unNop(inst.left) } } } @@ -619,10 +536,10 @@ func (re *Regexp) eliminateNops() { func (re *Regexp) dump() { print("prefix <", re.prefix, ">\n") for _, inst := range re.inst { - print(inst.index(), ": ") + print(inst.index, ": ") inst.print() - if inst.kind() != _END { - print(" -> ", inst.next().index()) + if inst.kind != iEnd { + print(" -> ", inst.next.index) } print("\n") } @@ -630,12 +547,12 @@ func (re *Regexp) dump() { func (re *Regexp) doParse() { p := newParser(re) - start := new(_Start) + start := &instr{kind: iStart} re.add(start) s, e := p.regexp() - start.setNext(s) + start.next = s re.start = start - e.setNext(re.add(new(_End))) + e.next = re.add(&instr{kind: iEnd}) if debug { re.dump() @@ -659,27 +576,25 @@ func (re *Regexp) doParse() { func (re *Regexp) setPrefix() { var b []byte var utf = make([]byte, utf8.UTFMax) + var inst *instr // First instruction is start; skip that. - i := re.inst[0].next().index() Loop: - for i < len(re.inst) { - inst := re.inst[i] + for inst = re.inst[0].next; inst.kind != iEnd; inst = inst.next { // stop if this is not a char - if inst.kind() != _CHAR { + if inst.kind != iChar { break } // stop if this char can be followed by a match for an empty string, // which includes closures, ^, and $. - switch re.inst[inst.next().index()].kind() { - case _BOT, _EOT, _ALT: + switch inst.next.kind { + case iBOT, iEOT, iAlt: break Loop } - n := utf8.EncodeRune(inst.(*_Char).char, utf) - b = bytes.Add(b, utf[0:n]) - i = inst.next().index() + n := utf8.EncodeRune(inst.char, utf) + b = append(b, utf[0:n]...) } // point prefixStart instruction to first non-CHAR after prefix - re.prefixStart = re.inst[i] + re.prefixStart = inst re.prefixBytes = b re.prefix = string(b) } @@ -696,7 +611,7 @@ func Compile(str string) (regexp *Regexp, error os.Error) { } }() regexp.expr = str - regexp.inst = make([]instr, 0, 10) + regexp.inst = make([]*instr, 0, 10) regexp.doParse() return } @@ -772,52 +687,45 @@ func (a *matchArena) noMatch() *matchVec { } type state struct { - inst instr // next instruction to execute - prefixed bool // this match began with a fixed prefix + inst *instr // next instruction to execute + prefixed bool // this match began with a fixed prefix match *matchVec } // Append new state to to-do list. Leftmost-longest wins so avoid // adding a state that's already active. The matchVec will be inc-ref'ed // if it is assigned to a state. -func (a *matchArena) addState(s []state, inst instr, prefixed bool, match *matchVec, pos, end int) []state { - switch inst.kind() { - case _BOT: +func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec, pos, end int) []state { + switch inst.kind { + case iBOT: if pos == 0 { - s = a.addState(s, inst.next(), prefixed, match, pos, end) + s = a.addState(s, inst.next, prefixed, match, pos, end) } return s - case _EOT: + case iEOT: if pos == end { - s = a.addState(s, inst.next(), prefixed, match, pos, end) + s = a.addState(s, inst.next, prefixed, match, pos, end) } return s - case _BRA: - n := inst.(*_Bra).n - match.m[2*n] = pos - s = a.addState(s, inst.next(), prefixed, match, pos, end) - return s - case _EBRA: - n := inst.(*_Ebra).n - match.m[2*n+1] = pos - s = a.addState(s, inst.next(), prefixed, match, pos, end) + case iBra: + match.m[inst.braNum] = pos + s = a.addState(s, inst.next, prefixed, match, pos, end) return s } - index := inst.index() l := len(s) // States are inserted in order so it's sufficient to see if we have the same // instruction; no need to see if existing match is earlier (it is). for i := 0; i < l; i++ { - if s[i].inst.index() == index { + if s[i].inst == inst { return s } } s = append(s, state{inst, prefixed, match}) match.ref++ - if inst.kind() == _ALT { - s = a.addState(s, inst.(*_Alt).left, prefixed, a.copy(match), pos, end) + if inst.kind == iAlt { + s = a.addState(s, inst.left, prefixed, a.copy(match), pos, end) // give other branch a copy of this match vector - s = a.addState(s, inst.next(), prefixed, a.copy(match), pos, end) + s = a.addState(s, inst.next, prefixed, a.copy(match), pos, end) } return s } @@ -860,7 +768,7 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int { s[out] = arena.addState(s[out], re.prefixStart, true, match, pos, end) prefixed = false // next iteration should start at beginning of machine. } else { - s[out] = arena.addState(s[out], re.start.next(), false, match, pos, end) + s[out] = arena.addState(s[out], re.start.next, false, match, pos, end) } arena.free(match) // if addState saved it, ref was incremented } @@ -886,29 +794,28 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int { } pos += charwidth for _, st := range s[in] { - switch st.inst.kind() { - case _BOT: - case _EOT: - case _CHAR: - if c == st.inst.(*_Char).char { - s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end) + switch st.inst.kind { + case iBOT: + case iEOT: + case iChar: + if c == st.inst.char { + s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end) } - case _CHARCLASS: - if st.inst.(*_CharClass).matches(c) { - s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end) + case iCharClass: + if st.inst.cclass.matches(c) { + s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end) } - case _ANY: + case iAny: if c != endOfFile { - s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end) + s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end) } - case _NOTNL: + case iNotNL: if c != endOfFile && c != '\n' { - s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end) + s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end) } - case _BRA: - case _EBRA: - case _ALT: - case _END: + case iBra: + case iAlt: + case iEnd: // choose leftmost longest if !found || // first st.match.m[0] < final.match.m[0] || // leftmost |