Compiler generation: from language definitions to abstract compilers