simple examples of how to

Thursday, October 20, 2011

[C++] Post-fix Calculator Source Code (String-calculator)

Here goes the c++ source code of post-fix calculator, which appears a lot in data structure class.

here it goes

#include stdio.h>
#include stdlib.h>
#include string.h>
#include ctype.h>


#define T_EOL                ';'
#define T_CONST                'C'
#define T_SYMBOL        'S'
#define T_LPAR                '('
#define T_RPAR                ')'
#define T_COMMA                ','
#define T_ASSIGN        '='
#define T_POINT                '$'
#define T_MUL                '*'
#define T_DIV                '/'
#define T_MOD                '%'
#define T_ADD                '+'
#define T_SUB                '-'
#define T_NEG                '_'
#define T_NOT                '~'
#define T_SHL                'L'
#define T_SHR                'R'
#define T_AND                '&'

class StringCalculator {
        // I don't know why defining another class makes all messages of redefinitions...,
        // just put postfix calcualtor here
public:
        StringCalculator();        
        double push_eval( double val );
        double push( double val );
        double pop_eval();
        double pop();
        char getoken(int* v = NULL);
        int isbinop( char** cpp );
        int expression();
        double evaluate();
        int primary();
        int binop( char op );
        int op_prim( int precedence, int lvalue );
        void generate( char tkn, double val, int index=-1 );
        double calc( char* line );
        void setup_symbol(int index, double value);
#define STAKSZ 128
        struct OPSTK {
                char o_token;
                double o_value;
                int symbol_index;
        } Opstk[ STAKSZ ];
        int Opbase;
        int Opsp;

        double Valstk[ STAKSZ ];
        int Valbase;
        int Valsp;

        double Valstk_eval[ STAKSZ ];
        int Valbase_eval;
        int Valsp_eval;

        double Symbols[26];
        double Value;

        char buff[128];

#define MAXLEVEL 32
        char Level; /* current recursion level in calc() */
        char Token; /* current input token */
        char Eol; /* set when end of line encountered */
        char *Lineptr; /* points to next character in input line */
        char *Ofmt; /* current output format (set by "base" command) */
        int Error; /* set if parsing error occurred */
        char Nohelp; /* set if help was given already */

        int symbol_index;
};



StringCalculator::StringCalculator()
{
    Nohelp = 1;
    Level = 0;
    Token = 0;
    Eol = 0;
    Lineptr = NULL;
    Ofmt = NULL;
    Error = 0;
    Nohelp = 0;
    Opbase=0;
    Opsp=0;
    Valbase=0;
    Valsp=0;

    push( 10 );
        for( int i=0; i<26; i++ )
        {
                Symbols[i]=0;
        }

}

void StringCalculator::setup_symbol(int index, double value)
{
        Symbols[index] = value;
}


double StringCalculator::calc( char* line )
{
        char *savLineptr;
        int savValbase, savValsp, savOpbase, savOpsp;

        /* save in my buff */
        strncpy(buff, line, 128);
        line = buff;


        if ( ++Level > MAXLEVEL )
        {
                printf("recursion\n");
        }
        else
        {
                savLineptr = Lineptr;
                savValbase = Valbase;
                savValsp = Valsp;
                savOpbase = Opbase;
                savOpsp = Opsp;

                Valbase = Valsp;
                Opbase = Opsp;
                Lineptr = line;

                Eol = 0;

                if ( getoken() != T_EOL )
                {
                        expression();
                        if ( Error <= 0 )
                        {
                        }
                        else {
                                printf("parse error: %s\n", buff);
                        }
                }
        }
        return 0.0;
}

