code: def roll_dice(spec):
      
      if spec[0] == 'c': return spec
      if spec[0] == 'r':
          r = spec[1:]
          if len(r) == 2: return ('r', perform_roll(r[0], r[1]))
          k = r[3] if r[2] == 'k' else -1 
          d = r[3] if r[2] == 'd' else -1
          return ('r', perform_roll(r[0], r[1], k, d))
      if spec[0] == "x":
          c = None
          roll = None
          if spec[1][0] == "c": c = spec[1]
          elif spec[1][0] == "r": roll = spec[1]
          if spec[2][0] == "c": c = spec[2]
          elif spec[2][0] == "r": roll = spec[2]
  
          if (c == None or roll == None):
              return ('*', roll_dice(spec[1]), roll_dice(spec[2]))
          else:
              if (c[1] > 50):
                  raise SillyDiceError("I don't have that many dice!")
              return ("x", [roll_dice(roll) for i in range(c[1])])
      if spec[0] in ops:
          return (spec[0], roll_dice(spec[1]), roll_dice(spec[2]))
      else: raise ValueError("Invalid dice specification")
docs: Perform the dice rolls and replace all roll expressions with lists of
      the dice faces that landed up.