Qual é a melhor maneira de prevenir vazamentos de memória em um yacc baseado no analisador?

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

  •  09-06-2019
  •  | 
  •  

Pergunta

Yacc não permite que objetos a serem passados ao redor.Porque o %união só pode conter tipos de POD, objetos complexos devem ser novos e passada pelo ponteiro.Se ocorre um erro de sintaxe, o yacc analisador apenas interrompe a execução e referências para todos os objetos criados são perdidas.

A única solução que eu vim acima com é que todos os novos iria herdar do objecto de uma particular classe base, ser adicionado a um recipiente quando alocados, e se houver um erro em tudo em que o recipiente pode ser excluído.

Alguém sabe de melhor yacc truques para resolver este problema?

Por favor, não me diga para escolher um diferente do analisador.

Foi útil?

Solução

Eu amo o Yacc, mas a discriminar união pilha apresenta um desafio.

Eu não sei se você estiver usando C ou C++.Que eu tenha modificado Yacc para gerar C++ para meus próprios fins, mas esta solução pode ser adaptada para C.

A minha solução preferida é passar uma interface para o proprietário até a árvore de análise, em vez de objetos construídos a pilha.Fazer isso através da criação de sua própria pilha fora do Yacc.Antes de você chamar um não-terminal que aloca um objeto, aperte o proprietário do objeto para esta pilha.

Por exemplo:

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;

    ...
};

Tudo o que quer uma expressão tem para implementar o IExpressionOwner interface e empurre próprio para a pilha antes de invocar a expressão não-terminal.É um monte de código extra, mas ele controla o tempo de vida do objeto.

Atualização

A expressão é um exemplo ruim, pois você não sabe a operação até que, depois de ter reduzido o operando esquerdo.Ainda assim, essa técnica funciona em muitos casos, e requer apenas um pouco de ajustes de expressões.

Outras dicas

Se ele se adapte ao seu projeto, considere o uso de Boehm coletor de Lixo.Dessa forma, você pode livremente alocar novos objetos e deixe o coletor de lidar com o exclui.É claro que existem tradeoffs envolvidos no uso de um coletor de lixo.Você teria que pesar os custos e benefícios.

Utilização ponteiros inteligentes!

Ou, se você está desconfortável, dependendo ainda de outra biblioteca, você sempre pode usar auto_ptr a partir da C++ standard library.

Por isso é utilizando um analisador de tal problema?Bison é prontamente disponível, e (pelo menos no linux) yacc é geralmente implementado como bison.Você não deve precisar de qualquer alteração à sua gramática de uso (exceto para a adição %destruidor para resolver o seu problema).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top