double StringCalculator::evaluate()
{
    int opsp;
    double val;
    char op;
    Valsp_eval = Valsp;
    Valbase_eval = Valbase;
    memcpy(Valstk_eval, Valstk, sizeof(Valstk));
#define TOS (Valstk_eval[Valsp_eval-1]) /* top of stack macro */

    for ( opsp=Opbase; opsp    {
        op = Opstk[ opsp ].o_token;

        if ( op == T_CONST )
                {
            push_eval( Opstk[ opsp ].o_value );
                }
        else if ( op == T_SYMBOL )
                {
            push_eval( Symbols[Opstk[ opsp ].symbol_index] );
                }
        else if ( op == T_ADD )
        {
            val = pop_eval();
            TOS += val;
        }
        else if ( op == T_SUB )
        {
            val = pop_eval();
            TOS -= val;
        }
        else if ( op == T_NEG )
            TOS = -TOS;
        else if ( op == T_MUL )
        {
            val = pop_eval();
            TOS *= val;
        }
        else if ( op == T_DIV )
        {
            val = pop_eval();
            TOS /= val;
        }
        else
            printf( "bad operator in stack: 0x%x (%c)\n", op, op );
    }
    return Valstk_eval[ Valbase_eval ];
}

double StringCalculator::push( double val )
{
        if ( Valsp >= STAKSZ )
                printf( "stack overflow" );
        return Valstk[ Valsp++ ] = val;
}

double StringCalculator::pop()
{
        if ( --Valsp < 0 )
                Valsp = 0;
        return Valstk[ Valsp ];
}

double StringCalculator::push_eval( double val )
{
        if ( Valsp_eval >= STAKSZ )
                printf( "stack overflow" );
        return Valstk_eval[ Valsp_eval++ ] = val;
}

double StringCalculator::pop_eval()
{
        if ( --Valsp_eval < 0 )
                Valsp_eval = 0;
        return Valstk_eval[ Valsp_eval ];
}
int StringCalculator::expression()
{
        int lvalue;
        if ( !(lvalue = primary()) )
        {
                printf( "bad expression" );
        }
        else if ( Eol )
        {
                if ( lvalue < 0 )
                        generate( T_POINT, 0 );
        }
        else
        {
                op_prim( 0, lvalue );
        }
        return 1;
}

int StringCalculator::op_prim( int precedence, int lvalue )
{
        char tkn;
        int pr, lv;

        while ( ! Eol )
        {

                pr = binop( Token );

                if (
                        (pr>precedence && pr>0) ||
                        (Token==T_ASSIGN && pr>=precedence)
                )
                {
                        if ( Token == T_ASSIGN )
                        {
                                if ( lvalue > 0 )
                                        printf( "= needs and lvalue" );
                        }
                        else if ( lvalue < 0 )
                                generate( T_POINT, 0 );
                        tkn = Token;
                        getoken();
                        if ( ! (lv = primary()) )
                                printf( "missing an operand" );
                        lvalue = op_prim( pr, lv );

                        if ( Token != T_ASSIGN && lvalue < 0 )
                        {
                                generate( T_POINT, 0 );
                                lvalue = 1;
                        }
                        else if ( tkn!=T_ASSIGN && Token==T_ASSIGN )
                        {
                                printf( "= needs an lvalue" );
                        }

                        generate( tkn, 0 );
                }
                else
                        break;
        }

        return lvalue;
}

int StringCalculator::primary()
{
        int rtn;

        if ( Eol )
                return 0;

        rtn = 1;

        switch ( Token )
        {
        case T_SYMBOL:        /* a symbol */
                generate( Token, Value, symbol_index );
                getoken();
                break;
        case T_CONST:        /* a constant */
                generate( Token, Value );
                getoken();
                break;
        case T_LPAR:        /* a parenthesized expression */
                getoken();
                expression();
                if ( Token != T_RPAR )
                {
                        printf( "missing ')'" );
                        rtn = 0;
                }
                else
                        getoken();
                break;
        case T_SUB:        /* unary - */
                getoken();
                expression();
                generate( T_NEG, 0 );
                break;
        case T_NOT:        /* unary ~ */
                getoken();
                expression();
                generate( T_NOT, 0 );
                break;
        case T_ADD:        /* unary + */
                getoken();
                expression();
                break;
        default:
                rtn = 0;
        }
        return rtn;
}

int StringCalculator::binop( char op )
{
        switch ( op )
        {
        case T_ADD:
        case T_SUB:
                return 7;
        case T_MUL:
        case T_DIV:
        case T_MOD:
                return 8;
        case T_NOT:
                return 9;
        }
        return 0;
}

void StringCalculator::generate( char tkn, double val, int index )
{
        if ( Opsp < STAKSZ )
        {
                Opstk[ Opsp ].o_token = tkn;
                Opstk[ Opsp ].o_value = val;
                Opstk[ Opsp ].symbol_index = index;
                ++Opsp;
        }
        else
                printf( "expression too complex" );
}
char StringCalculator::getoken(int* )
{
        char *cp, buf[ 128 ];

        if ( ! *Lineptr )
        {
                Eol = 1;
                Token = T_EOL;
        }
        else if ( isdigit( *Lineptr ) )
        {
                Token = T_CONST;
                for ( cp = buf; isdigit( *Lineptr ) || *Lineptr == '.'; )
                        *cp++ = *Lineptr++;
                *cp = 0;
                Value = atof(buf);
        }
        else if ( (Token = isbinop( &Lineptr )) )
        {
                ;
        }
        else if ( isalpha( *Lineptr ) )
        {
        Token = T_SYMBOL;
        symbol_index = toupper( *Lineptr ) - 'A';
        ++Lineptr;
        }
        else
        {
                printf( "bad syntax: %s", Lineptr );
                ++Lineptr;
        }


        return Token;
}

int StringCalculator::isbinop( char** cpp )
{
        int tkn=1;
        char c;

        c = **cpp;
        if ( c == ',' )
                tkn = T_COMMA;
        else if ( c == '=' )
                tkn = T_ASSIGN;
        else if ( c == '<' )
        {
                if ( *(++(*cpp)) == '<' )
                        tkn = T_SHL;
        }
        else if ( c == '>' )
        {
                if ( *(++(*cpp)) == '>' )
                        tkn = T_SHR;
        }
        else if ( c == '(' )
                tkn = T_LPAR;
        else if ( c == ')' )
                tkn = T_RPAR;
        else if ( c == '*' )
                tkn = T_MUL;
        else if ( c == '/' )
                tkn = T_DIV;
        else if ( c == '+' )
                tkn = T_ADD;
        else if ( c == '-' )
                tkn = T_SUB;
        else
                tkn = 0;

        if ( tkn )
                ++(*cpp);

        return tkn;
}

No comments:

Post a Comment