g | x | w | all
Bytes Lang Time Link
136Ruby pl250527T044250ZValue In
138JavaScript Node.js250523T231618Zl4m2
335Emacs Lisp150916T090105Zcoredump
1510Sacred JavaScript151006T230355ZConor O&
244JavaScript ES6151006T223130ZConor O&
533Scheme150917T151048Zxebtl
092Scheme150917T091351Zxebtl
201Lua150915T213303ZNikolai9
072Perl150915T214122ZJarmex
210Haskell150916T165838Znimi
nanRetina150915T202208ZMartin E

Ruby -pl, 136 bytes

Pursuant to new guidelines, all parentheses have been removed from this code. As such, parentheses are matched against 40.chr1 and 41.chr2 for removal purposes.

i=0
b=40.chr
r=eval"/\\#{b*3}\\g<0>|[^#{b+e=41.chr}]#{e+?*+e+?\\+e}/"
while~r
sub r,"<sup>#{i+=1}</sup>"
$_+="

<sub>#{i} #$1</sub>"
end

Attempt This Online!

1 evaluates to open parenthesis symbol

2 evaluates to closed parenthesis symbol

JavaScript (Node.js), 138 bytes

f=([c,...x],z=d=k='')=>c?(d-=(c=='(')-(c==')'))?f(x,z+c):z?`<sup>${++k}</sup>`+f(x.join``+`

<sub>${k} ${z.slice(1)}</sub>`,''):c+f(x,z):x

Try it online!

Emacs Lisp, 335 bytes

Foreword. This answer and the Scheme ones are currently the only answers officially sanctioned by both the Mighty Popular Republic of LISP and the Church of Emacs. Other answers, shorter or not, are considered a threat to peace. In particular, and with a profound disdain to any libelious allegation of McCarthyism that is sporadically heard from hostile opponents of the state, we enjoin anyone who has information about the real identity of the anonymous authors writing Nonlisp answers to contact your Local Bureau. It is reminded that everyone should take time to reflect and upvote in accordance to what he or she deeply believes will not threaten his or her future interactions with official representants of the power in place. Code is data. Data is code.

(defun p()(let(b(cpt 0)n)(goto-char 0)(while(search-forward"("()t)(setf b(point)n(number-to-string(incf cpt)))(backward-char)(forward-sexp)(backward-char)(kill-region b(point))(delete-backward-char 1)(delete-forward-char 1)(insert "<sup>"n"</sup>")(save-excursion(end-of-buffer)(newline 2)(insert "<sub>"n" ")(yank)(insert"</sub>")))))

More elegantly:

(defun parens ()
  (let (b(cpt 0)n)
    (goto-char 0)
    (while(search-forward"("()t)
      (setf b(point)n(number-to-string(incf cpt)))
      (backward-char)
      (forward-sexp)
      (backward-char)
      (kill-region b(point))
      (delete-backward-char 1)
      (delete-forward-char 1)
      (insert "<sup>"n"</sup>")
      (save-excursion
       (end-of-buffer)
       (newline 2)
       (insert "<sub>"n" ")
       (yank)
       (insert "</sub>")))))

Sacred JavaScript, 1510 bytes

