コンパイルのどの段階で、プログラミング言語のキーワードが認識されますか?
私はちょっと混乱しています
- 字句解析。
- プログラムの解析。
正規表現を使用して C で字句解析器を作成したことがありますが、main()
inint main(void)
もキーワードとして認識されました。
これらの行では、キーワードを認識するために解析ツリーを構築する必要があると思います。
コンパイルのどの段階で、プログラミング言語のキーワードが認識されますか?
私はちょっと混乱しています
正規表現を使用して C で字句解析器を作成したことがありますが、main()
inint main(void)
もキーワードとして認識されました。
これらの行では、キーワードを認識するために解析ツリーを構築する必要があると思います。
今年は、Java を使用したプロジェクトとして単純なコンパイラを構築する必要がありました。キーワードの認識は語彙分析で行われました。そのフェーズ中に、入力言語を読み取り、タイプ(キーワードのタイプは variable_declaration )とその値でトークンを作成します。また、識別子、定数、乗算操作、追加操作などのケースごとに異なるタイプもありました。次に、これらのトークンを渡しましたキューに移動し、次にパーサーに移動します。パーサーは文法をチェックし、出力言語の作成に使用されるバイナリ ツリーを作成します。
通常、コンパイルの語彙分析フェーズでは、入力テキストを一連の語彙素に分割します。各語彙素は、後の分析に役立つ特定のトークン タイプに属します。その結果、構文解析を容易にするために、キーワードは通常、字句解析中に最初に認識されます。パーサーは、語彙素ではなくトークンの文脈自由文法 (つまり、語彙素の内容ではなく語彙素のカテゴリー) を記述することによって実装される傾向があるため、字句解析中にキーワードがマークされている場合、パーサーを構築するのは非常に簡単です。 . たとえば、「if」をキーワードとして扱うパーサーが必要な場合、CFG で次のようなルールが必要になることがあります。
Statement ::= 'IF' Expr 'THEN' Expr
独自のトークン タイプに分類しないIF
と、パーサーは上記のようなステートメントを記述できません。THEN
伝統的に、キーワードはレクサーによって認識されます (これにより、固定された一連のキーワードで構成される言語が残ります)。もちろん、解析パス中に実行することもできます。多数のレクサーレス解析手法 ( PEGなど)の 1 つを使用して、レクサーを完全に取り除くこともできます。混乱を避けるのに役立つかもしれません。
それが字句解析になります。
一部の言語には、「特別な」識別子とキーワードがあります。これらは多くの場合、識別子テーブルに追加され、解析が開始される前に既知の定数 ID 値が割り当てられるため、簡単に見つけることができます。ただし、これらは通常、パーサーにとって特別な意味を持ちません。解析後に抽象構文ツリー (AST) で検出する必要があります。
たとえば、オベロン語のレポートを見てみましょう...
http://www-old.oberon.ethz.ch/oreport.html
言語の推奨事項ではありません - 簡単に利用できる単純な言語仕様 (非常に Wirths スタイル) です。
とにかく、「語彙と表現」セクションには、ほとんどの人がキーワードとして認識するものを含む「演算子と区切り文字」のリストが含まれています。これらは字句解析器によって認識されます。
「宣言とスコープ ルール」セクションには、「ABS」や「BOOLEAN」などの事前定義された識別子のリストがあります。私は確実に Oberon に精通しているわけではありませんが、コンパイラを作成する場合、通常の識別子テーブルを事前に初期化して、これらの事前定義された識別子を含める可能性が十分にあります。
C では、「メイン」はほとんどの点で単なる別の関数です。コンパイラは、それを特別なものとして扱う場合としない場合があります。それに関する唯一の「特別な」ことは、最終的な実行可能ファイルにリンクされるスタートアップ コードがその関数を呼び出すことである可能性があります。
それは定義の多くに依存します。特に、スキャナー、トークナイザー、レクサー、パーサーの間の線をどこに引くかによって異なります。これは宿題なので、教授が正しい場合にのみ正しいです。正しいと言っています: あなたの読み物で提供された定義を見てください。
main() について: main() は、他のすべての関数と同様にキーワードではなく、トークンであると断言できます。トークナイザーは部分文字列 "main" が 1 つのトークンであることを認識し、パーサーはそれを "(...)" および "{...}" 部分に関連付けて設定します。さらに、main() の場合、パーサーはプログラムのエントリポイントを自動的に生成します。