I'm trying to understand how a first compiler could be written.
Still confused after reading on the topic and what they said about this in "Perspectives".
If the very first compiler is written on the very first computer, then it would be written in machine language (only 0's and 1's).
But still, for that first compiler, how would I feed it with "asm" code like "@100" and "D=M" ?
It still only understands 0's and 1's ...
Is it because the first compiler would then understand the binary representation of the "@100"/"D=M" sequence of characters ?
In wikipedia : " self-compiling compiler — that is, compiler (or assembler) written in the source programming language that it intends to compile"
"written in the source programming language" means written in binary ?
With this Hack computer, we always have to use the host computer to change the assembly commands into machine language (binaries) that the Hack computer understands. If we always have to use the host computer to change our assembly commands to binaries, can I say that the Hack computer is incomplete, because it must depends on my host computer ? Is this where the Operating System comes into play ?
The earliest computers were hard wired to solve a single problem. To solve a different problem, the wiring had to be changed.
Then came stored-program computers which had a way to enter program codes (in machine language) into memory. The earliest papers I've read about stored-program computers include mnemonics along side the machine language, so the programming process was probably writing the programs on paper using the mnemonics and hand translating them into machine language when you were satisfied with your program.
Someone, probably many different people in different computer projects, realized that if the computer could process data, it could process mnemonics into machine language, and simple assemblers were hand coded. The simple assemblers were used to write more capable assemblers.
Assembly language would have been used to write early compilers. Better compilers and compilers for new languages and computers were written with earlier compilers.
Once you have a compiler for a language, you can use it to write a compiler that can compile itself. That's the self-compiling compiler.
Theoretically, given your Hack Assembler in Python you could write a Hack Assembler in Hack. You will need some way to read the .asm files and write the .hack files. This is identical in concept to my Jack Compiler written in Jack.
It would be a lot of work to write an assembly language program that large, and debug it. I did write a Hack Assembler in Jack that uses the same File System built-in OS class that I wrote for the compiler, but it ran out of RAM assembling Pong. The symbol table is too big to fit in 16K!
You won't be able to run the generated Assembler.hack files on the CPUEmulator, however, because the CPUEmulator has no provisions for simulating new hardware. There is no way that it could access the PC's disk the way my File System built-in class can do in the VMEmulator.
You might better understand the concept of self-compiling by thinking about writing a [subset of] Python interpreter in Python. As long as your interpreter is written in the subset you implement, it could run a copy of itself:
$ python mypy.py
would start your interpreter in interactive mode.
$ python mypy.py mypy.py
would start your interpreter in script mode and your interpreter would then load a copy of mypy.py and run that copy in interactive mode.
The only reason that you want a high-level language compiler to write another high-level language compile is because the work is Herculean it you try to do it in assembly language.
The Hack Hack assembler would get its source as characters from a hardware peripheral, just like reading the keyboard.