ANTLR3 C Target-parser return 'пропускает' корневой элемент


Я пытаюсь использовать цель ANTLR3 C, чтобы понять АСТ, но сталкиваюсь с некоторыми трудностями.

У меня есть простой SQL-подобный грамматический файл:

grammar sql;
options 
{
    language = C;
    output=AST;
    ASTLabelType=pANTLR3_BASE_TREE; 
}
sql :   VERB fields;
fields  :   FIELD (',' FIELD)*;
VERB    :   'SELECT' | 'UPDATE' | 'INSERT';
FIELD   :   CHAR+;
fragment
CHAR    :   'a'..'z';

И это работает, как и ожидалось в ANTLRWorks.

В моем C-коде у меня есть:

const char pInput[] = "SELECT one,two,three";
pANTLR3_INPUT_STREAM pNewStrm = antlr3NewAsciiStringInPlaceStream((pANTLR3_UINT8) pInput,sizeof(pInput),NULL);
psqlLexer lex =  sqlLexerNew         (pNewStrm);
pANTLR3_COMMON_TOKEN_STREAM   tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT,
    TOKENSOURCE(lex));
psqlParser ps = sqlParserNew( tstream );
sqlParser_sql_return ret = ps->sql(ps);
pANTLR3_BASE_TREE pTree = ret.tree;
cout << "Tree: " << pTree->toStringTree(pTree)->chars << endl;
ParseSubTree(0,pTree);

Это выводит плоскую структуру дерева, когда вы используете ->getChildCount и ->children->get для рекурсии через дерево.

void ParseSubTree(int level,pANTLR3_BASE_TREE pTree)
{
    ANTLR3_UINT32 childcount =  pTree->getChildCount(pTree);

    for (int i=0;i<childcount;i++)
    {
        pANTLR3_BASE_TREE pChild = (pANTLR3_BASE_TREE) pTree->children->get(pTree->children,i);
        for (int j=0;j<level;j++)
        {
            std::cout << " - ";
        }
        std::cout << 
            pChild->getText(pChild)->chars <<       
            std::endl;
        int f=pChild->getChildCount(pChild);
        if (f>0)
        {
            ParseSubTree(level+1,pChild);
        }
    }
}

Вывод программы: Дерево: выберите один, два, три ВЫБИРАТЬ один , два , три

Теперь, если я изменю файл грамматики:

sql :   VERB ^fields;

.. вызов ParseSubTree отображает только дочерние узлы полей.

Вывод программы: Дерево: (выберите один, два, три) один , два , три

Мой вопрос: почему во втором случае Antlr просто дает дочерние узлы? (фактически отсутствует маркер SELECT) Я был бы очень благодарен, если бы кто-нибудь мог дать мне какие-либо указания для понимания дерева, возвращенного Antlr.

Полезно Информация: AntlrWorks 1.4.2, Antlr C Цель 3.3, MSVC 10

2 2

2 ответа:

Размещение output=AST; в разделе options не приведет к фактическому AST, это только заставит ANTLR создавать токены CommonTree вместо CommonTokens (или, в вашем случае, эквивалентные структуры C).

Если вы используете output=AST;, Следующий шаг-поместить операторы дерева или переписать правила внутри правил синтаксического анализатора, которые придают форму вашему AST.

Смотрите этотпредыдущий вопрос и ответ , чтобы узнать, как создать правильный AST.

Например, следующая грамматика (с перезаписью правила):

options {
  output=AST;
  // ...
}

sql                        // make VERB the root
  :  VERB fields        -> ^(VERB fields) 
  ;

fields                     // omit the comma's from the AST
  :  FIELD (',' FIELD)* -> FIELD+
  ;

VERB  : 'SELECT' | 'UPDATE' | 'INSERT';
FIELD : CHAR+;
SPACE : ' ' {$channel=HIDDEN;};
fragment CHAR : 'a'..'z';

Проанализирует следующие входные данные:

UPDATE         field,     foo  ,  bar

В следующий АСТ:

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

Я думаю, что важно, чтобы вы поняли, что дерево, которое вы видите в Antrlworks, является Не AST. Этот ".дерево " в вашем коде является AST, но может выглядеть иначе, чем вы ожидаете. Чтобы создать AST, необходимо указать узлы, используя символ ^ в стратегических местах, используя правила перезаписи.

Вы можете прочитать больше здесь