Если я пишу свой собственный парсер, как я могу узнать, пишу ли я рекурсивный синтаксический анализатор восхождения?Я определенно заинтересован в сложности O (n) синтаксического анализа LALR (плюс у меня уже есть грамматика LALR) и не хочу позже узнать, что я написал вместо этого анализатор LL.
ПравитьЯ когда-либо видел только автоматические парсеры, управляемые таблицами, и несколько сгенерированных простых рекурсивных парсеров, ни один из которых не похож на то, что я бы создал вручную.Поэтому трудно связать «очевидный» код для работы с правилом с реальным алгоритмом.
Если вы берете код для относительно простого правила, например
name_or_qualified_name = identifier *('.' identifier);
который я перевел на
std::vector<std::wstring> RecursiveParseNameOrQualifiedName(Iterator& begin, Iterator end) {
std::vector<std::wstring> retval;
retval.push_back(begin->Codepoints);
CheckedIncrement(begin, end); // The only place that can legitimately expect end of input is namespace contents.
while(begin->type == Wide::Lexer::TokenType::Dot) {
CheckedIncrement(begin, end);
if (begin->type != Wide::Lexer::TokenType::Identifier)
Wide::ParserExceptionBuilder(*begin) << L"Expected 'identifier' after '.'";
retval.push_back(begin->Codepoints);
}
return retval;
}
В этом нет ничего особо левого или правого.Это, безусловно, полезная и важная информация, которую я должен знать, и я ее не вижу.Единственный очевидный факт - рекурсивность.
Редактировать: Извините, плохой пример.Как насчет такого:
void RecursiveParseUsing(Iterator& begin, Iterator end, Wide::Parser::NamespaceAST* current_namespace) {
auto new_using = std::unique_ptr<Wide::Parser::UsingAST>( new Wide::Parser::UsingAST() );
// expect "begin" to point to a using
CheckedIncrement(begin, end);
// Must be an identifier, at least
if (begin->type != Wide::Lexer::TokenType::Identifier)
Wide::ParserExceptionBuilder(*begin) << L"Expected 'identifier' after 'using'";
CheckedIncrement(begin, end);
switch(begin->type) {
case Wide::Lexer::TokenType::Dot: {
begin--; // back to identifier
new_using->original_name = RecursiveParseNameOrQualifiedName(begin, end);
current_namespace->unnamed_contents.push_back(std::move(new_using));
break; }
case Wide::Lexer::TokenType::Equals: {
begin--; // back to Identifier
new_using->new_name = begin->Codepoints;
begin++; // Back to equals
begin++; // The token ahead of equals- should be "identifier"
new_using->original_name = RecursiveParseNameOrQualifiedName(begin, end); // The only valid next production
// this should be left at the one past the name
current_namespace->contents[new_using->new_name] = std::move(new_using);
break; }
case Wide::Lexer::TokenType::Semicolon: {
begin--; // Identifier
new_using->original_name.push_back(begin->Codepoints);
begin++; // Semicolon
current_namespace->unnamed_contents.push_back(std::move(new_using));
break; }
default:
Wide::ParserExceptionBuilder(*begin) << L"Expected '.', '=' or ';' after 'identifier' when parsing 'using'.";
}
if (begin->type != Wide::Lexer::TokenType::Semicolon)
Wide::ParserExceptionBuilder(*begin) << L"Expected ';' after 'identifier'";
CheckedIncrement(begin, end); // One-past-the-end
}