Antlr3 .Net как построить простую грамматику

Я пытаюсь создать простую грамматику для анализа строки имени типа .Net, поддерживающей универсальные типы. Я признаю, что был совершенно новичком в построении грамматики на любом языке. Строка типа может выглядеть следующим образом.

Foo.Bar.Blah(Mom.Dad, Son.Daughter(Frank.Bob), Dog)

По сути, это рекурсивно. Ты должен это понять.

Я совсем в лесу с этим. Не знаю, с чего начать. То, что я построил сейчас, но на самом деле не работает, это следующее:

tree grammar XmlTypeName;

options {
    language=CSharp2;
}

RPAREN
  : '('
  ;

LPAREN
  : ')'
  ;

SEP
  : ','
  ;

TYPE  
  : ('a'..'z'|'A'..'Z'|'0'..'9'|'_')+
  ;

prog
  : type;

type
  : TYPE (RPAREN type (SEP type)? LPAREN)? (EOF)?
  ;

Это даже близко не работает. Antlr3.exe выдает ошибки о том, что RPARAM и LPARAM не разрешены в анализаторе дерева. Парсер дерева вообще то, что мне нужно?

Я хотел бы создать простой AST, который позволяет мне перемещаться по типам.


person Jerome Haltom    schedule 08.03.2012    source источник


Ответы (1)


Нет, вам не следует использовать древовидную грамматику. Грамматика дерева используется после создания AST парсером. Просто удалите из него ключевое слово tree.

Еще пара замечаний:

  • вы хотите сопоставить один или несколько разделенных запятыми type в скобках, но вы использовали type (SEP type)?, что соответствует одному или двум type. Вместо этого вам понадобится type (SEP type)*;
  • вы не учли . внутри types;
  • вам следует отбросить буквальные пробелы в лексере.

Что-то вроде этого, скорее всего, поможет:

grammar XmlTypeName;

options {
  language=CSharp2;
}

prog
 : type EOF
 ;

type
 : name (RPAREN type (SEP type)* LPAREN)? 
 ;

name
 : ID (DOT ID)*
 ;

RPAREN
 : '('
 ;

LPAREN
 : ')'
 ;

SEP
 : ','
 ;

DOT
 : '.'
 ;

ID  
 : ('a'..'z'|'A'..'Z'|'0'..'9'|'_')+
 ;

SPACE
 : (' '|'\t')+ {Skip();} // if 'Skip()' doesn't work, try 'skip()'
 ;

Однако приведенное выше просто создает плоский список токенов. Если вы хотите создать правильный AST, вам нужно «сообщить» ANTLR, какие узлы / токены являются корневыми токенами, а какие отбрасывать (например, запятую, круглые скобки и т. Д.).

grammar XmlTypeName;

options {
  output=AST;
  language=CSharp2;
}

tokens {
  TYPE;
  NAME;
}

prog
 : type EOF -> type
 ;

type
 : name (RPAREN type (SEP type)* LPAREN)? -> ^(TYPE name type*)
 ;

name
 : ID (DOT ID)* -> ^(NAME ID+)
 ;

RPAREN
 : '('
 ;

LPAREN
 : ')'
 ;

SEP
 : ','
 ;

DOT
 : '.'
 ;

ID  
 : ('a'..'z'|'A'..'Z'|'0'..'9'|'_')+
 ;

SPACE
 : (' '|'\t')+ {skip();}
 ;

который создает следующий AST:

введите описание изображения здесь

Дополнительная информация о создании AST с помощью ANTLR: Как вывести AST, построенный с использованием ANTLR ?

person Bart Kiers    schedule 08.03.2012
comment
Спасибо! Примерно через 2 часа мне удалось выяснить, что мне нужно разделить ID, а анализ «имени» во многом такой же, как и анализ списка типов »,«. Но так получилось плоское дерево. Я все еще не уверен, что на самом деле означает этот синтаксис. - ›это перезапись, поэтому он изменяет токены из лексера ... понял ... но что означает ^ ()? - person Jerome Haltom; 09.03.2012
comment
Без проблем. Операторы AST объясняются в ссылке, которую я разместил в конце моего ответа. - person Bart Kiers; 09.03.2012
comment
Кроме того, он фактически выдает NAME '(' TYPE ',' TYPE ',' TYPE ')' в AST. Как мне заставить его скрыть (из AST? Или я должен вообще беспокоиться? - person Jerome Haltom; 09.03.2012
comment
Как я показал, '(', ')' и ',' опущены в AST: попробуйте. Также прочтите ссылку, которую я разместил в конце: она объяснит, как исключить или включить токены в AST. - person Bart Kiers; 09.03.2012
comment
@wasabi, если вы используете мой второй пример и видите круглые скобки и запятые, вы, вероятно, используете интерпретатор ANTLRWorks: не надо, он немного глючит. Вместо этого используйте отладчик ANTLRWorks (который показывает фактический созданный AST, а не только дерево синтаксического анализа). - person Bart Kiers; 09.03.2012