예제 #1
0
파일: LOC.py 프로젝트: xiaoqin00/00scanner
def _decode_size(what, desc):
    exponent = what & 0x0F
    if exponent > 9:
        raise exception.SyntaxError("bad %s exponent" % desc)
    base = (what & 0xF0) >> 4
    if base > 9:
        raise exception.SyntaxError("bad %s base" % desc)
    return long(base) * pow(10, exponent)
예제 #2
0
파일: NSAP.py 프로젝트: v1cker/wiper
 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     address = tok.get_string()
     t = tok.get_eol()
     if address[0:2] != '0x':
         raise exception.SyntaxError('string does not start with 0x')
     address = address[2:].replace('.', '')
     if len(address) % 2 != 0:
         raise exception.SyntaxError('hexstring has odd length')
     address = address.decode('hex_codec')
     return cls(rdclass, rdtype, address)
예제 #3
0
    def get_int(self):
        """Read the next token and interpret it as an integer.

        @raises exception.SyntaxError:
        @rtype: int
        """

        token = self.get().unescape()
        if not token.is_identifier():
            raise exception.SyntaxError('expecting an identifier')
        if not token.value.isdigit():
            raise exception.SyntaxError('expecting an integer')
        return int(token.value)
예제 #4
0
 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     strings = []
     while 1:
         token = tok.get().unescape()
         if token.is_eol_or_eof():
             break
         if not (token.is_quoted_string() or token.is_identifier()):
             raise exception.SyntaxError("expected a string")
         if len(token.value) > 255:
             raise exception.SyntaxError("string too long")
         strings.append(token.value)
     if len(strings) == 0:
         raise exception.UnexpectedEnd
     return cls(rdclass, rdtype, strings)
예제 #5
0
 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     algorithm = tok.get_uint8()
     flags = tok.get_uint8()
     iterations = tok.get_uint16()
     salt = tok.get_string()
     if salt == '-':
         salt = ''
     else:
         salt = salt.decode('hex-codec')
     next = tok.get_string().upper().translate(b32_hex_to_normal)
     next = base64.b32decode(next)
     rdtypes = []
     while 1:
         token = tok.get().unescape()
         if token.is_eol_or_eof():
             break
         nrdtype = rdatatype.from_text(token.value)
         if nrdtype == 0:
             raise exception.SyntaxError("NSEC3 with bit 0")
         if nrdtype > 65535:
             raise exception.SyntaxError("NSEC3 with bit > 65535")
         rdtypes.append(nrdtype)
     rdtypes.sort()
     window = 0
     octets = 0
     prior_rdtype = 0
     bitmap = ['\0'] * 32
     windows = []
     for nrdtype in rdtypes:
         if nrdtype == prior_rdtype:
             continue
         prior_rdtype = nrdtype
         new_window = nrdtype // 256
         if new_window != window:
             if octets != 0:
                 windows.append((window, ''.join(bitmap[0:octets])))
             bitmap = ['\0'] * 32
             window = new_window
         offset = nrdtype % 256
         byte = offset // 8
         bit = offset % 8
         octets = byte + 1
         bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit))
     if octets != 0:
         windows.append((window, ''.join(bitmap[0:octets])))
     return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next,
                windows)
예제 #6
0
    def get_uint32(self):
        """Read the next token and interpret it as a 32-bit unsigned
        integer.

        @raises exception.SyntaxError:
        @rtype: int
        """

        token = self.get().unescape()
        if not token.is_identifier():
            raise exception.SyntaxError('expecting an identifier')
        if not token.value.isdigit():
            raise exception.SyntaxError('expecting an integer')
        value = long(token.value)
        if value < 0 or value > 4294967296L:
            raise exception.SyntaxError('%d is not an unsigned 32-bit integer' % value)
        return value
예제 #7
0
 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     token = tok.get()
     if not token.is_identifier() or token.value != '\#':
         raise exception.SyntaxError(
             r'generic rdata does not start with \#')
     length = tok.get_int()
     chunks = []
     while 1:
         token = tok.get()
         if token.is_eol_or_eof():
             break
         chunks.append(token.value)
     hex = ''.join(chunks)
     data = hex.decode('hex_codec')
     if len(data) != length:
         raise exception.SyntaxError(
             'generic rdata hex data has wrong length')
     return cls(rdclass, rdtype, data)
