Frage

Ich bin ein Compiler für ein Beschattungs Engine zu schreiben und jeder hat gut funktioniert, bis ich die Aussagen Parsen Teil erreicht.

Ich habe eine abstrakte Syntaxbaum mit Klassen definiert die ganze Arbeit zu tun (Typprüfung und Zwischencodegenerierung zu vereinfachen) .. so ich habe eine Vorfahrklasse ASTNode und alle absteigenden Klassen wie ASTFloat, ASTExpression , ASTIdentifier und so weiter ..

In .y Datei Ich bin in der Lage, den AST in gewohnter Weise aufzubauen:

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); }

und es funktioniert ganz gut, aber dann habe ich versucht, Aussagen eines Oszilloskops zu erzeugen (zum Beispiel den Körper eines , wenn statement) auf diese Weise: Ich habe eine Klasse ASTStatements verwendet, die eine Liste von ASTNode*, die mit jeder Anweisung angetroffen durch Parser ausgefüllt werden müssen.

So ist der Ansatz so etwas wie das sein würde:

statements:
statement { if ($$ == null) $$ = new ASTStatements(); ((ASTStatements*)$$)->addStatement($1); } statements { $$->generateASM(); }
;

Das Problem ist, dass der Versand der Ware pro Block von Anweisungen nur einmal initialisiert werden, aber ich weiß nicht, wie es zu tun. Mit if ($$ == null) ist ein Hack, den ich versuchte, aber es funktioniert nicht, weil yylval was auch immer bis zu diesem Punkt enthalten kann.

, die der normale / beste Weg ist, diese Art von Situationen zu bewältigen Bison mit?

War es hilfreich?

Lösung 3

ich dieses Problem gelöst, indem nicht eine Liste von Aussagen zu erzeugen, sondern einen degenerierten Baum. So ist die Klasse Objekt beteiligt ist:

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
}

Regeln in .y auf folgende Weise mit:

statements: /* empty */ { $$ = null; }
| statements statement { if ($1 == null) $$ = new ASTStatements($2); else $$ = new ASTStatements($2, (ASTStatements*)$1); }

Und in der Tat ist dies linksrekursive, so dass Aussagen so bald wie möglich reduziert werden, ohne den Stapel unübersichtlich. Ich folgte den gleichen Ansatz für jede andere Art von „Liste der Symbole“ beteiligt in meiner Sprache ..

Andere Tipps

Versuchen Sie, eine erweiterte Grammatik wie folgt aus:

statements: statement { $$ = new ASTStatements();
                       ((ASTStatements*)$$)->addStatement($1); }      
 | statements statement { ((ASTStatements*)$$)->addStatement($2); }

Nicht sicher, ob dies helfen wird.

Es gibt verschiedene Gründe linksrekursive Regeln für yacc bevorzugen, für eine Sache, die Sie dann so früh wie möglich in dem Eingang reduzieren.

Auf jeden Fall, wenn Sie das tun, dann können Sie ein Muster wie folgt verwenden:

statements:                { $$ = new ... }
    | statements statement { /* now $1 and $2 do just what you want */ }
    ;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top