[Tutor] how to cope with text litterals by code parsing?

denis denis.spir at free.fr
Mon May 17 11:12:32 EDT 2004


In a module that parses Python code, I have a symbol_row class that builds a
list of meaningful symbols (about what Guido van Rossum calls 'tokens' in
the language reference) out of a line of code. It splits the line and
defines each symbol's nature (e.g. keyword) and role (e.g. operator).
Everything works fine, but I'm not satisfied of how it's done.

The splitline function, among other problems, has to cope with the
well-known problem of explicit texts (so-called 'litterals') that can hold
anything; especially all kinds of signs that will be used as marks for
splitting. I couldn't find any smart and elegant algorithm for that.
I do it so:

-1- find, read, store and replace the explicit texts by a placeholder
(' $$$ ')
-2- split the line
-3- replace the placeholder by the original texts

I don't like that solution 'instinctively', so to say it hurts my sense of
easthetics ;-)
Also, it's not an overall solution: it works only because the code can't
hold anything (any character of sequence of characters); or rather because
if it does hold anything, it's not a valid piece of code and the problem of
explicit text isn't relevant anymore.

Well I would be happy to hear about alternative algorithms.
(below the guilty function, it's named and commented in a kind of english)


    def split_line(self):
        A task that seems easy.
        line = self.line
        # First, replace the texts (that could hold signs) by
        # placeholders: '$$$', surrounded with spaces
        pos, texts, placeholder = 0, [], '$$$'
        while pos < len(line):
            if line[pos] in quotes:
                # read the text
                chars, quote = line[pos:], line[pos]
                text = self.text_read(chars)
                size = len(text)
                if size == 0:   # '' was returned by text_read()
                    print 'Error found while reading explicit text ' \
                        'at position:', pos
                    return []
                texts.append(text)  # save the text
                # replace the text with a placeholder
                line = line[:pos] + \
                       space + placeholder + space + \
                pos += 5    # size of placeholder + 2 spaces
                pos +=1
        # Then, read across the line
        # to surround all signs with spaces.
        # We can't simply use replace(),
        # köz some signs (<) are part of other (<=).
        # The signs made of two chars are tested first.
        pos = 0
        while pos < len(line):
            sign_found = False
            for sign in signs:
                if line[pos:].startswith(sign):
                    size = len(sign)
                    line = line[:pos] + \
                           space + sign + space + \
                    pos += size + 2     # sign + 2 spaces around
                    sign_found = True
                    break               # don't check other signs!
            if not sign_found:
                pos += 1
        # now, erase useless spaces
        line = line.strip()
        two_spaces = space * 2
        while line.count(two_spaces) != 0:
            line = line.replace(two_spaces,space)
        # finally split the line...
        self.symbols = line.split(space)
        # ...and replace the placeholders with the original texts
        iText = 0
        for iSymbol in range(len(self.symbols)):
            if self.symbols[iSymbol] == placeholder:
                self.symbols[iSymbol] = texts[iText]
                iText += 1

More information about the Tutor mailing list