14

In a comment to an answer about AT&T assembly syntax, another-dave asked the following:

DEC used #foo for an immediate operand in -11 assemblers; the Unix guys apparently preferred $foo, which to my eyes lacks any mnemonic significance. Similarly @ became *. Does anyone know the rationale or is this just personal taste?

  • Thanks for posting this. I'd completely forgotten about it! – wizzwizz4 Jan 7 at 14:20
23

The Unix Assembly Reference Manual by Dennis M. Ritchie, at §8.1 notes that:

The syntax of the address forms is identical to that in DEC assemblers, except that ‘‘*’’ has been substituted for ‘‘@’’ and ‘‘$’’ for ‘‘#’’; the UNIX typing conventions make ‘‘@’’ and ‘‘#’’ rather inconvenient.

In a SO answer, and in this comment, fuz notes that this is because # and @ are used as control characters by the early TTY drivers in Unix. This is indeed so, with @ taking the kill-line function, and # erases the last character¹.

This can be seen in the Unix History Repository at u7.s:

    jsr    r0,cesc; 100 / test for @ (kill line)
           br canon / character was @ so start over
    jsr    r0,cesc; 43 / test for # (erase last char. typed)
           br 1b / character was #, go back

(100 is the octal code for @, and 43 the octal code for #).

One would expect Unix would have adopted other characters for erase-kill processing, since the chosen ones clash with characters used by the assembler. But recall that Unix originated in a PDP-7. Erase-kill processing with # and @ was already in PDP-7 Unix, Dennis M. Ritchie in The Evolution of the Unix Time-sharing System notes that:

Only a few programs (notably the shell and the editor) bothered to implement erase-kill processing.

which I think correspond to this code in ed1.s:

    esc: 0                                                                                                                                                                                                                    
       sna                                                                                                                                                                                                                    
       jmp i esc                                                                                                                                                                                                              
       jms putsc; tal                                                                                                                                                                                                         
       sad o12                                                                                                                                                                                                                
       jmp 2f                                                                                                                                                                                                                 
       sad o100                                                                                                                                                                                                               
       jmp 1f                                                                                                                                                                                                                 
       sad o43                                                                                                                                                                                                                
       skp                                                                                                                                                                                                                    
       jmp i esc                                                                                                                                                                                                              
       -1                                                                                                                                                                                                                     
       tad tal                                                                                                                                                                                                                
       dac tal                                                                                                                                                                                                                
       and o17777                                                                                                                                                                                                             
       sad linpm1                                                                                                                                                                                                             
       jmp 1f                                                                                                                                                                                                                 
       jmp i esc

    1:
       lac linep
       dac tal
       jmp i esc

    2:
       lac tal
       sma cla
       jmp 1f
       jms putsc; tal

and init.s:

    rline: 0
       law ibuf-1
       dac 8
    1:
       cla
       sys read; char; 1
       lac char
       lrss 9
       sad o100
       jmp rline+1
       sad o43
       jmp 2f
       dac 8 i
       sad o12
       jmp rline i
       jmp 1b
    2:
       law ibuf-1
       sad 8
       jmp 1b
       -1
       tad 8
       dac 8
       jmp 1b

Mark Plotnick notes in a comment that Unix inherited the erase and kill characters from Multics. Following that lead, we can arrive at "Remote Terminal Character Stream Processing in Multics" (1970), which explains that:

It should be possible to determine from the printed page, without ambiguity, both what went into the computer pro- gram and what the program tried to print out.

which is the rationale for using printing characters for erase and kill (recall that back then users typed at teletypes, the typewriter-like ones).

It also mentions a special editor on the 7094 Compatible Time-Sharing System as a prior implementation of the things talked about in the paper, which may or may not refer also to erase and kill. Anyway, that special editor is probably TYPSET (of the TYPSET/RUNOFF workflow²), and it indeed used # and @ as defaults for erase and kill characters, as mentioned in TYPSET and RUNOFF, Memorandum editor and type-out commands (1964). While Project MAC Technical Report MAC-TR-16 mentions erase and kill processing in CTSS (figure in page 23, first paragraph in page 24), that report is from a later date, and doesn't mention which characters were used.

A little more digging leads us to the CTSS Programmer's Guide, which in its 1963 edition uses " and ? for delete-character and delete-message while the 1966 edition already gives # and @. "Introduction to CTSS Usage" (July 1967) gives both " and # for deleting the previous character, and ? and @ for deleting everything typed since the previous carriage return. So TYPSET may well be the first program to use # and @, from where it spread to CTSS, Multics, and eventually Unix.


¹ Incidentally, in early Unix as, as documented in man11 from the 1st edition of the Unix Programmer's Manual, there is another substitution:

    Character changes are:
        for      use
         @        *
         #        $
         ;        /

So, comments are marked by a slash.

² A nice history of RUNOFF/roff/... can be found at https://manpages.bsd.lv/history.html

  • 2
    Re ; - Unlike the DEC assemblers, Unix as permitted multiple instructions per line, with semicolon as the separator, thus it wasn't available as a comment indicator. – another-dave Jan 7 at 22:28
  • 2
    Multics, sometimes cited as one of the inspirations for Unix, also used # and @ for erase and kill. – Mark Plotnick Jan 10 at 11:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.