39

We tend use the term assembler as if there is a fundamental implication of being different from a compiler. This disparity is usually taken as a fact, no matter how sophisticated or primitive either the tool or the language it handles is.

This is especially interesting when considering that early on only the term translator (*1) was used for the tool converting source text to machine code, independent of language. Even today IBM still uses the term translator when describing the actual zSeries HLL-Assembler, while FORTRAN has it in its name FORmula TRANslator.

So here's the question:

Why are assemblers named assemblers instead of translators?

Please note, this is not about the first use of the word assembly (*2), not even assembly language(*3), in history, but use of the term assembler for the program instead of translator.

I hope it may as well shed some light on a subsequent puzzle:

Since when are assemblers seen as something different than compilers?

Of course I'm not the first to ask so, there's for example a similar question on SoftwareEngineering.SE: 'Why is Assembly Language called "Assembly"?' (*4). But the answer given there is only citing a different Q&A site which doesn't offer any real insight, but rather self referencing assumptions.

The only plausible explanation I have (*5) is one I got ca. 1978/79 when asking several dinosaurs (*6) the very same question. I spend time lately digging thru old books as well as the net, to find any support, but couldn't find any authoritative answer or at least some tangible hints past common sense.


*1 - Funny enough, (early) German language literature uses Übersetzer, which is literally the same word. Zuse used 'übersetzen' in notes about Plankalkül during the early 1940s. Its use is as well documented with papers about the Z4 in Zürich in 1950.

*2 - As Thomas By reminded, the first use of 'assembly' in a book about computer programming might quite well be the 1951 book The Preparation of Programs for an Electronic Digital Computer which titles section 8-3 of the chapter about Automatic Programming (*7) as assembly of a program.

Wikipedia notes that the book includes

the first use of the term "assembly" in programming, though with a somewhat different meaning than the modern use of the term

When reading (*8) it becomes soon clear, that this 'assembly' is what in today's terminology would be a linker, although more close late binding or dynamic linking by inserting code stubs and indirect references into subroutines that need to be linked with a main program.

There is no resemblance of anything akin to a later assembler.

*3 - Assembly language as in the list of instructions and to to write them in for a certain assembler. These are not identical with the tool assembler or even a major art thereof. In context of an assembler they are a set of predefined shortcuts, much like predefined function provided by some HLL, to simplify usage.

*4 - Note the difference, as I'm asking why a assembler is called such, not why assembly language is, as the later is derivative of the first.

*5 - I was lucky to learn the trade from some exceptional veterans working EDP systems since the late 1950, so essentially since the very first days past of prototypes and one off designs.

*6 - Hoping for unbiased answer I will not replicate it here - at least not now. Eventually next month as an(other) answer.

*7 - There is no praise high enough for archive.org and its maintainers for preserving all of this for everyone (I got the dead tree version at hand :))

*8 - Reading it is really a worthwhile task - although a hard one for many as well, as next to everything may seem alien to today's readers. Written way before today's canon of terms was coined, every word had to be read at face value and considered within the context of the book and the machine (The English EDSAC) refereed to.

1
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Chenmunka
    Commented Jul 2, 2022 at 8:44

3 Answers 3

38

The first use seems to be in "Wilkes, M. V., D. J. Wheeler, and S. Gill, The Preparation of Programs for an Electronic Digital Computer. Reading, MA.: Addison-Wesley, 1951". This book can be found on Archive.org.

There's an entire section, appropriately titled "Assembly of a Program", that discusses using the machine to assist in producing the final machine code. Some quotes:

A simple illustration will now be given of the way in which a machine can be made to help with the clerical tasks involved in drawing up a program. A program is composed of a master routine and a number of subroutines and, in the ordinary way, the programmer must decide where these are to go in the store and provide the necessary cross referencing between them; for example, he must insert the correct addresses in those orders in the master routine which call in the subroutines.

The assembly subroutine given below allows the assembly of the master routine and the subroutines to be performed automatically by the machine.

The authors thought one of the more burdensome aspects of programming was bringing together a large program consisting of multiple subroutines. The bringing together of various parts into a final whole is more or less the definition of "to assemble". A program for the machine which automates this burdensome process would then naturally be an assembler. The book uses it in this sense.

Earlier in the book, the authors also use the term "assembly" in the sense of combining an operation, address, and modifier, into a final instruction value in memory:

It has already been explained that the translation of the orders, from the external form in which they are written and punched to the internal form which they take inside the machine, is performed by the initial input routine. This translation includes the conversion of the address to decimal form, the addition of any constant called for by the terminal code letter, the assembly of the complete order, and its placing in the correct storage location.

The Wilkes, Wheeler, and Gill text was the first book on computer programming. It was influential, with various sources online referring to it as the standard text into the late 1950s. Other terms from the book (such as "subroutine", and "libraries" of subroutines) also spread far.

