Nome corretto per un parser di discesa ricorsivo che utilizza loop per gestire la ricorsione a sinistra?


8

Questa grammatica è ricorsiva:

Expression  ::= AdditionExpression

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

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

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

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

Quindi, in teoria, la discesa ricorsiva non funzionerà. Ma sfruttando le proprietà della grammatica secondo cui ciascuna regola ricorsiva a sinistra corrisponde a un livello di precedenza specifico e che lo sguardo di un singolo token è sufficiente per scegliere la produzione corretta, le regole ricorsive a sinistra possono essere analizzate individualmente con mentre loop.

Ad esempio, per analizzare il terminale non AdditionExpression, questo pseudocodice è sufficiente:

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 è il nome corretto per questo tipo di parser? Questo articolo informativo si riferisce solo ad esso come alla "soluzione classica": https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm

Ci deve essere un nome proprio per questo tipo di parser.


Per me non è una specie di parser, è solo l'applicazione della rimozione della ricorsione sinistra combinata con un parser di discesa ricorsivo. Vedi questa domanda per una tecnica per rimuovere la ricorsione sinistra.
AProgrammer

Penso che potresti avere ragione. Assomiglia a un equivalente di runtime dell'algoritmo di rimozione della ricorsione sinistra.
user71015

1
Non utilizzare la casella "rispondi" per pubblicare commenti o altre osservazioni. Se crei un account , manterrai l'accesso e sarai in grado di accettare la risposta che ti ha aiutato di più. Se hai inserito un'email e hai perso l'accesso, puoi recuperare l'accesso . Se non hai inserito un indirizzo email e non hai accesso al browser / ai cookie che hai usato per pubblicare la domanda, probabilmente sei sfortunato. Nessun altro può accettare la risposta per te, nemmeno i moderatori.
DW

Risposte:


11

È solo un parser LL (1) implementato con discesa ricorsiva.

Inizia con:

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

applica la rimozione della ricorsione a sinistra per ottenere una grammatica LL (1):

AdditionExpression  ::= 
    MultiplicationExpression AdditionExpressionTail

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

scrivere le funzioni corrispondenti:

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()
        }
    }
}

rimuovere la ricorsione della coda:

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
        }
    }
}

in linea:

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 devi solo aggiungere l'elaborazione semantica per ottenere la tua funzione.


6

Vuoi dare un'occhiata a LL (K) analisi . L'articolo di Wikipedia è per lo più inutile, ma è fondamentalmente una discesa ricorsivaK simboli lookahead.

C'è anche LL (*) che consente lookahead illimitato.

Vedi qui per una panoramica completa di quanto sia potente questa classe di parser.


1
Non vedo come questo sia correlato. Il codice non utilizza più di un simbolo di look-ahead.
AProgrammer

@AProgrammer Quindi è un parser LL (1) o strettamente correlato.
Raffaello

È un parser LL (1). Ho ampliato il mio commento in una risposta.
Programmatore

2
@AProgrammer Non vedo come fosse necessaria una seconda risposta. LL (1) è LL (k) per k = 1 (non è così ovvio?). Ma bene.
Raffaello
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.