## Step 1: Define the symbolic representation of the problem
Let's denote the number of packages of drills as $x_1$ and the number of packages of saws as $x_2$. The objective is to maximize the profit $P = 35x_1 + 100x_2$. The constraints are based on the availability of the machines: 
- Milling machine: $20x_1 + 30x_2 \leq 800$
- CNG machine: $70x_1 + 90x_2 \leq 800$
Also, $x_1 \geq 0$ and $x_2 \geq 0$ because the number of packages cannot be negative.

## Step 2: Convert the problem into a Gurobi-compatible format
The symbolic representation can be directly translated into Gurobi code. We need to:
- Define the variables $x_1$ and $x_2$
- Define the objective function $35x_1 + 100x_2$
- Define the constraints $20x_1 + 30x_2 \leq 800$ and $70x_1 + 90x_2 \leq 800$

## 3: Write down the optimization problem in a structured format
```json
{
    'sym_variables': [('x1', 'drills'), ('x2', 'saws')],
    'objective_function': '35*x1 + 100*x2',
    'constraints': [
        '20*x1 + 30*x2 <= 800',
        '70*x1 + 90*x2 <= 800',
        'x1 >= 0',
        'x2 >= 0'
    ]
}
```

## 4: Implement the optimization problem using Gurobi in Python
```python
import gurobi

def solve_optimization_problem():
    # Create a new model
    model = gurobi.Model()

    # Define the variables
    x1 = model.addVar(name="drills", lb=0)
    x2 = model.addVar(name="saws", lb=0)

    # Define the objective function
    model.setObjective(35 * x1 + 100 * x2, gurobi.GRB.MAXIMIZE)

    # Define the constraints
    model.addConstr(20 * x1 + 30 * x2 <= 800, name="milling_machine")
    model.addConstr(70 * x1 + 90 * x2 <= 800, name="CNG_machine")

    # Optimize the model
    model.optimize()

    # Print the results
    if model.status == gurobi.GRB.OPTIMAL:
        print("Optimal solution found.")
        print(f"Number of drills: {x1.varValue}")
        print(f"Number of saws: {x2.varValue}")
        print(f"Maximum profit: {model.objVal}")
    else:
        print("No optimal solution found.")

solve_optimization_problem()
```