Nome correto para um analisador de descida recursiva que usa loops para manipular a recursão esquerda?

8

Essa gramática é deixada recursiva:

Expression  ::= AdditionExpression

AdditionExpression  ::=
    MultiplicationExpression
        | AdditionExpression '+' MultiplicationExpression
        | AdditionExpression '-' MultiplicationExpression

MultiplicationExpression    ::=
    Term
        | MultiplicationExpression '*' Term
        | MultiplicationExpression '/' Term

Term    ::=
    Number
        | '(' AdditionExpression ')'

Number  ::=
    [+-]?[0-9]+(\.[0-9]+)?

Portanto, em teoria, a descida recursiva não funcionará. Mas, explorando as propriedades da gramática em que cada regra recursiva à esquerda corresponde a um nível de precedência específico, e que a aparência de um único token é suficiente para escolher a produção correta, as regras recursivas à esquerda podem ser analisadas individualmente com loops while.

Por exemplo, para analisar o AdditionExpression não terminal, esse pseudocódigo é suficiente:

function parse_addition_expression() {
    num = parse_multiplication_expression()
    while (has_token()) {
        get_token()
        if (current_token == PLUS)
            num += parse_multiplication_expression()
        else if (current_token == MINUS)
            num -= parse_multiplication_expression()
        else {
            unget_token()
            return num
        }
    }
    return num
}

Qual é o nome correto para esse tipo de analisador? Este artigo informativo refere-se apenas a ele como "Solução clássica": https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm

Deve haver um nome adequado para esse tipo de analisador.

user71015
fonte
Para mim, não é um tipo de analisador, é apenas a aplicação da remoção da recursão esquerda combinada com um analisador de descida recursivo. Veja esta pergunta para uma técnica para remover a recursão esquerda.
AProgramador
Eu acho que você pode estar correto. Ele se parece com um equivalente em tempo de execução do algoritmo de remoção de recursão à esquerda.
user71015
1
Por favor, não use a caixa 'resposta' para postar comentários ou outras observações. Se você criar uma conta , manterá o acesso e poderá aceitar a resposta que mais o ajudou. Se você digitou um email e perdeu o acesso, poderá recuperar o acesso . Se você não inseriu um endereço de e-mail e não tem acesso ao navegador / cookies que usou para postar a pergunta, provavelmente está sem sorte. Ninguém mais pode aceitar a resposta para você - nem mesmo moderadores.
DW

Respostas:

11

É apenas um analisador LL (1) implementado com descida recursiva.

Começa com:

AdditionExpression  ::=
    MultiplicationExpression
        | AdditionExpression '+' MultiplicationExpression
        | AdditionExpression '-' MultiplicationExpression

aplique a remoção de recursão esquerda para obter uma gramática LL (1):

AdditionExpression  ::= 
    MultiplicationExpression AdditionExpressionTail

AdditionExpressionTail ::=
        | '+' MultiplicationExpression AdditionExpressionTail
        | '-' MultiplicationExpression AdditionExpressionTail

escreva as funções correspondentes:

function parse_AdditionExpression() {
    parse_MultiplicationExpression()
    parse_AdditionExpressionTail()
}

function parse_AdditionExpressionTail() {
    if (has_token()) {
        get_token()
        if (current_token == PLUS) {
            parse_MultiplicationExpression()
            parse_AdditionExpressionTail()
        } else if (current_token == MINUS) {
            parse_MultiplicationExpression()
            parse_AdditionExpressionTail()
        } else {
            unget_token()
        }
    }
}

remova a recursão da cauda:

function parse_AdditionExpressionTail() {
    while (has_token()) {
        get_token()
        if (current_token == PLUS)
            parse_MultiplicationExpression()
        else if (current_token == MINUS)
            parse_MultiplicationExpression()
        else {
            unget_token()
            return
        }
    }
}

na linha:

function parse_AdditionExpression() {
    parse_MultiplicationExpression()
    while (has_token()) {
        get_token()
        if (current_token == PLUS)
            parse_MultiplicationExpression()
        else if (current_token == MINUS)
            parse_MultiplicationExpression()
        else {
            unget_token()
            return
        }
    }
}

e você só precisa adicionar o processamento semântico para obter sua função.

AProgrammer
fonte
6

Você deseja analisar o LL (k) análise . O artigo da Wikipedia é praticamente inútil, mas é basicamente descendente recursivo comk lookahead de símbolos.

Há também LL (), que permite olhar atento sem limites.

Veja aqui uma visão abrangente de quão poderosa é essa classe de analisadores.

Rafael
fonte
1
Não vejo como isso está relacionado. O código não usa mais de um símbolo de previsão.
AProgrammer
@ AProgrammer Portanto, é um analisador LL (1) ou muito relacionado.
Raphael
É um analisador LL (1). Eu expandi meu comentário em uma resposta.
AProgramador
2
@ AProgrammer Não vejo como uma segunda resposta era necessária. LL (1) é LL (k) para k = 1 (isso não é óbvio?). Mas, bem.
Raphael