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 ответа:
Размещение
output=AST;
в разделе options не приведет к фактическому AST, это только заставит ANTLR создавать токеныCommonTree
вместоCommonToken
s (или, в вашем случае, эквивалентные структуры 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, необходимо указать узлы, используя символ ^ в стратегических местах, используя правила перезаписи.
Вы можете прочитать больше здесь