Scanner - Wie Tokenbaseklasse deklarieren?



  • Hallo,

    ich baue mir gerade einen Scanner fürs Parsen und würde gerne für die zu erzeugenden Symbole eine Baseklasse haben, so dass der Parser dann einen Array von Zeigern auf die Baseklasse erhält.

    Ein Symbol hat derzeit ein ID (z.B. NUM, OP_PLUS,...) und soll noch den Wert speichern, den das zugrundeliegende Lexem hat.
    Liest der Scanner z.B. "12345" ein soll er das Symbol (NUM, 12345) erzeugen, wobei 12345 dann die konkrete Zahl ist und nicht mehr der String.

    Ich hätte gerne etwas wie

    class Base
    {
    private:
       ID id;
     public:
         Base(ID _id):id(_id){}
         ID ID(){return id;}
    };
    
    template <type VAL>
    class Derived
    :public Base
    {
    private:
    VAL v;
    public:
     Derived(ID _id, VAL _v)
     :Base(_id), v(_v)
    {}
     VAL value(){return v;}
    };
    

    Da aber value() nicht in Base deklariert wurde kann ich natürlich nicht z.B.

    Base* b = new Derived(MyID, 12345);
    std::cout << b->value() << std::endl;
    

    schreiben.

    Später würde ich aber sehr gerne Paare von Werten haben über die ich iterieren kann, wobei der rechte Typ des Paares vom linken Wert abhängt.

    Hat jemand einen eleganten Vorschlag? Mir fällt nur

    Base* b = new Derived(MyID, 12345);
    if(b->type() == MyID)
    {
     Derived* A = static_cast<A*>(b);
     // Mach was mit A->value()
    }
    


  • Hab das vor kurzem erst selbst gemacht. Ich habe dafür das Visitor Pattern verwendet, ungefähr so:

    #include <iostream>
    #include <vector>
    #include <memory>
    
    struct Dog;
    struct Horse;
    
    struct AnimalVisitor
    {
    	virtual void visit(Dog const &dog) = 0;
    	virtual void visit(Horse const &horse) = 0;
    };
    
    struct AnimalWeightVisitor : AnimalVisitor
    {
    	int total_weight = 0;
    
    	virtual void visit(Dog const &dog);
    	virtual void visit(Horse const &horse);
    };
    
    struct Animal
    {
    	virtual void accept(AnimalVisitor &visitor) const = 0;
    	virtual int get_weight() const = 0;
    };
    
    struct Dog : Animal
    {
    	int weight = 0;
    	Dog(int weight) : weight(weight) {}
    
    	void accept(AnimalVisitor &visitor) const { visitor.visit(*this); }
    	int get_weight() const { return weight; }
    };
    
    struct Horse : Animal
    {
    	int weight = 0;
    	int horseman_weight = 0;
    	Horse(int weight, int horseman_weight) : weight(weight), horseman_weight(horseman_weight) {}
    
    	void accept(AnimalVisitor &visitor) const { visitor.visit(*this); }
    	int get_weight() const { return weight; }
    	int get_horseman_weight() const { return horseman_weight; }
    };
    
    void AnimalWeightVisitor::visit(Dog const &dog) { total_weight += dog.get_weight(); }
    void AnimalWeightVisitor::visit(Horse const &horse) { total_weight += horse.get_weight() + horse.get_horseman_weight(); }
    
    int main()
    {
    	std::vector<std::unique_ptr<Animal>> animals;
    
    	animals.push_back(std::make_unique<Dog>(5));
    	animals.push_back(std::make_unique<Dog>(15));
    	animals.push_back(std::make_unique<Horse>(500, 100));
    	animals.push_back(std::make_unique<Dog>(12));
    	animals.push_back(std::make_unique<Horse>(700, 80));
    
    	AnimalWeightVisitor visitor;
    
    	for (auto const &animal : animals)
    	{
    		animal->accept(visitor);
    	}
    
    	std::cout << "Total weight is " << visitor.total_weight << "\n";
    }
    


  • Top, danke dir 🙂


Log in to reply