5
  • 12
    My understanding has always been that they assemble complete instruction words from separate fields. This is the sense used in your reference to "Earlier in the book". FWIW, note that "compile" also meant combining a bunch of routines into a program, per Hopper.
    – dave
    Commented Jun 30, 2022 at 0:57
  • 2
    This reminds me of a simpler "assembler" I did for the 1802, which expected as input a mixture of raw hex bytes and three directives: set origin, store present location to label, and insert LSB of label value. Translation of opcodes into mnemonics had to be done by hand, but if the raw input to the assembler was edited to add or remove bytes, address fixups would be taken care of automatically.
    – supercat
    Commented Jun 30, 2022 at 16:00
  • 2
    I would think a program like that could have been designed in such a way as to allow machine code subroutines to be hand-punched onto cards in mostly-octal format, but with embedded-fixup information, such that if the cards for all required subroutines were put in the input hopper, they could be read directly into memory, with the "assembler" program's memory demands being small enough to fit in memory with the program being loaded.
    – supercat
    Commented Jun 30, 2022 at 16:12
  • When referring to dictionaries, the definition is of less use to this question than the etymology. Sadly in this case both Etymonline and Wiktionary offer nothing. The best dictionary on historical principles is the full OED (not any of Oxford's many other dictionaries). If you're a library member you may have access to it via your library's website. Sadly my library doesn't provide this so I can't check )-: Which came first between "assembler" and "assembly language" might not match our assumption. Could even be due to "assembly line". Commented Jul 1, 2022 at 11:40
  • @another-dave The machine was set up in a way that that wasn't really necessary. 5-bit code representing "A" meant add, and so on for other operations. And the simple ROM IO routines read in decimal numbers. So it sort of had that kind of very simple "assembly" built in.
    – RETRAC
    Commented Jul 2, 2022 at 17:59
23

"Compile" appears to have taken over for "translate" as an informal synonym until the term translate wasn't needed anymore. "Assemble" is older than either term.

The FORTRAN Automatic Coding System of February 1957 uses all three terms — compile, assemble, and translate — with different meanings. Compilation makes up the first several steps of the translator; assembly is the last step. I have bolded the words in the below excerpt:

The FORTRAN translator consists of six successive sections, as follows.

  1. Reads in and classifies statements. For arithmetic formulas, compiles the object (output) instructions. For nonarithmetic statements including input-output, does a partial compilation, and records the remaining information in tables. All instructions compiled in this section are in the COMPAIL file.
  2. Compiles the instructions associated with indexing, which result from DO statements and the occurrence of subscripted variables, These instructions are placed in the COMPDO file
  3. Merges the COMPAIL and COMPDO files into a single file, meanwhile completing the compilation of nonarithmetic statements begun in Section 1. The object program is now complete, but assumes an object machine with a large number of index registers.
  4. Carries out an analysis of the flow of the object program, to be used by Section 5.
  5. Converts the object program to one which involves only the three index registers of the 704.
  6. Assembles the object program, producing a relocatable binary program ready for running. Also on demand produces the object program in SHARE symbolic language.

(Note: Section 3 is of internal importance only; Section 6 is a fairly conventional assembly program. These sections will be treated only briefly in what follows.)

The note at the end implies that "assembly" was already such an established term at the time that the reader is expected to already know what it means. Translation and compilation were concepts layered on top of assembly.

Thus, I've come doubt a premise of this question — I'm not sure that "translator" is the oldest of the three terms. Because this text explains translation in detail but assumes understanding of assembly, it makes me guess that the term assembly was established a longer time ago.

The text also uses the word "compile" in a way that would be very familiar to us today:

These were compiled by the 704 in six minutes, producing about 1000 instructions. He ran the program and found the output incorrect. He studied the output (no tracing or memory dumps were used) and was able to localize his error in a FORTRAN statement he had written. He rewrote the offending statement, recompiled, and found that the resulting program was correct

This little anecdote about recompiling your code is an everyday experience for programmers today, but was novel enough in 1957 to require explanation. It shows us programmers who speak of "compiling" their code, not "translating" their code.

This 1957 document was the first published programmers' reference for the first compiled language. So, at a very early date, all three terms were used. A draft from 1954 (a few years before the first compiler was written) called The IBM Mathematical Formula Translating System does not use the terms compile, assemble, or translate. Thus it seems likely to me that "compile" and "translate" arose as distinct from "assemble" sometime between 1954 and 1957.

I feel the real question becomes: why did the word "translate" get dropped? The answer may simply be that, as we see in the 1957 anecdote, programmers were casually using the word "compile" instead of translate. Compilation was the first step in translation — the step that humans touched. Perhaps by synecdoche it came to stand for the entire translation process.

4
  • Interesting twist. I like it.
    – Raffzahn
    Commented Jun 30, 2022 at 16:52
  • 1
    There were earlier compiled languages before Fortran; see Knuth and Trabb-Pardo's "The Early Development of Programming Languages"
    – texdr.aft
    Commented Jun 30, 2022 at 20:03
  • 1
    To be fair, when it says it "assembles", there's nothing given that says that the intermediate forms fed into the assembler are actually mnemonic machine instructions. The way I read "assemble" here is more akin to linking. That it has these disparate components of the program from all of these phases and it now "puts them together" into the final binary. Maybe there's more to suggest that it is, indeed, just running what we today consider an "assembler", but from the anecdote as presented, that's not clear. Commented Jul 2, 2022 at 23:05
  • @WillHartung I was also going to comment that the use of "assemble" here is what we know refer to as "linking". In fact I think I just read that said on this or another Stack Exchange thread on a related topic. I'd also remind as I also just read that the first assembly languages didn't look as they now do with mnemonic instructions but looked more mathematical. Both the terms and the concepts become fuzzy as we peer into the primordial era of programming. Commented Oct 6 at 13:12
6

Why are Assemblers named Assemblers instead of Translators?

Assemblers do a bit more than simply convert mnemonics to opcodes.

They also handle and compute equates and labels, which is important because hard-coding addresses for jump/branch/subroutine destinations would cause you to have to modify a lot manually if you want ever needed your code to run from a different address.

Because of this, most assemblers are 2-pass and all addresses are resolved on the 2nd pass. It does a bit more than simple translation.

Versus compilers - compilers have to do more than just convert bits of text to binary values; unless the language is extremely simple.

Any language that supports:

  • if-then or while statements,
  • for-next loops,
  • the concept of functions, returning values, and passing parameters to them,
  • evaluation of expressions,
  • the concept of types,
  • especially, the concept of programmer-defined types such as structs, objects, etc.

is not going to be able to be trivally "translatable" to opcodes because common CPU instruction sets do not have a direct universal simple equivalent for those concepts -- especially per type.

A big deal is that the concept of functions isn't automatic to a CPU unless you implement it. A simple and common method: you can of course push and pull values stuff off the stack, but that's what it is to the CPU, PUSH and POP. Not a function. You need to keep track of what you pushed and popped otherwise you're returning to an address that is really one of your function arguments. Other ways of implementing function calls are possible, and some CPUs don't really have a stack pointer (MIPS and TMS9900).

Fundamental data types such as integers, strings, floats, and arrays of things that aren't bytes are basically different "worlds" in CPUs and don't use the same instructions.

Also when you want to treat collections of fundamental types as a type itself, especially for anything beyond simple arrays, then you're definitely looking into things that require collections of instructions - code that "knows" what type things are needs to be included because if the CPU can't process it with its byte, (DQ)word, block, or float instructions, then some combination of those instructions will be needed and either you or the compiler needs to generate that.

Why can't we just translate source code text into collections of assembler instructions then? Because CPU state is also part of the picture, and CPU state is affected by instructions, and also affects later instruction behavior. The simple example is the carry flag - if it's set when it shouldn't be by a previous instruction, your adds and subtracts will be off by one.

Naively resetting the CPU state between the code generated for each "high-level statement", such all the registers and the FLAGS register, for example, will make things slow. A compiler for a particular architecture will know what the state should be and not have to repeat "setup" type instructions for various operations.

8
  • 2
    Many ISAs have a plain add, separate from add-with-carry (adc), so you can add and subtract without worrying about the incoming value of the carry flag. Keeping variables in registers across statements is a huge deal, though, and something that non-optimizing compilers fail at. But you're over-stating the difficulty of things for strongly-typed languages like C. A one-pass C compiler is possible, (e.g. TCC the Tiny C Compiler). Commented Jun 30, 2022 at 20:45
  • 1
    Going back to fill in branch displacements from a table built during the one pass over the source code isn't normally counted as multi-pass. For stack space, TCC starts each function with a sub esp, imm32 whose displacement is filled in upon reaching the end of the function, once its seen all the locals. But locals can't be referenced before declaration, so reserving space for them can happen on the fly. The GNU assembler calls itself a one-pass assembler. Commented Jun 30, 2022 at 20:45
  • 2
    Another example is that most HLLs have separate types for signed and unsigned integers but assembly and machine code don't. The same bits have two interpretations and some instructions don't care which of the two are intended and others might and what happens to the flags might be interpreted differently for each. Keep track of that is part of a compilers job but an assembler just does what it's told. (Interesting questions would be whether there are ASMs that do differentiate signed vs unsigned types or HLLs that don't.) Commented Jul 1, 2022 at 11:36
  • 1
    There are many assemblers which don’t do all this stuff, and they’re still called assemblers (even the single-pass ones). Commented Jul 1, 2022 at 16:40
  • 2
    Even one-pass compilers can optimize objects to registers if they're marked with register storage class, and can even perform common subexpression elimination if they use use registers to hold temporary results in round-robin fashion, and notice that the value of a sub expression happens to be in a register when it is needed again.
    – supercat
    Commented Jul 1, 2022 at 20:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .