PyXR

c:\python24\lib \ sre_parse.py



0001 #
0002 # Secret Labs' Regular Expression Engine
0003 #
0004 # convert re-style regular expression to sre pattern
0005 #
0006 # Copyright (c) 1998-2001 by Secret Labs AB.  All rights reserved.
0007 #
0008 # See the sre.py file for information on usage and redistribution.
0009 #
0010 
0011 """Internal support module for sre"""
0012 
0013 # XXX: show string offset and offending character for all errors
0014 
0015 import sys
0016 
0017 from sre_constants import *
0018 
0019 SPECIAL_CHARS = ".\\[{()*+?^$|"
0020 REPEAT_CHARS = "*+?{"
0021 
0022 DIGITS = tuple("0123456789")
0023 
0024 OCTDIGITS = tuple("01234567")
0025 HEXDIGITS = tuple("0123456789abcdefABCDEF")
0026 
0027 WHITESPACE = tuple(" \t\n\r\v\f")
0028 
0029 ESCAPES = {
0030     r"\a": (LITERAL, ord("\a")),
0031     r"\b": (LITERAL, ord("\b")),
0032     r"\f": (LITERAL, ord("\f")),
0033     r"\n": (LITERAL, ord("\n")),
0034     r"\r": (LITERAL, ord("\r")),
0035     r"\t": (LITERAL, ord("\t")),
0036     r"\v": (LITERAL, ord("\v")),
0037     r"\\": (LITERAL, ord("\\"))
0038 }
0039 
0040 CATEGORIES = {
0041     r"\A": (AT, AT_BEGINNING_STRING), # start of string
0042     r"\b": (AT, AT_BOUNDARY),
0043     r"\B": (AT, AT_NON_BOUNDARY),
0044     r"\d": (IN, [(CATEGORY, CATEGORY_DIGIT)]),
0045     r"\D": (IN, [(CATEGORY, CATEGORY_NOT_DIGIT)]),
0046     r"\s": (IN, [(CATEGORY, CATEGORY_SPACE)]),
0047     r"\S": (IN, [(CATEGORY, CATEGORY_NOT_SPACE)]),
0048     r"\w": (IN, [(CATEGORY, CATEGORY_WORD)]),
0049     r"\W": (IN, [(CATEGORY, CATEGORY_NOT_WORD)]),
0050     r"\Z": (AT, AT_END_STRING), # end of string
0051 }
0052 
0053 FLAGS = {
0054     # standard flags
0055     "i": SRE_FLAG_IGNORECASE,
0056     "L": SRE_FLAG_LOCALE,
0057     "m": SRE_FLAG_MULTILINE,
0058     "s": SRE_FLAG_DOTALL,
0059     "x": SRE_FLAG_VERBOSE,
0060     # extensions
0061     "t": SRE_FLAG_TEMPLATE,
0062     "u": SRE_FLAG_UNICODE,
0063 }
0064 
0065 class Pattern:
0066     # master pattern object.  keeps track of global attributes
0067     def __init__(self):
0068         self.flags = 0
0069         self.open = []
0070         self.groups = 1
0071         self.groupdict = {}
0072     def opengroup(self, name=None):
0073         gid = self.groups
0074         self.groups = gid + 1
0075         if name is not None:
0076             ogid = self.groupdict.get(name, None)
0077             if ogid is not None:
0078                 raise error, ("redefinition of group name %s as group %d; "
0079                               "was group %d" % (repr(name), gid,  ogid))
0080             self.groupdict[name] = gid
0081         self.open.append(gid)
0082         return gid
0083     def closegroup(self, gid):
0084         self.open.remove(gid)
0085     def checkgroup(self, gid):
0086         return gid < self.groups and gid not in self.open
0087 
0088 class SubPattern:
0089     # a subpattern, in intermediate form
0090     def __init__(self, pattern, data=None):
0091         self.pattern = pattern
0092         if data is None:
0093             data = []
0094         self.data = data
0095         self.width = None
0096     def dump(self, level=0):
0097         nl = 1
0098         seqtypes = type(()), type([])
0099         for op, av in self.data:
0100             print level*"  " + op,; nl = 0
0101             if op == "in":
0102                 # member sublanguage
0103                 print; nl = 1
0104                 for op, a in av:
0105                     print (level+1)*"  " + op, a
0106             elif op == "branch":
0107                 print; nl = 1
0108                 i = 0
0109                 for a in av[1]:
0110                     if i > 0:
0111                         print level*"  " + "or"
0112                     a.dump(level+1); nl = 1
0113                     i = i + 1
0114             elif type(av) in seqtypes:
0115                 for a in av:
0116                     if isinstance(a, SubPattern):
0117                         if not nl: print
0118                         a.dump(level+1); nl = 1
0119                     else:
0120                         print a, ; nl = 0
0121             else:
0122                 print av, ; nl = 0
0123             if not nl: print
0124     def __repr__(self):
0125         return repr(self.data)
0126     def __len__(self):
0127         return len(self.data)
0128     def __delitem__(self, index):
0129         del self.data[index]
0130     def __getitem__(self, index):
0131         return self.data[index]
0132     def __setitem__(self, index, code):
0133         self.data[index] = code
0134     def __getslice__(self, start, stop):
0135         return SubPattern(self.pattern, self.data[start:stop])
0136     def insert(self, index, code):
0137         self.data.insert(index, code)
0138     def append(self, code):
0139         self.data.append(code)
0140     def getwidth(self):
0141         # determine the width (min, max) for this subpattern
0142         if self.width:
0143             return self.width
0144         lo = hi = 0L
0145         UNITCODES = (ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY)
0146         REPEATCODES = (MIN_REPEAT, MAX_REPEAT)
0147         for op, av in self.data:
0148             if op is BRANCH:
0149                 i = sys.maxint
0150                 j = 0
0151                 for av in av[1]:
0152                     l, h = av.getwidth()
0153                     i = min(i, l)
0154                     j = max(j, h)
0155                 lo = lo + i
0156                 hi = hi + j
0157             elif op is CALL:
0158                 i, j = av.getwidth()
0159                 lo = lo + i
0160                 hi = hi + j
0161             elif op is SUBPATTERN:
0162                 i, j = av[1].getwidth()
0163                 lo = lo + i
0164                 hi = hi + j
0165             elif op in REPEATCODES:
0166                 i, j = av[2].getwidth()
0167                 lo = lo + long(i) * av[0]
0168                 hi = hi + long(j) * av[1]
0169             elif op in UNITCODES:
0170                 lo = lo + 1
0171                 hi = hi + 1
0172             elif op == SUCCESS:
0173                 break
0174         self.width = int(min(lo, sys.maxint)), int(min(hi, sys.maxint))
0175         return self.width
0176 
0177 class Tokenizer:
0178     def __init__(self, string):
0179         self.string = string
0180         self.index = 0
0181         self.__next()
0182     def __next(self):
0183         if self.index >= len(self.string):
0184             self.next = None
0185             return
0186         char = self.string[self.index]
0187         if char[0] == "\\":
0188             try:
0189                 c = self.string[self.index + 1]
0190             except IndexError:
0191                 raise error, "bogus escape (end of line)"
0192             char = char + c
0193         self.index = self.index + len(char)
0194         self.next = char
0195     def match(self, char, skip=1):
0196         if char == self.next:
0197             if skip:
0198                 self.__next()
0199             return 1
0200         return 0
0201     def get(self):
0202         this = self.next
0203         self.__next()
0204         return this
0205     def tell(self):
0206         return self.index, self.next
0207     def seek(self, index):
0208         self.index, self.next = index
0209 
0210 def isident(char):
0211     return "a" <= char <= "z" or "A" <= char <= "Z" or char == "_"
0212 
0213 def isdigit(char):
0214     return "0" <= char <= "9"
0215 
0216 def isname(name):
0217     # check that group name is a valid string
0218     if not isident(name[0]):
0219         return False
0220     for char in name[1:]:
0221         if not isident(char) and not isdigit(char):
0222             return False
0223     return True
0224 
0225 def _class_escape(source, escape):
0226     # handle escape code inside character class
0227     code = ESCAPES.get(escape)
0228     if code:
0229         return code
0230     code = CATEGORIES.get(escape)
0231     if code:
0232         return code
0233     try:
0234         c = escape[1:2]
0235         if c == "x":
0236             # hexadecimal escape (exactly two digits)
0237             while source.next in HEXDIGITS and len(escape) < 4:
0238                 escape = escape + source.get()
0239             escape = escape[2:]
0240             if len(escape) != 2:
0241                 raise error, "bogus escape: %s" % repr("\\" + escape)
0242             return LITERAL, int(escape, 16) & 0xff
0243         elif c in OCTDIGITS:
0244             # octal escape (up to three digits)
0245             while source.next in OCTDIGITS and len(escape) < 4:
0246                 escape = escape + source.get()
0247             escape = escape[1:]
0248             return LITERAL, int(escape, 8) & 0xff
0249         elif c in DIGITS:
0250             raise error, "bogus escape: %s" % repr(escape)
0251         if len(escape) == 2:
0252             return LITERAL, ord(escape[1])
0253     except ValueError:
0254         pass
0255     raise error, "bogus escape: %s" % repr(escape)
0256 
0257 def _escape(source, escape, state):
0258     # handle escape code in expression
0259     code = CATEGORIES.get(escape)
0260     if code:
0261         return code
0262     code = ESCAPES.get(escape)
0263     if code:
0264         return code
0265     try:
0266         c = escape[1:2]
0267         if c == "x":
0268             # hexadecimal escape
0269             while source.next in HEXDIGITS and len(escape) < 4:
0270                 escape = escape + source.get()
0271             if len(escape) != 4:
0272                 raise ValueError
0273             return LITERAL, int(escape[2:], 16) & 0xff
0274         elif c == "0":
0275             # octal escape
0276             while source.next in OCTDIGITS and len(escape) < 4:
0277                 escape = escape + source.get()
0278             return LITERAL, int(escape[1:], 8) & 0xff
0279         elif c in DIGITS:
0280             # octal escape *or* decimal group reference (sigh)
0281             if source.next in DIGITS:
0282                 escape = escape + source.get()
0283                 if (escape[1] in OCTDIGITS and escape[2] in OCTDIGITS and
0284                     source.next in OCTDIGITS):
0285                     # got three octal digits; this is an octal escape
0286                     escape = escape + source.get()
0287                     return LITERAL, int(escape[1:], 8) & 0xff
0288             # not an octal escape, so this is a group reference
0289             group = int(escape[1:])
0290             if group < state.groups:
0291                 if not state.checkgroup(group):
0292                     raise error, "cannot refer to open group"
0293                 return GROUPREF, group
0294             raise ValueError
0295         if len(escape) == 2:
0296             return LITERAL, ord(escape[1])
0297     except ValueError:
0298         pass
0299     raise error, "bogus escape: %s" % repr(escape)
0300 
0301 def _parse_sub(source, state, nested=1):
0302     # parse an alternation: a|b|c
0303 
0304     items = []
0305     itemsappend = items.append
0306     sourcematch = source.match
0307     while 1:
0308         itemsappend(_parse(source, state))
0309         if sourcematch("|"):
0310             continue
0311         if not nested:
0312             break
0313         if not source.next or sourcematch(")", 0):
0314             break
0315         else:
0316             raise error, "pattern not properly closed"
0317 
0318     if len(items) == 1:
0319         return items[0]
0320 
0321     subpattern = SubPattern(state)
0322     subpatternappend = subpattern.append
0323 
0324     # check if all items share a common prefix
0325     while 1:
0326         prefix = None
0327         for item in items:
0328             if not item:
0329                 break
0330             if prefix is None:
0331                 prefix = item[0]
0332             elif item[0] != prefix:
0333                 break
0334         else:
0335             # all subitems start with a common "prefix".
0336             # move it out of the branch
0337             for item in items:
0338                 del item[0]
0339             subpatternappend(prefix)
0340             continue # check next one
0341         break
0342 
0343     # check if the branch can be replaced by a character set
0344     for item in items:
0345         if len(item) != 1 or item[0][0] != LITERAL:
0346             break
0347     else:
0348         # we can store this as a character set instead of a
0349         # branch (the compiler may optimize this even more)
0350         set = []
0351         setappend = set.append
0352         for item in items:
0353             setappend(item[0])
0354         subpatternappend((IN, set))
0355         return subpattern
0356 
0357     subpattern.append((BRANCH, (None, items)))
0358     return subpattern
0359 
0360 def _parse_sub_cond(source, state, condgroup):
0361     item_yes = _parse(source, state)
0362     if source.match("|"):
0363         item_no = _parse(source, state)
0364         if source.match("|"):
0365             raise error, "conditional backref with more than two branches"
0366     else:
0367         item_no = None
0368     if source.next and not source.match(")", 0):
0369         raise error, "pattern not properly closed"
0370     subpattern = SubPattern(state)
0371     subpattern.append((GROUPREF_EXISTS, (condgroup, item_yes, item_no)))
0372     return subpattern
0373 
0374 def _parse(source, state):
0375     # parse a simple pattern
0376     subpattern = SubPattern(state)
0377 
0378     # precompute constants into local variables
0379     subpatternappend = subpattern.append
0380     sourceget = source.get
0381     sourcematch = source.match
0382     _len = len
0383     PATTERNENDERS = ("|", ")")
0384     ASSERTCHARS = ("=", "!", "<")
0385     LOOKBEHINDASSERTCHARS = ("=", "!")
0386     REPEATCODES = (MIN_REPEAT, MAX_REPEAT)
0387 
0388     while 1:
0389 
0390         if source.next in PATTERNENDERS:
0391             break # end of subpattern
0392         this = sourceget()
0393         if this is None:
0394             break # end of pattern
0395 
0396         if state.flags & SRE_FLAG_VERBOSE:
0397             # skip whitespace and comments
0398             if this in WHITESPACE:
0399                 continue
0400             if this == "#":
0401                 while 1:
0402                     this = sourceget()
0403                     if this in (None, "\n"):
0404                         break
0405                 continue
0406 
0407         if this and this[0] not in SPECIAL_CHARS:
0408             subpatternappend((LITERAL, ord(this)))
0409 
0410         elif this == "[":
0411             # character set
0412             set = []
0413             setappend = set.append
0414 ##          if sourcematch(":"):
0415 ##              pass # handle character classes
0416             if sourcematch("^"):
0417                 setappend((NEGATE, None))
0418             # check remaining characters
0419             start = set[:]
0420             while 1:
0421                 this = sourceget()
0422                 if this == "]" and set != start:
0423                     break
0424                 elif this and this[0] == "\\":
0425                     code1 = _class_escape(source, this)
0426                 elif this:
0427                     code1 = LITERAL, ord(this)
0428                 else:
0429                     raise error, "unexpected end of regular expression"
0430                 if sourcematch("-"):
0431                     # potential range
0432                     this = sourceget()
0433                     if this == "]":
0434                         if code1[0] is IN:
0435                             code1 = code1[1][0]
0436                         setappend(code1)
0437                         setappend((LITERAL, ord("-")))
0438                         break
0439                     elif this:
0440                         if this[0] == "\\":
0441                             code2 = _class_escape(source, this)
0442                         else:
0443                             code2 = LITERAL, ord(this)
0444                         if code1[0] != LITERAL or code2[0] != LITERAL:
0445                             raise error, "bad character range"
0446                         lo = code1[1]
0447                         hi = code2[1]
0448                         if hi < lo:
0449                             raise error, "bad character range"
0450                         setappend((RANGE, (lo, hi)))
0451                     else:
0452                         raise error, "unexpected end of regular expression"
0453                 else:
0454                     if code1[0] is IN:
0455                         code1 = code1[1][0]
0456                     setappend(code1)
0457 
0458             # XXX: <fl> should move set optimization to compiler!
0459             if _len(set)==1 and set[0][0] is LITERAL:
0460                 subpatternappend(set[0]) # optimization
0461             elif _len(set)==2 and set[0][0] is NEGATE and set[1][0] is LITERAL:
0462                 subpatternappend((NOT_LITERAL, set[1][1])) # optimization
0463             else:
0464                 # XXX: <fl> should add charmap optimization here
0465                 subpatternappend((IN, set))
0466 
0467         elif this and this[0] in REPEAT_CHARS:
0468             # repeat previous item
0469             if this == "?":
0470                 min, max = 0, 1
0471             elif this == "*":
0472                 min, max = 0, MAXREPEAT
0473 
0474             elif this == "+":
0475                 min, max = 1, MAXREPEAT
0476             elif this == "{":
0477                 here = source.tell()
0478                 min, max = 0, MAXREPEAT
0479                 lo = hi = ""
0480                 while source.next in DIGITS:
0481                     lo = lo + source.get()
0482                 if sourcematch(","):
0483                     while source.next in DIGITS:
0484                         hi = hi + sourceget()
0485                 else:
0486                     hi = lo
0487                 if not sourcematch("}"):
0488                     subpatternappend((LITERAL, ord(this)))
0489                     source.seek(here)
0490                     continue
0491                 if lo:
0492                     min = int(lo)
0493                 if hi:
0494                     max = int(hi)
0495                 if max < min:
0496                     raise error, "bad repeat interval"
0497             else:
0498                 raise error, "not supported"
0499             # figure out which item to repeat
0500             if subpattern:
0501                 item = subpattern[-1:]
0502             else:
0503                 item = None
0504             if not item or (_len(item) == 1 and item[0][0] == AT):
0505                 raise error, "nothing to repeat"
0506             if item[0][0] in REPEATCODES:
0507                 raise error, "multiple repeat"
0508             if sourcematch("?"):
0509                 subpattern[-1] = (MIN_REPEAT, (min, max, item))
0510             else:
0511                 subpattern[-1] = (MAX_REPEAT, (min, max, item))
0512 
0513         elif this == ".":
0514             subpatternappend((ANY, None))
0515 
0516         elif this == "(":
0517             group = 1
0518             name = None
0519             condgroup = None
0520             if sourcematch("?"):
0521                 group = 0
0522                 # options
0523                 if sourcematch("P"):
0524                     # python extensions
0525                     if sourcematch("<"):
0526                         # named group: skip forward to end of name
0527                         name = ""
0528                         while 1:
0529                             char = sourceget()
0530                             if char is None:
0531                                 raise error, "unterminated name"
0532                             if char == ">":
0533                                 break
0534                             name = name + char
0535                         group = 1
0536                         if not isname(name):
0537                             raise error, "bad character in group name"
0538                     elif sourcematch("="):
0539                         # named backreference
0540                         name = ""
0541                         while 1:
0542                             char = sourceget()
0543                             if char is None:
0544                                 raise error, "unterminated name"
0545                             if char == ")":
0546                                 break
0547                             name = name + char
0548                         if not isname(name):
0549                             raise error, "bad character in group name"
0550                         gid = state.groupdict.get(name)
0551                         if gid is None:
0552                             raise error, "unknown group name"
0553                         subpatternappend((GROUPREF, gid))
0554                         continue
0555                     else:
0556                         char = sourceget()
0557                         if char is None:
0558                             raise error, "unexpected end of pattern"
0559                         raise error, "unknown specifier: ?P%s" % char
0560                 elif sourcematch(":"):
0561                     # non-capturing group
0562                     group = 2
0563                 elif sourcematch("#"):
0564                     # comment
0565                     while 1:
0566                         if source.next is None or source.next == ")":
0567                             break
0568                         sourceget()
0569                     if not sourcematch(")"):
0570                         raise error, "unbalanced parenthesis"
0571                     continue
0572                 elif source.next in ASSERTCHARS:
0573                     # lookahead assertions
0574                     char = sourceget()
0575                     dir = 1
0576                     if char == "<":
0577                         if source.next not in LOOKBEHINDASSERTCHARS:
0578                             raise error, "syntax error"
0579                         dir = -1 # lookbehind
0580                         char = sourceget()
0581                     p = _parse_sub(source, state)
0582                     if not sourcematch(")"):
0583                         raise error, "unbalanced parenthesis"
0584                     if char == "=":
0585                         subpatternappend((ASSERT, (dir, p)))
0586                     else:
0587                         subpatternappend((ASSERT_NOT, (dir, p)))
0588                     continue
0589                 elif sourcematch("("):
0590                     # conditional backreference group
0591                     condname = ""
0592                     while 1:
0593                         char = sourceget()
0594                         if char is None:
0595                             raise error, "unterminated name"
0596                         if char == ")":
0597                             break
0598                         condname = condname + char
0599                     group = 2
0600                     if isname(condname):
0601                         condgroup = state.groupdict.get(condname)
0602                         if condgroup is None:
0603                             raise error, "unknown group name"
0604                     else:
0605                         try:
0606                             condgroup = int(condname)
0607                         except ValueError:
0608                             raise error, "bad character in group name"
0609                 else:
0610                     # flags
0611                     if not source.next in FLAGS:
0612                         raise error, "unexpected end of pattern"
0613                     while source.next in FLAGS:
0614                         state.flags = state.flags | FLAGS[sourceget()]
0615             if group:
0616                 # parse group contents
0617                 if group == 2:
0618                     # anonymous group
0619                     group = None
0620                 else:
0621                     group = state.opengroup(name)
0622                 if condgroup:
0623                     p = _parse_sub_cond(source, state, condgroup)
0624                 else:
0625                     p = _parse_sub(source, state)
0626                 if not sourcematch(")"):
0627                     raise error, "unbalanced parenthesis"
0628                 if group is not None:
0629                     state.closegroup(group)
0630                 subpatternappend((SUBPATTERN, (group, p)))
0631             else:
0632                 while 1:
0633                     char = sourceget()
0634                     if char is None:
0635                         raise error, "unexpected end of pattern"
0636                     if char == ")":
0637                         break
0638                     raise error, "unknown extension"
0639 
0640         elif this == "^":
0641             subpatternappend((AT, AT_BEGINNING))
0642 
0643         elif this == "$":
0644             subpattern.append((AT, AT_END))
0645 
0646         elif this and this[0] == "\\":
0647             code = _escape(source, this, state)
0648             subpatternappend(code)
0649 
0650         else:
0651             raise error, "parser error"
0652 
0653     return subpattern
0654 
0655 def parse(str, flags=0, pattern=None):
0656     # parse 're' pattern into list of (opcode, argument) tuples
0657 
0658     source = Tokenizer(str)
0659 
0660     if pattern is None:
0661         pattern = Pattern()
0662     pattern.flags = flags
0663     pattern.str = str
0664 
0665     p = _parse_sub(source, pattern, 0)
0666 
0667     tail = source.get()
0668     if tail == ")":
0669         raise error, "unbalanced parenthesis"
0670     elif tail:
0671         raise error, "bogus characters at end of regular expression"
0672 
0673     if flags & SRE_FLAG_DEBUG:
0674         p.dump()
0675 
0676     if not (flags & SRE_FLAG_VERBOSE) and p.pattern.flags & SRE_FLAG_VERBOSE:
0677         # the VERBOSE flag was switched on inside the pattern.  to be
0678         # on the safe side, we'll parse the whole thing again...
0679         return parse(str, p.pattern.flags)
0680 
0681     return p
0682 
0683 def parse_template(source, pattern):
0684     # parse 're' replacement string into list of literals and
0685     # group references
0686     s = Tokenizer(source)
0687     sget = s.get
0688     p = []
0689     a = p.append
0690     def literal(literal, p=p, pappend=a):
0691         if p and p[-1][0] is LITERAL:
0692             p[-1] = LITERAL, p[-1][1] + literal
0693         else:
0694             pappend((LITERAL, literal))
0695     sep = source[:0]
0696     if type(sep) is type(""):
0697         makechar = chr
0698     else:
0699         makechar = unichr
0700     while 1:
0701         this = sget()
0702         if this is None:
0703             break # end of replacement string
0704         if this and this[0] == "\\":
0705             # group
0706             c = this[1:2]
0707             if c == "g":
0708                 name = ""
0709                 if s.match("<"):
0710                     while 1:
0711                         char = sget()
0712                         if char is None:
0713                             raise error, "unterminated group name"
0714                         if char == ">":
0715                             break
0716                         name = name + char
0717                 if not name:
0718                     raise error, "bad group name"
0719                 try:
0720                     index = int(name)
0721                     if index < 0:
0722                         raise error, "negative group number"
0723                 except ValueError:
0724                     if not isname(name):
0725                         raise error, "bad character in group name"
0726                     try:
0727                         index = pattern.groupindex[name]
0728                     except KeyError:
0729                         raise IndexError, "unknown group name"
0730                 a((MARK, index))
0731             elif c == "0":
0732                 if s.next in OCTDIGITS:
0733                     this = this + sget()
0734                     if s.next in OCTDIGITS:
0735                         this = this + sget()
0736                 literal(makechar(int(this[1:], 8) & 0xff))
0737             elif c in DIGITS:
0738                 isoctal = False
0739                 if s.next in DIGITS:
0740                     this = this + sget()
0741                     if (c in OCTDIGITS and this[2] in OCTDIGITS and
0742                         s.next in OCTDIGITS):
0743                         this = this + sget()
0744                         isoctal = True
0745                         literal(makechar(int(this[1:], 8) & 0xff))
0746                 if not isoctal:
0747                     a((MARK, int(this[1:])))
0748             else:
0749                 try:
0750                     this = makechar(ESCAPES[this][1])
0751                 except KeyError:
0752                     pass
0753                 literal(this)
0754         else:
0755             literal(this)
0756     # convert template to groups and literals lists
0757     i = 0
0758     groups = []
0759     groupsappend = groups.append
0760     literals = [None] * len(p)
0761     for c, s in p:
0762         if c is MARK:
0763             groupsappend((i, s))
0764             # literal[i] is already None
0765         else:
0766             literals[i] = s
0767         i = i + 1
0768     return groups, literals
0769 
0770 def expand_template(template, match):
0771     g = match.group
0772     sep = match.string[:0]
0773     groups, literals = template
0774     literals = literals[:]
0775     try:
0776         for index, group in groups:
0777             literals[index] = s = g(group)
0778             if s is None:
0779                 raise error, "unmatched group"
0780     except IndexError:
0781         raise error, "invalid group reference"
0782     return sep.join(literals)
0783 

Generated by PyXR 0.9.4
SourceForge.net Logo