ChrisF's answer is excellent, but I wanted to add this example that always stuck by me after my computer science course on bootstrapping.
Suppose you have a basic C compiler that does not support escape codes for strings yet, and you wanted to add that. You could add a snippet of code similar to this:
if( str[i] == 0x5c ) { // ASCII code for backslash switch( str[i+1] ) { case 'n': return 0x0a; // ASCII code for new line case 't': return 0x09; // ASCII code for tab // ... // more ASCII code for other escapes default: return str[i+1]; } }
After you have added this to the compiler, and generated a new compiler binary, you could then rewrite this into:
if( str[i] == '\\' ) { switch( str[i+1] ) { case 'n': return '\n'; case 't': return '\t'; // ... default: return str[i+1]; } }
That would remove any knowledge about ASCII codes from the compiler source code, but the compiler would still magically generate the correct codes.