Jump to content
  • Advertisement
TheComet

Manual syntax trees

Recommended Posts

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?

Edited by TheComet

Share this post


Link to post
Share on other sites
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.

Edited by Nypyren

Share this post


Link to post
Share on other sites
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.

Edited by Awoken

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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.

Edited by Nypyren

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Posted (edited)

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

 

Edited by SyncViews

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!