正規表現が見つかるたびにコードを実行するためにLexと協力しましたが、Yaccはそれ以上のことを実行できますか?はいの場合、それでは何ですか?
はい、YACCはパーサーであり、Lexは字句解析プログラムです。これらは通常、一緒に使用されます。文字列入力をLexし、Lexによって提供されるトークン化された入力をYACCします。
現在、正規表現は正規言語のみを表すことができます。正規言語の制約の1つは、「記憶」の欠如です。以前に起こったことに基づいて、文字列のさらに下にある受け入れのルールを定義することはできません。
これは、括弧の場合にほとんどはっきりと見られます。正規言語では、ネストされた括弧を正しいレベルに一致させることはできません。または他のそのような構造。 (ほとんどの)コンピューター言語の文法は可能であり、実行できるため、レクサーや正規表現で解析することはできません。そこでYACCが登場します。
質問を逆にすることもできます。 YACCでさらに多くのことができるのであれば、字句解析に使用してみませんか?たまたま、正規表現の有効性を非常に効率的に検証できます。これは、一般的な文法の場合ではなく、同じレベルではありません。それでも、言語の字句規則が十分に単純であれば、YACCは基本的な字句解析を行うことができます。
Lexは 字句解析器 です。テキストをトークンに分割します。その能力は、正規表現マッチングとほぼ同等です。 yaccは パーサジェネレータ です。一連のトークン(たとえば、Lexから)を受け取り、それらを一連のステートメントとして解釈します。その能力は、文脈自由文法とほぼ同等です。
Lexとyaccの典型的なアプリケーションは、プログラミング言語の実装です。 Lexは入力をトークン化し、キーワード、定数、句読点などに分割します。次に、yaccは実際のコンピューター言語を実装します。たとえば、forステートメントまたは関数定義を認識します。
実用的な意味では、Lexを使用して入力テキストをチャンクに処理することがよくあります。次に、yaccを使用してこれらのチャンクをつなぎ合わせ、より大きな意味に処理します。
Lexは入力をトークン化するためのものです。つまり、入力を、文法で定義されている最下位レベルのオブジェクトに分離します。たとえば、Lexを使用して、キーワード、識別子、文字列、コメント、空白などを識別します。
yaccはあなたの文法を解析するためのものです。文法は言語の説明であり、通常はEBNFまたはその他の文脈自由文法で定義されます。文法をyaccに記述したら、それを使用して、言語の要素が認識されたときにツールのアクションを実行できます。これは、たとえば、式を解くための構文ツリーの構築、スコープオブジェクトの定義、変数定義の記録などです。
これらは無料の製品です。
Lexとyaccは通常一緒に使用されます。これは通常、両方を使用してアプリケーションを構築する方法です。
入力ストリーム(文字)-> Lex(トークン)-> Yacc(抽象構文木)->アプリケーション
より一般的には、Lexは最初からソースファイルを読み取り、いくつかの正規表現を照合しようとします(Lexには独自の特別な構文があり、Perlやsedの正規表現とは少し異なります)。次に、認識したトークンごとに別のプログラムを呼び出します。トークンは、キーワードや演算子のように単純な列挙値である場合もあれば、リテラル値のようにメタデータが添付されている場合もあります。
Lexは通常(必ずしも必要ではありませんが)Yaccを呼び出すために使用されます。 YaccはLALRパーサーアルゴリズムを使用します。これは大まかに言えば、各トークンをスタックにプッシュすることで機能します。スタックに認識可能なトークンのシーケンスがある場合、スタックはすべてのトークンをポップし、アクションを実行して、別のトークンをスタックにプッシュバックします。
Yaccが機能する適切な語彙は、実際には終端記号と非終端記号です。終端記号は、呼び出しプログラム(通常はLex)から取得したトークンであり、非終端記号は、スタック上のシーケンスを照合した結果です。
通常、各Yaccルールによって実行されるアクションは、ルールが対応する計算の結果を評価するか、別のアプリケーション層が処理するための構文ツリーなどの中間表現を生成することです。
Yaccは、Lexと同様に、他とは別に使用できます。たとえば、ソーステキストから個々の文字を渡すことでYaccを使用し、Yaccルールを使用して各種類のトークンを認識することができます。ただし、Yaccはそのように非常に使いやすいように設計されていないため、結果のレクサーはLexの同等のレクサーよりもはるかに複雑になります。より一般的な使用法は、パフォーマンス上の理由から、またはよりスマートなレクサーが必要なために、手動でコーディングされたレクサーを作成することです。 2番目のケースの一般的な例は、タイプまたは変数を記述するために使用されているかどうかを知るために、識別子の以前の使用について知る必要があるCのような言語で使用されるものです。
Lexは、字句アナライザーを構築するためのツールであり、かなり愚かな字句処理(キーワードの検索など)を実行できます。 Yaccは、実際のコンピューター言語用のパーサーを作成できるパーサージェネレーターです。その分析は通常、Lex(トークンのストリーム)の出力に基づいており、これからプログラミング言語の解析ツリーを作成できます。これは、Lexよりも優れたものです。
従来、コンパイラビルダーは、字句分析と構文分析を区別します。これらは、コンパイラーの2つの重要なステップです(コードの作成、最適化など、さらに従うべきステップです)。