Лекции по построению компилятора на Pascal
{--------------------------------------------------------------}
Как вы можете видеть, процедура Block сейчас вызывает AssignOrProc вместо Assignment.
Назначение этой новой процедуры просто считать идентификатор, определить его тип и
затем вызвать процедуру, соответствующую этому типу. Так как имя уже прочитано, мы
должны передать его в эти две процедуры и соответственно изменить Assignment. Процедура
CallProc - это просто подпрограмма генерации кода:
{--------------------------------------------------------------}
{ Call a Procedure }
procedure CallProc(N: char);
begin
#### EmitLn('BSR ' + N);
end;
{--------------------------------------------------------------}
Хорошо, к этому моменту у нас есть компилятор, который может работать с процедурами.
Стоить отметить, что процедуры могут вызывать процедуры с любой степенью вложенности.
Так что, даже хотя мы и не разрешаем вложенные объявления, нет ничего, чтобы удерживало
нас от вложенных вызовов, точно так, как мы ожидали бы на любом языке. Мы получили это
и это было не слишком сложно, не так ли?
Конечно, пока мы можем работать только с процедурами, которые не имеют параметров.
Процедуры могут оперировать глобальными переменными по их глобальным именам. Так
что к этому моменту мы имеем эквивалент конструкции Бейсика GOSUB. Не слишком
плохо... в конце концов масса серьезных программ была написана с применением GOSUBа.,
но мы можем добиться большего и добьемся. Это следующий шаг.
ПЕРЕДАЧА ПАРАМЕТРОВ
Снова, все мы знаем основную идею передачи параметров, но давайте просто для]
надежности разберем ее заново.
Вообще, процедуре предоставляется список параметров, например:
### PROCEDURE FOO(X, Y, Z)
В объявлении процедуры параметры называются формальными параметрами и могут
упоминаться в теле процедуры по своим именам. Имена, используемые для формальных
параметров в действительности произвольны. Учитывается только позиция. В примере выше
имя 'X' просто означает "первый параметр" везде, где он используется.
Когда процедура вызывается, "фактические параметры" переданные ей, связаны с
формальными параметрами на взаимно-однозначном принципе.
БНФ для синтаксиса выглядит приблизительно так:
### <procedure> ::= PROCEDURE <ident> '(' <param-list> ')' <begin-block>
### <param_list> ::= <parameter> ( ',' <parameter> )* | null
Аналогично, вызов процедуры выглядит так:
### <proc call> ::= <ident> '(' <param-list> ')'
Обратите внимание, что здесь уже есть неявное решение, встроенное в синтаксис. Некоторые
языки, такие как Pascal и Ada разрешают списку параметров быть необязательным. Если нет
никаких параметров, вы просто полностью отбрасываете скобки. Другие языки, типа C и
Modula-2, требуют скобок даже если список пустой.]]]] Ясно, что пример, который мы] только
что привели, соответствует первой точке зрения. Но, сказать правду, я предпочитаю
последний. Для одних процедур решение кажется должно быть в пользу "без списочного"
подхода. Оператор
### Initialize; ,