Parse a Scala expression
JavaScript (ES6),  180 ... 155  152 bytes
Returns a multidimensional list. The outermost expression is parenthesized, and so are the atoms.

f=(i,a=i.split(/ +/))=&gt;&quot;w | ^ &amp; &lt;&gt; =! : +- */%&quot;.split` `.some(p=&gt;a.map((s,j)=&gt;i=!!s.match(`^[\\${p}]`)&amp;j?j:i)|i)?[f(i=a.splice(i),a),i.shift(),f(a,i)]:a

Try it online!
How?
This is a recursive algorithm. At each iteration, we look for the last operator with the lowest precedence, split the expression at this position and process recursive calls on both resulting parts. We stop the recursion when we reach an atom.
In order to split the expression and isolate the operator, we use a combination of splice() and shift() as shown in the following example, where integers are used instead of operators and operands.
a = [ 0, 1, 2, 3, 4, 5, 6 ];
i = 3;
i = a.splice(i); // --&gt; a[] = [ 0, 1, 2 ] (left expression)
                 //     i[] = [ 3, 4, 5, 6 ] (operator + right expression)
i.shift();       // --&gt; operator = 3
                 //     i[] = [ 4, 5, 6 ] (right expression)

Commented
f = (                      // f is a recursive function taking:
  i,                       //   i   = input string on the 1st iteration,
                           //         and then some non-empty array
  a = i.split(/ +/)        //   a[] = input string split on spaces
) =&gt;                       //         NB: operators are expected at odd positions
  &quot;w | ^ &amp; &lt;&gt; =! : +- */%&quot; // this string describes the groups of operators,
                           // from lowest to highest precedence
  .split` `                // split it
  .some(p =&gt;               // for each pattern p:
    a.map((s, j) =&gt;        //   for each string s at position j in a[]:
      i =                  //     update i:
        !!s.match(         //       see if s matches p; the '\' is required for
          `^[\\${p}]`      //       'w' and '^', and harmless for the other ones
        ) &amp; j ?            //       if there's a match and j is odd:
          j                //         update i to j
        :                  //       else:
          i                //         leave i unchanged
    )                      //   end of map()
    | i                    //   make some() succeed if i is a number
  ) ?                      // end of some(); if successful:
    [                      //   build a new array consisting of:
      f(                   //     the result of a recursive call ...
        i = a.splice(i), a //     ... with the left expression
      ),                   //
      i.shift(),           //     followed by the operator
      f(                   //     followed by the result of a recursive call ...
        a, i               //     ... with the right expression
      )                    //
    ]                      //   end of new array
  :                        // else:
    a                      //   just return a[]