0

私は、任意のプログラミング言語を使用して構文アナライザーを作成するプロジェクトを提供しました。C#でやっています。簡単な文脈自由文法が作成されました。しかし、今はシンタックスアナライザーのアルゴリズムを作るのにとても混乱しています。

文法は次のようになります。

    Namespace       var . { class }
    Class           var . { method  } . class | null
    Method          function | null
    Function        return_type.var.(function_arguements).{.stmt_list.} . Method
                    .......... and so on

エラーとエラーの行番号も表示する必要があります。コーディングを開始するには、いくつかのガイダンスが必要です。2D 配列、連結リスト、列挙、構造を試しました。しかし、これに適したアルゴリズムを作成できませんでした。

4

1 に答える 1

2

私がコンパイラーを取ったとき、単純な言語用のコンパイラーを書かなければなりませんでした。質問の言語定義に正確に従っているかどうか、またはどこまで到達したかはわかりませんが、これは言語を解析するときに使用したアプローチです。

まず、入力で次のトークンを取得することのみを担当する字句解析クラスが必要です。これは本質的にコードを進め、各呼び出しでGetNextToken()コード内の次の文字列を返します。次のコード行があるとします。

PROCEDURE sum() RETURN INTEGER;

への最初の呼び出しはGetNextToken()を返しPROCEDUREます。2 番目の呼び出しは を返しsum、3 番目は を返し(、次に)RETURNINTEGERそして最後に;

次に、構文パーサーが必要です。アイデアは、言語定義が最終的に終了トークンにヒットする必要があるということです。これは私のコンパイラ言語定義の小さな断片です:

<program> -> $UNIT <prog-identifier> $SEMICOLON
                   <block> $PERIOD
<block> -> [<label-declaration>]
                   {<variable-dec-sec>}*
                   {<procedure-declaration>}*
                   $LEFTBRACE <statement> {$SEMICOLON <statement>}*
                   $RIGHTBRACE

したがって、アナライザーでは関数を呼び出しますProgram()Program()次のトークンを取得します。そのトークンがUNIT別の関数を呼び出すことになり、ProgIdentifier()それが再び を呼び出しますGetNextToken()ProgramIdentifier()識別子タイプを探します。に進みProgram()、次のトークンが であるかどうかを確認します;Block()次に、と同じように機能する which を呼び出しProgram()て、アフターがあるかどうかを確認します.

重要なのは、各終了トークン ( など) にステートメント;があることです。ifしたがって、 の簡単なコードは次のProgram()ようになります。

public int Program()
{
    lex.GetNextToken();
        if (lex.InternalCode == TokenTable.UNIT)
        {
            lex.GetNextToken();
            ProgIdentifier();
            if (lex.InternalCode == TokenTable.SEMICOLON)
            {
                lex.GetNextToken();
                Block();
                if (parseErrors)
                {
                    //Drop out into Statement Level Parsing
                    //Statement Level Parsing just calls Statement() for <statement>
                    //until you have gone through the entire input.
                    //The point is to avoid getting many errors if you are missing a
                    //single token.
                    StatementLevelParse();
                }
                if (lex.InternalCode == TokenTable.PERIOD)
                {
                    lex.GetNextToken();
                    if (lex.EndOfFile)
                    {
                        if (!parseFailed)
                        {
                            //Success
                            echo("Success");
                        }
                        else
                        {
                            echo("Parse Failed");
                        }
                    }
                    else
                    {
                        Error(lex.CurrentLine, 200, false, "Expected End Of File: Found " + lex.NextSymbol);
                    }
                }
                else
                {
                    //Fail. Expected $PERIOD
                    Error(lex.CurrentLine, 200, false, "Expected \".\": Found " + lex.NextSymbol);
                }
            }
            else
            {
                //Fail. Expected $SEMICOLON
                Error(lex.CurrentLine, 200, false, "Expected \";\": Found " + lex.NextSymbol);
            }
        }
        else
        {
            //Fail. Expected $UNIT
            Error(lex.CurrentLine, 200, false, "Expected \"UNIT\": Found " + lex.NextSymbol);
        }
        EchoOutput("LEAVING PROGRAM");
        return 0;
}

読む量が多いことがわかりました。これがインストラクターが望んでいるアプローチであるかどうかはわかりませんが、言語を理解していれば、非常にシンプルで簡単に実装できることがわかりました. これがこれを行うための最も効果的または効率的な方法であるという保証はありません。使用する必要があった方法にすぎません。

あなたの質問を正しく理解できたことを本当に願っています...

于 2013-03-24T14:33:49.167 に答える