スピリットとフォワード宣言の問題を後押しします
-
16-09-2019 - |
質問
誰かが、現在の瞬間に正しいセマンティックアクションを作成できるようにさらに宣言を見る必要がある場合に、状況に対処する方法についてアドバイス/アイデアを教えてください。たとえば、誰かが「フォワード宣言」をサポートしていないプログラミング言語の通訳/コンパイラを書くとき、それはよく知られている出来事です。例を持ってみましょう:
foo(123);//<-- our parser targets here. we estimate we have a function
// invocation, but we have no idea about foo declaration/prototype,
// so we can't be sure that "foo" takes one integer argument.
void foo(int i){
//...
}
少なくとも2つのパスが必要である必要があることは明らかです。まず、すべての関数宣言を解析し、次のような必要なすべての情報を取得します。関数が取る量、それらのタイプ、次に、関数の呼び出しに対処し、上記のように困難を解決することができます。このように行けば、いくつかを使用してこれらすべてのパスを行う必要があります AST 移動メカニズム/訪問者。この場合、私たちは訪問者を横断/適用するASTに対処する必要があり、パーサーに直接統合されたフェニックス構造のすべての美しさに「さようなら」と言わなければなりません。
これにどのように対処しますか?
解決
2番目の回答、セマンティクスについて]この特定の例は単純です。あなたができることは、まだ宣言されていない関数と実際の引数タイプに作られた関数呼び出しを記録することです。後で関数宣言に遭遇した場合、この新しい関数に一致する(より良い)前の関数呼び出しがあるかどうかを確認します。最後の行が欠落している機能を導入する可能性があるため、解析の終了時にのみエラーを検出します。しかし、その行の後、まったく一致していない関数呼び出しはエラーです。
さて、問題は、これが単純なセマンティクスのために機能することです。あなたがより複雑な言語を見るなら - 例えばc ++ - 類似の関数 テンプレート - 単純なテーブルでそのようなルックアップを行うことはできなくなりました。言語構造を構造的に一致させる特殊なタブが必要です。 ASTは、解析中の部分的なASTは言うまでもなく、それらにとって最良の構造ではありません。
他のヒント
最初のパスの終わりにセマンティックチェックの代わりに2つのパスを実行したい場合、アクションで呼び出される関数がそれらがどのパスにあるかを知ることができます。したがって、いくつかのアクションがあった場合
[functionCall(name, args)]
[functionDef(name, args, body)]
それらはこのようなものを定義されます(適切なスピリットの構文ではありませんが、ポイントが得られます)
functionCall(string name, vector<string> args)
{
if (!first_pass) {
// check args for validity
// whatever else you need to do
}
}
functionDef(string name, vector<string> args, ... body)
{
if (first_pass)
// Add function decleration to symbol table
else
// define function
}
根拠のない仮定をしていると思います。たとえば、「少なくとも2回のパスが必要なことは明らかです」。いいえ、そうではありません。構文がそのような場合 foo(123)
として解析することができます function-name "(" expression ")"
, 、1つのパスで十分です。
したがって、明確な解析のために構文を設計することをお勧めします。単独で解析できないコンストラクトを避けてください。