# 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::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::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 on other sites

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 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 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 on other sites

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

##### 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 on other sites

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

##### 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 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 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.


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

## Create an account

Register a new account

1. 1
2. 2
Rutin
21
3. 3
A4L
15
4. 4
5. 5

• 13
• 26
• 10
• 11
• 44
• ### Forum Statistics

• Total Topics
633741
• Total Posts
3013624
×