web-dev-qa-db-ja.com

範囲外のリテラルは構文エラーまたは意味エラーですか?

構文とセマンティクスの違いについて詳しく読んでいますが、これについてはまだ疑問に思っています。

整数のみを0〜255の範囲にできるようにする言語があるため、8ビットであり、パーサーが256または257を受信するとします。

それは構文またはセマンティクスのエラーでしょうか?


私がチェックしたリソース:

2
Joan Vene

言語の文法に依存します。

文法が256または257の認識を妨げている場合、それらの文字シーケンスは構文エラーです。その文字シーケンスは認識できる範囲外です。たとえば、文法で1桁または2桁と1 [0-9] [0-9]、および2 [0-4] [0-9]、および25 [0-5]が認められ、それ以外は何も認められない場合。

構文エラーが発生した場合、パーサーはこの入力の正当な解析を見つけることができません。エラーである必要があります。優れた言語実装は、解析出力を構築するために最善を尽くすかもしれませんが、不正なプログラムを受け入れていることを知っています(たとえば、単に1つで停止するのではなく、さらに他の構文エラーを報告しようとするためにこれを行う可能性があります)。

ただし、文法で任意の数字列が許可されていて、言語が255を超える値を除外している場合、これらは意味論的エラーまたは実行時エラー(例:128 + 128は意味論的エラーまたは実行時エラーのいずれかである可能性があります)として検出する必要があります。

したがって、これらの処理方法にはある程度の自由度があり、解析を続行できるかどうかに依存します。より一般的な文法では、256を使用してプログラムを解析し、過去の解析を続行して他のエラーを報告することができますプログラムも同様です。

一部の言語は公式文法を公開しています。他の人は非公式の文法を持っています。

8
Erik Eidt

文法を任意に複雑にすることで、静的エラーを構文エラーに変えることができると確信しています(ただし、これを証明するものはありません)。

歴史的に、パフォーマンス上の理由から、字句解析(字句解析/スキャン)、構文解析(構文解析)、および意味論的解析(型チェック、型推論、名前解決など)を区別してきました。コンパイラ全体を適合させることは不可能でした。コンピュータのメモリなので、いくつかのコンポーネントに分けました。

  1. readerは、ビットのストリームを文字のストリームに変換します(これは通常、単純なマッピングテーブルですが、UTF-8などの可変長エンコーディングの場合はより複雑になる可能性があります)
  2. lexerは、文字のストリームをトークンのストリームに変換します(通常、レクサーは通常の言語を認識します。つまり、レクサーは有限オートマトンです)
  3. parserは、トークンのストリームを解析ツリー(具体的な構文ツリー)に変換します(通常、パーサーは文脈自由言語を認識します)
  4. セマンティックアナライザーは、最初に解析ツリーを抽象構文ツリーに変換します(任意のチューリング対応計算を使用)。
  5. コンパイラーのさまざまな追加コンポーネントは、ASTに追加情報で注釈を付けたり、別の表現に変換したりします。

今日では、これはもはや厳密に必要ではありません。 readerは通常、オペレーティングシステムまたは言語の標準ライブラリによって提供されます。スキャナーレスパーサーは、スキャンを解析プロセスに統合するパーサーです。

また、必要に応じて、文脈自由言語だけでなく、それ以上のものを認識する複雑なパーサーを任意に構築できます。最新のレクサーフレームワークとパーサーフレームワークの両方で、従来の通常のコンテキストフリーレクサーとパーサーよりも強力なレクサーとパーサーを構築できます。さらに、チューリング完全言語で任意のコードを添付できます。例えば。 GNU BisonからCコードを生成する場合、生成されたパーサーに独自の任意のCコードを埋め込むことができます。パーサーは、コードと相互運用して、コードの生成部分に影響を与えることができます。

あなたの例では、0〜255の整数のみを許可するように文法を変更するのは簡単です。 Javaのような言語では、一部の場所でbytesを使用し、他の場所でlongsを使用できるため、これを文法として表現することははるかに複雑になります。したがって、Javaの設計者が行ったのは、one整数リテラルだけを定義し、このリテラルの方法についてsemanticルールを定義することでした。異なる文脈で解釈されます。

ただし、構文解析段階でこれをチェックして構文エラーにすることは可能だと私は信じています。パーサーをより複雑にするだけでなく、実際には、パーサーをコンパイラ全体と同じくらい複雑にします(少なくともコンパイラの分析部分からオプテ​​ィマイザとコードジェネレータを除いたもの)。

4
Jörg W Mittag

コンパイラの作成者として決定します。コンパイラーのユーザーであれば、それほど大きな違いはありません。

しかし、整数リテラルのさまざまな範囲が許容されるさまざまな状況があるため、さまざまな範囲に対してさまざまなスキャナートークンを生成し、構文でこれを処理することは、コンパイラー作成者にとって絶対的な苦痛になります。そして、もしあなたが「int a [100];」を宣言したらどうなるでしょう。ここで、割り当てa [99] = 0;正当ですが、a [100] = 0;そうではありませんか?これは、意味論的ルールでしか合理的にチェックできません。

0
gnasher729