私がコンパイラーを取ったとき、単純な言語用のコンパイラーを書かなければなりませんでした。質問の言語定義に正確に従っているかどうか、またはどこまで到達したかはわかりませんが、これは言語を解析するときに使用したアプローチです。
まず、入力で次のトークンを取得することのみを担当する字句解析クラスが必要です。これは本質的にコードを進め、各呼び出しでGetNextToken()
コード内の次の文字列を返します。次のコード行があるとします。
PROCEDURE sum() RETURN INTEGER;
への最初の呼び出しはGetNextToken()
を返しPROCEDURE
ます。2 番目の呼び出しは を返しsum
、3 番目は を返し(
、次に)
、RETURN
、INTEGER
そして最後に;
次に、構文パーサーが必要です。アイデアは、言語定義が最終的に終了トークンにヒットする必要があるということです。これは私のコンパイラ言語定義の小さな断片です:
<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;
}
読む量が多いことがわかりました。これがインストラクターが望んでいるアプローチであるかどうかはわかりませんが、言語を理解していれば、非常にシンプルで簡単に実装できることがわかりました. これがこれを行うための最も効果的または効率的な方法であるという保証はありません。使用する必要があった方法にすぎません。
あなたの質問を正しく理解できたことを本当に願っています...