Разбор с неполными грамматиками - PullRequest
5 голосов
/ 26 августа 2011

Есть ли общие решения, как использовать неполные грамматики?В моем случае я просто хочу обнаружить методы в Delphi (Pascal) -файлах, что означает procedures и functions.Следующая первая попытка работает

    methods
      : ( procedure | function | . )+
      ;

, но это решение вообще?Есть ли лучшие решения?Можно ли прекратить анализ с действием (например, после обнаружения implementation).Имеет ли смысл использовать препроцессор?А когда да - как?

Ответы [ 2 ]

4 голосов
/ 26 августа 2011

То, о чем вы спрашиваете, называется островная грамматика .Идея состоит в том, что вы определяете синтаксический анализатор для той части языка, которая вас интересует («остров») со всеми классическими токенизациями, необходимыми для этой части, и что вы определяете крайне небрежный синтаксический анализатор для пропуска остальной части («океан»)в который остров встроен).Один из распространенных способов сделать это - определить соответственно небрежные лексеры, которые собирают огромное количество материала (чтобы пропустить HTML-код во встроенном коде, вы можете попробовать пропустить все, что не похоже на тег сценария в лексере, дляпример).

На сайте ANTLR даже обсуждаются некоторые связанные проблемы , но, в частности, говорится, что есть примеры, включенные в ANTLR.У меня нет опыта работы с ANTLR, поэтому я не знаю, насколько полезна эта конкретная информация.

Создав много инструментов, использующих анализаторы для анализа / преобразования кода (проверьте мою биографию), я немного пессимистоб общей полезности островных грамматик.Если ваша цель не состоит в том, чтобы сделать что-то довольно тривиальное с разобранным островом, вам нужно будет собрать значение всех идентификаторов, которые он использует прямо или косвенно ... и большинство из них, к сожалению, для вас определены в океане.Так что ИМХО вам в значительной степени придется разбирать океан тоже, чтобы пройти тривиальные задачи.У вас будут и другие проблемы, убедившись, что вы действительно пропустили вещи острова;это в значительной степени означает, что ваш океанский лексер знает о пробелах, комментариях и всем придирчивом синтаксисе символьных строк (это сложнее, чем это выглядит в современных языках), так что они должным образом пропускаются.YMMV.

4 голосов
/ 26 августа 2011

Если вы ищете только имена, тогда что-то простое:

grammar PascalFuncProc;

parse
  :  (Procedure | Function)* EOF
  ;

Procedure
  :  'procedure' Spaces Identifier
  ;

Function
  :  'function' Spaces Identifier
  ;

Ignore
  :  (StrLiteral | Comment | .) {skip();}
  ;

fragment Spaces     : (' ' | '\t' | '\r' | '\n')+;
fragment Identifier : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*;
fragment StrLiteral : '\'' ~'\''* '\'';
fragment Comment    : '{' ~'}'* '}';

поможет.Обратите внимание, что я не очень хорошо знаком с Delhpi / Pascal, поэтому я наверняка обманываю StrLiteral s и / или Comment s, но это будет легко исправить.выше будет выдавать только два типа токенов (Procedure s и Function s), остальная часть ввода (строковые литералы, комментарии или, если ничего не найдено, один символ: .) удаляется изнемедленно lexer (метод skip()).

Для такого ввода:

some valid source
{ 
  function NotAFunction ...
}

procedure Proc
Begin
  ...
End;

procedure Func
Begin
  s = 'function NotAFunction!!!'
End;

создается следующее дерево разбора:

enter image description here

...