Проблема с грамматикой antlr - PullRequest
2 голосов
/ 05 июня 2011

Я пытаюсь выяснить грамматику для следующего синтаксиса.

foreach
    where x = 1 when some_variable = true
    where x = 2 when some_variable = false
    where y = 0
        print z              // Main block

    when none                // optional
        print 'not found'    // Exception block
endfor

Моя грамматика выглядит так:

foreach_stmt    : 'for' 'each' where_opt* blockstmt* whennone_opt? 'endfor'
                ;
where_opt       : 'where' cond_clause
                ;
cond_clause     : test when_opt*
                ;
when_opt        : 'when' test
                ;
whennone_opt    : 'when' 'none' blockstmt*
                ;
test            : or_test
                ;
// further rules omitted

Но когда основной блок пуст, например,

foreach
    where x = 1
        // main block is blank, do nothing
    when none
        print 'none'
endfor

В этом случае моя грамматика считает, что "когда нет" - это cond_clause для "где x = 1", а это не то, что я ожидаю.

Также рассмотрим следующий случай:

foreach
    where x = 1 when none = 2
        print 'none'
    // exceptional block is blank
endfor

Где «none» может быть переменной, а «none = 2» должно соответствовать правилу «test», поэтому оно является частью «where ... when ...».

Однако, когда «none» отсутствует в выражении, я хочу, чтобы «none» совпадало с «foreach», а не с предыдущим «where». Как я могу изменить мою грамматику, чтобы сделать это?

Извините, этот заголовок - отстой, но я не знаю, как описать проблему в нескольких словах. Любая помощь будет принята с благодарностью.

1 Ответ

2 голосов
/ 06 июня 2011

Анализатор, сгенерированный из следующей грамматики ANTLR:

grammar Genexus;

parse
  :  foreach_stmt* EOF
  ;

foreach_stmt    
  :  'foreach' where_opt* blockstmt* whennone_opt? 'endfor'
  ;

where_opt
  :  'where' cond_clause
  ;

cond_clause
  :  test when_opt*
  ;

when_opt
  :  'when' test
  ;

whennone_opt
  :  'when' 'none' blockstmt*
  ;

test
  :  identifier '=' atom
  ;

identifier
  :  'none'
  |  Identifier
  ;

blockstmt
  :  'print' atom
  ;

atom
  :  Boolean
  |  Number
  |  StringLiteral
  |  Identifier
  ;

Number
  :  '0'..'9'+
  ;

Boolean
  :  'true'
  |  'false'
  ;

Identifier
  :  ('a'..'z' | 'A'..'Z' | '_')+
  ;

StringLiteral
  :  '\'' ~'\''* '\''
  ;

Ignore
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  |  '//' ~('\r' | '\n')*       {skip();}
  |  '/*' .* '*/'               {skip();}
  ;

Создает следующие 3 дерева разбора из ваших примеров:


1

Источник:

foreach
    where x = 1 when some_variable = true
    where x = 2 when some_variable = false
    where y = 0
        print z              // Main block

    when none                // optional
        print 'not found'    // Exception block
endfor

Дерево разбора:

enter image description here

увеличить изображение


2

Источник:

foreach
    where x = 1
        // main block is blank, do nothing
    when none
        print 'none'
endfor

Дерево разбора:

enter image description here


3

Источник:

foreach
    where x = 1 when none = 2
        print 'none'
    // exceptional block is blank
endfor

Дерево разбора:

enter image description here


...