48
FOR <ident> = <expr1> TO <expr2> <block> ENDFOR
Сложность трансляции цикла "FOR" зависит от выбранного вами способа его
реализации, от пути, которым вы решили определять правила обработки ограничений.
Рассчитывается ли expr2 каждый раз при прохождении цикла, например, или оно
обрабатывается как постоянное ограничение? Всегда ли вы проходите цикл хотя бы раз,
как в Fortran, или нет. Все становится проще, если вы приверженец точки зрения что эта
конструкция эквивалентна:
<ident> = <expr1>
TEMP = <expr2>
WHILE <ident> <= TEMP
<block>
ENDWHILE
Заметьте, что с этим определением цикла <block> не будет выполнен вообще если
<expr1> изначально больше чем <expr2>.
Код 68000, необходимый для этого, сложней чем все что мы делали до сих пор. Я
сделал несколько попыток, помещая и счетчик и верхний предел в стек, в регистры и т.д.
В конечном итоге я остановился на гибридном варианте размещения, при котором
счетчик помещается в памяти (поэтому он может быть доступен внутри цикла) а верхний
предел - в стеке. Оттранслированный код получился следующий:
<ident> ; получить имя счетчика цикла
<expr1> ; получить начальное значение
LEA <ident>(PC),A0 ; обратиться к счетчику цикла
SUBQ #1,D0 ; предварительно уменьшить его
MOVE D0,(A0) ; сохранить его
<expr1> ; получить верхний предел
MOVE D0,-(SP) ; сохранить его в стеке
L1: LEA <ident>(PC),A0 ; обратиться к счетчику цикла
MOVE (A0),D0 ; извлечь его в D0
ADDQ #1,D0 ; увеличить счетчик
MOVE D0,(A0) ; сохранить новое значение
CMP (SP),D0 ; проверить диапазон
BLE L2 ; пропустить если D0 > (SP)
<block>
BRA L1 ; цикл для следующего прохода
L2: ADDQ #2,SP ; очистить стек
Ничего себе! Это же куча кода... строка, содержащая <block> кажется совсем
потерявшейся. Но это лучшее из того, что я смог придумать. Я полагаю, чтобы вам
помочь, вы должны иметь в виду что в действительности это всего лишь шестнадцать
слов, в конце концов. Если кто-нибудь сможет оптимизировать это лучше, пожалуйста
дайте мне знать.
Однако, подпрограмма анализа довольно проста теперь, когда у нас есть код:
{ Parse and Translate a FOR Statement }
procedure DoFor;
var L1, L2: string;
Name: char;
begin
Match('f');
L1 := NewLabel;
L2 := NewLabel;
Name := GetName;
Match('=');
Expression;