Как использовать пробел в простой грамматике - PullRequest
0 голосов
/ 27 августа 2018

Я новичок в antlr и ebnf.

У меня есть следующая грамматика, выраженная в antlr4:

grammar RecordGrammar;

Record: 'record';
EndRecord: 'endrecord';

Track: 'track';
EndTrack: 'endtrack';

Length: 'length';

Name: [a-zA-Z]+;
Number: [0-9]+;
WS: [ \t\r\n]+;

records: (record)+ EOF;

record: Record WS Name WS
            tracks WS?
        EndRecord WS?;

tracks: track WS? (track WS)*;

track: Track WS
          length
       EndTrack WS?;

length: Length WS Number WS?;

Когда я использую грамматику выше (с antlr) для этого текста:

record help
    track
     length 2
    endtrack
    track
       length 4
    endtrack
    track
       length 42
    endtrack
endrecord

... работает хорошо и модно.

Но я хочу расширить правило 'Name' в EBNF, чтобы также принимать пробел.

Итак, я хочу, чтобы грамматика также принимала этот текстовый файл:

record help me
    track
     length 2
    endtrack
    track
       length 4
    endtrack
    track
       length 42
    endtrack
endrecord

Обратите внимание на текст «помогите мне» справа от тега записи.

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

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Вы должны начать с того, чтобы решить, как определить, где на самом деле заканчивается имя. В начальной грамматике это просто - это одно слово, поэтому оно заканчивается пробелом. В ответе Барта, это каждое слово между словами «запись» и «дорожка» *. Но так ли это в вашем случае, или имя может содержать слово «track»?

Возможно, вы также захотите рассмотреть следующие варианты:

  • Завершение имени в конце строки (в этом случае пробел становится значительным, и вам нужно разрешить это слово в имени, делая его незарезервированным ключевым словом ).
  • Заключение имени в несколько слов в кавычках (") или апострофах (') - в этом случае пробел не имеет значения и может быть пропущен согласно ответу Барта.

*) На самом деле все сложнее, но это основная идея того, как выглядит конец названия записи.

0 голосов
/ 27 августа 2018

Вы можете создать name правило синтаксического анализатора, которое соответствует нескольким Name токенам:

name : Name (WS+ Name)*;

Но так как вы на самом деле ничего не делаете с пробелами, помните также об их отбрасывании во время токенизации, добавив к нему -> skip и затем удалив все WS из правил вашего парсера:

grammar RecordGrammar;

records     : record+ EOF;
record      : Record name tracks EndRecord;
tracks      : track+;
track       : Track length EndTrack;
length      : Length Number;
name        : Name+;

Record      : 'record';
EndRecord   : 'endrecord';
Track       : 'track';
EndTrack    : 'endtrack';
Length      : 'length';
Name        : [a-zA-Z]+;
Number      : [0-9]+;
WS          : [ \t\r\n]+ -> skip;

, что приведет к следующему дереву разбора:

enter image description here

...