要素のリストを解析するためにバイソンを使用しました
-
11-09-2019 - |
質問
私はシェーディングエンジン用のコンパイラを書いていると私は一部を解析ステートメントに達するまで、すべてがうまく働いています。
私はASTNode
、 ..(型チェックおよび中間コード生成を簡素化するために)すべての作業を行うために、クラスで定義されたので、私は先祖クラスASTFloat
とASTExpression
などのすべての降順のクラスを持っているの抽象構文木を使用しました、ASTIdentifier
など..
.y
ファイルでは、私は、共通の方法でASTを構築することができるよ。
nexp:
T_LPAR nexp T_RPAR { $$ = $2; }
| nexp OP_PLUS nexp { $$ = new ASTBExpression('+', (ASTExpression*)$1, (ASTExpression*)$3); }
| nexp OP_MINUS nexp { $$ = new ASTBExpression('-', (ASTExpression*)$1, (ASTExpression*)$3); }
| nexp OP_TIMES nexp { $$ = new ASTBExpression('*', (ASTExpression*)$1, (ASTExpression*)$3); }
と、それはかなりうまく動作しますが、その後、私は、このように範囲(の場合の文の例えばボディ)の文を生成しようとしました:私はのリストを持つクラスのASTStatements
を使用していました遭遇した各ステートメントでパーサによって満たされなければならないASTNode*
ます。
だから、アプローチは次のようにものになるだろう
statements:
statement { if ($$ == null) $$ = new ASTStatements(); ((ASTStatements*)$$)->addStatement($1); } statements { $$->generateASM(); }
;
問題は、アイテムが文のブロックごとに一度だけ初期化する必要がありますが、私はどのように行うのか分からないということです。 if ($$ == null)
を使用すると、yylval
はその時点まで何でもアップを含めることができますので、私が試したが、それは動作しませんハックされます。
バイソンを使って状況のこの種を処理するため、通常/最良の方法はどれ?
解決 3
私はない文のリストが、縮退ツリーを生成することで、この問題を解決しました。だから、関係するクラスオブジェクトがあります:
ASTStatements
{
ASTStatements *m_next;
ASTStatement *m_statement;
....
public:
ASTStatements(ASTStatement *statement) // used for last one
ASTStatements(ASTStatement *stat, ASTStatements *next) // used with a next one
}
次のように.y
のルールを使用します:
statements: /* empty */ { $$ = null; }
| statements statement { if ($1 == null) $$ = new ASTStatements($2); else $$ = new ASTStatements($2, (ASTStatements*)$1); }
そして実際、この文は、スタックを混乱せず、できるだけ早く減らすことができるように、左再帰的です。私は自分の言語に関わる「シンボルのリスト」の他の種類のために同じアプローチを踏襲..
他のヒント
次のように拡張さの文法を試します:
statements: statement { $$ = new ASTStatements();
((ASTStatements*)$$)->addStatement($1); }
| statements statement { ((ASTStatements*)$$)->addStatement($2); }
これが役立つかどうかわからない。
あなたはできるだけ早い段階での入力で減らすことができます一つには、yaccのために左再帰ルールを好むために、様々な理由があります。
いずれにせよ、あなたがそれを行うとき、あなたは、このようなパターンを使用することができます:
statements: { $$ = new ... }
| statements statement { /* now $1 and $2 do just what you want */ }
;