Базовый CS с нуля
Control flow: постройте jump-машину
Прочитать, что if — это conditional jump, а loop — backward jump, — одно дело. Построить машину, которая не делает ничего, кроме jump, и увидеть, как из неё возникают ваши if/else и while loop, — вот что превращает идею в модель, которой вы владеете. Вы напишете крошечный интерпретатор, чей единственный примитив control flow — «выставить program counter», а затем заставите реальные branch и loop работать на нём.
Превратите модель unit в работающий код: представьте программу как список инструкций, ведите её явным program counter, реализуйте только последовательное продвижение плюс conditional и безусловный jump и покажите, что любой if/else и любой loop, который вы строите, сводится к этим jump — включая режимы отказа off-by-one и infinite loop.
Постройте на любом языке маленький интерпретатор инструкций (jump-машину), чей единственный способ менять control flow — запись program counter. Затем прогоните на нём несколько написанных вручную программ — straight-line, if/else, считающий loop и багованный loop — и для каждой выдайте трассу исполнения, следящую за PC и переменными по шагам.
- Прогон программы A показывает, что PC продвигается ровно на единицу каждый шаг и каждая инструкция исполняется один раз, без взятых jump.
- Программа B даёт два разных пути PC для истинного и ложного случаев, блок else исполняется только в ложном случае, и видно, что именно безусловный skip-jump не даёт истинному пути исполнить блок else.
- Трасса программы C показывает, что backward jump срабатывает ровно N раз, а conditional jump выхода — один раз, и переменная loop совпадает с примером обратного отсчёта из unit.
- Программа D демонстрирует отказ: трасса off-by-one явно читает или считает на один элемент за границей, ЛИБО трасса infinite loop показывает одно и то же значение флага каждый проход, пока не сработает защита по шагам, — и абзац-заметка объясняет, какое условие так и не стало ложным.
- Короткое резюме (несколько предложений), своими словами объясняющее, почему любой branch и loop в четырёх программах свёлся ни к чему иному, как к переписыванию program counter.
- Добавьте do-while, перенеся CMP + conditional jump вниз loop, и покажите в трассе, что тело теперь исполняется хотя бы раз, даже когда условие ложно на входе.
- Добавьте поддержку цепочки else-if (несколько пар CMP + conditional jump) и протрассируйте, какая ветвь выигрывает для нескольких входов.
- Реализуйте short-circuit && и || в гостевой программе как цепочку conditional jump и протрассируйте вход, доказывающий, что правый операнд никогда не вычисляется.
- Добавьте крошечный визуализатор: печатайте список инструкций со стрелкой, отмечающей текущий PC на каждом шаге, чтобы трасса читалась как ячейки MachineFigure из уроков.
Это unit, сделанный исполняемым. Построив машину, чей единственный примитив control flow — «записать program counter», вы доказываете себе, что sequential исполнение, if/else и loop — не отдельные возможности, а три применения одного механизма. Straight-line программа никогда не трогает PC; if/else ведёт его на два адреса назначения со skip-jump на границе; loop отматывает его backward jump под тестом наверху loop; а сломанный loop показывает ровно, как off-by-one и infinite loop возникают из неверного теста или границы. Увидев, как branch и loop возникают из ничего, кроме jump, вы читаете любую программу на уровне самой машины.