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.