def parse(self, chars):
        token = ''
        for char in chars:
            if '<*(' in char:
                if token:
                    yield TextNode(token)
                token = ''
            if char == '\\':
                # escape with backslash
                token += next(chars)
            elif char == '<':
                tag_content = self.read_until(chars, '>')
                name = ''
                regex = None
                macro = None
                for char in tag_content:
                    if char == '=':
                        name, regex = tag_content.split('=', 1)
                        break
                    if char == ':':
                        name, macro = tag_content.split(':', 1)
                        break
                if regex:
                    yield RegexTagNode(name, regex)
                elif macro:
                    yield MacroTagNode(name, macro)
                else:
                    yield TagNode(tag_content)
            elif char == '*':
                # wildcard
                yield WildcardNode()
            elif char == '(':
                yield OptionalNode(list(self.parse(chars)))
            elif char == ')':
                # end of node list, stop parsing
                break
            else:
                # literal output
                token += char
        if token:
            yield TextNode(token)
dataset/ETHPy150Open codysoyland/surlex/src/surlex/grammar.py/Parser.parse/swapped operands of `in`