Note that there are some explanatory texts on larger screens.

plurals
  1. POAdding Conditionals & Functions to a Math Parser
    text
    copied!<p>I have a binary tree based mathematical expression parser I built, which works great for 'normal' math, like: <code>(3.5 * 2) ^ 1 / (1 &lt;&lt; 6)</code>. however, I would like to expand it a little to add a ternary selection operator, mirroring the one from C: <code>{expr} ? {true-expr} : {false-expr}</code>. I would also like to add functions, like <code>sin(x)</code> or <code>ave(...)</code>. </p> <p>I however have no clue to how the handle this (due to the way the evaluation works), nor can I find anything on the web that covers this, atleast in a non-grammer based way (I'd like to avoid grammer parser generators for this, if possible).</p> <p>My parser current works by evaluating an infix expression and immediatly converting it to a tree, then from there the tree can be evaluated, ie: its you bog standard expression tree.</p> <p>currently my evaluator looks like so:</p> <pre><code>struct Node { int nType; union { unsigned long dwOperator; BOOL bValue; int nValue; //for indices, args &amp; functions number_t fValue; char* szValue; //for string literals to pass to functions }; Node* pLeft; Node* pRight; }; number_t EvaluateTree(Node* pNode) { if(pNode == NULL) return 0.0f; int nType = pNode-&gt;nType; if(nType == TOKEN_OPERATOR) { number_t fLeft = EvaluateTree(pNode-&gt;pLeft); number_t fRight = EvaluateTree(pNode-&gt;pRight); switch(pNode-&gt;dwOperator) { case '+': return fLeft + fRight; case '-': return fLeft - fRight; case '*': return fLeft * fRight; case '/': return fLeft / fRight; case '^': return pow(fLeft,fRight); case '_': return pow(fLeft,1.0f/fRight); case '%': return fmod(fLeft,fRight); //case '?': return bSelect = ?; //case ':': return (bSelect) ? fLeft : fRight; //case '&gt;': return fLeft &gt; fRight; //case '&lt;': return fLeft &lt; fRight; //case '&gt;=': return fLeft &gt;= fRight; //case '&lt;=': return fLeft &lt;= fRight; //case '==': return fLeft == fRight; //case '!=': return fLeft != fRight; //case '||': return fLeft || fRight; //case '&amp;&amp;': return fLeft &amp;&amp; fRight; case '&amp;': return static_cast&lt;number_t&gt;(static_cast&lt;unsigned long&gt;(fLeft) &amp; static_cast&lt;unsigned long&gt;(fRight)); case '|': return static_cast&lt;number_t&gt;(static_cast&lt;unsigned long&gt;(fLeft) | static_cast&lt;unsigned long&gt;(fRight)); case '~': return static_cast&lt;number_t&gt;(~static_cast&lt;unsigned long&gt;(fRight)); case '&gt;&gt;': return static_cast&lt;number_t&gt;(static_cast&lt;unsigned long&gt;(fLeft) &gt;&gt; static_cast&lt;unsigned long&gt;(fRight)); case '&lt;&lt;': return static_cast&lt;number_t&gt;(static_cast&lt;unsigned long&gt;(fLeft) &lt;&lt; static_cast&lt;unsigned long&gt;(fRight)); default: { printf("ERROR: Invalid Operator Found\n"); return 0.0f; } } } else if(nType == TOKEN_NUMBER) return pNode-&gt;fValue; else if(nType == TOKEN_CALL) return CreateCall(pNode); //not implemented else if(nType == TOKEN_GLOBAL) return GetGlobal(pNode); else if(nType == TOKEN_ARGUMENT) return GetArgument(pNode); else if(nType == TOKEN_STRING) return 0.0f; return 0.0f; } </code></pre> <p>Any tips/pointers/advice or useful links on how I can accomplish this?</p> <hr> <p>A small set of examples (as requested):</p> <h2>What I already have working</h2> <p>Input: <code>2 * (3 ^ 1.5) - 4 / (1 &lt;&lt; 3)</code></p> <p>Output: <code>In-Order: 2.0 * 3.0 ^ 1.5 - 4.0 / 1.0 &lt;&lt; 3.0</code></p> <p><code>Pre-Order: - * 2.0 ^ 3.0 1.5 / 4.0 &lt;&lt; 1.0 3.0</code></p> <p><code>Post-Order: 2.0 3.0 1.5 ^ * 4.0 1.0 3.0 &lt;&lt; / -</code></p> <p><code>Result: 9.892304</code></p> <h2>What I want to add</h2> <p>Input: <code>(GetDay() == 31) ? -15.5 : 8.4</code></p> <p>Output: <code>8.4</code></p> <p>Output on the 31st: <code>-15.5</code></p> <p>Input: <code>max([0],20)</code> (where [0] denotes argument 0, and [0] = 35)</p> <p>Output: <code>20</code></p> <p>Input: <code>(GetField('employees','years_of_service',[0]) &gt;= 10) ? 0.15 : 0.07</code> (where [0] is argument 0, and [0] is set to a valid index)</p> <p>Output (if years_of_service for the emplyee is less than 10: <code>0.15</code></p> <p>else Output: <code>0.07</code></p> <p>Its basically math with some C inspired additions, except arguments aren't passed by name, but rather index, and strings are escaped by single quotes instead doubles. </p> <p>When once I have the final bit done, I'm hoping to either bytecode compile or JIT it, as I'm planing to use this for things like games or math reliant programs, where the input set data is constant, but the input set can change, but its being used frequently, so it needs to be 'fast', and it needs to be usable by non-programmers.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload