Was ist der beste Weg, Speicherlecks in einem yacc-basierten Parser zu verhindern?

StackOverflow https://stackoverflow.com/questions/64958

  •  09-06-2019
  •  | 
  •  

Frage

Yacc nicht erlaubt, Gegenstände herumgereicht werden. Da die% Vereinigung nur Typen POD enthalten können, müssen komplexe Objekte durch Zeiger new'd und herumgereicht werden. Wenn ein Syntaxfehler auftritt, nur der yacc-Parser nicht mehr läuft, und Verweise auf alle diese erstellten Objekte verloren.

Die einzige Lösung, die ich habe kommen mit ist, dass alle new'd Objekt eine bestimmte Basisklasse erben, in einen Behälter gegeben werden, wenn zugeordnet, und wenn ein Fehler alles in diesem Container ist, können gelöscht werden.

Kennt jemand ein besseren yacc Tricks dieses Problem zu lösen?

Bitte erzählen Sie mir nicht einen anderen Parser zu wählen.

War es hilfreich?

Lösung

Ich liebe Yacc, aber die diskriminierende Vereinigung Stapel hat eine Herausforderung dar.

Ich weiß nicht, ob Sie C oder C ++ verwenden. Ich habe Yacc modifizierte C ++ für meine eigenen Zwecke zu generieren, aber diese Lösung kann auf C angepasst werden.

Meine bevorzugte Lösung ist eine Schnittstelle zum Eigentümer auf dem Parsing-Baum passieren, anstatt konstruierten Objekte auf den Stapel. Tun Sie dies, indem Sie Ihren eigenen Stapel außerhalb von Yacc der Erstellung. Bevor Sie ein Nicht-Terminal aufrufen, die ein Objekt zuweist, drücken Sie den Eigentümer des Objekts zu diesem Stapel.

Zum Beispiel:

class IExpressionOwner
{
public:
    virtual ExpressionAdd *newExpressionAdd() = 0;
    virtual ExpressionSubstract *newExpressionSubtract() = 0;
    virtual ExpressionMultiply *newExpressionMultiply() = 0;
    virtual ExpressionDivide *newExpressionDivide() = 0;
};

class ExpressionAdd : public Expression, public IExpressionOwner
{
private:
    std::auto_ptr<Expression> left;
    std::auto_ptr<Expression> right;

public:
    ExpressionAdd *newExpressionAdd()
    {
        ExpressionAdd *newExpression = new ExpressionAdd();
        std::auto_ptr<Expression> autoPtr(newExpression);
        if (left.get() == NULL)
            left = autoPtr;
        else
            right = autoPtr;
        return newExpression;
    }

    ...
};

class Parser
{
private:
    std::stack<IExpressionOwner *> expressionOwner;

    ...
};

Alles, was einen Ausdruck will, muss die IExpressionOwner Schnittstelle implementieren und sich drücken, um den Stapel vor dem Ausdruck nicht-Terminal aufrufen. Es ist eine Menge zusätzlichen Code, aber es steuert Objekt Lebensdauer.

Aktualisieren

Der Ausdruck Beispiel ist ein schlechter, da Sie den Vorgang nicht wissen, bis Sie den linken Operanden reduziert haben. Trotzdem funktioniert diese Technik in vielen Fällen und erfordert nur ein wenig Gefummel für Ausdrücke.

Andere Tipps

Wenn es Ihr Projekt passt, sollten Sie die Boehm Garbage Collector verwenden. Auf diese Weise können Sie frei neue Objekte zuweisen und lassen Sie den Kollektor die Löschungen handhaben. Natürlich gibt es bei der Verwendung eines Garbage Collector beteiligt Kompromisse. Sie müssten die Kosten und Nutzen abwägen.

Verwenden Sie intelligente Zeiger !

Oder, wenn Sie unbequem sind abhängig von noch einer anderen Bibliothek, können Sie immer verwenden auto_ptr aus der Standardbibliothek C ++.

Warum einen anderen Parser, ein solches Problem verwendet? Bison ist leicht verfügbar, und (zumindest unter Linux) yacc wird gewöhnlich als Bison umgesetzt. Sie sollten keine Änderungen an der Grammatik brauchen, es zu benutzen (mit Ausnahme der Zugabe% destructor Ihr Problem zu lösen).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top