def evaluate(self, tokens, evaluation=''):
        """A basic parser for a custom attribute grammar.

        One thing to note is that ambiguous grammars need to be iterated over,
        since the duplicate rules can't be mapped via dictionary key.
        Unambiguous grammars are therefore more performant,
        because the lookup is O(1) vs. O(N).
        """
        if self.DEBUG:
            prnt('Ruleset', self.rules)
            print('\nEvaluating tokens: {}'.format(tokens))
        for token in tokens:
            for rule in self.rules:
                # Expressions are already parsed when adding: (L => R = [L, R])
                left, right = rule
                print('Current rule = {} => {}'.format(left, right))
                if token == left:
                    is_attr = right in self.attr_token
                    is_terminal = right.endswith(self.terminus)
                    if is_attr and is_terminal:
                        print('\nEvaluating terminal: `{}`'.format(token))
                        evaluation += self._parse_terminal(
                            self._attr(right), token)
                    else:
                        non_terms = list(right)
                        print('\nEvaluating non-terminal {}'.format(non_terms))
                        evaluation += self.evaluate(
                            non_terms, evaluation=evaluation)
        return evaluation
dataset/ETHPy150Open christabor/MoAL/MOAL/languages/formal_language_theory/grammars/attribute_context_free.py/AttributeContextFreeGrammar.evaluate/swapped operands of `in`