プログラムをある言語から別の言語に翻訳するために、コンパイラはまずプログラムのさまざまな要素を分解し、その構造と意味を理解し、次に別の方法でこれらの要素を組み合わせる必要があります。コンパイラのフロントエンドは分析を実行し、バックエンドは合成を行います。
分析は一般的に 3 つに分けられます:字句解析、構文解析、意味解析
この段階では字句解析を行い、入力ファイルを独立した字句記号、つまり単語に分解することを目的としています。
虎書の指示に従い、この段階は 3 つのモジュールに分かれています:
- エラーハンドリングモジュール(errormsg.c errormsg.h):ファイル名と行番号を含むエラーメッセージを生成するためのもの
- 字句解析モジュール(lexical.lex token.h):Lex を使用して字句解析を行う
- 一般的なツールモジュール(util.c util.h):いくつかの一般的な関数を定義する
字句解析モジュールとエラーハンドリングモジュール:両者は errormsg.h で宣言された変数と関数を介して通信します:EM_tokPos 変数は各単語の文字単位の位置を伝達します;EM_newline () 関数は行番号を記録します;EM_error () はエラーメッセージを出力します。
エラーハンドリングモジュールと一般的なツールモジュール:エラーハンドリングモジュールは util.h で宣言された checked_malloc () メモリ割り当て関数を使用します。
さらに、ドライバプログラム(driver.c)、テストファイル(test.c)、makefile も含まれています
以下では、この段階で最も重要な字句解析モジュールについて主に紹介します。
tokens.h:字句単語定数および yylval を定義します
上記のコードは yylval を定義しており、yylval は異なる意味値を表す集合であり、その中の ival、cval、dval、sval はそれぞれ整数、文字、浮動小数点数、文字列、単語の意味値を保存するために使用されます。
この部分ではいくつかの定数が定義されており、これらの定数は lexical.lex で使用され、マッチする単語の種類を示します。
lexical.lex:Lex のソースファイルで、Lex を使用して字句解析器を生成できます。
Lex は正規表現を字句解析器に変換するためのジェネレーターであり、字句規則から C プログラム(lex.yy.c)を生成します。この規則には正規表現とアクションが含まれています。このアクションは単語の種類(他の情報と共に)をコンパイラの次の処理段階に渡します。
最初の部分、つまり %{...%} の間にある部分には、このファイルの残りの部分で使用されるいくつかの include と宣言が含まれています。
2 番目の部分、つまり %}...%% の間にある部分には、正規表現の省略形と状態説明が含まれています。たとえば、次のように書くことができます。
これにより、3 番目の部分では {digits} を [0-9]+ の代わりに使用できます。
3 番目の部分、つまり %% の後にある部分には、正規表現とアクションが含まれています。各アクションは int 型の値(token.h で定義された定数)を返し、マッチする単語の種類を示します。
ここには二重性を排除するための 2 つのマッチング原則があります:
ルール優先:特定の最長初期部分文字列に対して、最初にマッチした正規表現がその部分文字列の単語の種類を決定します;
最長マッチ:ルール優先で正規表現が決定された後、部分文字列は正規表現にマッチする最長の文字列を取ります。
いくつかの変数:yytext は正規表現にマッチした文字列;yyleng はマッチした文字列の長さ;charPos は各単語の位置を追跡し、EM_tokPos に通知します。
字句解析完了。