Все действия процессора подчиняются точно сформулированной процедуре, называемой алгоритмом Трак. Процессор содержит три структуры: активную цепочку, нейтральную цепочку и указатель сканирования. Для наглядности обычно считают, что нейтральная цепочка располагается слева, указатель сканирования — посередине и активная цепочка — справа. Указатель сканирования всегда указывает на левый конец активной цепочки, обозревая первую литеру. Литеры, как правило, переходят из активной в нейтральную цепочку; там литеры накапливаются до тех пор, пока их не станет достаточно для построения всех аргументов некоторой функции. Тогда эта функция выполняется и ее результат помещается в активную или нейтральную цепочку в соответствии с типом функции.
Алгоритм состоит из 10 пронумерованных шагов. Работа процессора начинается с шага 1. В алгоритме кое-где говорится о различных отметках литер нейтральной цепочки. Представляйте себе эти отметки как флажки, поставленные у отмеченных литер (конечно, в реализации отметки будут представлены, вероятно, указателями). В любой практической реализации существует специальная клавиша «прерывание» для прекращения бесконечного цикла, предписанного алгоритмом.
1. Очистить процессор; для этого опустошить нейтральную цепочку, удалить содержимое активной цепочки, если оно есть, поместить туда цепочку # (пц, # (чц)) и установить указатель сканирования на первую литеру активной цепочки [59]. Перейти к следующему шагу.
2. Проанализировать литеру, на которую указывает указатель сканирования. Если ее нет, т. е. активная цепочка пуста, вернуться к шагу 1.
3. Если под указателем сканирования — литера табуляции, перевода строки, конца записи или возврата каретки, то удалить ее, продвинуть указатель к следующей литере и вернуться к шагу 2.
4. Если под указателем сканирования — левая скобка, то удалить ее и просмотреть активную цепочку вперед, пока не будет найдена соответствующая ей правая скобка. Переместить в неизменном виде все расположенные между этими скобками литеры в нейтральную цепочку, удалить правую скобку, продвинуть указатель сканирования вперед к следующей за ней литере и после этого вернуться к шагу 2. Если соответствующую правую скобку не удается найти, то вернуться к шагу 1.
5. Если литера, находящаяся под указателем сканирования,— запятая, то удалить ее, пометить самую правую литеру нейтральной цепочки как конец одного аргумента, а следующую литеру — как начало нового аргумента, продвинуть вперед указатель сканирования и вернуться к шагу 2.
6. Если под указателем сканирования — знак диез, а следующая литера — левая скобка, то это означает, что перед нами — начало активной функции. Удалить диез и скобку, продвинуть указатель сканирования после них, отметить самую правую литеру нейтральной цепочки одновременно как начало аргумента и начало активной функции и вернуться к шагу 2.
7. Если под указателем сканирования — знак диез и вслед за ним стоят еще один диез и левая скобка, то это значит, что начинается нейтральная функция. Удалить три литеры ##(, продвинуть указатель после них, отметить самую правую литеру нейтральной цепочки одновременно как начало аргумента и начало нейтральной функции и вернуться к шагу 2.
8. Если под указателем сканирования находится знак диез, но условия шагов 6, 7 не выполняются, то переместить диез в правый конец нейтральной цепочки, передвинуть указатель и вернуться к шагу 2.
9. Если под указателем сканирования оказалась правая скобка, это говорит об окончании функции. Удалить эту скобку, передвинуть указатель сканирования и отметить самую правую литеру нейтральной цепочки как конец аргумента и конец функции. Теперь нейтральная цепочка от самой правой отметки начала функции до только что поставленной отметки конца функции составляет вызов функции Трака. (Если в нейтральной цепочке нет отметки начала функции, то вернуться к шагу 1.) Удалить из нейтральной цепочки аргументы функции (все те аргументы, отметки которых стоят после отметки начала функции) вместе с отметками функции и аргументов. (Ввиду способа нанесения отметок все отметки начала стоят в действительности у литер, непосредственно предшествующих отмечаемым элементам.) Предполагается, что первым аргументом является имя встроенной функции Трака. Вычислить функцию с данными аргументами; лишние аргументы игнорируются, недостающие аргументы автоматически добавляются со значением «пустая цепочка». Значение функции присоединяется справа к нейтральной цепочке, если функция была отмечена как нейтральная, и слева к активной цепочке, если функция была отмечена как активная; в последнем случае указатель сканирования устанавливается на левый конец новой активной цепочки. Если первый аргумент не является именем никакой встроенной функции, то просто поместить в качестве результата функции пустую цепочку. Вернуться к шагу 2.
59
Сейчас Муэрс использует холостую цепочку # (пц (CR LF)) # (пц, # (чц)), где CR — литера «возврат каретки», a LF — «перевод строки»