Si j'écris mon propre analyseur personnalisé, comment puis-je savoir si j'écris un analyseur d'ascension récursif? Je suis définitivement intéressé par la complexité O (n) de l'analyse LALR (plus j'ai déjà une grammaire LALR) et je ne veux pas savoir plus tard que j'ai écrit un analyseur LL à la place. Edit: Je n'ai vu que des parseurs automatiques pilotés par des tables et un couple a généré des exemples simples d'analyseurs récursifs, dont aucun ne ressemble à distance à ce que je construisais à la main. Il est donc assez difficile d'associer le code "évident" pour traiter une règle avec un algorithme réel.Descente récursive et analyse ascendante récursive
Si vous prenez le code pour une règle relativement simple, par exemple
name_or_qualified_name = identifier *('.' identifier);
que je l'ai traduit en
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;
}
Il n'y a rien de très gauche ou à droite à ce sujet. C'est évidemment une information utile et importante à connaître, et je ne la vois pas. Le seul fait évident ici est que c'est récursif.
Editer: Désolé, mauvais exemple. Que diriez-vous de quelque chose comme ceci:
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
}
Je ne suis pas sûr de comprendre la question. Vous écrivez un analyseur et vous ne savez pas s'il s'agit d'une descendance récursive ou non? Cela signifie que vous êtes en train d'écrire des phrases en transe ou quoi? – 6502
@ 6502: Les seuls exemples que j'ai jamais vus sont générés automatiquement. Ils ne correspondent pas exactement au code que j'écrirais moi-même. – Puppy
Il est difficile de dire en regardant un exemple où vous n'appelez pas d'autres fonctions d'analyse (vous appelez seulement le lexeur) ... mais je parierais que votre est un analyseur de descente récursif. De quel type de langue s'agit-il? Pas un langage de type C je suppose (ou sinon comment des choses comme 'a.b [4] .c(). D parsed? Point devrait être un opérateur ...). – 6502