ОГРАНИЧЕНИЯ НА ВЫПОЛНЕНИЕ ЦИКЛА
Есть несколько важных правил, которых нужно придерживаться, программируя циклы DO. Прежде всего в операторе DO начальный индекс никогда не должен совпадать с границей. Если вы хотите, чтобы цикл не был выполнен ни разу, и определили его следующим образом: : ОШИБКА 10 10 DO I . LOOP ;
то не получите ожидаемого результата. Результат будет таков:
К сожалению, LOOP уже переступил финишную черту и не попадет под электронный глаз в течение длительного времени (до тех пор, пока не вернется назад через 65535 шагов)1.
Если вы не уверены в том, что граница и индекс в каком-то вашем определении не совпадут, используйте вместо DO слово ?DO, которое, как и первое, берет из стека (границу индекс --), но сразу передает управление LOOP в том случае, когда граница и индекс совпадают.
Возвращаясь к слову STARS из гл. 1, напишем его правильное определение: : STARS ( число-звездочек) 0 ?DO 42 EMIT LOOP ;
При отсутствии в вашей системе слова ?DO используйте следующее определение:: STARS ( число-звездочек) ?DUP IF О DO 42 EMIT LOOP THEN ;
С какими неприятностями вы еще можете столкнуться? В большинстве Форт-систем при выполнении цикла DO текущие значения счетчика хранятся в стеке возвратов (введенном в гл. 5). Это при-
1 Для пользователей систем, созданных до принятия Стандарта-83. В более старых системах цикл выполнился бы один раз (вместо 64К раз), но и это не то, что вам нужно.
водит к некоторым ограничениям. В частности, слово I можно употреблять только в том определении, в котором используются слова DO и LOOP. Вы не имеете права ввести такой текст: : ТЕСТ I . ; : ДЕКАДА 10 0 DО ТЕСТ LOOP ;
Если вспомогательное определение (ТЕСТ) требует значения индекса, вы должны передать его через стек, например: : ТЕСТ ( индекс -- ) . ; : ДЕКАДА 10 0 DO I ТЕСТ LOOP ;
Отметим еще несколько ограничений. Вы не должны перед словом DO помещать в стек возвратов с помощью слова >R промежуточные значения с тем, чтобы использовать их внутри цикла. Если же вы запрограммировали внесение некоторого значения в стек возвратов внутри цикла, то обязаны перед выходом из цикла, до начала выполнения LOOP (или слова LEAVE, которое мы рассмотрим ниже), запрограммировать его удаление словом R>.