Google の新しい言語「Go」は、そのウェブサイトで次のように述べています。
言語は分析しやすいように設計されており、記号テーブルなしで解析できます
私は確かにこれらの問題の専門家ではありませんが、シンボル テーブルは、変数を使用する言語のすべてのコンパイラに共通の基本的な構造であり、Go は明らかに変数を使用していると思いました。私は何を理解していませんか?
Google の新しい言語「Go」は、そのウェブサイトで次のように述べています。
言語は分析しやすいように設計されており、記号テーブルなしで解析できます
私は確かにこれらの問題の専門家ではありませんが、シンボル テーブルは、変数を使用する言語のすべてのコンパイラに共通の基本的な構造であり、Go は明らかに変数を使用していると思いました。私は何を理解していませんか?
解析とは、プログラム構造を理解することを意味します。モジュールをステートメント/宣言に分離し、式を部分式に分解するなどです。最終的には、「解析ツリー」または「抽象構文ツリー」として知られるツリー構造になります ( AST)。
どうやら、C++ では解析を行うためにシンボル テーブルが必要です。
このページでは、C++ が構文解析のためにシンボル テーブルを必要とするいくつかの理由について説明します。
もちろん、構文解析はコンパイルの一部に過ぎず、完全なコンパイルを行うにはシンボル テーブルが必要です。
ただし、解析自体は分析ツールを作成する際に役立ちます (たとえば、どのモジュールがどのモジュールをインポートするか)。したがって、解析プロセスを単純化するということは、コード分析ツールの作成が容易になるということです。
@正義は正しいです。これを少し拡張すると、Cでは、実際に注意が必要なのは、変数とは別に型を区別することだけです。特にこれを見たとき:
T t;
T
それが合法的な構文解析であるためのタイプであることを知る必要があります。それはあなたがシンボルテーブルで調べなければならないものです。解析が続行されるときにタイプがシンボルテーブルに追加される限り、これは比較的簡単に理解できます。コンパイラで余分な作業を行う必要はありT
ません。テーブルに存在するか、存在しないかのどちらかです。
C ++では、物事ははるかに複雑です。あいまいな、またはあいまいな可能性のある構成要素は膨大な数になります。最も明白なのはこれです:
B::C (c);
が、、、、またはであるかどうかB
が明確でないという事実は別として、が型であり、その型のオブジェクトであるかどうか、または引数として取る関数(またはコンストラクター)であるかどうか(またはCである場合でも)も明確ではありません。オーバーロードされたオブジェクトです)。解析を続行するにはシンボルテーブルが必要ですが、シンボルのタイプはシンボルテーブルにあるため、十分に迅速に続行することは可能です。class
typedef
namespace
C
c
C
c
operator()
テンプレートが混在する場合よりも、事態ははるかに悪化します。がテンプレート内にある場合C (c)
、Cが型であるか関数/オブジェクトであるかは、テンプレートの実際の定義ではわからない可能性があります。これは、テンプレートが型または変数のいずれかであるC
と宣言できるためです。これが意味するのは、シンボルテーブルが必要ですが、シンボルテーブルがないということです。そして、テンプレートが実際に宣言されるまで、シンボルテーブルを持つことはできません。さらに悪いことに、シンボルのタイプだけで十分ではありません。サイズ、配置、その他のマシン固有の情報など、シンボルが表すタイプの完全な情報が必要な状況を考え出すことができます。
これにはすべて、いくつかの実用的な効果があります。私が言う最も重要な2つは次のとおりです。
解釈とコンパイルには、シンボル テーブルまたは類似のものが絶対に必要です。これは、ほぼすべての言語に当てはまります。
C および C++ では、言語の構文解析にもシンボル テーブルが必要です。
ほとんどの言語を解析するには、名前が変数、型、または関数であることを知って、特定の構造を明確にする必要があります。Go には、そのようなあいまいな構造はありません。
例えば:
int x = Foo(バー);
Foo は型または関数である可能性があり、それらは異なる AST 型で表されます。基本的に、パーサーは AST の構築方法を知るためにシンボルを検索する必要はありません。文法と AST は、ほとんどの言語より単純です。本当にかっこいい。
シンボル テーブルは低速であり、通常は必要ありません。だから、それをやめることを選んでください。他の関数型言語も必要ありません。高速検索にはハッシュが必要ですが、ネストされたスコープをサポートするには、名前をスタックにプッシュ/ポップする必要があります。単純な symtab は線形検索スタックとして実装され、より優れた symtab はシンボルごとのスタックを持つハッシュとして実装されます。ただし、検索は実行時に行う必要があります。
レキシカル スコープの言語の解釈とコンパイルには、シンボル テーブルなどはまったく必要ありません。ダイナミック スコープのシンボルのみがシンボル テーブルを必要とし、厳密に型指定された言語を使用する一部のコンパイラでは、型注釈を保持するためにある種の内部シンボル テーブルが必要です。
C および C++ では、グローバルと関数の型と宣言を格納する必要があるため、言語の解析にもシンボル テーブルが必要です。
レキシカル スコープのシンボルは symtab には保存されませんが、関数型言語のように、ブロック フレーム内の名前のインデックス付きリストとして保存されます。これらのインデックスはコンパイル時に計算されます。そのため、ランタイム アクセスは即時です。スコープを離れると、これらの変数に自動的にアクセスできなくなるため、名前空間/symtab から名前をプッシュ/ポップする必要はありません。
ファーストクラスの関数を持たない関数型言語では、多くの場合、関数名をシンボル テーブルに格納する必要があります。言語設計者として、代わりに関数をレキシカルにバインドして、symtab での動的な名前検索を取り除くことができるようにします。