Содержание материала

ВЫЗОВ ПРОЦЕДУРЫ

Если вы удовлетворены работой программы, давайте обратимся ко второй половине уравнения... вызову.

Рассмотрим БНФ для вызова процедуры:

    <proc_call> ::= <identifier>

с другой стороны БНФ для операции присваивания:

    <assignment> ::= <identifier> '=' <expression>

Кажется у нас проблема. Оба БНФ утверждения с правой стороны начинаются с токена <identifier>. Как мы предполагаем узнать, когда мы видим идентификатор, имеем ли мы вызов процедуры или операцию присваивания? Это похоже на случай, когда наш синтаксический анализатор перестает быть предсказывающим и действительно это точно такой случай. Однако, оказывается эту проблему легко решить, так как все, что мы должны сделать - посмотреть на тип идентификатора, записанный в таблице идентификаторов. Как мы обнаружили раньше, небольшое локальное нарушение правила предсказывающего синтаксического анализа может быть легко обработано как специальный случай.

Вот как это делается:

Code:

{ Parse and Translate an Assignment Statement }

procedure Assignment(Name: char);

begin

     Match('=');

     Expression;

     StoreVar(Name);

end;

 

{ Decide if a Statement is an Assignment or Procedure Call }

procedure AssignOrProc;

var Name: char;

begin

     Name := GetName;

     case TypeOf(Name) of

          ' ': Undefined(Name);

          'v': Assignment(Name);

          'p': CallProc(Name);

          else Abort('Identifier ' + Name +

                                   ' Cannot Be Used Here');

     end;

end;

 

{ Parse and Translate a Block of Statements }

procedure DoBlock;

begin

     while not(Look in ['e']) do begin

          AssignOrProc;

          Fin;

   end;

end

 

 

Как вы можете видеть, процедура Block сейчас вызывает AssignOrProc вместо Assignment. Назначение этой новой процедуры просто считать идентификатор, определить его тип и затем вызвать процедуру, соответствующую этому типу. Так как имя уже прочитано, мы должны передать его в эти две процедуры и соответственно изменить Assignment. Процедура CallProc - это просто подпрограмма генерации кода:

 

Code:

{ Call a Procedure }

procedure CallProc(N: char);

begin

     EmitLn('BSR ' + N);

end;

 

Хорошо, к этому моменту у нас есть компилятор, который может работать с процедурами. Стоить отметить, что процедуры могут вызывать процедуры с любой степенью вложенности. Так что, даже хотя мы и не разрешаем вложенные объявления, нет ничего, чтобы удерживало нас от вложенных вызовов, точно так, как мы ожидали бы на любом языке. Мы получили это и это было не слишком сложно, не так ли?

Конечно, пока мы можем работать только с процедурами, которые не имеют параметров. Процедуры могут оперировать глобальными переменными по их глобальным именам. Так что к этому моменту мы имеем эквивалент конструкции Бейсика GOSUB. Не слишком плохо... в конце концов масса серьезных программ была написана с применением GOSUBа., но мы можем добиться большего и добьемся. Это следующий шаг.

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить