code: def operatorPrecedence(base, operators):
      
  
      # The full expression, used to provide sub-expressions
      expression = Forward()
  
      # The initial expression
      last = base | Suppress('(') + expression + Suppress(')')
  
      def parse_operator(expr, arity, association, action=None, extra=None):
          return expr, arity, association, action, extra
  
      for op in operators:
          # Use a function to default action to None
          expr, arity, association, action, extra = parse_operator(*op)
  
          # Check that the arity is valid
          if arity < 1 or arity > 2:
              raise Exception("Arity must be unary (1) or binary (2)")
  
          if association not in (opAssoc.LEFT, opAssoc.RIGHT):
              raise Exception("Association must be LEFT or RIGHT")
  
          # This will contain the expression
          this = Forward()
  
          # Create an expression based on the association and arity
          if association is opAssoc.LEFT:
              new_last = (last | extra) if extra else last
              if arity == 1:
                  operator_expression = new_last + OneOrMore(expr)
              elif arity == 2:
                  operator_expression = last + OneOrMore(expr + new_last)
          elif association is opAssoc.RIGHT:
              new_this = (this | extra) if extra else this
              if arity == 1:
                  operator_expression = expr + new_this
              # Currently no operator uses this, so marking it nocover for now
              elif arity == 2:                                      # nocover
                  operator_expression = last + OneOrMore(new_this)  # nocover
  
          # Set the parse action for the operator
          if action is not None:
              operator_expression.setParseAction(action)
  
          this <<= (operator_expression | last)
          last = this
  
      # Set the full expression and return it
      expression <<= last
      return expression
docs: This re-implements pyparsing's operatorPrecedence function.
  
      It gets rid of a few annoying bugs, like always putting operators inside
      a Group, and matching the whole grammar with Forward first (there may
      actually be a reason for that, but I couldn't find it). It doesn't
      support trinary expressions, but they should be easy to add if it turns
      out I need them.