どのプロセスで構文エラーが発生しますか?(トークン化または解析)


23

私はコンパイルと解釈を理解しようと、段階的に全体像を把握しようとしています。だから、この記事を読んでいる間に質問に思いついた。http://www.cs.man.ac.uk/~pjj/farrell/comp3.htmlこの記事

それは言います:

コンパイラの次の段階は、パーサーと呼ばれます。コンパイラのこの部分は、言語の文法を理解しています。構文エラーを特定し、エラーのないプログラムを別の言語で解釈または書き出すことができる内部データ構造に変換する責任があります。

しかし、トークナイザーが構文エラーのある特定のストリームを適切にトークン化する方法を理解できませんでした。

そこにとどまるか、パーサーに間違った情報を提供する必要があります。トークン化は一種の翻訳者でもないのですか?

したがって、トークン化中にコードの字句破損行をどのように単に克服するか。

トークナイザーの見出しの上のリンク内にトークンの例があります。

私が理解しているように、トークンの形式は次のように思えます。コードに何か問題があると、トークンも破損します。

私の誤解を明確にしていただけますか?

回答:


32

トークナイザーは単なるパーサーの最適化です。トークナイザーなしでパーサーを実装することは完全に可能です。

トークナイザー(またはレクサー、スキャナー)は、入力をトークンのリストに分割します。通常、文字列の一部(コメント、空白)は無視されます。各トークンには、タイプ(言語でのこのストリングの意味)と値(トークンを構成するストリング)があります。たとえば、PHPソーススニペット

$a + $b

トークンで表すことができます

Variable('$a'),
Plus('+'),
Variable('$b')

トークナイザーは、このコンテキストでトークンが可能かどうかを考慮しません。たとえば、入力

$a $b + +

トークンストリームを喜んで生成します

Variable('$a'),
Variable('$b'),
Plus('+'),
Plus('+')

パーサーがこれらのトークンを消費すると、2つの変数が互いに追従できず、2つの中置演算子も追従できないことに気付くでしょう。(他の言語は、そのようなトークンストリームが合法である場合があるが、PHPでは異なる構文を持っていることに注意してください)。

パーサーはトークナイザーの段階で失敗する可能性があります。たとえば、不正な文字がある可能性があります。

$a × ½ — 3

PHPトークナイザーは、この入力をルールに一致させることができず、メインの解析が開始される前にエラーを生成します。

より正式には、各トークンを通常の言語として記述することができる場合、トークナイザーが使用されます。トークンは非常に効率的に照合でき、DFAとして実装される可能性があります。対照的に、メインの文法は通常コンテキストに依存せず、LALRなどのより複雑でパフォーマンスの低い解析アルゴリズムが必要です。


したがって、トークナイザーはパーサーの一部であり、構文エラーは、トークン化ステップまたは構文エラー形式に応じた解析ステップのいずれかで発生する可能性があります。説明をありがとう。
FZE

4
@FZE:そのように考えることはできますが、誤解を招く可能性があります。Lexingは「単なるパーサー最適化」ではありません。むしろ、字句解析は、物理表現(文字のシーケンス)を論理表現(それらの文字で表されるトークン)にマップします。これにより、行末がどのように表されるか、または論理的なand andまたは&&or何かを表すかどうかのように、パーサーが特徴点から分離されます。(ほとんど)構文解析とは異なります。最適化(存在する場合)は、ほぼ偶発的な副作用です。
ジェリーコフィン

@JerryCoffinは、より意味のある説明に感謝します。
FZE

2
@ JerryCoffin、amonは正しい、つまり違いは基本的ではない。「レクサー」と「パーサー」の両方の部分をカバーするまとまりのあるBNF文法を作成できます。通常、ルールは低レベル(たとえば、数値、加算演算子)と高レベル(合計)に分類されますが、文法自体はそのような区別を行いません。
ポールドレイパー

1
@PaulDraper最初の段階として通常の言語を分離することが正しい選択かどうかはわかりません。たとえば、一部の言語で文字列リテラルを記述するためには、一致するペア(非正規)が必要な場合がありますが、それでも最初のフェーズでそれらを処理することは意味があります。バックトラッキングの回避/最小化は、より良いガイドラインのようです。
CodesInChaos

16

あなたはと思い、通常はほとんどの構文エラーがパーサではなく、レクサーから来ることを期待しています。

入力にトークン化できない何かが存在する場合(およびほとんどの場合のみ)、レクサーはエラーを生成します。ただし、多くの言語では、ほとんどすべての文字のシーケンスを何らかのトークンに変換できるため、ここでのエラーは非常にまれです。

入力に有効なトークンが含まれている場合、パーサーはエラーを生成しますが、これらのトークンはターゲット言語で有効なステートメント/式を形成するように配置されていません。これは原則としてはるかに一般的です。


11

Tokenizerは、文字ストリームをトークンに分割するだけです。tokenizer POVから、これは完全に有効です:

1 * * 1

:とのようなものに変換["1", MULTIPLY, MULTIPLY, "1"] -それは乗算演算子が他の乗算演算子を追跡することはできません知っているだけパーサは、このような表現を拒否することができます。たとえば、JavaScriptでは次のようになります。

Uncaught SyntaxError: Unexpected token *(…)

トークナイザーによって検出される可能性のあるエラーがあります。たとえば、未完成の文字列リテラル:"abcまたは無効な数字:0x0abcdefg。それでも構文エラーとして報告される場合があります:

Uncaught SyntaxError: Unexpected token ILLEGAL

ただし、トークンは認識されず、として報告されることに注意してくださいILLEGAL

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.