[Question]
  [
In most programming languages, arithmetic is written with *infix notation* -- i.e. the operator is put in between the operands -- e.g. `1+2`. In contrast, with **Polish notation** (a.k.a *prefix notation*), the operator comes *before* the operands -- e.g. `+1 2`. As long as the number of operands for each operator is fixed, this means that parentheses are never necessary, unlike with infix notation.
## The Challenge
Given a string consisting of nonnegative integers (digits 0 through 9), spaces, `+`, `-`, `*`, and `/` representing a single expression in Polish notation, add parentheses around each sub-expression, maintaining the whitespace. The parentheses should start right before the operator and end right after the last operands. You can assume each function has arity 2 (i.e. it takes in exactly 2 operands). You can also assume there will be no extra preceding zeros (e.g. `000` or `09`).
## Test Cases
| Input | Output |
| --- | --- |
| `+1 2` | `(+1 2)` |
| `++ 1 2 3` | `(+(+ 1 2) 3)` |
|  `+1 +2 3` |  `(+1 (+2 3))` |
| `* *1 2 /3 0`  | `(* (*1 2) (/3 0))`  |
| `//30 300/18 205` | `(/(/30 300)(/18 205))` |
| `/ -20/ 30 30 999` | `(/ (-20(/ 30 30)) 999)` |
| `/////1 2 3 4 5 6` | `(/(/(/(/(/1 2) 3) 4) 5) 6)` |
| `/1/2/3/4/5/6/7/8 9` | `(/1(/2(/3(/4(/5(/6(/7(/8 9))))))))` |
Standard loopholes are forbidden. As this is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), the shortest program wins.
  
