ループを使用して左再帰を処理する再帰降下パーサーの正しい名前は?


8

この文法は再帰的に残されています:

Expression  ::= AdditionExpression

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

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

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

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

したがって、理論的には、再帰的降下は機能しません。ただし、各左再帰ルールが特定の優先レベルに対応し、単一のトークンの先読みで正しい生成を選択するのに十分であるという文法のプロパティを利用することで、左再帰ルールをwhileループで個別に解析できます。

たとえば、AdditionExpression非終端を解析するには、次の疑似コードで十分です。

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
}

このタイプのパーサーの正しい名前は何ですか?この有益な記事では、「クラシックソリューション」としてのみ言及していますhttps : //www.engr.mun.ca/~theo/Misc/exp_parsing.htm

このタイプのパーサーには適切な名前が必要です。


私にとってそれは一種のパーサーではありません、それは再帰的降下パーサーと組み合わされた左再帰除去の適用です。左再帰を削除する方法については、この質問を参照してください 。
AProgrammer 2017

あなたは正しいかもしれません。これは、左再帰の削除アルゴリズムに相当するランタイムに似ています。
user71015

1
「回答」ボックスを使用してコメントやその他のコメントを投稿しないでください。アカウント作成すると、アクセスを保持し、最も役に立った回答を受け入れることができます。メールアドレスを入力してアクセスできなくなった場合は、アクセスを回復できます。メールアドレスを入力せず、質問の投稿に使用したブラウザやCookieにアクセスできない場合は、おそらく運が悪いでしょう。他の誰もあなたのために答えを受け入れることができません-モデレーターすらです。
DW

回答:


11

これは、再帰的降下で実装されたLL(1)パーサーにすぎません。

で始まる:

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

左再帰の削除を適用してLL(1)文法を取得します。

AdditionExpression  ::= 
    MultiplicationExpression AdditionExpressionTail

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

対応する関数を記述します。

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

末尾再帰を削除します。

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

列をなして:

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

関数を取得するには、セマンティック処理を追加する必要があります。


6

kk

このクラスのパーサーがいかに強力であるかについての包括的な概要については、ここを参照してください。


1
これがどのように関係しているかはわかりません。このコードでは、複数の先読み記号を使用していません。
AProgrammer 2017

@AProgrammerつまり、LL(1)パーサーか、非常に密接に関連しています。
ラファエル

これはLL(1)パーサーです。コメントを回答に拡大しました。
AProgrammer 2017

2
@AProgrammer 2番目の回答がどのように必要だったかわかりません。LL(1)は、k = 1のLL(k)です(それは明白ではありませんか?)。しかしよく。
ラファエル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.