MATL, 93 92 90 89 86 85 84 bytes
t"t'(?<!\()[*-/]'1&XXX<t?:&)w0XH&)40hwb'\d+|[\(-/ ]'XX"@gt1)t47>Ew41>-H+XH2=?41XH]&h
Try it online! Or verify all test cases.
The code uses a non-recursive approach, based on the facts that
- each operator must have a
(
immediately before, and - the corresponding
)
must be placed immediately after the first number for which the count of numbers minus operators to the right of the(
equals2
.
The procedure is as follows:
Repeat these steps as many times as the input length (it would suffice to repeat as many times as the number of operators in the input string):
- Find the first operator (
+-/*
) that is not predeced by(
, if any. - Insert
(
right before that. - Take the substring after that position until the end and split it into groups, where each group is either a number (one or more digits), an operator, an opening or closing parenthesis, or whitespace (one or more spaces).
- Start a counter at
0
. For each group from the previous step, increment the counter if the group is a number, and decrement it if itthe group is an operator. - When the counter reaches
2
, insert)
right after that group.