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

       

МНОГОСИМВОЛЬНЫЕ РАЗДЕЛИТЕЛИ


Все это хорошо для случаев, когда комментарии ограничены одиночными символами, но как быть с такими случаями как C или стандартный Pascal, где требуются два символа? Хорошо, принцип все еще тот же самый, но мы должны совсем немного изменить наш подход. Я уверен, что вы не удивитесь узнав, что это более сложный случай.

Для много символьной ситуации проще всего перехватывать левый ограничитель в GetChar.  Мы можем "токенизировать" его прямо здесь, заменяя его одиночным символом.

Давайте условимся, что мы используем ограничители C '/*' и '*/'. Сначала мы должны возвратиться к методу 'GetCharX'. В еще одной копии вашего компилятора переименуйте GetChar в GetCharX и затем введите следующую новую процедуру GetChar:

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

{ Read New Character.  Intercept '/*' }

procedure GetChar;

begin

   if TempChar <> ' ' then begin

      Look := TempChar;

      TempChar := ' ';

      end

   else begin

      GetCharX;



      if Look = '/' then begin

         Read(TempChar);

         if TempChar = '*' then begin

            Look := '{';

            TempChar := ' ';

         end;

      end;

   end;

end;

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

Как вы можете видеть эта процедура перехватывает каждое появление '/'. Затем она исследует следующий символ в потоке. Если это символ '*', то мы нашли начало комментария и GetChar возвратит его одно-символьный заменитель. (Для простоты я использую тот же самый символ '{' как я делал для Паскаля. Если бы вы писали компилятор C, вы без сомнения захотели бы использовать какой-то другой символ, не используемый где-то еще в C. Выберите что вам нравится... даже $FF, что-нибудь  уникальное).


Если символ, следующий за '/' не '*', тогда GetChar прячет его в новой глобальной переменной TempChar и возвращает '/'.

Обратите внимание, что вы должны объявить эту новую переменную и присвоить ей значение ' '. Мне нравится делать подобные вещи с использование конструкции "типизированная константа" в Turbo Pascal:

     const TempChar: char = ' ';

Теперь нам нужна новая версия SkipComment:

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

{ Skip A Comment Field }

procedure SkipComment;

begin

   repeat

      repeat

         GetCharX;

      until Look = '*';

      GetCharX;

   until Look = '/';

   GetChar;

end;

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

Обратите внимание на несколько вещей: прежде всего нет необходимости изменять функцию IsWhite и процедуру SkipWhite так как GetChar возвращает токен '{'. Если вы измените этот символ токена, тогда конечно вы также должны будете изменить символ в этих двух подпрограммах.

Во-вторых, заметьте, что SkipComment вызывает в своем цикле не GetChar а GetCharX. Это означает, что завершающий '/' не перехватывается и обрабатывается SkipComment. В-третьих, хотя работу выполняет процедура GetChar, мы все же можем работать с символами комментариев, вложенными в строки в кавычках,  вызывая GetCharX  вместо GetChar  пока мы находимся внутри строки. Наконец, заметьте, что мы можем снова обеспечить вложенные комментарии добавив одиночное утверждение в SkipComment, точно также как мы делали прежде.


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