personal lab / renos.tk archive

~/renjfk $ open /renos/calculating-string-expressions

renos.tk artifact / archive

Calculating string expressions

old C++ note for evaluating basic string expressions

created
07/03/2010

> notes

This was an old code-blog note about evaluating basic arithmetic expressions from strings for Otaku+.

The archived post described converting a string expression into an infix queue, then into a postfix queue, while stacking operators along the way. The source used STL stack and queue and handled basic operators, parentheses, and unary minus priority.

Historical context

This is not a standalone tool like the RO utilities. It is a small programming note from the same renos.tk period, useful mostly as a snapshot of the kind of C++ problem-solving notes that lived beside the downloadable utilities.

Archived source

The original post included the source inline:

#include <stack>
#include <queue>
#include "stdio.h"
using namespace std;

typedef struct tstack
{
    int val;
    char OP;
    int priority;
};

int Expression(const char *src, int *out, char *error)
{
    queue<tstack> infix;
    queue<tstack> postfix;
    stack<tstack> token;
    tstack op;
    size_t src_len = strlen(src);

    char val[10]; //max 10 digits
    int j = 0;

    //create infix queue
    for(int i = 0; i < src_len; i++)
    {
        if(isdigit(src[i]))
        {
            val[j] = src[i];
            j++;
        }
        else
        {
            if((!i || !j) && src[i] == '-') // minus as sign should have max high priority
                op.priority = 1;
            else if(src[i] == '-' || src[i] == '+') //add or minus have lowest priority
                op.priority = -1;
            else if(src[i] == '*' || src[i] == '/') //multiply or divide have second highest priority
                op.priority = 0;
            else if(src[i] == '(' || src[i] == ')')
                op.priority = 2;
            else if(src[i] == ' ') //no operation between two operands
            {
                if(j && isdigit(src[i + 1]))
                {
                    sprintf(error, "waiting operator before %s", &src[i]);
                    return 0;
                }
            }
            else
            {
                sprintf(error, "%c is unknown", src[i]);
                return 0;
            }

            if(j && src[i] != ' ')
            {
                val[j] = 0;
                tstack oval = {atoi(val), 0, 0};
                infix.push(oval);
                j = 0;
            }

            if(src[i] != ' ')
            {
                op.OP = src[i];
                infix.push(op);
            }
        }
    }
    if(j)
    {
        val[j] = 0;
        tstack oval = {atoi(val), 0, 0};
        infix.push(oval);
    }
    //create postfix queue
    while(!infix.empty())
    {
        if(infix.front().OP)
        {
            if(token.empty())
                token.push(infix.front());
            else
            {
                if(infix.front().OP == '(')
                    token.push(infix.front());
                else if(infix.front().OP == ')')
                {
                    while(token.top().OP != '(')
                    {
                        postfix.push(token.top());
                        token.pop();
                    }
                    token.pop();
                }
                else if(infix.front().priority > token.top().priority)
                    token.push(infix.front());
                else if(infix.front().priority == token.top().priority)
                {
                    postfix.push(token.top());
                    token.pop();
                    token.push(infix.front());
                }
                else if(infix.front().priority < token.top().priority)
                {
                    while(token.top().OP != '(')
                    {
                        postfix.push(token.top());
                        token.pop();
                    }
                    token.push(infix.front());
                }
            }
        }
        else
            postfix.push(infix.front());

        infix.pop();
    }
    //check if there are still ops at stack
    while(!token.empty())
    {
        postfix.push(token.top());
        token.pop();
    }
    //calculate result
    while(!postfix.empty())
    {
        if(postfix.front().OP)
        {
            if(postfix.front().OP == '-' && postfix.front().priority == 1) //check if its sign
                token.top().val*=-1;
            else
            {
                if(token.empty())
                {
                    sprintf(error, "syntax error", postfix.front().OP);
                    return 0;
                }

                tstack oval = token.top();
                token.pop();

                if(token.empty())
                {
                    sprintf(error, "syntax error", postfix.front().OP);
                    return 0;
                }

                switch(postfix.front().OP)
                {
                    case '+':token.top().val+=oval.val;break;
                    case '-':token.top().val-=oval.val;break;
                    case '*':token.top().val*=oval.val;break;
                    case '/':
                        if(oval.val)
                            token.top().val/=oval.val;
                        else
                        {
                            sprintf(error, "can't divide by zero");
                            return 0;
                        }
                    break;
                    default:
                        sprintf(error, "%c o.O''", postfix.front().OP);
                        return 0;
                }
            }
        }
        else
            token.push(postfix.front());

        postfix.pop();
    }

    if(!token.empty())
        *out = token.top().val;

    return 1;
}