私は、全体像を理解するために、段階的に編集と解釈を理解しようとしています。だから私は http://www.cs.man.ac.uk/~pjj/farrell/comp3.html この記事を読んでいるときに質問に思いつきました
それは言う:
コンパイラの次の段階はパーサーと呼ばれます。コンパイラのこの部分は、言語の文法を理解しています。構文エラーを識別し、エラーのないプログラムを別の言語で解釈または書き出すことができる内部データ構造に変換します。
しかし、私はトークナイザーが構文エラーのある特定のストリームを適切にトークン化できる方法を理解できませんでした。
それはそこで止まっているか、パーサーに誤った情報を提供しているはずです。トークン化は一種の翻訳者でもないのですか?
それで、トークン化中に字句の破損したコード行をどのように克服するか。
The Tokenizer見出しの上のリンク内のトークンの例があります。
トークンの形式は次のように見えるので、コードに問題があるとトークンも破損します。
私の誤解を明確にしていただけませんか?
トークナイザーは単なるパーサー最適化です。トークナイザーなしでパーサーを実装することは完全に可能です。
トークナイザー(またはレクサー、スキャナー)は、トークンのリストに入力を切り分けます。文字列の一部(コメント、空白)は通常無視されます。各トークンには、タイプ(言語におけるこの文字列の意味)と値(トークンを構成する文字列)があります。たとえば、PHPソーススニペット
$a + $b
トークンで表すことができます
Variable('$a'),
Plus('+'),
Variable('$b')
トークナイザーは、このコンテキストでトークンが可能かどうかを考慮しません。たとえば、入力
$a $b + +
喜んでトークンストリームを生成します
Variable('$a'),
Variable('$b'),
Plus('+'),
Plus('+')
次に、パーサーがこれらのトークンを使用すると、2つの変数が互いに続くことができず、2つの中置演算子もできないことがわかります。 (他の言語では、そのようなトークンストリームは合法であるがPHPではそうではない場合、構文が異なることに注意してください).
パーサはトークナイザー段階でまだ失敗するかもしれません。たとえば、不正な文字がある可能性があります。
$a × ½ — 3
PHPトークナイザーはこの入力をそのルールに一致させることができず、メインの解析が始まる前にエラーを生成します。
より正式には、各トークンが通常の言語として記述できる場合、トークナイザーが使用されます。トークンは非常に効率的に照合され、DFAとして実装される可能性があります。対照的に、メインの文法は通常、文脈に依存せず、LALRなどのより複雑でパフォーマンスの低い解析アルゴリズムを必要とします。
通常ほとんどの構文エラーは、レクサーではなく、パーサーから発生すると予想されます。
入力にトークン化できない何かがある場合(およびほとんどの場合のみ)、レクサーはエラーを生成します。ただし、多くの言語では、ほとんどすべての文字シーケンスを何らかのトークンに変換できるため、ここでのエラーはかなり珍しいものです。
入力に有効なトークンが含まれている場合、パーサーはエラーを生成しますが、それらのトークンは配置されていないため、ターゲット言語で有効なステートメント/式を形成します。これは一般的にはるかに一般的です。
Tokenizerは、文字ストリームをトークンに分割するだけです。トークナイザーPOVから、これは完全に有効です。
1 * * 1
["1", MULTIPLY, MULTIPLY, "1"]
パーサーのみがそのような式を拒否できます-乗算演算子が別の乗算演算子の後に続くことができないことがわかっています。たとえば、JavaScriptでは次のようになります。
Uncaught SyntaxError: Unexpected token *(…)
トークナイザーによって検出される可能性のあるエラーがあります。たとえば、未完成の文字列リテラル:"abc
または無効な数値:0x0abcdefg
。ただし、構文エラーとして報告される場合があります。
Uncaught SyntaxError: Unexpected token ILLEGAL
ただし、トークンは認識されず、ILLEGAL
として報告されることに注意してください。