| Bytes | Lang | Time | Link |
|---|---|---|---|
| 200 | Haskell | 241105T081713Z | Dannyu N |
| 053 | Charcoal | 210731T111556Z | Neil |
| 094 | Retina 0.8.2 | 210731T104315Z | Neil |
| 060 | Jelly | 210724T201718Z | Nick Ken |
| 071 | JavaScript | 210723T021602Z | tsh |
| 073 | Perl 5 p | 210723T034402Z | Anders K |
Haskell, 203 200 bytes
Saved 3 bytes thanks to Unrelated String.
import Text.ParserCombinators.ReadP
data T=L Char|T:!T
p=chainl1(between(char '(')(char ')')p<++(L<$>get))$pure(:!)
s(L c)=[c]
s(L c:!r)=c:s r
s(l:!r)='(':s l++')':s r
c t=do(r,"")<-readP_to_S p t;s r
I don't know how to golf this further, but practically speaking, this kind of parsing is really where parser combinators shine.
Charcoal, 53 bytes
F⁺(S¿⁼ι(⊞υ⟦⟧«F⁼ι)≔⪫⊟υωιF‹¹L§υ±¹⊞υ⟦⪫()⪫⊟υω⟧⊞§υ±¹ι»⪫⊟υω
Try it online! Link is to verbose version of code. Explanation:
F⁺(S
Loop over the input with an extra ( prefixed as this is golfier then setting up the stack manually.
¿⁼ι(⊞υ⟦⟧«
For each (, push a new empty list to the stack.
F⁼ι)
If the next character is a ), then...
≔⪫⊟υωι
the next term is actually the joined list at the top of the stack.
F‹¹L§υ±¹
If the list at the top of the stack already has two terms, then...
⊞υ⟦⪫()⪫⊟υω⟧
... replace it with a list of a () wrapped term.
⊞§υ±¹ι
Push the current term to the list at the top of the stack.
»⪫⊟υω
Join and output any remaining terms.
Retina 0.8.2, 94 bytes
+1`((\w|(\()|(?<-3>\)))+?(?(3)^)){2}(?!\))
($&)
+`\(((\w|(\()|(?<-3>\)))+)\)(?(3)^)(?=\)|$)
$1
Try it online! Link includes test cases. Explanation:
+1`
Make the first possible substitution each time, looping until no more substitutions are possible. This means that in the case of abcde, only ab is surrounded the first time, then (ab)c the second time, et cetera.
((\w|(\()|(?<-3>\)))+?(?(3)^)){2}(?!\))
($&)
Put parentheses around any pair of expressions that does not already have one.
+`\(((\w|(\()|(?<-3>\)))+)\)(?(3)^)(?=\)|$)
$1
Remove any parentheses not needed under right association.
Jelly, 60 bytes
;Ṫ$FL$¡1ĿØ(jƊ¹ŒḊ?€
=þØ(Ä_Ż}ỊṖʋ/aSƲœp⁸;2ĿW$}¥2/Ẏ3œṖW;¥2/ẎƲÐLÇ
A full program taking a string argument and printing the result to STDOUT. Uses recursion in both links, but in both cases replacing 1Ŀ or 2Ŀ with ß fails to work.
JavaScript, 71 bytes
Saved 2 bytes by Arnauld.
f=(e,l='',r=e.shift())=>(r=r>{}?r:r<f&&f(e))?f(e,l[1]?`(${l})`+r:l+r):l
l,rare two operand
Perl 5 -p, 73 bytes
1while$e='(\w|\((?1)*\))',s/$e$e(?=$e)/($&)/;1while s/\(($e*)\)(?!$e)/$1/