내 자신 만의 사용자 정의 파서를 작성하는 경우 재귀 적 상승 파서를 작성하고 있는지 어떻게 알 수 있습니까? 나는 확실히 LALR 구문 분석의 O (n) 복잡성에 관심이 있으며 (필자는 이미 LALR 문법을 가지고있다.) 나중에 LL 파서를 대신 작성했다는 것을 알기를 원하지 않는다.재귀 적 하강 대 재귀 적 상승 파싱
편집 : 필자는 자동 테이블 구동 파서 만 보았고 한 쌍의 간단한 예제 재귀 파서를 만들었습니다. 아무 것도 원격으로 손으로 구성 할 수있는 것처럼 보이지 않았습니다. 따라서 실제 알고리즘을 가진 규칙을 다루기 위해 "명백한"코드를 연관시키는 것은 다소 어렵습니다. 나는 매우 왼쪽 또는 그것에 대해 바로 거기에 아무것도
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;
}
로 번역 한 예를
name_or_qualified_name = identifier *('.' identifier);
에 대한
당신이 비교적 간단한 규칙의 코드를 가지고가는 경우. 그것은 분명히 유용하고 중요한 정보입니다. 나는 그것을보고 있지 않습니다. 여기에서 유일한 명백한 사실은 재귀 적이라는 것입니다.
편집 : 죄송합니다. 나쁜 예입니다. 어때 이런 식으로 :
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