3 ms·
> All those "if"s, and "while"s, and "break"s, and "return"s jump to the not-yet-generated places in code just fine; a similar technique could be used for delay
by Someone 2y ago
> All those "if"s, and "while"s, and "break"s, and "return"s jump to the not-yet-generated places in code just fine; a similar technique could be used for delaying the resolution of function/procedure calls as well.
Not quite. When compiling "if"s, and "while"s, and "break"s, a compiler will make use of the fact that code is structured. Because of that, a stack of addresses is sufficient to track (similar to how Forth uses the return stack to compile such constructs)
For returns, the compiler doesn’t resolve the target address; that happens at runtime.
For function calls, a compiler would need a map mapping function names to addresses.
Also, generating good error messages is harder if you allow forward references. You cannot generate an error before seeing the definition, even if, say you encounter two calls to foo before seeing its definition.
- Joker_vD 2y agoOf course you can do all of this! After all, the sources of e.g. Wirth's Modula-2 single-pass compiler for the Macintosh (that generates native MC68000 code) have survived, and it doesn't use "stack of addresses": it uses "fixup()" calls when compiling conditions, loops, references to (imported) global variables etc. and, surely enough, calls to functions. It even has "CheckUDProc()" call at the end of the module-translation procedure to check whether there are any undefined procedures left in the symbol table. It would be entirely possible to treat calls to undefined functions as implicit forward declarations; he simply never chose to do so.