Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 [ 65 ] 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

Используя эту процедуру мы можем переписать Block так:

{ Parse and Translate a Block of Statements }

procedure Block;

begin

Statement;

while Token = ; do begin

Next;

Statement; end; end;

Это, уверен, не повредило, не так ли? Теперь мы можем анализировать точки с запятой в Паскаль-подобном стиле.

КОМПРОМИСС

Теперь, когда мы знаем как работать с точками с запятой, означает ли это, что я собираюсь поместить их в KISS/TINY? И да и нет. Мне нравится дополнительный сахар и защита, которые приходят с уверенным знанием, где заканчиваются утверждения. Но я не изменил своей антипатии к ошибкам компиляции, связанным с точками с запятой.

Так что я придумал хороший компромис: сделаем их необязательными!

Рассмотрите следующую версию Semi:

{ Match a Semicolon } procedure Semi; begin

if Token = ; then Next; end;

Эта процедура будет принимать точку с запятой всякий раз, когда вызвана, но не будет настаивать на ней. Это означает, что когда вы решите использовать точки с запятой, компилятор будет использовать дополнительную информацию чтобы удержаться на правильном пути. Но если вы пропустите одну (или пропустите их всех) компилятор не будет жаловаться. Лучший из обоих миров.

Поместите эту процедуру на место в первую версию вашей программы (с синтаксисом для C/Ada) и вы получите TINY Version 1.2.

КОММЕНТАРИИ

Вплоть до этого времени я тщательно избегал темы комментариев. Вы могли бы подумать, что это будет простая тема... в конце концов компилятор совсем не должен иметь дела с комментариями; он просто должен игнорировать их. Чтож, иногда это так.

Насколько простыми или насколько трудными могут быть комментарии, зависит от выбранного вами способа их реализации. В одном случае, мы можем сделать так, чтобы эти комментарии перехватывались как только они поступят в компилятор. В другом, мы можем обрабатывать их как лексические элементы. Станет интереснее когда вы рассмотрите вещи, типа разделителей комментариев, содержащихся в строках в кавычках.

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

Вот пример. Предположим, мы принимаем стандарт Turbo Pascal и используем для комментариев фигурные скобки. В этом случае мы используем односимвольные разделители, так что наш анализ немного проще.



Один подход состоит в том, чтобы удалять комментарии как только мы встретим их во входном потоке, т.е. прямо в процедуре GetChar. Чтобы сделать это сначала измените имя GetChar на какое-нибудь другое, скажем GetCharX. (На всякий случай запомните, это будет временное изменение, так что лучше не делать этого с вашей единственной копией TINY. Я полагаю вы понимаете, что вы всегда должны делать эти эксперименты с рабочей копией).

Теперь нам нужна процедура для пропуска комментариев. Так что наберите следующее:

{ Skip A Comment Field } procedure SkipComment; begin

while Look <> } do

GetCharX; GetCharX; end;

Ясно, что эта процедура будет просто считывать и отбрасывать символы из входного потока, пока не найдет правую фигурную скобку. Затем она считывает еще один символ и возвращает его в Look.

Теперь мы можем написать новую версию GetChar, которая вызывает SkipComment для удаления комментариев:

{ Get Character from Input Stream } { Skip Any Comments } procedure GetChar; begin

GetCharX;

if Look = { then SkipComment; end;

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

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

Во-вторых, так как остальная часть синтаксического анализатора не может даже получить символ {, вам не будет позволено поместить его в строку в кавычках.

Однако, прежде чем вы отвернете свой нос от такого упрощенного решения, я должен подчеркнуть, что столь уважаемый компилятор, как Turbo Pascal, также не позволит использовать { в строке в кавычках. Попробуйте. Относительно комментариев, вложенных в идентификатор, я не могу представить чтобы кто-то захотел сделать подобные вещи, так что вопрос спорен. Для 99% всех приложений то что я показал, будет работать просто отлично.

Но, если вы хотите быть щепетильным в этом вопросе и придерживаться стандартного обращения, тогда нам нужно переместить место перехвата немного ниже.

Чтобы сделать это сперва верните GetChar на старое место и измените имя,



вызываемое в SkipComment Затем, давайте добавим левую фигурную скобку как возможный символ незаполненного пространства:

{ Recognize White Space }

function IsWhite(c: char): boolean;

begin

IsWhite := c in [ , TAB, CR, LF, {]; end;

Теперь мы можем работать с комментариями в процедуре SkipWhite:

{ Skip Over Leading White Space }

procedure SkipWhite;

begin

while IsWhite(Look) do begin if Look = { then

SkipComment else

GetChar;

end; end;

Обратите внимание, что SkipWhite написан так, что мы пропустим любую комбинацию незаполненного пространства и комментариев в одном вызове.

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

Остался последний вопрос: вложенные комментарии. Некоторым программистам нравится идея вложенных комментариев так как это позволяет комментировать код во время отладки. Код, который я дал здесь не позволит этого и, снова, не позволит и Turbo Pascal.

Но исправить это невероятно просто. Все, что нам нужно - сделать SkipComment рекурсивной:

{ Skip A Comment Field } procedure SkipComment; begin

while Look <> } do begin

GetChar;

if Look = { then SkipComment; end;

GetChar; end;

Готово. Настолько утонченный обработчик комментариев, какой вам когда-либо может понадобиться.

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

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



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 [ 65 ] 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97