a++;  // add one to a
 Totally pointless. 
 [...] 
  Certainly when I'm annotating previously
unknown assembly [...], I
 tend to annotate EVERY line unless it does something stupidly obvious
 [...] because I know I can't juggle all the register semantics around
 in my head while I'm still discovering them. 
 
Sure, but
        incl    d4      ; increment d4
is pointless even then.  What helps under those circumstances - and, I
would hope, what you do - is
        incl    d4      ; increment array index
or
        incl    d4      ; increment count of...whatevers-they-are
or
        incl    d4      ; compensate for extra decrement inside loop
or some such.
  Or, of course, if you've been intentionally obtuse
about your
 variable names 
...then, unless you're writing for the IOCCC or some such, you've got
bad code there, in at least that respect.
Of course, one person's "intentionally obtuse" is another's "why
bother, it's a temporary for all of ten lines of code" or even "what do
you mean obtuse, it's perfectly clear".
  (chances are you should never REALLY have a variable
named "a" unless
 there's a very good reason to do so), 
NODE *sort_nodes(NODE *list)
{
 NODE *a;
 NODE *b;
 NODE *t;
 NODE **tp;
 if (!list || !list->link) return(list);
 a = 0;
 b = 0;
 while (list)
  { t = list;
    list = list->link;
    t->link = a;
    a = b;
    b = t;
  }
 sort_nodes(a);
 sort_nodes(b):
 ...(merge step omitted)...
}
I am unconvinced this is either a bad use of the names "a" and "b" or
a
case where there's "a very good reason" to use them (x and y, or s1 and
s2, or any of many other choices, would be equally good).
/~\ The ASCII                             Mouse
\ / Ribbon Campaign
 X  Against HTML                mouse at 
rodents-montreal.org
/ \ Email!           7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B