Richtiger Name für einen rekursiven Abstiegsparser, der Schleifen verwendet, um die linke Rekursion zu behandeln?

8

Diese Grammatik bleibt rekursiv:

Expression  ::= AdditionExpression

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

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

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

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

Theoretisch funktioniert ein rekursiver Abstieg also nicht. Durch Ausnutzen der Eigenschaften der Grammatik, dass jede linksrekursive Regel einer bestimmten Prioritätsebene entspricht und der Lookahead eines einzelnen Tokens ausreicht, um die richtige Produktion auszuwählen, können die linksrekursiven Regeln einzeln mit while-Schleifen analysiert werden.

Um beispielsweise das nicht-terminale AdditionExpression zu analysieren, reicht dieser Pseudocode aus:

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
}

Wie lautet der richtige Name für diesen Parsertyp? In diesem informativen Artikel wird es nur als "klassische Lösung" bezeichnet: https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm

Für diesen Parsertyp muss ein Eigenname vorhanden sein.

user71015
quelle
Für mich ist es keine Art Parser, sondern nur die Anwendung der Entfernung linker Rekursionen in Kombination mit einem Parser rekursiver Abstammung. In dieser Frage finden Sie eine Technik zum Entfernen der linken Rekursion.
AProgrammer
Ich denke, Sie könnten richtig sein. Es ähnelt einem Laufzeitäquivalent des Algorithmus zum Entfernen der linken Rekursion.
user71015
1
Bitte benutzen Sie nicht das Antwortfeld, um Kommentare oder andere Bemerkungen zu posten. Wenn Sie ein Konto erstellen , behalten Sie den Zugriff und können die Antwort akzeptieren, die Ihnen am meisten geholfen hat. Wenn Sie eine E-Mail eingegeben und den Zugriff verloren haben, können Sie den Zugriff wiederherstellen . Wenn Sie keine E-Mail-Adresse eingegeben haben und keinen Zugriff auf den Browser / die Cookies haben, mit denen Sie die Frage gestellt haben, haben Sie wahrscheinlich kein Glück. Niemand sonst kann die Antwort für Sie akzeptieren - nicht einmal Moderatoren.
DW

Antworten:

11

Es ist nur ein LL (1) -Parser, der mit rekursivem Abstieg implementiert ist.

Beginnt mit:

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

gelten links Beseitigung der Rekursion eine LL (1) Grammatik zu erhalten:

AdditionExpression  ::= 
    MultiplicationExpression AdditionExpressionTail

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

Schreiben Sie die entsprechenden Funktionen:

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

Schwanzrekursion entfernen:

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 der Reihe:

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

und Sie müssen nur die semantische Verarbeitung hinzufügen, um Ihre Funktion zu erhalten.

Ein Programmierer
quelle
6

kk

Sehen Sie hier für einen umfassenden Überblick darüber , wie mächtig diese Klasse von Parsern ist.

Raphael
quelle
1
Ich sehe nicht, wie das zusammenhängt. Der Code verwendet nicht mehr als ein Vorausschau-Symbol.
AProgrammer
@AProgrammer Es ist also ein LL (1) -Parser oder sehr eng verwandt.
Raphael
Es ist ein LL (1) -Parser. Ich habe meinen Kommentar zu einer Antwort erweitert.
AProgrammer
2
@ AProgrammer Ich sehe nicht, wie eine zweite Antwort benötigt wurde. LL (1) ist LL (k) für k = 1 (ist das nicht offensichtlich?). Aber gut.
Raphael