Parse a token stream from inside an attribute selector.
    
        Enter this function after a left-bracket is found:
        http://www.w3.org/TR/CSS2/selector.html#attribute-selectors

def parse_attribute(tokens, is_merc):
    """ Parse a token stream from inside an attribute selector.
    
        Enter this function after a left-bracket is found:
        http://www.w3.org/TR/CSS2/selector.html#attribute-selectors
    """
    #
    # Local helper functions
    #

    def next_scalar(tokens, op):
        """ Look for a scalar value just after an attribute selector operator.
        """
        while True:
            tname, tvalue, line, col = tokens.next()
            if tname == 'NUMBER':
                try:
                    value = int(tvalue)
                except ValueError:
                    value = float(tvalue)
                return value
            elif (tname, tvalue) == ('CHAR', '-'):
                tname, tvalue, line, col = tokens.next()
                if tname == 'NUMBER':
                    try:
                        value = int(tvalue)
                    except ValueError:
                        value = float(tvalue)
                    return -value
                else:
                    raise ParseException('Unexpected non-number after a minus sign', line, col)
            elif tname in ('STRING', 'IDENT'):
                if op in ('<', '<=', '=>', '>'):
                    raise ParseException('Selector attribute must use a number for comparison tests', line, col)
                if tname == 'STRING':
                    return tvalue[1:-1]
                else:
                    return tvalue
            elif tname != 'S':
                raise ParseException('Unexpected non-scalar token in attribute', line, col)
    
    def finish_attribute(tokens):
        """ Look for the end of an attribute selector operator.
        """
        while True:
            tname, tvalue, line, col = tokens.next()
            if (tname, tvalue) == ('CHAR', ']'):
                return
            elif tname != 'S':
                raise ParseException('Found something other than a closing right-bracket at the end of attribute', line, col)
    
    #
    # The work.
    #
    
    while True:
        tname, tvalue, line, col = tokens.next()
        
        if tname == 'IDENT':
            property = tvalue
            
            while True:
                tname, tvalue, line, col = tokens.next()
                
                if (tname, tvalue) in [('CHAR', '<'), ('CHAR', '>')]:
                    _tname, _tvalue, line, col = tokens.next()
        
                    if (_tname, _tvalue) == ('CHAR', '='):
                        #
                        # Operator is one of '<=', '>='
                        #
                        op = tvalue + _tvalue
                        value = next_scalar(tokens, op)
                        finish_attribute(tokens)
                        return SelectorAttributeTest(property, op, value)
                    
                    else:
                        #
                        # Operator is one of '<', '>' and we popped a token too early
                        #
                        op = tvalue
                        value = next_scalar(chain([(_tname, _tvalue, line, col)], tokens), op)
                        finish_attribute(tokens)
                        return SelectorAttributeTest(property, op, value)
                
                elif (tname, tvalue) == ('CHAR', '!'):
                    _tname, _tvalue, line, col = tokens.next()
        
                    if (_tname, _tvalue) == ('CHAR', '='):
                        #
                        # Operator is '!='
                        #
                        op = tvalue + _tvalue
                        value = next_scalar(tokens, op)
                        finish_attribute(tokens)
                        return SelectorAttributeTest(property, op, value)
                    
                    else:
                        raise ParseException('Malformed operator in attribute selector', line, col)
                
                elif (tname, tvalue) == ('CHAR', '='):
                    #
                    # Operator is '='
                    #
                    op = tvalue
                    value = next_scalar(tokens, op)
                    finish_attribute(tokens)
                    return SelectorAttributeTest(property, op, value)
                
                elif tname != 'S':
                    raise ParseException('Missing operator in attribute selector', line, col)
        
        elif tname != 'S':
            raise ParseException('Unexpected token in attribute selector', line, col)

    raise ParseException('Malformed attribute selector', line, col)