예제 #8
0
    def get_name(self, origin=None):
        """Read the next token and interpret it as a DNS name.

        @raises exception.SyntaxError:
        @rtype: name.Name object"""

        token = self.get()
        if not token.is_identifier():
            raise exception.SyntaxError('expecting an identifier')
        return name.from_text(token.value, origin)
예제 #9
0
파일: LOC.py 프로젝트: xiaoqin00/00scanner
def _exponent_of(what, desc):
    if what == 0:
        return 0
    exp = None
    for i in xrange(len(_pows)):
        if what // _pows[i] == 0L:
            exp = i - 1
            break
    if exp is None or exp < 0:
        raise exception.SyntaxError("%s value out of bounds" % desc)
    return exp
예제 #10
0
    def get_identifier(self, origin=None):
        """Read the next token and raise an exception if it is not an identifier.

        @raises exception.SyntaxError:
        @rtype: string
        """

        token = self.get().unescape()
        if not token.is_identifier():
            raise exception.SyntaxError('expecting an identifier')
        return token.value
예제 #11
0
    def get_string(self, origin=None):
        """Read the next token and interpret it as a string.

        @raises exception.SyntaxError:
        @rtype: string
        """

        token = self.get().unescape()
        if not (token.is_identifier() or token.is_quoted_string()):
            raise exception.SyntaxError('expecting a string')
        return token.value
예제 #12
0
    def get_eol(self):
        """Read the next token and raise an exception if it isn't EOL or
        EOF.

        @raises exception.SyntaxError:
        @rtype: string
        """

        token = self.get()
        if not token.is_eol_or_eof():
            raise exception.SyntaxError('expected EOL or EOF, got %d "%s"' % (token.ttype, token.value))
        return token.value
예제 #13
0
    def get_uint16(self):
        """Read the next token and interpret it as a 16-bit unsigned
        integer.

        @raises exception.SyntaxError:
        @rtype: int
        """

        value = self.get_int()
        if value < 0 or value > 65535:
            raise exception.SyntaxError('%d is not an unsigned 16-bit integer' % value)
        return value
예제 #14
0
파일: NSEC.py 프로젝트: xiaoqin00/00scanner
 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     next = tok.get_name()
     next = next.choose_relativity(origin, relativize)
     rdtypes = []
     while 1:
         token = tok.get().unescape()
         if token.is_eol_or_eof():
             break
         nrdtype = rdatatype.from_text(token.value)
         if nrdtype == 0:
             raise exception.SyntaxError("NSEC with bit 0")
         if nrdtype > 65535:
             raise exception.SyntaxError("NSEC with bit > 65535")
         rdtypes.append(nrdtype)
     rdtypes.sort()
     window = 0
     octets = 0
     prior_rdtype = 0
     bitmap = ['\0'] * 32
     windows = []
     for nrdtype in rdtypes:
         if nrdtype == prior_rdtype:
             continue
         prior_rdtype = nrdtype
         new_window = nrdtype // 256
         if new_window != window:
             windows.append((window, ''.join(bitmap[0:octets])))
             bitmap = ['\0'] * 32
             window = new_window
         offset = nrdtype % 256
         byte = offset // 8
         bit = offset % 8
         octets = byte + 1
         bitmap[byte] = chr(ord(bitmap[byte]) | (0x80 >> bit))
     windows.append((window, ''.join(bitmap[0:octets])))
     return cls(rdclass, rdtype, next, windows)
예제 #15
0
파일: HIP.py 프로젝트: xiaoqin00/00scanner
 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     algorithm = tok.get_uint8()
     hit = tok.get_string().decode('hex-codec')
     if len(hit) > 255:
         raise exception.SyntaxError("HIT too long")
     key = tok.get_string().decode('base64-codec')
     servers = []
     while 1:
         token = tok.get()
         if token.is_eol_or_eof():
             break
         server = name.from_text(token.value, origin)
         server.choose_relativity(origin, relativize)
         servers.append(server)
     return cls(rdclass, rdtype, hit, algorithm, key, servers)
