C isn't converted into assembler language unless you ask the compiler to. For example, LLVM lowers IR AST structures into target specific machine code. Assembler is never involved.
ASM is just a human readable representation of machine code for a particular ISA. So in your mental model, C and ASM exist at the same level.
Further, Java bytecode would exist above the the machine code level (again, alongside C then, since the VM is compiled to machine code) and Java on top of that.
It just doesn't make any sense to define languages like this. I don't see any benefit, and I don't even see it as being correct.
[1] https://www.oldcomputerbooks.com/pages/books/R504/james-mart...
[2] I can't find a good example, but I remember seeing ads for "4GL" tools in Dr Dobbs regularly in the mid-90s.
That depends on the compiler. GCC, for instance, most certainly emits assembler code as part of its standard compilation process.
"The SSA form is also used for optimizations. GCC performs more than 20 different optimizations on SSA trees. After the SSA optimization pass, the tree is converted back to the GIMPLE form which is then used to generate a register-transfer language (RTL) form of a tree. RTL is a hardware-based representation that corresponds to an abstract target architecture with an infinite number of registers. An RTL optimization pass optimizes the tree in the RTL form. *Finally, a GCC back-end generates the assembly code for the target architecture using the RTL representation.* Examples of back-ends are x86 back end, mips back end, etc."
Then, there's the official GCC documentation[2]:
"Compilation can involve up to four stages: preprocessing, compilation proper, assembly and linking, always in that order. GCC is capable of preprocessing and compiling several files either into several assembler input files, or into one assembler input file; then each assembler input file produces an object file, and linking combines all the object files (those newly compiled, and those specified as input) into an executable file."
You can also just run GCC -- either with --verbose or --save-temps -- and observe what the compiler toolchain is doing.
[1] https://en.m.wikibooks.org/wiki/GNU_C_Compiler_Internals/GNU...
[2] https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Overall-Option...
> SSA GIMPLE is low level GIMPLE rewritten in SSA form.
I’m by no means a compiler internals expert, but to my knowledge there’s no translation from RTL to assembly. The compiler is directly emitting the machine code directly without first emitting assembler. You have to ask the compiler to serialize to assembly explicitly.
> several assembler input files, or into one assembler input file; then each assembler input file produces an object file,
That doesn’t sound right. Seems more like an abstract description. You can’t dump assembly out of an object file either. You have to do a conversion from an intermediary form to get back out a form of the assembly.
I think at this point it’s splitting hairs but assembly is not used as an intermediary at any point, even for generating machine code.
You asked me for a citation. I provided two, as well as a means by which you could see for yourself that what I am saying is correct.
Believe what you want, but all of the GCC documentation, as well as the output of the compiler if you run with --verbose or --save-temps supports what I have described of GCC's operation.
The compiler internals manual[1] also describes the backend machine descriptions, and how they are used in detail:
"There are three main conversions that happen in the compiler:
1. The front end reads the source code and builds a parse tree.
2. The parse tree is used to generate an RTL insn list based on named instruction patterns.
3. The insn list is matched against the RTL templates to produce assembler code."
> hover none of them improves programmer productivity by an order of magnitude.
I disagree. I can write efficient SQL statement in 2 minutes, but implementing efficient multiple "table" join with spill to disk took me much longer than 20 minutes.
It's like saying Windows 11 and OS/2 are the same because they are both Operating Systems.
In this context, the question is more, are Lisp or Haskell, or Python 10 times as productive as C? I used to think so, but now I seriously doubt it.
I mean, the reason I’m so much faster at writing small Python programs than I am at writing equivalent C programs, is because Python’s standard library is so damn huge. This is not a case of the language being more productive, this is a case of the work already being done.
Your portability point mostly stands, though.
«A Compiler is a software that typically takes a high level language (Like C++ and Java) code as input and converts the input to a lower level language at once.»
«Assembler A translator from assembly language programs to machine language programs.
Compiler A translator from “high-level” language programs into programs in a lower-level language.
Transpiler A translator from high-level language programs into programs in a different high-level language.»
«The compiler is software that converts a program written in a high-level language (Source Language) to low-level language (Object/Target/Machine Language).»
This the best possible outcome, though -- since they used up these kind of "biggest classification that doesn't sound totally silly" labels in the 70's and 80's or whatever, we don't have to worry about classifying languages anymore, which was not really all that productive to do anyway.
Although I do wonder what level Verilog should be considered.
For example, surely languages like Typescript are "level 4" as you cannot manipulate memory directly but only use the languages higher level type structures.
https://en.wikipedia.org/wiki/Fourth-generation_programming_...
They considered things like excel 4GL: You program some formulas and excel magically finds out what the necesarry steps are to do the computation.
A lot of vendors created graphical programming languages and declared them 4GL. The term mostly died because nobody could stop laughing.
The first 3 generation of languages were powered by higher levels of abstraction, which were possible because of better machines.
However, further increase in level of abstraction did not make developers an order of magnitude more productive, except for niche areas. Switching to a better development process (Scrum) can achieve order of magnitude improvement in developer performance, while switching of programming language cannot.
Anybody can claim that their product is a next gen revolutionary market shaking breakthrough. It's the self-promotion, not a science.
And I still have to review all of them.
How is that "4th level abstraction" whatever the current usage of the term?
Transpilers are compiling from one 3rd level language into another 3rd level language.
Code generators or macros are receiving data and producing code in a 3rd level language.
4th level language receives plain text explanation of a goal and produces code in a 3rd level language. AI based tool is the only tool which is capable to do that, because such process requires understanding of the goal, not a mechanical transformation of input into output. It's possible to implement such AI in Lisp, Prolog, or using ML. Copilot is an example of such AI.
Such an explanation would read like this:
I require some glue code so the system our company uses to pass messages between our services, can talk to the system of the company we talked to 2 days ago. Also, there should be a web interface or something to monitor it.
Not like this: A function that queries the user from the database by its surname apt-get install foo bar baz
Just few words, but they can generate very complex ready to run systems.Unfortunately, this is not a general-purpose language, but apt + shell is.
I issue an imperative command to apt-get, and it tries to execute it.
It has no knowledge of why I want foo bar and baz installed, nor can it decide if these 3 programs make sense for what I am trying to do, or if there is a better way to do it (maybe there is a package "bazinga", that can replace the foo-bar-baz stack?).
A goal-aware package manager would look like this:
super-apt "i need the system ready to function as a webserver, with a high availability database and backup capabilities"A typical package manager is already goal-aware, like `make`. It's input DSL is far from English, but it's not hard to translate your English sentence into «apache postgress rsync» by matching text to package descriptions.
Package manager requires a solver for dependencies, constraints, and conflicts, which is far from trivial. For example, Fedora(RedHat) switched from in-house solver for yum/dnf to zypper SAT solver (libzypp) developed by SuSE/Ximian/Novell.
Unfortunately, package managers are DSL, not a general purpose language.
If you are asking what level of abstraction is used by Forth, then the answer is: 2nd. It directly exposes stack, memory, and machine code and provides a thin wrapper on top of that. Developers can build higher levels of abstraction then, of course. It's possible to do an object-oriented programming in machine code, because compiler can.
The trickier question is: What level is Lisp? Is it assembler for Lisp machine (because of opcodes like car, cdr, etc.)? Or, maybe, it is a 4GL because of it advanced meta-programming possibilities?
So, it's expected to see an order of magnitude improvement in development speed, on average, when jumping from machine code to asm, or from asm to a 3rd level language. Forth doesn't improve speed of development by an order of magnitude comparing to asm, because of the steep learning curve and low level stack management. I tried to learn Forth multiple times, but still cannot program in Forth freely, which makes it unique among 20+ other programming languages I know.
Chuck Moore created Forth to improves his productivity versus conventional tools and there is some anecdotal evidence that it worked for him and those that worked with him, particularly where direct hardware control on new hardware could be interrogated and validated via the interpreter rather than an Edit/Assemble/Link/Test loop.
[1] - https://www.discoverbooks.com/Forth-The-Fourth-Generation-La...
Language levels of abstraction:
1. Machine code
2. Assembler
3. A high-level language
C does allow low level things, e.g. access of machine registers or embedding of assembler or machine code, but it is also capable of quite high level of abstraction.
Some of 3-rd level languages allows higher level of abstraction, or hide low level abstractions, e.g. memory management, stack, byte order, bits per number, etc., hover none of them improves programmer productivity by an order of magnitude.