Manual syntax trees

Started by
9 comments, last by fornishkel 5 years, 4 months ago

I thought this thing I wrote might be a worthy candidate for a coding horror.


Expression* SymbolicMatrix::determinant3x3() const
{
    /*
     * Given the matrix
     *
     *      / a b c \
     *  A = | d e f |
     *      \ g h i /
     *
     * The determinant can be calculated with:
     *
     *  det(A) = (aei + bfg + cdh) - (gec + hfa + idb)
     *
     * The entries in the matrix are stored such that a=0, b=1, c=2, etc.
     */
    return Expression::make(op::sub,                   // (aei + bfg + cdh) - (gec + hfa + idb)
            Expression::make(op::add,                  // aei + bfg + cdh
                Expression::make(op::add,              // aei + bfg
                    Expression::make(op::mul,          // aei
                        Expression::make(op::mul,      // ae
                            entries_[0]->clone(),      // a
                            entries_[4]->clone()),     // e
                        entries_[8]->clone()),         // i
                    Expression::make(op::mul,          // bfg
                        Expression::make(op::mul,      // bf
                            entries_[1]->clone(),      // b
                            entries_[5]->clone()),     // f
                        entries_[6]->clone())),        // g
                Expression::make(op::mul,              // cdh
                    Expression::make(op::mul,          // cd
                        entries_[2]->clone(),          // c
                        entries_[3]->clone()),         // d
                    entries_[2*3+1]->clone())),        // h
            Expression::make(op::add,                  // gec + hfa + idb
                Expression::make(op::add,              // gec + hfa
                    Expression::make(op::mul,          // gec
                        Expression::make(op::mul,      // ge
                            entries_[6]->clone(),      // g
                            entries_[4]->clone()),     // e
                        entries_[2]->clone()),         // c
                    Expression::make(op::mul,          // hfa
                        Expression::make(op::mul,      // hf
                            entries_[7]->clone(),      // h
                            entries_[5]->clone()),     // f
                        entries_[0]->clone())),        // a
                Expression::make(op::mul,              // idb
                    Expression::make(op::mul,          // id
                        entries_[8]->clone(),          // i
                        entries_[3]->clone()),         // d
                    entries_[1]->clone())));           // b
}

All jokes aside, how would one make this look better?

"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty
Advertisement

Maybe overload the operators on the Expression type itself (or a type specific to performing AST generation) to make the combined expression.  Then the C++ parser itself will construct your AST creation calls properly due to operator precedence rules.

Also it might be worth investing time in seeing whether your 'entries' can be immutable.  If so, you won't need to clone() them.

On 12/12/2017 at 9:55 PM, Nypyren said:

'entries' can be immutable

Huh, so I'm using javascript's three.js and given the following code:


var a = Mesh.geometry.vertices[0];
a.multiplyScalar(2);

Mesh.geometry.vertices[0] will also be multiplied by 2.  O.k I understand this part and why, a is just acting as a temporary place holder for vertices[0].   How, or can someone, make the situation immutable?  Is my question even relevant? I'm under the impression that if it becomes immutable than I don't need to .clone() vertices[0] when declaring a and a becomes it's own unique entity.

7 minutes ago, Awoken said:

How, or can someone, make the situation immutable? 

You are using Javascript, where pretty much everything is a reference. TheComet appears to be using C++, where things are generally manipulated by-value instead (references/pointers have to be explicitly opted into).

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This looks like the kind of thing that Lisp would be good at.

1 hour ago, Awoken said:

Huh, so I'm using javascript's three.js and given the following code:



var a = Mesh.geometry.vertices[0];
a.multiplyScalar(2);

How, or can someone, make the situation immutable?  Is my question even relevant? I'm under the impression that if it becomes immutable than I don't need to .clone() vertices[0] when declaring a and a becomes it's own unique entity.

Immutability in languages that are mutable by default would be something like:  "multiplyScalar" would return a new vertex instead of modifying the existing one.  But if that method is part of three.js, then you don't really have a choice.

How many hours did it take you to write this code?

On 8/5/2018 at 7:12 PM, fornishkel said:

How many hours did it take you to write this code?

Honestly? It was probably about 5-10 minutes.

"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty

What exactly is clone() returning? I assume its something that references the SymbolicMatrix matrix fields so that the expression can be reused, and not just the current value? If its just the current value, then what exactly is the point?

 

If your going to be doing a lot of them, maybe parse it into a tree yourself either at runtime or as a buildstep. Creating the syntax tree from even relatively complex languages is generally not too difficult (there are also tools that can codegen it for you), exceptions being things like C++ (especially templates).

 

Using overloading in C++ or similar if you don't want your own syntax, you can build a tree, and handling brackets, operator precedence, etc. is free.


typedef float Value;
class Expression
{
public:
    virtual ~Expression() {};

    virtual Value exec()const = 0;
};
typedef std::unique_ptr<Expression> ExpressionPtr;
class ExpressionMul : public Expression
{
public:
    ExpressionMul(ExpressionPtr &&a, ExpressionPtr &&b) : a(std::move(a)), b(std::move(b)) {}

    virtual Value exec()const override { return a->exec() * b->exec(); }
private:
    ExpressionPtr a, b;
};
class ExpressionValue : public Expression
{
public:
    ExpressionValue(Value v) : v(v) {}
    virtual Value exec()const override { return v; }
private:
    Value v;
};
ExpressionPtr make_value(Value v) { return std::make_unique<ExpressionValue>(v); }
ExpressionPtr operator * (ExpressionPtr &&a, ExpressionPtr &&b)
{
    return std::make_unique<ExpressionMul>(std::move(a), std::move(b));
}


int main()
{
    auto expr = make_value(5) * make_value(6);
    auto result = expr->exec();
    std::cout << result << std::endl;
}

 

On 8/23/2018 at 6:04 PM, SyncViews said:

What exactly is clone() returning? I assume its something that references the SymbolicMatrix matrix fields so that the expression can be reused, and not just the current value? If its just the current value, then what exactly is the point?

 

If your going to be doing a lot of them, maybe parse it into a tree yourself either at runtime or as a buildstep. Creating the syntax tree from even relatively complex languages is generally not too difficult (there are also tools that can codegen it for you), exceptions being things like C++ (especially templates).

 

Using overloading in C++ or similar if you don't want your own syntax, you can build a tree, and handling brackets, operator precedence, etc. is free.

https://stylufka.pl/jakie-sa-pierwsze-objawy-ciazy/



typedef float Value;
class Expression
{
public:
    virtual ~Expression() {};

    virtual Value exec()const = 0;
};
typedef std::unique_ptr<Expression> ExpressionPtr;
class ExpressionMul : public Expression
{
public:
    ExpressionMul(ExpressionPtr &&a, ExpressionPtr &&b) : a(std::move(a)), b(std::move(b)) {}

    virtual Value exec()const override { return a->exec() * b->exec(); }
private:
    ExpressionPtr a, b;
};
class ExpressionValue : public Expression
{
public:
    ExpressionValue(Value v) : v(v) {}
    virtual Value exec()const override { return v; }
private:
    Value v;
};
ExpressionPtr make_value(Value v) { return std::make_unique<ExpressionValue>(v); }
ExpressionPtr operator * (ExpressionPtr &&a, ExpressionPtr &&b)
{
    return std::make_unique<ExpressionMul>(std::move(a), std::move(b));
}


int main()
{
    auto expr = make_value(5) * make_value(6);
    auto result = expr->exec();
    std::cout << result << std::endl;
}

 

Now seems work

This topic is closed to new replies.

Advertisement