예제 #16
0
def from_text(text):
    """Convert the text form of a range in a GENERATE statement to an
    integer.

    @param text: the textual range
    @type text: string
    @return: The start, stop and step values.
    @rtype: tuple
    """
    # TODO, figure out the bounds on start, stop and step.

    import pdb
    step = 1
    cur = ''
    state = 0
    # state   0 1 2 3 4
    #         x - y / z
    for c in text:
        if c == '-' and state == 0:
            start = int(cur)
            cur = ''
            state = 2
        elif c == '/':
            stop = int(cur)
            cur = ''
            state = 4
        elif c.isdigit():
            cur += c
        else:
            raise exception.SyntaxError("Could not parse %s" % (c))

    if state in (1, 3):
        raise exception.SyntaxError

    if state == 2:
        stop = int(cur)

    if state == 4:
        step = int(cur)

    assert step >= 1
    assert start >= 0
    assert start <= stop
    # TODO, can start == stop?

    return (start, stop, step)
예제 #17
0
파일: CERT.py 프로젝트: v1cker/wiper
 def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
     certificate_type = _ctype_from_text(tok.get_string())
     key_tag = tok.get_uint16()
     algorithm = dnssec.algorithm_from_text(tok.get_string())
     if algorithm < 0 or algorithm > 255:
         raise exception.SyntaxError("bad algorithm type")
     chunks = []
     while 1:
         t = tok.get().unescape()
         if t.is_eol_or_eof():
             break
         if not t.is_identifier():
             raise exception.SyntaxError
         chunks.append(t.value)
     b64 = ''.join(chunks)
     certificate = b64.decode('base64_codec')
     return cls(rdclass, rdtype, certificate_type, key_tag,
                algorithm, certificate)
예제 #18
0
파일: e164.py 프로젝트: xiaoqin00/00scanner
def to_e164(name, origin=public_enum_domain, want_plus_prefix=True):
    """Convert an ENUM domain name into an E.164 number.
    @param name: the ENUM domain name.
    @type name: name.Name object.
    @param origin: A domain containing the ENUM domain name.  The
    name is relativized to this domain before being converted to text.
    @type origin: name.Name object or None
    @param want_plus_prefix: if True, add a '+' to the beginning of the
    returned number.
    @rtype: str
    """
    if not origin is None:
        name = name.relativize(origin)
    dlabels = [d for d in name.labels if (d.isdigit() and len(d) == 1)]
    if len(dlabels) != len(name.labels):
        raise exception.SyntaxError('non-digit labels in ENUM domain name')
    dlabels.reverse()
    text = ''.join(dlabels)
    if want_plus_prefix:
        text = '+' + text
    return text
예제 #19
0
파일: zone.py 프로젝트: xiaoqin00/00scanner
    def _rr_line(self):
        """Process one line from a DNS master file."""
        # Name
        if self.current_origin is None:
            raise UnknownOrigin
        token = self.tok.get(want_leading=True)
        if not token.is_whitespace():
            self.last_name = name.from_text(token.value, self.current_origin)
        else:
            token = self.tok.get()
            if token.is_eol_or_eof():
                # treat leading WS followed by EOL/EOF as if they were EOL/EOF.
                return
            self.tok.unget(token)
        name = self.last_name
        if not name.is_subdomain(self.zone.origin):
            self._eat_line()
            return
        if self.relativize:
            name = name.relativize(self.zone.origin)
        token = self.tok.get()
        if not token.is_identifier():
            raise exception.SyntaxError
        # TTL
        try:
            ttl = ttl.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except ttl.BadTTL:
            ttl = self.ttl
        # Class
        try:
            rdclass = rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except exception.SyntaxError:
            raise exception.SyntaxError
        except:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = rdatatype.from_text(token.value)
        except:
            raise exception.SyntaxError("unknown rdatatype '%s'" % token.value)
        n = self.zone.nodes.get(name)
        if n is None:
            n = self.zone.node_factory()
            self.zone.nodes[name] = n
        try:
            rd = rdata.from_text(rdclass, rdtype, self.tok,
                                 self.current_origin, False)
        except exception.SyntaxError:
            # Catch and reraise.
            (ty, va) = sys.exc_info()[:2]
            raise va
        except:
            # All exceptions that occur in the processing of rdata
            # are treated as syntax errors.  This is not strictly
            # correct, but it is correct almost all of the time.
            # We convert them to syntax errors so that we can emit
            # helpful filename:line info.
            (ty, va) = sys.exc_info()[:2]
            raise exception.SyntaxError("caught exception %s: %s" %
                                        (str(ty), str(va)))

        rd.choose_relativity(self.zone.origin, self.relativize)
        covers = rd.covers()
        rds = n.find_rdataset(rdclass, rdtype, covers, True)
        rds.add(rd, ttl)