[Answer]
# Regex (Perl / PCRE / Python[`regex`](https://bitbucket.org/mrabarnett/mrab-regex/src/hg/)), ~~48~~ ~~47~~ ~~45~~ ~~44~~ 43 bytes
```
s~([*-/]( *(\d++|\((?1)\))){2})(?!\))~($1)~
```
[Try it online!](https://tio.run/##HYzbCoJQEEXfz1fsROJciDkXrcQuH5LRQwkKVmJBoOWvn47uh5m9FsO0ZdekPu73Ov9UdVPy3UEM1@p5b3OD2fjXyE9yRWcOyYubUt@C86MRhRBisD/Bj4tQRx4bMfo87pfLtqsf76h4RIH2JsfM8eXnlYFlSiEsOIaQYKY5oYScPDlogBE5Dac1mS2sThlhZTVhlkCWZeEiZP6EBCnWjAxZcpRQSmva0BbZHw "Perl 5 – Try It Online") - Perl  
[Try it online!](https://tio.run/##nVNhb5swEP3Or7giVNsJxJC0XVNCo0ptpUzbPqyrNinJEAGTsBJANlmjpslfz85E09Rp3YcigY/z@b13z/YsUov96PYuACmiBByZACEgBwMSvukhxmBYLSqwJARQSTEPpajyKBaU8E5rGIaLKK/DuFxWWS7khE6YP/nMFbGR1oYUk@Fc6IKiFkWtaBjejj7chCGzwWO@kaVALTl2p0cBUYRBvZDlIxTiEW7WsajqrCwo@ZgplRVzMJVJcI2VoBRc5E19aNYnl2RH4Pn5oG8Z1fEC1Y1dp3/lTKaRs7Uoa7U7g8vh9ykntpWwfxOZo@JnlGcJJCLPllktpKnpdOdiXeVlIpDLRmp2II7LVVGjfHYUnLyC@FWWKLxYLWdCQpn@QVYNtDp00sVOrPQQ93SsKbHNzqFNPSaYnWM2jXIlfCMtcXuxTVXLUFV5hjJSBpECK2abxpQYjo8Bp6tSUXOeLdX66vr@2/uVaWNJEAQN0CuG3xdSxOW8yJ5EAmkeofWkY8Udov0/eB4HAZkTZs2DWq6EDwLRtO4OCo/9rZEVWahETc0qlqIzi@KHWuInbNo3bTAdz9RYL8qQdSUVSvh/2Y/DlKstRCOo9RS4vpUHKZ40Re@@XI8@MZ9tUCi18jF6kIsCI@Z40yAwJ4XJsFitZjiDadu1Ha9pC4GYiBelLkG7nwLPNwA0g49wVhW8OP@WxKOg8M1tcDxbO9@AHGEww915QIhc72Plb0HDgmnlpr/968pQ5u/Vjo5bDp9SaNFJ0m4/TygdemzCGNt0t4wOjzDcUctju/3brrHRCHAK1LCRFxeOtzUvYzzQHbzbvliLGPhKST7LCq5v@@@pfduDrtFuAw7QQzMAMKO/@rcFLZ3nPXABDM57LvRcl3vn0HVPDQ5O1@XQJAH6/T5W4NMgwQmcwpnBPd7lPX7CT/kZf8fPof8L "Bash – Try It Online") - PCRE1  
[Try it online!](https://tio.run/##fVNhb5swEP3Or7giq9gJxJC0XSPqRpPaSZ22fdhWbVLIEAFDWAkgm6xV2@SvZ2fyYeq0Dsn4OJ/fvfds2lW7v5i1qxaIAgGtkkWsZFslqaQOHw1mcbxKqi5Om3VbVlJFNGJh9JlrxwUHR47JuJCmoO5k3Wkax@9uPlzHMXMhYKFV5kCJmvuLI@Foh0G3Us091PIerh9S2XZlU1PnY6l1WRdga9vBPSRDKrgpWITQ788unZ0Dz88HfuukS1fIbu5707detEi8LaFsMBxdXM5@LLjjkoz9u5F9U/9KqjKDTFbluuyksk07o1w@tFWTSezlYmt2aJw2m7pD@uxInLyC@E01SLzerJdSQZP/QdY9tD4oGaMSkh/iiYlNS5Q5Osg0c4bZArN5UmkZWnmjZIIydadi3VYl0sgZJBpIyp56U1I4PgZcbhtN7aJc64e3V7ff329sF0uEED3QK4bf1kqmTVGXjzKDvErQemdE0pFj/D94ngrhFA4jhejURoYgEc3wHiHxNNxaZV3GWnbUblMlR8skvesUvuJevu2C7QW2wXpRhl03SiOF/5f9PCz5xkI0gpJH4YekEjneNE2/fL26@cRC9oREKanm6EEla4yYFyyEsKPaZlisN0tcwbTru17Qy0IgJtNVY0rQ7kcRhBaA6RAiHGnFi/tPFF4FjaNywQtc43wPcoTBEk/nDiEqc45tuAUDCzap7HD71y9DWbjXOzofeHxBYUCjbDh8jiidBSxijD2Nt4zOjjDcURKw3X4/DGBsDYeAE0yQHwBmzNt8DmBg8nwCPoDF@cSHie/z4BzG/qnFwRv7HPokwHQ6xQp8eiQ4gVM4s3jAx3zCT/gpP@Nv@DlMfwM "PHP – Try It Online") - PCRE2  
[Try it online!](https://tio.run/##bVJdb9owFH3Pr7iNJsWGFOcDKIR5VbehCYkWqe22h8CkdHGoNcdBdthKv/46uwmrqknNQ2If3XvuOfdks6tvKx3vZbmpTA12Z30j1uJuAoYb13X39pmknWO2ItAhy7zbfVwSchrSJaX0IXqi5PQIj89kGdLnPdanYXIcrhxZgEmD1RH3rJeAyaQVcLXTdXY3NaYyxDuX1kq9Bte6HnVybtJDV2VyklOQGqyoe1stK03wREym14L0R/5gRKn/ioxP/DAa/AcNB/44RuShU2YbgoS@@47QTrf3/sPpD5c@0TcFzfTvTMkccqFkKWthUJYBDqZnN0rWKKqRp4Qmhh7x/psc302FlvS2vBEGquKVyyJZobK15cEEflZbXfPQKSoDRePUpPEqcQDpC869NS7sUBI4IJQVCbSt8MjhwZNe0ubTm325WFxOP51dTX3wyhf0/Ov8ejafXTSgfQE/L67P5nNE7l6Qb9PLj4ur6VNarByLu49Wbd6YwQTucW4jTbUh7GzP1rnUB32NfUUh0zmoFHNGuUuNehVXadAGD39upRIQYj2UzfraeXZ7g3vzwfqg/IM7/@CKTnAQhxJ/FuzAEWXa0AYJ3BiR/Wqn3iewMVLXhDqoLpz8uwmdc0X33RAip9sF/ECMHACINO/m2oFOg7MYAgCHsTiAOAhYOIIoGDgMjqOAQQsCjMdjrMCnZYI@DGDosJBFLGZ9NmBDdsJGMP4L "Python 3 – Try It Online") - Python `import regex`
This is a single regex substitution to be repeatedly applied until it has nothing to match (or until there is no change, where necessary or convenient).
In the following explanation, `␣` represents a space:
```
s~         # Begin substitution - match the following:
(          # Define subroutine (?1); $1 = the following (the entire match):
    [*-/]  # Character class of the four arithmetic operators. This also
           # includes "," and ".", but those are guaranteed not to be in the
           # input.
    (
        ␣*        # Any number of spaces, minimum zero.
        (         # Define subroutine (?2) as an argument to an operator:
            \d++  # Any number of digit characters, minimum one; force all of
                  # them to be consumed (prevent backtracking).
        |  # or...
            \(    # An opening parenthesis
            (?1)  # Recursively call (?1)
            \)    # A closing parenthesis
        )
    ){2}   # Do the above twice (for two arguments).
)
(?!\))     # Assert there is no closing parenthesis following this, as that
           # would indicate that this expression has already been parenthesized.
~          # Replace with the following:
($1)       # Preserve $1 (the entire match), and surround it with parentheses.
~          # Flags:
           # No global flag. For better efficiency, adding the "g" flag
           # would allow the substitution loop to end sooner, but it's
           # not needed.
```
Saved 1 byte by using `{2}` instead of a subroutine call for the second argument (shamelessly stolen from [Neil's regex](https://codegolf.stackexchange.com/a/250879/17216)).
## Bonus: Convert Polish notation to infix notation, ~~58~~ 52 bytes
```
s~([*-/]) *(\d++|\((?2)(?1)(?2)\)) *((?2))~($2$1$3)~
```
[Try it online!](https://tio.run/##fVNhb5swEP3Or7giq9gJxJC0XSPqRpPaSZ22fdhWbVLIEAFDWAkgm6xV2@SvZ2fyYeq0Dsn4OJ/fe/ds2lW7v5i1qxaIAgGtkkWsZFslqaQOHw1mcbxKqi5Om3VbVlJFNGJh9JlrxwUHR47JuJCmoO5k3Wkax@9uPlzHMXMhYKFV5kCJmvuLI@Foh0G3Us091PIerh9S2XZlU1PnY6l1WRdga9vBPSRDKbgpWITQ788unZ0Dz88HfeukS1eobu5707detEi8LaFsMBxdXM5@LLjjkoz9m8i@qX8lVZlBJqtyXXZS2YbOdC4f2qrJJHK5SM0OxGmzqTuUz47EySuI31SDwuvNeikVNPkfZN1D60MnY@yE5Id4YmJDiW2ODm2aOcNsgdk8qbQMrbxRMsE2dadi3VYlysgZJBpIyp56U1I4PgZcbhtN7aJc64e3V7ff329sF0uEED3QK4bf1kqmTVGXjzKDvErQemdE0pFj/D94ngrhFA4jhejURoYgEc3oHqHwNNxaZV3GWnbUblMlR8skvesUvuK@fdsF2wtsg/WiDFk3SqOE/5f9PCz5xkI0gpJH4YekEjneNE2/fL26@cRC9oRCKanm6EEla4yYFyyEsKPaZlisN0tcwbTru17Qt4VATKarxpSg3Y8iCC0AwxAiHGnFi/tPFF4FjaNywQtc43wPcoTBEk/nDiEqc45tuAUDCzap7HD71y9DWbjXOzofeHzBYECjbDh8jiidjRmdBczMETMLJmI7SsYkIBO22@@HAYyt4RBwggkKBcCMeZvPAQxMnk/AB7A4n/gw8X0enMPYP7U4eGOfQ58EmE6nWIFPjwQncApnFg/4mE/4CT/lZ/wNP4fpbw "PHP – Try It Online") - PCRE2
```
s~        # Begin substitution - match the following:
([*-/])   # Define subroutine (?1): Character class of the four arithmetic
          # operators. This also includes "," and ".", but those are guaranteed
          # not to be in the input.
␣*        # Any number of spaces, minimum zero.
(         # Define subroutine (?2) as an argument to an operator:
    \d++  # Any number of digit characters, minimum one; force all of
          # them to be consumed (prevent backtracking).
|  # or...
    \(    # An opening parenthesis
    (?2)  # An argument
    (?1)  # An operator
    (?2)  # An argument
    \)    # A closing parenthesis
)
␣*        # Any number of spaces, minimum zero.
(         # $3 = the following:
    (?2)  # second argument
)
          # No need for "(?!\))", because parenthesized expressions won't be in
          # ARGUMENT ARGUMENT OPERATOR format.
~         # Replace with the following:
($2$1$3)  # ( argument1 operator argument2 )
~         # No flags
```
See also [Convert from postfix notation to infix notation](https://codegolf.stackexchange.com/questions/5847/convert-from-postfix-notation-to-infix-notation/250890#250890), which adds parsing of operator precedence.
# Regex (Perl / Boost), ~~47~~ 46 bytes
```
s~([*-/] *(\d++|\((?1)\)) *(?2))(?!\))~\($1\)~
```
[Try it online!](https://tio.run/##HYzbCsIwEETf8xWjFEkayubSqiVqP8SID1powUtRQajaX49p52GHc1imqx@XIiT9Vrl3015qvtmJz6m5XzunMZnwHPg@zeiAlPuzlF/PeaWFFyKKygjBq1mEwfNEezEEl/SLRfdob6@5v80jbbXDxMnxF6SGYVIiFixDTDTjHTFFOnqyUAAjsgpWKdJrGFUwQmYUYZJAWZbxI2ZaQo4CS0aaDFnKqaAlrWiN8g8 "Perl 5 – Try It Online") - Perl  
**[Try it online!](https://tio.run/##fVRtj9o4EP6eXzHQqthJaAIsW0jIrlTpPpxU9UPbk@5UelFIHIganCg23TfYn146dgIbuHIRSvDMPI8fz4wnLsv@Mo73rzIe55uEwWxRFEI6FVuy@7ersrwx4lVUQVh@/QYBfOq@v7v7vhht/nl4@PvL6vpuRfbimXw1@843MMk8saztnJDbAZ1TiobbIaXktoOL5zl5PZjT5z09Z@jaYJZBWPrGi4gMNVQsWt8YGZdQVvgOWVUVFYkLLiRoTeaaCREtGX0SMvG8GANgNoPGqv5qO@NJ7kPF5KbiMPB3oCjFA5fRfcNJnxpve6PuZx0CetWl/q5ORMLybB24PmCecqSqIr5kRLu4rT9R/VkcWTdIOgkl4f2Iwiw4rhe4PtCaacaTUJPXZKag8GQAPmlRAfF9YVkHi3qyFEhHBTWbfPzrwwf/6GW5YDrEFEHQm897CK0RlnWG2f0epKUcI0VNvTN2uiDrKOPkoEYjLKvsBD3R2247pE6RMtEXgpN8@xqk42budnvIojbYVxN7PKFn1u1oaE/f2YPhGD3YG/EKK/SaUNN6O7u5/bdr13qP@51U8k/@I8qzpK5dJpkqJ6C8@lBNurG7WzUoG40dcfEIJlYEc@v22jTpKY040KSXadITGtUco2EooUAmfRc9T19Gz@NFuC6ScO1DtJEFiFYE9sg6kmGaVUKGBc8fYHvmivLcb7UTbov1mvOeD6lqLHGXyXiFhUwPZY0j7IZe1vMApWwDOBOTKb9fN84Cr@p3v4USl1BKv7iEuv8/1P0l1LpGvQng@VK6foNaIkqcoP6TQr@NSlgabXLpwcmo6f6hqujBocHSPFpCV3mwES7Nn1qFHmNtwRhBShsKbAkNwybP@BInTLmRrcqp6/eo5o8OWjKZZ5yRWlXG7Tqe@uej4pEC2lWPElV13OQxGLzMi2bGtFHqaQspNvKsI8OKlXkUM6L3tPEANgj84RFOWNT@Gh006tqJPQYpD25QHE5bz5sTJbFiwbS2clJHNMl1fWO3twYwNCwL8AMj7UWLequlCaayOyNwAQzHGbkwcl1nMIGhOzYc6A9dB7QRYDqdYgQ@mgmuYAzXhjNwhs7IuXLGzrXzzpnA9Gesqi72/VznJtSp@QU "C++ (gcc) – Try It Online") - Boost**
Boost needs parentheses escaped in its replacement argument, because its conditional-replacement syntax uses parentheses. This isn't compatible with PCRE or Python[`regex`](https://bitbucket.org/mrabarnett/mrab-regex/src/hg/), as they will interpret it as a literal `\(` and `\)`.
This exposes a bug in Boost's subroutine call processing. If `{2}` is used to match two arguments, instead of `(?2)` to match the second argument, it makes an incorrect full match. Example:
`+(+ 1 2) 3`
If the regex `([*-/]( *(\d++|\((?1)\))){2})(?!\))` is used, it matches `+(+ 1 2)` instead of the entire expression, so the closing parenthesis is added in the wrong place.
But if the regex `([*-/]( *(\d++|\(([*-/]( *\d++){2})\))){2})(?!\))` (with `(?1)` replaced with itself to one level of depth) is used instead, it correctly matches the full string.
The bug is still present in the latest version of Boost. I have [reported it](https://github.com/boostorg/regex/issues/178).
# Regex (PCRE / Ruby), ~~47~~ ~~46~~ 44 bytes
```
s~([*-/]( *(\d++|\(\g<1>\))){2})(?!\))~(\1)~
```
[Try it online!](https://tio.run/##nVNhb5swEP3Or7ggVNsJxJC0XVNCo0ptpUzbPqyrNqnJEAFDWAkgm6xR2/SvZ2eiaeq07kORApfz@b13z75FpJa76dV1AFJECTgyAUJAjsckfNNDjPGkXtZgSQigliILpaiLKBaU8H53EobLqGjCuFrVeSHkjM6YP/vMFbGR1oYUk2EmdEHZiLJRNAyvph8uw5DZ4DHfyFOglrx1552AKMKgWcrqHkpxD5ebWNRNXpWUfMyVyssMTGUS3GMlKAU3eXMf2v3JGXkm8PS017eKmniJ6m5dZ3TuzOaRs7Uo6/b647PJ9zkntpWwfxOZ0/JnVOQJJKLIV3kjpKnpdOdiUxdVIpDLRmq2J46rddmgfNYJDl9B/CorFF6uVwshoUr/IKsWWu07GWAnVrqPhzrWlNhmf9@m/iaYzTCbRoUSvpFWeLzYpmpkqOoiRxkpg0iBFbPH1pQYDg4Al@tKUTPLV2pzfnHz7f3atLEkCIIW6BXDb0op4ior8weRQFpEaD3pW3GfaP/3nsdBQDLCrCxo5Fr4IBBN6@6j8NjfGnmZh0o01KxjKfqLKL5rJL7Ctn3TBtPxTI31ogxZ11KhhP@X/dgvudpCNIJaD4HrW0WQ4k1T9PrLxfQT89kjCqVWcYseFKLEiDnePAjMWWkyLFbrBa5g2nZtx2vbQiAm4mWlS9Duh8DzDQDN4COcVQcv7r8l8Soo/BU2OJ6tnW9BOhgs8HTuEKLQ51j7W9CwYFqF6W//GhnK/J16prddh88pdOks6fWecI6ysXc2Y4w9DraMTjoYPtOZx553b5tjo1XglCjiUZ6eOt7WPIvxRvdxuH2xETHwtZJ8kZdcj/vvpV3Pg4HR6wF@YIhuAGBGv/XfLnR1ng/BBTA4H7owdF3uncDAPTI4OAOXQ5sEGI1GWIFPiwSHcATHBvf4gA/5IT/ix/wdP4HRLw "Bash – Try It Online") - PCRE1  
[Try it online!](https://tio.run/##fVNhb5swEP3Or7giq9gJxJC0XSNKo0ntpE7bPmyrNilkiIAhrA4gm6xV2@SvZ2fyYeq0DsnmOJ/fe/ds2lW7v5i1qxaIgghaJcpEiVammaAOHw1mSbJKZZdkzbqtpFAxjVkYf@baccHBUWAyKYUpqDtRd5omybubD9dJwlwIWGhVBVCi5v7iKHK0w6BbqeYeanEP1w@ZaLuqqanzsdK6qkuwte3gHpKjFNwULELo9@eXzs6B5@eDvnXaZStUN/e96VsvXqTellA2GI4uLmc/FtxxSc7@TWTf1L9SWeWQC1mtq04o29CZzsVDK5tcIJeL1OxAnDWbukP57Cg6eQXxm2pQeL1ZL4WCpviDrHtofehkjJ2Q4hBPTGwosc3RoU3zzjFbYrZIpRahVTRKpNim7lSiW1mhjIJBqoFk7Kk3JYPjY8DlttHULqu1fnh7dfv9/cZ2sSSKoh7oFcNvayWypqyrR5FDIVO03hmRbOQY/w@eZ1HklA4jZdSpjQhBIJrRPULhWbi1qrpKtOio3WZKjJZpdtcpnJK@fdsF2wtsg/WiDFk3SqOE/5f9PCz5xkI0gpLHyA@JjAq8aZp@@Xp184mF7AmFUiLn6IEUNUbMCxZRZMe1zbBYb5a4gmnXd72gbwuBmMhWjSlBux@jILQADEOIcKSNXtx/ovAqaBzSBS9wjfM9yBEGSzydO4SQ5hzbcAsGFmwi7XD71y9DWbjXOzofeHxBYUDjfDh8xv@ovAguY8bY03jL6OwIwx2NA7bb74cBjK3hEPAFExQIgBkzm88BDEyeT8AHsDif@DDxfR6cw9g/tTh4Y59DnwSYTqdYgU@PBCdwCmcWD/iYT/gJP@Vn/A0/h@lv "PHP – Try It Online") - PCRE2  
**[Try it online!](https://tio.run/##bZJtb5swFIW/8ytOsklACBhI2zVtSRWtaIrUdlPaaZOARTQYgkRIZifrS17@enZJ0myqygdsX5/7@Ppci/nD80bAw1X3vmsJHieGCvUceQoR2FHNUyWtRJxLjrvnchY/@UJMRBPqTS5lXmaoyzopeJkoCWFE4ETb7KSjrlUsl0i8NQtss901wyg2Vx81vWFYF53LXxF7H9wr/8RFniDhRT7OZ1zs8VWVwpLTIp9pib4r0Sp4mc1GqHk4ep/2Q0yoyHI@fuACk/QfVe6xKWHtc2SSRrMjm9OFtOT8oaZNmyJwI31F3KAVWTwejgbDUSywwHK4xDCms4YK8DjiJci0wzQncoqlhz7P@NP07Kz35fZr3//cvfMPmqe3Gv/nvX975V8dFOO3ipvv1/e9696tD3yAjMccscQ3LgpVgrqEtIgzaH1qKAX473lONvJyVl36VTVWkUvExWP8LDEp9cNhmfq/A01BHmRvTCCvVkofr/VYJX/cdruZVnVuMxc24fKCEyqQTfTpJUjKfPHI391G4WV8JulYat5LrYpP5zO5hVc6Z7dTBKYTeV49LOvnlFIEtmWZbrTrFzAVOV0rDYp9ZDAg5waDjVxrQcNkkYaGFiaGsQy1MLtwOqGu6wt3pWuXNZqutdDR15uN4cBVDAM0oEVUgCLVv1o20KjirAUbUBhr2WjZNnNO4drHCoPp2gzbINBut0lB35aEIxzjRGEOc1mLHbFjdsI@sVO0/wI "Ruby – Try It Online") - Ruby**
Ported to Ruby's subroutine syntax.
## \$\large\textit{Functions}\$
# [Ruby](https://www.ruby-lang.org/), ~~75~~ ~~74~~ ~~69~~ ~~67~~ 66 bytes
*-5 bytes thanks to Steffan*  
*-1 byte thanks to Dingus*
```
->s{0while s[/([*-\/]( *(\d++|\(\g<1>\))){2})(?!\))/]&&="(#$1)";s}
```
[Try it online!](https://tio.run/##JYzRjoIwFETf@YqR3ZhCU29bRCXduh9C@7IRXJKGGNGYxfXb2cLOw70zJ5O53r9@ptZO4jg85eO7Cw2GmlidC0eeIWfuxPmvY@78oY4uy7KnfmXscxUt@fXapuztXWWpGV7TaKXB/0Sw5@Y2GHQtxlXEl3tMTX8yo1ULDbVQ3trU9akJNtRysxHaLxVcrl1/Q1sHbxDBxBV0wjniQ5EgKpL5zjFHPnMqIIGEqJAopCR1gJZlQhBaEhYIVFUVG1HLErYosUtIkaaCtlTSjvZ0QPUH "Ruby – Try It Online")
# [Python](https://docs.python.org/) (with [`regex`](https://bitbucket.org/mrabarnett/mrab-regex/src/hg/)), ~~107~~ ~~106~~ 105 bytes
```
import regex
f=lambda s,p=0:s==p and s or f(regex.sub('([*-/]( *(\d++|\((?1)\))){2})(?!\))',r'(\1)',s),s)
```
[Try it online!](https://tio.run/##NY1NboMwEIX3PsXrChtCxoaQBiIrB4EsiIAWyTEIU6lJ27NTg9rRaH4@vXkzPub3wabL0t/HYZoxtW/tJ@u0qe@3pobbjVoWTusRtW3gMEzo@Cbau48bD3gZxnTlCHnVRNF3xflFiUoI8ZX8CH558WOwmwJeKd@d8Pn/yT3cGU8tWec9DXq7kr2bm94WDH0H01puxPbXlLG6ah1UNihgtCll4cGmehYYp97OXDDvps5/W2sb3flzsUQKCYsi@IaUwYcna13XEOHKKYUEGFEqkUpJ6oREZowQJ5KwQSDPc6/wsTnhgAxHRooSSulAGR3plU7IfwE "Python 3 – Try It Online")
# [Python 3.8+](https://docs.python.org/3.8/) (with [`regex`](https://bitbucket.org/mrabarnett/mrab-regex/src/hg/)), ~~101~~ ~~100~~ 99 bytes
```
lambda s:[s:=regex.sub('([*-/]( *(\d++|\((?1)\))){2})(?!\))',r'(\1)',s)for i in s][-1]
import regex
```
Can't [Try it online!](https://tio.run/##LYzBboMwEETv/orpCRtK1oYkBSIrHwI5JAJSJMdBmEpN2n47tVHmsLszmn3jY/6827wYp6XXzWLOt0t7hqtqV@mpu3bfG/d14RGv45ROHDFv2iT5bTg/KtEIIX6yP8GPb/6M3qeIN8pvJ/r7hAGDhTvVqTqx4TbepxkrcHkZ93AHPLVkoWzW8sNt3NwOtmIYepjOciNwti1MoGgdNTaqYLSpZRWwofWsME6DnblgnqYOL9fZVvf@XSyJQsaSBH4hZ/DySZjBxohDTjkkwIhyiVxKUgUyuWOENJOENQTKsvQNr5WELXbYM1KUUU5b2tGePqhA@Q8 "Python 3.8 (pre-release) – Try It Online") - Confirmed to work on my machine, but `regex` is not installed on TIO or ATO.
Just like in [Remove redundant parentheses](https://codegolf.stackexchange.com/questions/250596/remove-redundant-parentheses/250617#250617), it's guaranteed that a fewer number of substitution iterations will be needed than the number of characters in the input, so this "do this for each character of `s`" trick works. The maximum number of substitutions approaches \$1/2\$ of the number of characters in the input string:
$$\lim\_{n\to\infty}{n\over {2n+2}}= {1\over 2}$$
# [PowerShell](https://github.com/TryItOnline/TioSetup/wiki/Powershell), 100 bytes
```
[char[]]($p="$args")|%{$p=$p-replace'[*-/](?> *(\d+|\(((\()|[^)]|(?<-3>.))+\))){2}(?!\))','($&)'};$p
```
[Try it online!](https://tio.run/##RYzRboJAFETf@Yop2cpdKL0LqJVY9UOAJsQuhYQAQRoTgW@niy@dh7l3TibTtXfd30pd14soTuOSXMu8T7KMRHeyRd7/3Gw5vY4mic7vdVfnV@0krs8ZXc5wKf32ppSIUpJT8iWziS6ffnR@l9JLpZRjONPlxXzOm0NiI535KLrF2OOkjkXb6/xakqhRNRBV0/0OcqwKEg853vtq0H7Z3obZlIMj/gH8pm30va4aDVvQRhQQtbTnxQsQWp4HcxBZMDJk9TW6cFfOERRgMUcKkVIcHBCqncXwQ8V4QiCOY9Mwei5hix32FgcccsRb3vGeP/iA@A8 "PowerShell – Try It Online")
Uses [Neil's regex](https://codegolf.stackexchange.com/a/250879/17216) with an additional -8 byte golf. Applies the substitution the same number of times as the length of the input in characters.
# [PHP](https://php.net/), 104 bytes
```
function($s){while($p!=$s=preg_replace('~([*-/]( *(\d++|\((?1)\))){2})(?!\))~','($1)',$p=$s));return$s;}
```
[Try it online!](https://tio.run/##HY5Pb4JAEMXvfIqRbMIOf7K7oFakhEtN04s2tDcxxNpFSAhuFkwPtn51uzCHnZ3fvLx5qlaP50zVCkiVPqprdxqaS0dJj7efumklJWqWkj5VWp5LLVV7PEnq3OneDdiBgkuLb8/7LSjNBBaIeAv/kGYz8707vkOJQMcnyjggJloOV92RPvl7JNVFU9KkPCFtWp3l0NOPz5e3LSZ4g6aipN33g26lSdJiIA5pahedjUbcX7/MxmCf@4HAZFI3KE/1ZZQkYFxFAuMMU@j22A@l1NocxFn6nm9ey@2u3OT5Ls/szcjXYK/JeBNNMk9AaHkemAaRBaYMGd9xdMEdOYuAA1iMRRwizplYQcgXFoMg5AwmCBDHsVGYmpxgDgtYWkywkEVszhZsyZ7YCuJ/ "PHP – Try It Online")
Thanks to Steffan for pointing out a 1 byte golf that has the added bonus of making this anonymous rather than recursive. Knocking off an additional 2 bytes from that has the further bonus of removing the "Undefined variable" warnings from this non-recursive function.
## \$\large\textit{Full programs}\$
# [MATL](https://github.com/lmendo/MATL), ~~54~~ 48 bytes
*-6 bytes thanks to Luis Mendo*
```
t"'([*-/]( *(\d++|\((?1)\))){2})(?!\))' '($1)'YX
```
[Try it online!](https://tio.run/##JYy7DsIwDEV3vuKCkOwkqpxHW5qpC5/AAKKVQGKErRvw7cEpd7DOPbb8ui/PcivLjvhqG5kZlqeHc5@JeQxmMsa849fwuFUkEO@Docu5zMdTIRcQaUPOQQFJERq1df6Fha07SfCAdpHkkbyXMCD6rho00QtWDeSc1yvN@hMtOvRVBYmSpJVOejnIgEw/ "MATL – Try It Online")
This too applies the substitution the same number of times as the length of the input in characters.
# [Perl](https://www.perl.org/) `-p`, ~~51~~ ~~50~~ 49 bytes
```
1while s;([*-/]( *(\d++|\((?1)\))){2})(?!\));($1)
```
[Try it online!](https://tio.run/##HYzNDoIwEITvfYox8dDSkOkPRRoOPIh4k0QSIkRMPKivbi18h92ZL5tdhscUUrKv2zgNWFt5LkpeJArZX7X@9FJ2VvVKqbf7Ktkdcmzl0aqUtIUTWiMveIFMNtvcaoFi8/QwgCC9gTeGtoEzQRClM8QugRhjvsjsn1AhoBa0dPSsGFjzxAbxNy/Pcb6vqVz@ "Perl 5 – Try It Online")
# [PHP](https://php.net/) `-F`, 98 bytes
```
<?for($s=$argn;$p!=$s=preg_replace('~([*-/]( *(\d++|\((?1)\))){2})(?!\))~','($1)',$p=$s););echo$s;
```
[Try it online!](https://tio.run/##VZBPT@MwEMXP5FM8ogjbDdbkD2WpnJAbUk972CNFlUlMU6mKLSfSSqXw1btOFw68w4zn59Ebj1/12J@90R2k78AYfFWx7ZfYuWrerOfJWCfa7waVuOs6FM6b3dYbd9Ct4eyTPy8kvXAs@KZL09OG8yYXGyHEe/EheHMdjp/slvEkF@w2ccFBKKFM29tkVOfvYdEMIAfEVfPePCY@Zh8zijdDrBge0drOKPBWTwrzhQhsrTCaCdLC7Z150/uDAlk3kesdve6HOUO2IDO1kB3G3vppa50ZtpPe1b8HyKeLMSqsccLffn8wWD/9qfH1KdAKnY2uniGPSI54OZ3m4epY5@pn4wHVTfn/aZc1Eh1HnR0MyuB9TnMUUZoiJJQRggKZ41wusJg5lciAiKjMUGYZ5Q8osmVEkEVGuEBgtVqFjqCLE@6wxH1EORVU0h0t6Z5@0QNW/wA "Bash – Try It Online")
[Answer]
# [Curry (PAKCS)](https://www.informatik.uni-kiel.de/%7Epakcs/), 102 bytes
```
f(s++t)|all(<'!')t=g s++t
g(' ':s)=' ':g s
g s|all(>'/')s=s
g(c:s++t)|elem c"+-*/"='(':c:g s++g t++")"
```
[Try it online!](https://tio.run/##NczBToQwEAbgO0/x05i0pZIpsKwLEe4ejAePxhhCWNwIK6HdGBPfHduuNmk7@eaf6S/r@p0u3Udvtu0ojFJW/nTTJO55zKVtRniKRsHBayMb/zmL3A2xlhOXpnEg@vo6PUzDjJ6pNCHWcMHrvg5bRlilmGSbHYxFXePZrqfziLTFwxOEjIIbNFgu1vUgzPvnF4xE2/4T82nmQSxu2OImjnF0mSiau9PZzc7d8viGsOqFqQw5uwVTCq5C4Wu449y/f5Ig8V0qoAEPRIVGoTVlB@S6DIQ014TgQFVV15w7YTF2KLEPllFOBe2opD3d0QEVe91@AQ "Curry (PAKCS) – Try It Online")
[Answer]
# [MATL](https://github.com/lmendo/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!](https://tio.run/##FcJBCoQgFADQq1gLv06I2giDQ2WbwCN8SBcTQS1mdh/czN2NHu/3oW@t1BKIMDRJyPWhdAbLEXGg8OayGIxcOnOWDdLe/dcklGYZENv5ICvJvaalODup2GHsx@AsxszPWkEz1RvNnubOvPdwAQ) Or [verify all test cases](https://tio.run/##JYmxCsIwFEV3v@LZIWkaQl6aiFZq66CQD3B40AZUBDvoFujiv8dU73A599z3Lb7SNcUi8rJv12MphkrpwA0jojb2eyZmJM@Ew2m@8/EhP8NYKg2BExXHZzQium13np3plJfk60PvDPnAphRCoNMlcWmg5isuJWQAmxFysl36Lyqolk9bQIC8tbYIFlGbHdS4WQyoGjX8NEDTNPwL).
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 `(` equals `2`.
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):
1. Find the first operator (`+-/*`) that is not predeced by `(`, if any.
2. Insert `(` right before that.
3. 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).
4. 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 the group is an operator.
5. When the counter reaches `2`, insert `)` right after that group.
[Answer]
# Rust Nightly, ~~332~~ ~~319~~ ~~307~~ 292 bytes
Can probably be golfed a lot more.
```
|b:&[char]|b.iter().chain([&' ']).scan((vec![9],1),|(a,q),&b|Some(if '0'>b{let mut o=if*q<1{*q=1;let mut u=format!("");while{let z=a.last_mut()?;*z-=1;*z<1}{a.pop();u.push(')')};u.push(b);u}else{b.into()};if b!=' '{o.insert(o.len()-1,'(');a.push(2)}o}else{*q=0;b.into()})).collect::<String>()
```
[Playground Link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=0dbe926fc22712cbb2512dd45e26d65c)
[Answer]
# [Prolog (SWI)](http://www.swi-prolog.org/), ~~292~~ ~~274~~ ~~125~~ ~~91~~ 129 bytes
* -18 bytes thanks to Steffan
* -999999 bytes thanks to Seffan
* -19 bytes thanks to JoKing
* -15 bytes by myself :). I realized I didn't really need to return the value "Z" since it's only possible value could be a space.
* +28 bytes to fix spacing bug :(
Just like my other answer inputs require a trailing space. I'm very new to prolog so this is probably nowhere near optimal.
```
N+Z:-N=32,$N,\X,X+Z;N/Z.
$N:-put(N).
\N:-get0(N).
32/32.
X/Z:-X<48,$40,$X,\D,D+W,W+Z,$41;X^Z.
X^Z:-X>48,$X,\W,W^Z;X=Z.
:- \X,X+_.
```
[TIO](https://tio.run/##HY2xDsIwDET3fEWGDKA4SZt0QAll6uy1VhSVCVWVkFpBEZ8fTJeTfffs217rc53N@7vUijpHg33woBAKAemc0GUrFEazffYTnq0oPM@PvTmW4F3wVpDjQ7p2F1BdA4qgDDDoEUad2WkTTfyEhaHbH2KAwykn6jmIRh5ld1urdK13XgYpfw)
[Answer]
# [Pip](https://github.com/dloscutoff/pip), 50 bytes
```
W#aI@aQsOPOaEIaLT0OxPBt&'(.POaEL{Oa~XIa:$'WDQxO')}
```
[Try It Online!](https://dso.surge.sh/#@WyJwaXAiLCIiLCJXI2FJQGFRc09QT2FFSWFMVDBPeFBCdCYnKC5QT2FFTHtPYX5YSWE6JCdXRFF4TycpfSIsIlwiXCIiLCIiLCJcIiArLyAtMjAvIDMwIDMwICA5OTkyIDBcIiJd) (Note: the footer is because DSO doesn't flush the output buffer until a newline is output.)
### Explanation
Loop through the input string.
* If the first character is a space, pop and output it.
* If the first character is an operator:
	+ Output an open paren.
	+ Pop and output the operator.
	+ Push 1 (representing a close-paren) and 0 (representing the space between an operator's first and second operands) to a stack.
* Else (this is a number):
	+ Output the first run of digits in the string.
	+ Remove the first run of digits from the string.
	+ Pop the stack; while the result is 1, output a close-paren and repeat.
### Ungolfed
```
$expr: a
$stack: ""
W # $expr {
 I @ $expr Q " " {
  O PO $expr
 } EI $expr LT "0" {
  O '(
  O PO $expr
  $stack PB 1
  $stack PB 0
 } EL {
  O $expr ~ `^\d+`
  $expr : $'
  W DQ $stack {
   O ')
  }
 }
}
```
[Answer]
# [Ruby](https://www.ruby-lang.org/), 129 bytes
```
f=->(s){def k a;i,j=a.shift;j=~/\d/?(i+j): i+"("+j+k(a)+k(a)+")"end;h,t=s.scan(/(.*[^ ])( *)$/)[0];k(h.scan(/( *)([0-9]+|.)/))+t}
```
[Try it online!](https://tio.run/##XYzdasJAEEbvfYqPxYuZrNlZEwpNQ@qDpBFWY8iPiDTxQqq@erq2CMa5@C7OOcz3aXMexyoLP6nnn3JXoYNLm0WbOdPXTTWkbXaTr1JW1OiWP9BoRUq3uiPH/6NY7Q5lWi@GrDf91h1IyAT5GgUTAp4L57ZIO6of0kPKbZgU@mJYmPVwHY@ozNbt9/73EpHi2RPQ8AjxBMKfL@/7qgIE915iWGBiRGKL2FpZviOyb1OHMLKCvwBIkkTx@As "Ruby – Try It Online")
[Answer]
# [Pip](https://github.com/dloscutoff/pip), 47 bytes
```
O({a:POysNa?a.VfaLT0?pJa.(fMJt)a}Y(aw,+XD,XX))y
```
This is a different enough approach that I thought it warranted its own answer. [Try It Online!](https://dso.surge.sh/#@WyJwaXAiLCIiLCJPKHthOlBPeXNOYT9hLlZmYUxUMD9wSmEuKGZNSnQpYX1ZKGF3LCtYRCxYWCkpeSIsIiIsIiIsIlwiICsvIC0yMC8gMzAgMzAgIDk5OSAwICBcIiJd)
### Explanation
First, we tokenize the input:
```
(aw,+XD,XX)
 a           Command-line argument
(         )  Find all matches of this regex:
  w            Run of whitespace
   ,           or
    +XD        Run of digits
       ,       or
        XX     Any single character
```
Now we're going to run a recursive descent parser on this list of tokens, popping each token as it's parsed. Unfortunately, functions in Pip are call-by-value rather than call-by-reference, so we store the list in the global variable `y` and modify that at each step. This also means our function doesn't actually take any arguments. Calling a function with no arguments can be a bit tricky in Pip, so sometimes we'll call it with a dummy argument that gets ignored.
```
{a:POysNa?a.VfaLT0?pJa.(fMJt)a}
{                             }  Recursive function, parses y and returns a parenthesized string
   POy                           Pop the first token from y
 a:                              Store it in the local variable a
      sNa?                       If it contains a space (whitespace token):
          a.                      Concatenate it to
            Vf                    a recursive call to the current function
              aLT0?              Else, if it is lexicographially earlier than "0" (operator):
                     a.(    )     Concatenate it to
                        f          the current function
                         MJ        called on each character in
                           t       "10" (i.e., called twice)
                                   and the results joined into a single string
                   pJ             Join the string "()" on the above result
                             a   Else (number token), just return the token
```
This function parses exactly one expression. In particular, if the input had trailing spaces, the final whitespace token is not parsed and remains in `y`. Therefore, the overall program is:
```
O({...}Y(...))y
        (...)    Tokenize the input
       Y         Yank the list of tokens into y
 (           )   Call, with that argument
  {...}          the parser function
O                Output the resulting parenthesized expression without a newline
              y  Autoprint the remainder of y, if any, with a trailing newline
```
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), ~~67~~ ~~66~~ 58 bytes
```
+`[*-/](?> *\d+| *\(((\()|[^)]|(?<-2>.))+\)){2}(?!\))
($&)
```
[Try it online!](https://tio.run/##HYu9CgIxEIT7PMUIIrsJcfcSBANyeZDLiYIWNhZiZ3z2c88p5ueDed3fj@d1WcJl8lFmqiN8u4VuTkSNuE9nnjvVU0zjnjk05k/6Ut1YcbTdsX0HJBcCLJAdTEZWX6eHX7lkKOBEsiKrynBE0oMTxKSCPwRKKT8 "Retina 0.8.2 – Try It Online") Link includes test cases. Explanation: Much like @Deadcode's answer, the expression tries to find unparenthesised expressions to parenthesise. Explanation:
```
+`
```
Repeat until no more substitutions can be made.
```
[*-/]
```
Match an operator. Edit: Saved 1 byte thanks to @Deadcode.
```
(?> *\d+
```
Atomically match an integer parameter, ...
```
| *\(((\()|[^)]|(?<-2>.))+\))
```
... or a balanced parenthesised parameter, ... (Edit: Saved a further 8 bytes thanks to @Deadcode)
```
{2}
```
... twice.
```
(?!\))
```
Ensure that the operator wasn't previously parenthesised. (This test shamelessly stolen from @Deadcode to save 1 byte.)
```
($&)
```
Parenthesise the operator and its parameters.
Alternative approach, ~~60~~ 58 bytes:
```
(?<=(()\d+|[^*-/]|(\2|())(?<-2>.))*)\d+
$&$#4$*)
[*-/]
($&
```
[Try it online!](https://tio.run/##HYq9CgIxEIT7fYoB47GbEDeXKBjwp/Qh7hQPtLCxEMu8e0ycYob5Zj7P7@u91DVf7pXPhyOzzA9Xppv1ei08x8IibfDxtBGxfSQzmNXWWKGpn4jNUKsbEck5tEAiNDXSvVcL27kmBIBUU0AKQcc9YtiRwseg@EMg5/wD "Retina 0.8.2 – Try It Online") Link includes test cases. Explanation:
```
(?<=(()\d+|[^*-/]|(\2|())(?<-2>.))*)\d+
$&$#4$*)
```
Consider the minimum number of integers that would complete the prefix expression at any given point; this value increases at an operator and (obviously) decreases at an integer. Working back from a given integer, up to the point that the value decreases below the current value, count the number of times it is equal. This is the number of parentheses that should be appended.
```
[*-/]
($&
```
Prefix a `(` to each operator.
[Answer]
# [Python](https://www.python.org), 186 bytes
```
lambda s,a=[]:(t:=s.rstrip(),[a:=c<'!'and a[:-1]+[c+a[-1]]or a+[c.isdigit()and c or"("+c+a.pop()+a.pop()+")"]for c in re.findall("\d+|.",t)[::-1]],a)[2][-1]+' '*(len(s)-len(t))
import re
```
[Attempt This Online!](https://ato.pxeger.com/run?1=PU9LboNADF2HU7hssBl-AVVKULlFd4TFAKEdicBomC4q9SbdRKraI3TRm-Q29SS0s7Cfn5-fPe9f-tU-z9P5Y6gOny92iHeXn1Ge2l7CEsmqbkq0ZbUkZrFGaaSolmXVPQR3gZx6kHUZbxtRd0LWDJrZgOQqUUuvnpRFcqIOZuOjL1iU6Jk9_rNPfjPwTAdqAnNMBjX1chzRP_TiLfEjS3XpFjSRpDpv3AoRQBDieJxwodglS-Spk56NZYf1B4_OVDnTWbMko9IDGbWVup6bLHrk2_yD9ckDbdRkcUBJVdVG5qgNw1t25Apbopv3-fIttpBv0EXyhADOUHCNV0hQsCk_7rvoeg7grUZH8MUhhG4uLSAD2GAIGF6H0TFEAF6aFhkUWZZud5Bn9xtMcWUIV459UojzLIVrA2C_37MOkDlcSefF9N_5vw)
Handling trailing whitespace added a lot of bytes, even though leading whitespace didn't.
If we didn't have to handle trailing whitespace:
# [Python](https://www.python.org), 149 bytes
```
lambda s,a=[]:[a:=c<'!'and a[:-1]+[c+a[-1]]or a+[c.isdigit()and c or"("+c+a.pop()+a.pop()+")"]for c in re.findall("\d+|.",s)[::-1]][-1][-1]
import re
```
[Attempt This Online!](https://ato.pxeger.com/run?1=PU5BboNADDyHV7h7ia0lQIIqJaj8ojfCYYHQrkRgtdBDpT6jPfUSqWr_lN_UJrQr2R6Px975_HGv0_PQX77a_Pj9MrWb_fWjM-eqMTCGJi_KrDBZXj-s79amb8AU2WZb6qLWpmBQDh4Md5EdG_tkJyQR1TB4hUqzKHKDQ_qvilTZ8k4Ntgd_ilrbN6brUB0b_RapcKQikw9KOS4R2LMb_MTaxdyjrFtZH9ypx4SyAExY5XY2Fo2uYxfqOCkKwHnbT9iioTyvQn9ynuGtCrnAiuh2-3J911vYrVAyBVoDV0i5xxkSpHyUH88ly0wA3noUgiiI4zSBNEni7R52yf0KY1wYwoUTFWx2SQzzAOBwOLAOkDlcSKKZ_jP3Cw)
If there was no whitespace or multi-digit numbers:
## [Python](https://www.python.org), 90 bytes
```
lambda s,a=[]:[a:=a+[c.isdigit()and c or"("+c+a.pop()+a.pop()+")"]for c in s[::-1]][-1][0]
```
[Attempt This Online!](https://ato.pxeger.com/run?1=m72soLIkIz9vweI025ilpSVpuhY3o3ISc5NSEhWKdRJto2OtohOtbBO1o5P1MotTMtMzSzQ0E_NSFJIV8ouUNJS0k7UT9QryCzQ04bSSplJsWn4RUEVmnkJxtJWVrmFsbDSQiDaIhdiwuaAoM69EI01DSV_XSN_Y2FJJUxMis2ABhAYA)
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), 46 bytes
```
⊞υω⭆θ⎇№+-*/ι∧⊞Ｏ⊞Ｏυ⁺⊟υ)ω⁺(ι⎇›№⭆χλι№⭆χλ§θ⊕κ⁺ι⊟υι
```
[Try it online!](https://tio.run/##dY7LDoIwEEX3fEXT1YyWgLoirowLw8JIoj/QQCNELDi0Pr6@FsQQF04mmczrnpuXkvJG1s5ltivBCvbAdZBRpQ0cjS/nvWzhJthJkZb0gm1j/YrPw1nEBatQsI0uoH8@tIqkaei38YpZbTvImhasv@bIEXvKOOcwyOBE2JGSRtFImkwsYsFq/DD/7TYm1YV69oZTnZO6Km1UARdE/AIrXwcvg5SPtXMRC5dxxFZxnyxJksCF9/oN "Charcoal – Try It Online") Link is to verbose version of code. Explanation:
```
⊞υω
```
Start with `0` on top of the stack.
```
⭆θ
```
Loop through the input characters.
```
⎇№+-*/ι
```
If this is an operator, then...
```
∧⊞Ｏ⊞Ｏυ⁺⊟υ)ω
```
... increment the top of the stack, push `0` to the top of the stack, and...
```
⁺(ι
```
... output the operator prefixed with a `(`.
```
⎇›№⭆χλι№⭆χλ§θ⊕κ
```
Otherwise, if this is a digit but the next isn't, then...
```
⁺ι⊟υ
```
... output the digit followed by a number of `)`s given by the top of the stack.
```
ι
```
Otherwise, just output the character.
[Answer]
# [nearley](https://nearley.js.org), 78 bytes
```
m->_ p _{%a=>a.flat(1/0)%}
p->[\d]:+|[-+/*] _ p _ p{%a=>['(',a,')']%}
_->" ":*
```
Post-processing functions for production rules, denoted by `{%...%}`, are evaluated in JavaScript. Each function is called with an array of post-processed results for each terminal or non-terminal from which the rule is produced.
This [EBNF grammar](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form) is defined by three non-terminal production rules `m`, `p`, and `_`.
* `_` is zero or more spaces
* `p` is one or more digits OR one of `-`, `+`, `/`, `*` followed by `_`, `p`, `_`, then `p`.
* `m` is `_`, `p`, then `_`.
The post-processing function of `p` wraps the result in parentheses when it is produced by `[-+/*] _ p _ p`, and the post-processing function of `m` flattens the nested array of characters produced from parsing the complete input.
You can test it in the [Nearley Parser Playground](https://omrelli.ug/nearley-playground/), but you'll need to add the the code above and the test cases yourself since there's no permalink feature.
Alternatively, if you're comfortable with the Developer Tools in your browser, you can evaluate the following snippet on the console while loaded on that page to save yourself from having to insert the test cases manually.
```
localStorage.playgroundState=String.raw`{"active":0,"compiled_grammar":"module.exports={ParserRules:[{name:'m',symbols:['_','p','_'],postprocess:a=>a.flat(1/0)},{name:'p$ebnf$1',symbols:[/[\\d]/]},{name:'p$ebnf$1',symbols:[/[\\d]/,'p$ebnf$1'],postprocess:a=>[a[0],...a[1]]},{name:'p',symbols:['p$ebnf$1']},{name:'p',symbols:[/[-+/*]/,'_','p','_','p'],postprocess:a=>['(',a,')']},{name:'_$ebnf$1',symbols:[]},{name:'_$ebnf$1',symbols:[{literal:' '},'_$ebnf$1'],postprocess:a=>[a[0],...a[1]]},{name:'_',symbols:['_$ebnf$1']}],ParserStart:'m'}","tabs":[{"name":"Add parentheses to Polish notation","editor_value":"m->_ p _{%a=>a.flat(1/0)%}\np->[\\d]:+|[-+/*] _ p _ p{%a=>['(',a,')']%}\n_->\" \":*","errors":[],"tests":["+1 2","++ 1 2 3","    +1    +2 3","* *1 2 /3 0  ","//30 300/18 205","/ -20/ 30 30  999","/////1 2 3 4 5 6","/1/2/3/4/5/6/7/8 9"]}]}`;location.reload()
```
[Answer]
# [Prolog (SWI)](http://www.swi-prolog.org), ~~178~~ ~~177~~ 175 bytes
*-3 bytes thanks to [Steffan](https://codegolf.stackexchange.com/users/92689/steffan)*
```
S/L:-atom_codes(S,L).
[C|T]*P*R:-C=32,T*Q*R,P=[C|Q];C>47,[C|T]+P+R;T*E*Q,Q*F*R,append([[40,C],E,F,[41]],P).
[N|T]+[N|P]+R:-N>47,T+P+R.
X+_+X.
S^T:-S/L,L*P*R,append(P,R,M),T/M.
```
[Try it online!](https://tio.run/##Nc7BCoJAEAbgu08xdNLd2TXNChS7SJ0sVt2DIKtISgiVUkGX3t12g@Ywh@Gfb2Z6jNfxwp7vYZ4LNw1Z@xpvzXns@qddYOpwq0o@UhFB8pAl8cpHSTKSo4j1PFNRsgu2@ItQQfNIkj3JMCMHHWmnqb93dlUFS0wU7vGAVeAphcKoJ7Oiu1BUyyfDSENwq6QNLblV1DJk@iVMzfG/JjDHo4PSPfI5ZAsAVxe4nueB78MKAljDBmBRlwjvx/Dq7dLh8xc "Prolog (SWI) – Try It Online")
### Explanation
The other Prolog answer cleverly reads characters from stdin one at a time. I wanted to try a more "traditional" solution, a predicate which takes a string and generates another string.
```
S/L:-atom_codes(S,L).
```
Define the `/` operator as a shortcut for converting an atom or string to a list of codepoints and vice versa.
```
[C|T]*P*R:-
```
The `*` operator is the main workhorse here. It takes a list of codepoints (the first of which is `C` and the remainder of which are `T`) and parses one Polish-notation expression from the beginning of it, returning the correctly parenthesized parsed expression in `P` and the rest of the list of codepoints in `R`. It has three branches:
```
C=32,T*Q*R,P=[C|Q]
```
If `C` is a space, parse everything after the space and prepend a space to the result.
```
C>47,[C|T]+P+R
```
If `C` is a digit, parse a run of digits using the `+` operator (defined below).
```
T*E*Q,Q*F*R,append([[40,C],E,F,[41]],P).
```
Otherwise, `C` is an operator. Parse a subexpression `E`, then parse another subexpression `F`. Finally, concatenate an open paren, the operator `C`, both subexpressions, and a close paren together to form the result `P`.
To parse a run of digits:
```
[N|T]+[N|P]+R:-N>47,T+P+R.
```
If the list of codepoints starts with a digit `N`, parse a run of digits from the portion following `N`, and prepend `N` to the result.
```
X+_+X.
```
Otherwise, the remainder is the same as the input. The result is a "don't care" (`_`), which apparently works because (based on its use in the calling predicate) it has to be a list, and the empty list is the first possibility Prolog tries.
The `^` operator is the main predicate:
```
S^T:-S/L,L*P*R,append(P,R,M),T/M.
```
It takes a string `S`, converts it to a list of codepoints `L`, parses `L` into a parenthesized expression `P` and remainder `R`, concatenates `P` and `R` into `M` (so as to keep any trailing spaces), and converts `M` back into the string result `T`.
---
If I can take and return lists of codepoints instead of strings, this solution is **145 bytes**:
```
[C|T]*P*R:-C=32,T*Q*R,P=[C|Q];C>47,[C|T]+P+R;T*E*Q,Q*F*R,append([[40,C],E,F,[41]],P).
[N|T]+[N|P]+R:-N>47,T+P+R.
X+_+X.
X^Y:-X*P*R,append(P,R,Y).
```
[Answer]
# Python3, 226 bytes
```
lambda s:f(s)[0]
import re
f=lambda s:((' '*O[0].count(' '))+'('+O[0].lstrip()+(J:=f(s[len(O[0]):]))[0]+(T:=f(J[1]))[0]+')',T[1])if(O:=re.findall('^(?:\s+)*[\*\-\+/]',s))else((O:=re.findall('^(?:\s+)*\d+',s))[0],s[len(O[0]):])
```
[Try it online!](https://tio.run/##dY5Ba4QwFITv/op3y0vibqJSWAXpbQ972cvejAVblQayGhL3sL/eJlJaLDSHwMw3zBv7XD7nqThZt55rtZru/t534KsRPW1km@i7nd0CbkjG@gciEiDsGvjxY35MS5SUcoKEb6bxi9MWKcdLVYemxgwTRkKrlsZajrcILk32rQkl6S0qPeK1qt1wHPXUd8YgecPXSnlOWaOYOiguWpJ6SgfjB/w3q3q@pUJ3uj@/WqfD4nPYmkEeZie/BodgQbEzIbyQjP9fxIDFvChAAuyIEIWEQkqRnSCXL3sGh1wK2AIAZVkGun4B)
[Answer]
# [C (GCC)](https://gcc.gnu.org), 174 bytes
```
#define p putchar(
f(char *x){int s[100]={0},*S=s,b,c;for(;*x;){if(b=*x==32)p*x++);for(c=0;isdigit(*x);b=c=1)p*x++);for(*S+=c;*S==2;)p')'),*S=0,*--S+=1;b||++S+p'(')+p*x++);}}
```
[Attempt This Online!](https://ato.pxeger.com/run?1=TZLBboMwDIa1IzyF1R2wExABNKlVlqfosUJTS0uXw1pUqITU8iS79NLr3md7mjkZVOMQ7P-zfyyHz3v1tq-q2-1-7upk_v31vN3V9rCDBppzV72vTxjW6N4gerrYQwftKlOqNBc1xGJp2ngTV7o-nlCLXnNFjRsjemOKnBrRS0keVkZp227t3nbIRnpjKpP9LxBLaSrNhibX1EQUkXNXsUgSJpneXK9SLmUTYURy7BuGv6l_ntYfa3tAuoSBH9UeV6WfEgywFsxkBvksdhG6kDj2sgTOoJgQ-pygmAqAH25w56PMZfgnolNpKhYgnFtagBoNBaDwhuhEIgAPHEvTQkGhVJrNIVcvY0OKo0w4god7CkmuUvAYYLFYTC2ADHAk7hvMaBYGg-Y-Xi2guzXLFwD2Ncv5lCZ3qwpq5EXZkvTjrjNFmgGnrWcyK50whOOmp__kFw)
Note: as it is, it works up to `100` nested brackets.
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands), ~~32~~ 30 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
ÎĆü2vyÇн₆%Ígi'(?>0}y¬?dRJi')×?
```
Input as a list of characters.
[Try it online](https://tio.run/##yy9OTMpM/f//cN@RtsN7jMoqD7df2PuoqU31cG96prqGvZ1BbeWhNfYpQV6Z6pqHp9v//x@tpK@ko6QAxLpAbATEBkAMEzOG8tHZIGwJx7EA) or [verify all test cases](https://tio.run/##yy9OTMpM/V9TVnlopb2SwqO2SQpK9pXBof8NIo60Hd5jVFZ5uP3C3kdNbaqHe9Mz1TXs7QxqKw@tsU8J8spU1zw83f5/be2hbfb/tQ0VjLi0tRWAlIIxlwIQAEVAJIirpaAFEtc3VjDg0tc3NlAwNjDQN7RQMDIw5dJX0DUy0FcACyooWFpaAlUAAdgcBRMFUwUzLn1DfSN9Y30TfVN9M31zfQsFSwA).
Port of [*@Neil*'s Charcoal answer](https://codegolf.stackexchange.com/a/250895/52210), so make sure to upvote him as well!
**Explanation:**
```
Î              # Push 0 and the input character-list
 Ć             # Enclose it; append its own head
  ü2           # Pop and push its overlapping pairs
 v             # Loop over each pair of characters `y`:
  y            #  Push the current pair `y`
   Ç           #  Convert both to its codepoint integer
    н          #  Pop and leave just the first integer
     ₆%        #  Modulo-36
       Í       #  +2
        g      #  Then pop and push the length
         i     #  If this is 1 (which means it's an operator character):
          '(? '#   Print "("
          >    #   Increase the current value by 1
          0    #   Push a new 0
         }     #  Close the if-statement
  y            #  Push pair `y` again
   ¬           #  Push its first character (without popping the pair)
    ?          #  Pop and output this first character
     d         #  Check for both characters whether they're digits
      R        #  Reverse the pair
       J       #  Join them together to a string
        i      #  If this is "01":
         ')×  '#   Pop the top value, and push a string with that many ")"
            ?  #   Pop and print it
```
[Answer]
# [C (clang)](http://clang.llvm.org/), ~~136~~ ~~132~~ 125 bytes
```
#define p putchar(
x;*s;r(n){for(;*s&&n<2;x||p*s<40?n--,*s++:p'(')+!!r(!p*s++))))for(x=!++n;*s>47;)x=p*s++);}f(*a){s=a;r(0);}
```
[Try it online!](https://tio.run/##dVDvboIwEP8sT3GwTK8goYDLppXtBfYGygeC4EhYJYAJifLqY9eimCzZfWj7@3dtL3XTMpHHYXg6ZHkhM6igOrfpV1Kj0Qm7ETVKdslPNRKYz@U2EN31WtnNdsU/pOsu7cZxNtUCF8wxzRrNShGMSmW6yHQcScn31atgXTSKos/RTtiliRJqzwkP30khkV2MWSFbKE67eOdzHkMERM0@LceHwFrqI6ozIzAKDhCEcBJREwzCyQJUlFHrw6ggjiwqmk12G2zV0QuB35vagLZuioplDEArWvS8kEPIuee/QcBf7hEPbzzDm/K4wQM34B5oHWC9Xk8hQFLwJql7SGSWMesFJWmegHo8ERdQbP2AVicKaGrwp6qafDlaz2Wzl1lXZWmbHTagYZ0157IF2NAn1KSLeNyABhczQS/JUdNMwL@N93IvLWXujX74SfMyOTbDLw "C (clang) – Try It Online")
]