Компилятор преобразует текст на языке в грамматическое дерево.
Кодогенератор по грамматическому дереву генерирует машинный код.
Например. код:
a = b * c + d
грамматическое дерево:
=
/ \
a +
/ \
* d
/ \
b c
машинный код (в ассемблерной нотации x86):
mov eax,
mov ecx, [c]
imul ecx
add eax, [d]
mov [a], eax
Здесь описан только принцип. Естественно, в реальных примерах всё сложнее. Каждая операция может быть вызовом какой-нибудь навороченной подпрограммы, которая вызывает другие подпрограммы. Вызов подпрограммы в грамматике - это тоже узел дерева, ничего сверхъестественного. Также применяются оптимизации уровня кодогенератора (инлайн, развёртка циклов, преобразование в более дешёвые инструкции, например, сдвиг вместо умножения, и т.п.) и уровня компилятора (вычисление константных поддеревьев и др.)
Существуют стандартизированные грамматические описания, например, LLVM. Можно сделать компилятор своего языка высокого уровня, который переводит его код в LLVM, а потом воспользоваться готовыми кодогенераторами из LLVM в машинные коды соответствующих платформ. И наоборот, если кто-то выводит на рынок своё железо, то он может написать кодогенераторы из LLVM в его систему команд, и тогда оно станет доступным всем языкам, имеющим компиляторы в LLVM.