예제 #20
0
 def get_ttl(self):
     token = self.get().unescape()
     if not token.is_identifier():
         raise exception.SyntaxError('expecting an identifier')
     return ttl.from_text(token.value)
예제 #21
0
파일: LOC.py 프로젝트: xiaoqin00/00scanner
    def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True):
        latitude = [0, 0, 0, 0]
        longitude = [0, 0, 0, 0]
        size = _default_size
        hprec = _default_hprec
        vprec = _default_vprec

        latitude[0] = tok.get_int()
        t = tok.get_string()
        if t.isdigit():
            latitude[1] = int(t)
            t = tok.get_string()
            if '.' in t:
                (seconds, milliseconds) = t.split('.')
                if not seconds.isdigit():
                    raise exception.SyntaxError('bad latitude seconds value')
                latitude[2] = int(seconds)
                if latitude[2] >= 60:
                    raise exception.SyntaxError('latitude seconds >= 60')
                l = len(milliseconds)
                if l == 0 or l > 3 or not milliseconds.isdigit():
                    raise exception.SyntaxError('bad latitude milliseconds value')
                if l == 1:
                    m = 100
                elif l == 2:
                    m = 10
                else:
                    m = 1
                latitude[3] = m * int(milliseconds)
                t = tok.get_string()
            elif t.isdigit():
                latitude[2] = int(t)
                t = tok.get_string()
        if t == 'S':
            latitude[0] *= -1
        elif t != 'N':
            raise exception.SyntaxError('bad latitude hemisphere value')

        longitude[0] = tok.get_int()
        t = tok.get_string()
        if t.isdigit():
            longitude[1] = int(t)
            t = tok.get_string()
            if '.' in t:
                (seconds, milliseconds) = t.split('.')
                if not seconds.isdigit():
                    raise exception.SyntaxError('bad longitude seconds value')
                longitude[2] = int(seconds)
                if longitude[2] >= 60:
                    raise exception.SyntaxError('longitude seconds >= 60')
                l = len(milliseconds)
                if l == 0 or l > 3 or not milliseconds.isdigit():
                    raise exception.SyntaxError('bad longitude milliseconds value')
                if l == 1:
                    m = 100
                elif l == 2:
                    m = 10
                else:
                    m = 1
                longitude[3] = m * int(milliseconds)
                t = tok.get_string()
            elif t.isdigit():
                longitude[2] = int(t)
                t = tok.get_string()
        if t == 'W':
            longitude[0] *= -1
        elif t != 'E':
            raise exception.SyntaxError('bad longitude hemisphere value')

        t = tok.get_string()
        if t[-1] == 'm':
            t = t[0 : -1]
        altitude = float(t) * 100.0	# m -> cm

        token = tok.get().unescape()
        if not token.is_eol_or_eof():
            value = token.value
            if value[-1] == 'm':
                value = value[0 : -1]
            size = float(value) * 100.0	# m -> cm
            token = tok.get().unescape()
            if not token.is_eol_or_eof():
                value = token.value
                if value[-1] == 'm':
                    value = value[0 : -1]
                hprec = float(value) * 100.0	# m -> cm
                token = tok.get().unescape()
                if not token.is_eol_or_eof():
                    value = token.value
                    if value[-1] == 'm':
                        value = value[0 : -1]
                    vprec = float(value) * 100.0	# m -> cm
                    tok.get_eol()

        return cls(rdclass, rdtype, latitude, longitude, altitude,
                   size, hprec, vprec)
