Лекции по построению компилятора на Pascal

       

ЛИТЕРАЛЬНЫЕ АРГУМЕНТЫ


Зоркие читатели могли бы отметить, однако, что мы еще даже не имеем правильной формы простого показателя, потому что мы не разрешаем загрузку литеральных констант, только переменных. Давайте исправим это сейчас.

Для начала нам понадобится функция GetNum. Мы уже видели ее несколько версий, некоторые возвращают только одиночный символ, некоторые строку, а некоторые целое число. Та, которая нам здесь нужна будет возвращать длинное целое, так что она может обрабатывать все, что мы ей подбросим. Обратите внимание, что здесь не возвращается никакой информации о типах: GetNum не интересуется тем, как будет использоваться число:

{--------------------------------------------------------------}

{ Get a Number }

function GetNum: LongInt;

var Val: LongInt;

begin

   if not IsDigit(Look) then Expected('Integer');

   Val := 0;

   while IsDigit(Look) do begin

      Val := 10 * Val + Ord(Look) - Ord('0');

      GetChar;

   end;



   GetNum := Val;

   SkipWhite;

end;

{---------------------------------------------------------------}

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

Лучшим подходом было бы выбрать тип, основанный на значении литерала, как показано далее:

{--------------------------------------------------------------}

{ Load a Constant to the Primary Register }

function LoadNum(N: LongInt): char;

var Typ : char;


begin

   if abs(N) <= 127 then

      Typ := 'B'

   else if abs(N) <= 32767 then

      Typ := 'W'

   else Typ := 'L';

   LoadConst(N, Typ);

   LoadNum := Typ;

end;

{---------------------------------------------------------------}

 ( Я знаю, знаю, база числа не является в действительности симметричной. Вы можете хранить -128 в одиночном байте и -32768 в слове. Но это легко исправить и не стоит затраченного времени или дополнительной сложности возиться с этим сейчас. Стоящая мысль.)

Заметьте, что LoadNum вызывает новую версию подпрограммы генерации кода LoadConst, которая имеет дополнительный параметр для определения типа:

{---------------------------------------------------------------}

{ Load a Constant to the Primary Register }

procedure LoadConst(N: LongInt; Typ: char);

var temp:string;

begin

   Str(N, temp);

   Move(Typ, '#' + temp, 'D0');

end;

{--------------------------------------------------------------}

Теперь мы можем изменить процедуру Expression для использования двух возможных видов показателей:

{---------------------------------------------------------------}

{ Parse and Translate an Expression }

function Expression: char;

begin

   if IsAlpha(Look) then

      Expression := Load(GetName)

   else

      Expression := LoadNum(GetNum);

end;

{--------------------------------------------------------------}

 (Вау, это, уверен, не причинило слишком большого вреда! Всего несколько дополнительных строк  делают всю работу.)

ОК, соберите этот код в вашу программу и испытайте ее. Вы увидите, что она теперь работает и для переменных и для констант как допустимых выражений.


Содержание раздела







Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий