ANTLR3 C Target - парсер возвращает "пропущенный" корневой элемент - PullRequest
2 голосов
/ 26 марта 2011

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

У меня есть простой 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 Target 3.3, MSVC 10

Ответы [ 2 ]

2 голосов
/ 26 марта 2011

Размещение output=AST; в разделе опций не даст фактического AST, оно только заставляет ANTLR создавать CommonTree токенов вместо CommonToken с (или, в вашем случае, эквивалентных структур Си).

Если вы используете 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

в следующие AST:

enter image description here

2 голосов
/ 26 марта 2011

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

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

...