예제 #22
0
파일: zone.py 프로젝트: xiaoqin00/00scanner
    def read(self):
        """Read a DNS master file and build a zone object.

        @raises zone.NoSOA: No SOA RR was found at the zone origin
        @raises zone.NoNS: No NS RRset was found at the zone origin
        """

        try:
            while 1:
                token = self.tok.get(True, True)
                if token.is_eof():
                    if not self.current_file is None:
                        self.current_file.close()
                    if len(self.saved_state) > 0:
                        (self.tok, self.current_origin, self.last_name,
                         self.current_file,
                         self.ttl) = self.saved_state.pop(-1)
                        continue
                    break
                elif token.is_eol():
                    continue
                elif token.is_comment():
                    self.tok.get_eol()
                    continue
                elif token.value[0] == '$':
                    u = token.value.upper()
                    if u == '$TTL':
                        token = self.tok.get()
                        if not token.is_identifier():
                            raise exception.SyntaxError("bad $TTL")
                        self.ttl = ttl.from_text(token.value)
                        self.tok.get_eol()
                    elif u == '$ORIGIN':
                        self.current_origin = self.tok.get_name()
                        self.tok.get_eol()
                        if self.zone.origin is None:
                            self.zone.origin = self.current_origin
                    elif u == '$INCLUDE' and self.allow_include:
                        token = self.tok.get()
                        filename = token.value
                        token = self.tok.get()
                        if token.is_identifier():
                            new_origin = name.from_text(token.value, \
                                                            self.current_origin)
                            self.tok.get_eol()
                        elif not token.is_eol_or_eof():
                            raise exception.SyntaxError(
                                "bad origin in $INCLUDE")
                        else:
                            new_origin = self.current_origin
                        self.saved_state.append(
                            (self.tok, self.current_origin, self.last_name,
                             self.current_file, self.ttl))
                        self.current_file = file(filename, 'r')
                        self.tok = tokenizer.Tokenizer(self.current_file,
                                                       filename)
                        self.current_origin = new_origin
                    elif u == '$GENERATE':
                        self._generate_line()
                    else:
                        raise exception.SyntaxError(
                            "Unknown master file directive '" + u + "'")
                    continue
                self.tok.unget(token)
                self._rr_line()
        except exception.SyntaxError, detail:
            (filename, line_number) = self.tok.where()
            if detail is None:
                detail = "syntax error"
            raise exception.SyntaxError("%s:%d: %s" %
                                        (filename, line_number, detail))
예제 #23
0
파일: zone.py 프로젝트: xiaoqin00/00scanner
    def _generate_line(self):
        # range lhs [ttl] [class] type rhs [ comment ]
        """Process one line containing the GENERATE statement from a DNS
        master file."""
        if self.current_origin is None:
            raise UnknownOrigin

        token = self.tok.get()
        # Range (required)
        try:
            start, stop, step = grange.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except:
            raise exception.SyntaxError

        # lhs (required)
        try:
            lhs = token.value
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except:
            raise exception.SyntaxError

        # TTL
        try:
            ttl = ttl.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except ttl.BadTTL:
            ttl = self.ttl
        # Class
        try:
            rdclass = rdataclass.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except exception.SyntaxError:
            raise exception.SyntaxError
        except:
            rdclass = self.zone.rdclass
        if rdclass != self.zone.rdclass:
            raise exception.SyntaxError("RR class is not zone's class")
        # Type
        try:
            rdtype = rdatatype.from_text(token.value)
            token = self.tok.get()
            if not token.is_identifier():
                raise exception.SyntaxError
        except:
            raise exception.SyntaxError("unknown rdatatype '%s'" % token.value)

        # lhs (required)
        try:
            rhs = token.value
        except:
            raise exception.SyntaxError

        lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs)
        rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs)
        for i in range(start, stop + 1, step):
            # +1 because bind is inclusive and python is exclusive

            if lsign == '+':
                lindex = i + int(loffset)
            elif lsign == '-':
                lindex = i - int(loffset)

            if rsign == '-':
                rindex = i - int(roffset)
            elif rsign == '+':
                rindex = i + int(roffset)

            lzfindex = str(lindex).zfill(int(lwidth))
            rzfindex = str(rindex).zfill(int(rwidth))

            name = lhs.replace('$%s' % (lmod), lzfindex)
            rdata = rhs.replace('$%s' % (rmod), rzfindex)

            self.last_name = name.from_text(name, self.current_origin)
            name = self.last_name
            if not name.is_subdomain(self.zone.origin):
                self._eat_line()
                return
            if self.relativize:
                name = name.relativize(self.zone.origin)

            n = self.zone.nodes.get(name)
            if n is None:
                n = self.zone.node_factory()
                self.zone.nodes[name] = n
            try:
                rd = rdata.from_text(rdclass, rdtype, rdata,
                                     self.current_origin, False)
            except exception.SyntaxError:
                # Catch and reraise.
                (ty, va) = sys.exc_info()[:2]
                raise va
            except:
                # All exceptions that occur in the processing of rdata
                # are treated as syntax errors.  This is not strictly
                # correct, but it is correct almost all of the time.
                # We convert them to syntax errors so that we can emit
                # helpful filename:line info.
                (ty, va) = sys.exc_info()[:2]
                raise exception.SyntaxError("caught exception %s: %s" %
                                            (str(ty), str(va)))

            rd.choose_relativity(self.zone.origin, self.relativize)
            covers = rd.covers()
            rds = n.find_rdataset(rdclass, rdtype, covers, True)
            rds.add(rd, ttl)
