Friday, July 1, 2011

INFIX to POSTFIX conversion


#define MAX 255

struct list
{
    char c;                     //store a character here
    struct list *prev;          //pointer to previou element
};

struct stack
{
    struct list *top;           //stack top pointer
    struct list *start;         //stack start(base) pointer
};

void push(struct stack *top,char c);
void pop(struct stack *top, char *c);

void push(struct stack *stk, char c)
{
    struct list *temp;

    temp = (struct list*)malloc(1*sizeof(struct list));
    temp->c = c;
    temp->prev = stk->top;
    stk->top = temp;
}

void pop(struct stack *stk,char *c)
{
    struct list *temp;

    *c = stk->top->c;
    temp = stk->top;
    stk->top = temp->prev;
    free(temp);
}

//precedence function for operators
int prec(char a);

char* to_postfix(char *str)
{
    struct stack stk;
    char post[MAX],*p,ch,*backup;

    //post[] is a string that will have post fix string
    //p is pointer to it.
    //backup is a pointer to input string that will be user later to copy post[] to *str
    p = post;
    backup = str;

    //create a stack
    stk.start = (struct list*)malloc(1*sizeof(struct list));
    //initially start == top
    stk.top = stk.start;
    //since no item is in stack prev of both top & stack is NULL
    stk.start->prev = NULL;
    stk.top->prev = NULL;

    while(*str!='\0')
    {
        //if operand add it to o/p string
        if( isalnum(*str) )
            *p++ = *str++;

        else if(*str == '(' || *str == '+' || *str == '-' || *str == '*' || *str == '/')
        {
            //if '(' push it directly
            if( *str == '(' )
                push(&stk,*str++);
            //push higher precedence operator
            else if( stk.start==stk.top || (prec(*str) > prec(stk.top->c)))
                push(&stk,*str++);
            else
            {
                //pop operators from stack till we get lesser precedence operator or empty stack
                while( ( prec(*str) <= prec(stk.top->c) ) && (stk.top != stk.start) )
                    pop(&stk,p++);
                //now push current opreator from i/p string
                push(&stk,*str++);
            }
        }

        //if closing bracket in input string encountered
        else if(*str == ')' )
        {
            //then while we encounter opening bracket or reach start of stack
            while(stk.top != stk.start)
            {
                if(stk.top->c == '(')
                {
                    //just pop ')' in a dummy variable and break out of loop
                    pop(&stk,&ch);
                    break;
                }
                else
                    //keep popping operators and adding to o/p string if '(' not found
                    pop(&stk,p++);
            }
            //check that last item popped was a matching '('
            if(ch != '(')
            {
                printf("\nERROR: ')' NOT MATCHED...EXITING\n");
                exit(1);
            }
            //go to next char in input string on matching ')'
            str++;
        }
        //ignore white spaces
        else if(*str == ' ' || *str == '\t')
            str++;
        //if unexpected operator then exit
        else
        {
            printf("\n\nERROR : \"%c\" -> WRONG INPUT...EXITING\n",*str);
            exit(1);
        }
    }

    //now pop any remaing opeartors in stack and add them to o/p string
    while(stk.top != stk.start)
    {
        pop(&stk,p);
        //check that last item popped was a matching '('
        //if so then we have extra '('
        if(*p == '(')
        {
            printf("\nERROR: '(' NOT MATCHED...EXITING\n");
            exit(1);
        }
        p++;
    }

    *p = '\0';
    //now we need to copy because post[] is destroyed and can be overwritten
    //as soon as we return from this function
    strcpy(backup,post);
    return backup;
}

int prec(char a)
{
    //make '(' lowest precedence so that it is not popped by any other opeartor
    if(a=='(')
        return 1;
    if(a == '+' || a == '-')
        return 2;
    else if (a == '/' || a == '*')
        return 3;

    return 0;
}


No comments:

Post a Comment