如果我正在編寫自己的自定義解析器,如何知道是否正在編寫遞歸上升解析器?我對LALR解析的O(n)複雜性(加上我已經有一個LALR語法)一定感興趣,並且不想在以後發現我寫了一個LL解析器。遞歸下降vs遞歸上升解析
編輯:我只見過自動的表驅動解析器和一對夫婦生成簡單的示例遞歸解析器 - 其中沒有一個看起來像我手動構建的任何東西。因此,將「明顯的」代碼與實際算法相關聯的規則進行關聯很難。
如果採取相對簡單的規則的代碼,例如
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
}
我不確定我是否理解這個問題。你正在編寫一個解析器,你不知道它是否是一個遞歸下降?這意味着你只是在恍惚中寫什麼語句? – 6502
@ 6502:我見過的唯一例子是自動生成的。它們並不完全對應我自己寫的代碼。 – Puppy
通過查看一個沒有調用其他解析函數的例子(你只是調用詞法分析器)很難說清楚......但我敢打賭你是一個遞歸下降解析器。它是什麼類型的語言?不是我想象的類C語言(或者其他類似'a.b [4] .c().d'解析的東西?點應該是操作符...)。 – 6502