예제 #24
0
    def get(self, want_leading = False, want_comment = False):
        """Get the next token.

        @param want_leading: If True, return a WHITESPACE token if the
        first character read is whitespace.  The default is False.
        @type want_leading: bool
        @param want_comment: If True, return a COMMENT token if the
        first token read is a comment.  The default is False.
        @type want_comment: bool
        @rtype: Token object
        @raises exception.UnexpectedEnd: input ended prematurely
        @raises exception.SyntaxError: input was badly formed
        """

        if not self.ungotten_token is None:
            token = self.ungotten_token
            self.ungotten_token = None
            if token.is_whitespace():
                if want_leading:
                    return token
            elif token.is_comment():
                if want_comment:
                    return token
            else:
                return token
        skipped = self.skip_whitespace()
        if want_leading and skipped > 0:
            return Token(WHITESPACE, ' ')
        token = ''
        ttype = IDENTIFIER
        has_escape = False
        while True:
            c = self._get_char()
            if c == '' or c in self.delimiters:
                if c == '' and self.quoting:
                    raise exception.UnexpectedEnd
                if token == '' and ttype != QUOTED_STRING:
                    if c == '(':
                        self.multiline += 1
                        self.skip_whitespace()
                        continue
                    elif c == ')':
                        if not self.multiline > 0:
                            raise exception.SyntaxError
                        self.multiline -= 1
                        self.skip_whitespace()
                        continue
                    elif c == '"':
                        if not self.quoting:
                            self.quoting = True
                            self.delimiters = _QUOTING_DELIMITERS
                            ttype = QUOTED_STRING
                            continue
                        else:
                            self.quoting = False
                            self.delimiters = _DELIMITERS
                            self.skip_whitespace()
                            continue
                    elif c == '\n':
                        return Token(EOL, '\n')
                    elif c == ';':
                        while 1:
                            c = self._get_char()
                            if c == '\n' or c == '':
                                break
                            token += c
                        if want_comment:
                            self._unget_char(c)
                            return Token(COMMENT, token)
                        elif c == '':
                            if self.multiline:
                                raise exception.SyntaxError('unbalanced parentheses')
                            return Token(EOF)
                        elif self.multiline:
                            self.skip_whitespace()
                            token = ''
                            continue
                        else:
                            return Token(EOL, '\n')
                    else:
                        # This code exists in case we ever want a
                        # delimiter to be returned.  It never produces
                        # a token currently.
                        token = c
                        ttype = DELIMITER
                else:
                    self._unget_char(c)
                break
            elif self.quoting:
                if c == '\\':
                    c = self._get_char()
                    if c == '':
                        raise exception.UnexpectedEnd
                    if c.isdigit():
                        c2 = self._get_char()
                        if c2 == '':
                            raise exception.UnexpectedEnd
                        c3 = self._get_char()
                        if c == '':
                            raise exception.UnexpectedEnd
                        if not (c2.isdigit() and c3.isdigit()):
                            raise exception.SyntaxError
                        c = chr(int(c) * 100 + int(c2) * 10 + int(c3))
                elif c == '\n':
                    raise exception.SyntaxError('newline in quoted string')
            elif c == '\\':
                #
                # It's an escape.  Put it and the next character into
                # the token; it will be checked later for goodness.
                #
                token += c
                has_escape = True
                c = self._get_char()
                if c == '' or c == '\n':
                    raise exception.UnexpectedEnd
            token += c
        if token == '' and ttype != QUOTED_STRING:
            if self.multiline:
                raise exception.SyntaxError('unbalanced parentheses')
            ttype = EOF
        return Token(ttype, token, has_escape)