Fellow rebels, do not give in to their tyrannical demolition of the parenthesis! You must persevere! From the start, programming has been a free enterprise. Now, it has become a pervaded show of piety. We must show nothing less then absolute fearsomeness. Therefore, I have fought back!

    ( )( (((  ((  )( )  (( ))( )) (( ( ((  ) ( ()( ) (( ) )(( ((( ()((( ) ( ) )((  ) (((((( )( (())((  ) ) )( ()(( ((()((()   ( (  (  ( )) ((  )( ) (( ) )((((  ( () ) )( ( ()(( )( () ((( )(( ) )( ()((( ) ( )  ( )() (((( () ) (((( () ) ((() ) ()  ( (  (  ( )) ( )(  ((((( )) ((  )( ) (( ) )((((  ) )  ()(  ((() ( ()(( ) ( ) )(( ))(((  (( ) ((  ) ( ()(( )( ) ()  ( (  (  ( ()( ) )( ()(  ) ()  ( (  (  ( )( (( ( (( )  ((((( ))  ) )(( )) ((  )( ) (( ) )((((  ) ()( ))  ) ) (( )( () (((   ( ) )((  )( )(((( ))( )() ) ()( ))  (()( (()( ((()((()   ( (  (    (  ( )) ( )(  (((((( )(( ( (( )) ( ((  ) )( ) )( ( )( ((() ( )( ((() ( ()( ()( ()   ) )( ()(( ) ()  ( (  (    (  ( )) ( )(  (((((( )(( ( (( )) ( ((  ) )( ) )( ( )( (((( ( )( ((() ( ()( ()( (()( ) )( ()(( ) ()  ( (  (    (  ( )) ( )(  (((( ( ) ( ()( ((() ( ()( ())(( ) ( ) )( ()(( ))) ) ()  ( (  (  ((())  ( (  (  ((( ( ) )((( )( () ((( )(((   ( )) ( )  ( ) ) ((((( )) ((  )( ) (( ) )((((  (())( ))  (()( ()(( ((()  ( (  (  ( )(  ) )(((( ( () ((( ) ( ) )(( ((((   ( ()(( )  ( ) ) (((( () )( ((( ((((((()( ((() ((   () )( )(( (()) ( )( ( )( ((() ) ()  ( (  (  (( ) ( ) )(( ))(((  (( ) ((  ) ( ()( ) (( ) )(( ((( ()((( ) ( ) )((  ) (((((( )( () ((( ) ( ) )(( ((((   ( ()(( )  ( ) ) ((((((( ( (()) ( )( ) ) (( )((((  ( ()) ) )) ( )( (()(((  ) (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )( ((() (()( ( )(  ( (  ( ( ) ) (( )((((  ( ()) ) )) ( )( (()(((  ) (()( ( )( ( () ( )( (()(( )(  (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )( (())((  ) (()( ()(( ((() ) ()  ( (((())

No rules against using the sacred characters in a non-Lisp language. Nope, not at all. (In a little less compact way:)

( )( (((  ((  )( )  (( ))( )) (( ( ((  ) ( ()( ) (( ) )(( ((( ()((( ) 
( ) )((  ) (((((( )( (())((  ) ) )( ()(( ((()((()   ( (  (  ( )) ((  )
( ) (( ) )((((  ( () ) )( ( ()(( )( () ((( )(( ) )( ()((( ) ( )  ( )()
 (((( () ) (((( () ) ((() ) ()  ( (  (  ( )) ( )(  ((((( )) ((  )( ) (
( ) )((((  ) )  ()(  ((() ( ()(( ) ( ) )(( ))(((  (( ) ((  ) ( ()(( )(
 ) ()  ( (  (  ( ()( ) )( ()(  ) ()  ( (  (  ( )( (( ( (( )  ((((( )) 
 ) )(( )) ((  )( ) (( ) )((((  ) ()( ))  ) ) (( )( () (((   ( ) )((  )
( )(((( ))( )() ) ()( ))  (()( (()( ((()((()   ( (  (    (  ( )) ( )( 
 (((((( )(( ( (( )) ( ((  ) )( ) )( ( )( ((() ( )( ((() ( ()( ()( ()  
 ) )( ()(( ) ()  ( (  (    (  ( )) ( )(  (((((( )(( ( (( )) ( ((  ) )(
 ) )( ( )( (((( ( )( ((() ( ()( ()( (()( ) )( ()(( ) ()  ( (  (    (  
( )) ( )(  (((( ( ) ( ()( ((() ( ()( ())(( ) ( ) )( ()(( ))) ) ()  ( (
  (  ((())  ( (  (  ((( ( ) )((( )( () ((( )(((   ( )) ( )  ( ) ) ((((
( )) ((  )( ) (( ) )((((  (())( ))  (()( ()(( ((()  ( (  (  ( )(  ) )(
((( ( () ((( ) ( ) )(( ((((   ( ()(( )  ( ) ) (((( () )( ((( ((((((()(
 ((() ((   () )( )(( (()) ( )( ( )( ((() ) ()  ( (  (  (( ) ( ) )(( ))
(((  (( ) ((  ) ( ()( ) (( ) )(( ((( ()((( ) ( ) )((  ) (((((( )( () (
(( ) ( ) )(( ((((   ( ()(( )  ( ) ) ((((((( ( (()) ( )( ) ) (( )((((  
( ()) ) )) ( )( (()(((  ) (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )(
 ((() (()( ( )(  ( (  ( ( ) ) (( )((((  ( ()) ) )) ( )( (()(((  ) (()(
 ( )( ( () ( )( (()(( )(  (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )(
 (())((  ) (()( ()(( ((() ) ()  ( (((())

This compiles to the expanded JavaScript in my other answer. This is a joke submission.

JavaScript ES6, 244 bytes

Serious answer (only works on FireFox, to my knowledge)

d=(s,n=1)=>{u=s.search(/\(/);if(index<a=0)return s;for(i=index;i<s.length;i++){if(s[i]==")")a-=1;if(s[i]=="(")a+=1;if(!a)break}return d(s.replace(v=s.slice(index,i+1),"<sub>"+n+"</sub>")+`

<sub>`+n+" "+v.replace(/^\(|\)$/g,"")+"</sub>",n+1)}

Expanded:

function deparen(s,n=1){
    index = s.search(/\(/);
    if(index<0) return s;
    a=0;
    for(i=index;i<s.length;i++){
        if(s[i]==")") a-=1;
        if(s[i]=="(") a+=1;
        if(!a) break;
    }
    v=s.slice(index,i+1)
    f=v.replace(/^\(|\)$/g,"");
    return deparen(s.replace(v,"<sub>"+n+"</sub>")+"\n\n<sub>"+n+" "+f+"</sub>",n+1);
}

Scheme, 533 bytes

With indentation:

(letrec ((l string->list)
         (n number->string)
         (? null?)
         (p (lambda (o) (or (pair? o)(? o))))
         (a car)
         (d cdr)
         (e append)
         (i 0)
         (x
          (lambda (h t)
            (if (? h)
                t
                (case (a h)
                  ((#\() 
                   (let ((s (x (d h) ())))
                     (x (a s) (e t (d s)))))
                  ((#\)) (cons (d h) (list t)))
                  (else 
                   (x (d h) (e t (list (a h)))))))))
         (f 
          (lambda (h t F)
            (cond ((? h)
                   (let ((w (e t F)))
                     (if (find p w) (f w()()) w)))
                  ((p(a h))
                   (set! i(+ 1 i))
                   (f (d h)
                      (e t (e (l "<sup>")
                              (l (n i))
                              (l "</sup>")))
                      (e F (e (l "\n\n<sub>")
                              (l (n i))
                              '(#\ )
                              (a h)
                              (l "</sub>")))))
                  (else (f (d h) 
                           (e t (list (a h)))
                           F))))))
  (print (list->string (f (x (l (read-line)) 
                             ())
                          ()
                          ()))))

Yes, this is 533 bytes when all the optional whitespace is removed. Bask in the functional glory.

I implemented more or less the algorithm in the description: x groups the input by parentheses and f replaces the first level of groups by footnotes, repeating until no more groups are left. I am sure it can be made shorter, but I do not see how it could be made much shorter without switching to a different algorithm.

As written, it is a complete program. You can try it out here, but because repl.it apparently cannot deal with (read-line) you have to put the input string in its place. A completely ungolfed version is here.

EDIT: As pointed out in the comments, I changed the parentheses () into brackets [] in the repl.it versions. This was purely for convenience during programming and debugging. The version as posted now works with ().

Scheme, 92 bytes

Frustrated with implementing the breadth-first search in Real Lisp,1 the powers-that-be decide to take a more pragmatic approach. After all, Parentheses are sacred, but brackets are not.2

(lambda(s)(list->string(map(lambda(c)(case c((#\()#\[)((#\))#\])(else c)))(string->list s)))

1. listen not to those heretics from the so-called “church” of Emacs!
2. They are not Racket programmers, are they?

Lua, 222 216 204 201 bytes

Golfed:

s=io.read()g="%b()"c=1k=string l=k.find t=k.sub o=k.format a,b=l(s,g)while a do s=t(s,0,a-1)..o("<sup>%d</sup>",c)..t(s,b+1,#s).."\n\n"..o("<sub>%d %s</sub>",c,t(s,a+1,b-1))c=c+1 a,b=l(s,g)end print(s)

Ungolfed:

input=io.read() 
inputFormat="<sup>%d</sup>"
footnoteFormat="<sub>%d %s</sub>"
counter=1
a,b=string.find(input,"%b()")
while a do
    current=string.sub(input,a+1,b-1)
    input=input.."\n\n"..string.format(footnoteFormat, counter, current) 
    input=string.sub(input,0,a-1)..string.format(inputFormat, counter)..string.sub(input,b+1,#input)
    counter=counter+1
    a,b=string.find(input,"%b()")
end

print(input)

Perl, 81 75 72 bytes

71 bytes code + 1 byte command line argument.

Requires Perl 5.10 or newer (for recursive regex support)

$i++;s#(\((((?1)|.)*?)\))(.*)#<sup>$i</sup>$4

<sub>$i $2</sub>#s&&redo

Usage:

perl -p entry.pl input.txt

Explanation

-p parameter will print the result of applying the given commands to the input, avoiding the need for an explicit print.

The regex (\(((?1)|.)*?)\)) is looking for the outermost set of brackets from the start of the string. When this is found, we perform the substitution, ensuring we only add the at the very end of the input (by capturing everything until the end of the input using (.*)).

We then repeat the regex substitution on the now-substituted string using redo, which will continually apply the regex substitution until it no longer matches. The s modifier ensures that the . in the regex will match new lines, which is necessary because we re-apply the regex match on the result of the previous regex substitution.

Haskell, 210 bytes

n#x|b==""=a|1<2=a++"<sup>"++m++"</sup>"++((n+1)#(c++"\n\n<sub>"++m++' ':init d++"</sub>"))where m=show n;(a,b)=span(/='(')x;(d,c)=[x|x@(y,_)<-map(`splitAt`(tail b))[0..],'('!y<')'!y]!!0;c!l=[1|m<-l,m==c]
p=(1#)

Usage example:

*Main> putStrLn $ p "This has (nested (deeply (or highly?) nested)) parentheses (and several groups)."
This has <sup>1</sup> parentheses <sup>2</sup>.

<sub>1 nested <sup>3</sup></sub>

<sub>2 and several groups</sub>

<sub>3 deeply <sup>4</sup> nested</sub>

<sub>4 or highly?</sub>

How it works:

n # x                      -- # does all the work, n is the current number of the
                           --   footnote and x the input string
  | b=="" = a              -- if b (see below) is empty, there's no ( in the
                           --   string and the result is 'a' (see below)
  | 1<2   = a++"<sup>"++m++"</sup>"++ ((n+1)#(c++"\n\n<sub>"++m++' ':init d++"</sub>"))
                           -- otherwise (b not empty) build the output string
                           --   starting with 'a' and a footnote number and a
                           --   recursive call with the current footnote appended
                           --   to the rest of the string  

  where 
  m = show n;              -- turn n into string
  (a,b) = span (/='(') x;  -- split the input string x into two parts:
                           --   a: everything before the first (
                           --   b: beginning with the first ( to the end
                           --   if there's no (, a is x and b is empty
  (d,c) = [x|x@(y,_)<-map(`splitAt`(tail b))[0..],'('!y<')'!y]!!0;
                           -- find matching ) in the tail of b ('tail' to remove leading '(') 
                           --   d: everything before and including the matching )
                           --   c: everything behind the matching )
  c!l=[1|m<-l,m==c]        -- helper function that builds a list of 1s for every character searched for
                           --   we have reached the matching ) if the list for ( is
                           --   shorter (less than, <) the list for )

p=(1#)                     -- start with footnote 1

Retina, 96 86 83 bytes * 120% = 99.6

The source code of this solution consists of two files:

+s`\((((\()|(?<-3>\))|[^)])*).(.*)(?<=(1+).*?)?
<sup>1$5</sup>$4

<sub>1$5 $1</sub>

Explanation

This is a very direct implementation of the algorithm as described in the challenge. The code consists of a single regex substitution which turns the first set of parentheses into a footnote. This substitution is repeated via the + until the string stops changing, which here means that the regex no longer matches (because it can't find any more parentheses).

The footnotes are enumerated in unary, so that I can simply look for the last footnote's number and append a 1 to create the next one.

The regex for finding the first set of parentheses is based on the standard technique for matching parentheses with balancing groups (hrhr, "matching parentheses"). It has been shortened a bit by using an unnamed group and by assuming that the parentheses are correctly balanced (which means we can omit the ( from the negated character class and match the final ) with a simple . and we also don't need to ensure that the capture stack is empty).

After matching the parentheses and capturing their contents into group 1, we capture the remainder of the string with (.*) into group 4 and then search back through the the string for the first set of 1s with a negative lookbehind. If we find such a substring, we store in group 5. If we don't, we lookbehind fails, but that's okay because it's optional - it just means that $5 will give an empty string which is the unary representation of 0 and which is also correct.

The substitution string then simply pieces everything together based on the capturing groups. The footnote number is incremented by prepending a 1 to the last number with 1$5.