To run the main code, go to the directory containing the files and run the following commands on bash/terminal.
- gcc -o main central_code.c infixtopostfix.c parsetree.c
- ./main
- gcc -o test unittests.c parsetree.c infixtopostfix.c
- ./test
| #include <stdio.h> | |
| #include <string.h> | |
| // Double quotes as we get this header file from local repository | |
| #include "infixtopostfix.h" // For infix to postfix conversion functions | |
| #include "parsetree.h" // For converting postfix to parse tree functions | |
| #define MAXSIZE 4000 | |
| char storeInfix[MAXSIZE], storePostfix[MAXSIZE]; | |
| int top; | |
| struct treeNode *storeTreeRoot; | |
| int main() | |
| { | |
| // Note - How difficult is it to implement a is-infix-expression checker? | |
| // The above is not required as it has been guaranteed that input is a proper infix expression. | |
| // However, due to the use of isalnum(), any other character besides the 4 defined operators will be | |
| // treated as an operand | |
| printf("Please enter an infix expression\n"); | |
| scanf("%s", storeInfix); | |
| // The Infix to Postfix Section | |
| inToPostfix(storeInfix, storePostfix); | |
| printf("\nGiven Infix Expression: %s \nPostfix Expression: %s\n",storeInfix, storePostfix); | |
| // Feed Postfix to ParseTree Section | |
| storeTreeRoot = postfixToTree(storePostfix); | |
| printf("Postfix Expression has been converted into rooted binary parse tree"); | |
| // Get back our infix expression | |
| printf("\n Our original Infix Expression :"); | |
| inOrderTraversal(storeTreeRoot); | |
| printf("\n"); | |
| return 0; | |
| } |
| #include "infixtopostfix.h" | |
| // The following functions are for converting from Prefix to PostFix Expression | |
| // arrstk_x means arraystack_x, pointing to stack operations happening on array | |
| // Gives a initial value to the top of stack | |
| void arrstk_initialize(int *top) | |
| { | |
| *top = 0; | |
| } | |
| // Pop the topmost element of stack (by changing where top points) | |
| int arrstk_pop(char *stack, int *top) | |
| { | |
| return stack[(*top)--]; | |
| } | |
| // Add an element to the stack, it will replace any other element that was at that | |
| // array index | |
| void arrstk_push(char *stack, int* top, char elem) | |
| { | |
| stack[++(*top)] = elem; | |
| } | |
| // Precedence of operators checker | |
| int oper_prec(char opr) | |
| { | |
| switch(opr) | |
| { | |
| case '(': return 1; | |
| case '>': return 2; | |
| case '+': return 3; | |
| case '*': return 4; | |
| case '~': return 5; | |
| default : return 0; | |
| } | |
| } | |
| // Check if stack is empty | |
| int arrstk_empty(int *top) | |
| { | |
| return *top == 0 ? 1 : 0; | |
| } | |
| // The Infix to PostFix Function | |
| void inToPostfix(char *arg_inFix, char *arg_postfix) | |
| { | |
| char arr_stack[4000]; // The max size of the expression that we consider | |
| int stack_top, infix_iter = 0, postfix_iter=-1; //The indicies for our arrays | |
| char checker, element; | |
| arrstk_initialize(&stack_top); | |
| while((checker = arg_inFix[infix_iter++]) != '\0') | |
| { | |
| if( checker == '(') // If '(' then push on stack | |
| { | |
| arrstk_push(arr_stack, &stack_top, checker); | |
| } | |
| else if(isalnum(checker)) // If an operand then send to postfix | |
| { | |
| arg_postfix[++postfix_iter] = checker; | |
| } | |
| // For closing bracket pop elements from stack and send to postfix | |
| else if(checker == ')') | |
| { while((arr_stack[stack_top] != '(')) | |
| { | |
| arg_postfix[++postfix_iter] = arrstk_pop(arr_stack, &stack_top); | |
| } | |
| arrstk_pop(arr_stack, &stack_top); | |
| } | |
| // It is an operator | |
| else | |
| { | |
| while(!arrstk_empty(&stack_top) && (oper_prec(arr_stack[stack_top]) >= oper_prec(checker))) | |
| { | |
| arg_postfix[++postfix_iter] = arrstk_pop(arr_stack, &stack_top); | |
| } | |
| arrstk_push(arr_stack, &stack_top, checker); | |
| } | |
| } | |
| while(stack_top != 0) | |
| { | |
| arg_postfix[++postfix_iter] = arrstk_pop(arr_stack, &stack_top); | |
| } | |
| arg_postfix[++postfix_iter]='\0'; | |
| } |
| // The purpose of this header file is to store minimum practical interface to a corresponding | |
| // .c file, including function declarations used in multiple source files. | |
| /* However, the declarations here are used in only one source file currently. | |
| They are still kept here for convenience and as they maybe required for multiple | |
| source files in the future (for later assignments) | |
| */ | |
| #ifndef _INFIXTOPOSTFIX_H_ /* Include guard */ | |
| #define _INFIXTOPOSTFIX_H_ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| // Functions for the array stack | |
| void arrstk_initialize(int *top); | |
| // Pop the topmost element of stack | |
| int arrstk_pop(char *stack, int *top); | |
| // Push an element into the stack | |
| void arrstk_push(char *stack, int* top, char elem); | |
| // Function to check precedence | |
| int oper_prec(char opr); | |
| // To check if stack is empty | |
| int arrstk_empty(int *top); | |
| // Infix to Postfix function | |
| void inToPostfix(char *arg_inFix, char *arg_postfix); | |
| #endif |
| #include "parsetree.h" | |
| // strstk_x means structurestack_x, pointing to stack operations happening on the treeNode structure | |
| void strstk_initialize(int *top) | |
| { | |
| *top = 0; | |
| } | |
| struct treeNode* strstk_pop(struct treeNode* *stack, int *top) | |
| { | |
| return stack[(*top)--]; | |
| } | |
| void strstk_push(struct treeNode* *stack, int* top, struct treeNode* elem) | |
| { | |
| stack[++(*top)] = elem; | |
| } | |
| struct treeNode* addNewNode(char nodeValue) | |
| { | |
| // Memory allocation syntax is [type - malloc - size ] | |
| struct treeNode *currentNode = (struct treeNode *) malloc(sizeof(struct treeNode)); | |
| currentNode->parentNode = NULL; | |
| currentNode->value = nodeValue; | |
| // Seperate functions allocate memory to these subtrees | |
| currentNode->childNode_Left = NULL; | |
| currentNode->childNode_Right = NULL; | |
| return currentNode; | |
| } | |
| struct treeNode* postfixToTree(char arg_postfix[]) | |
| { | |
| // A frustrating treenode* a,b versus treenode *a,*b bug was here | |
| struct treeNode *mainStore, *secondaryStore1, *secondaryStore2; | |
| struct treeNode *str_stack[4000]; // Return of the stack | |
| int stack_top, treeIter, store_element; // And it's top position | |
| strstk_initialize(&stack_top); | |
| for (treeIter=0; treeIter < 4000; treeIter++) | |
| { | |
| store_element = arg_postfix[treeIter]; | |
| if(store_element == '\0') | |
| break; | |
| // The standard function `isalnum` returns 1 if the argument is | |
| // alpha-numeric, else zero | |
| if (isalnum(store_element)) | |
| { // For now, just push any operand onto the stack | |
| mainStore = addNewNode(arg_postfix[treeIter]); | |
| strstk_push(str_stack, &stack_top, mainStore); | |
| } | |
| // Special negation shenanigans | |
| else if (store_element == '~') | |
| { | |
| mainStore = addNewNode(arg_postfix[treeIter]); | |
| // Pop only one node since it's negation | |
| secondaryStore1 = strstk_pop(str_stack, &stack_top); | |
| // Store the element, the left child remains NULL | |
| mainStore->childNode_Right = secondaryStore1; | |
| // Add this subexpression to stack | |
| strstk_push(str_stack, &stack_top, mainStore); | |
| } | |
| else // If we have operators other than negation | |
| { | |
| mainStore = addNewNode(arg_postfix[treeIter]); | |
| // Pop two top nodes | |
| secondaryStore1 = strstk_pop(str_stack, &stack_top); | |
| secondaryStore2 = strstk_pop(str_stack, &stack_top); | |
| // Store them as children of the current node | |
| mainStore->childNode_Right = secondaryStore1; | |
| mainStore->childNode_Left = secondaryStore2; | |
| // Add this subexpression to stack | |
| strstk_push(str_stack, &stack_top, mainStore); | |
| } | |
| } | |
| // only element will be root of expression | |
| // tree | |
| mainStore = strstk_pop(str_stack, &stack_top); | |
| return mainStore; | |
| } | |
| // Finally, let's get back our Infix expression by in-order traversal of tree | |
| // With some friendly recursion | |
| void inOrderTraversal(struct treeNode *Node) | |
| { | |
| if(Node != NULL) | |
| { | |
| // Parenthesis printf's added | |
| if(!(Node->childNode_Left == NULL) || !(Node->childNode_Right == NULL)) | |
| printf("("); | |
| inOrderTraversal(Node->childNode_Left); | |
| printf("%c", Node->value); | |
| inOrderTraversal(Node->childNode_Right); | |
| if(!(Node->childNode_Left == NULL) || !(Node->childNode_Right == NULL)) | |
| printf(")"); | |
| /* | |
| NOTE - | |
| An important point to note is that the infix expression we gave | |
| as input and the infix expression we get from in-order traversal will have some | |
| difference in number of parenthesis. This is because information is lost due to | |
| conversion of the expression to postfix. | |
| And so, | |
| Infix Input 1: A+(B*C+(D*E+F)*G)*H | |
| Infix Input 2: (A+(((B*C)+(((D*E)+F)*G))*H)) | |
| both will give In-Order Traversal Infix as (A+(((B*C)+(((D*E)+F)*G))*H)) | |
| */ | |
| } | |
| } |
| #ifndef _PARSETREE_H_ /* Include guard */ | |
| #define _PARSETREE_H_ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| // The structure (of nodes) to hold the parse tree | |
| struct treeNode | |
| { | |
| char value; | |
| struct treeNode *parentNode; | |
| struct treeNode *childNode_Left; | |
| struct treeNode *childNode_Right; | |
| }; | |
| void strstk_initialize(int *top); | |
| struct treeNode* strstk_pop(struct treeNode* *stack, int *top); | |
| void strstk_push(struct treeNode* *stack, int* top, struct treeNode* elem); | |
| struct treeNode* addNewNode(char nodeValue); | |
| struct treeNode* postfixToTree(char arg_postfix[]); | |
| void inOrderTraversal(struct treeNode *Node); | |
| #endif |
| /* | |
| This is an additional C file that is used for testing the code of the main file. | |
| A standard practice in open source development, unit testing helps detect errors and | |
| hidden problems in the code. | |
| */ | |
| #include <stdio.h> | |
| #include "unittests.h" | |
| #include "parsetree.h" | |
| #include "infixtopostfix.h" | |
| // No of tests (runs) | |
| int tests_run = 0; | |
| int finalInfix_Iter = 0; | |
| char storePostfix[100]; | |
| char finalInfix[100]; | |
| // Test 1 | |
| static char * testCase1() | |
| { | |
| char storeInfix1[] = "A+(B*C)"; | |
| inToPostfix(storeInfix1, storePostfix); | |
| assert_test("Test Case 1 fails for postfix expression!", strcmp(storePostfix, "ABC*+") == 0); | |
| return 0; | |
| } | |
| // Test 2 | |
| static char * testCase2() | |
| { | |
| char storeInfix2[] = "A+(B*C+(D*E+F)*G)*H"; | |
| inToPostfix(storeInfix2, storePostfix); | |
| assert_test("Test Case 2 fails for postfix expression!", strcmp(storePostfix, "ABC*DE*F+G*+H*+") == 0); | |
| return 0; | |
| } | |
| static char * testCase3() | |
| { | |
| char storeInfix3[] = "P*~(P+~Q)>(R>S)"; | |
| inToPostfix(storeInfix3, storePostfix); | |
| assert_test("Test Case 3 fails for postfix expression!", strcmp(storePostfix, "PPQ~+~*RS>>") == 0); | |
| return 0; | |
| } | |
| static char * all_tests() { | |
| run_test(testCase1); | |
| run_test(testCase2); | |
| run_test(testCase3); | |
| return 0; | |
| } | |
| int main(int argc, char **argv) { | |
| char *result = all_tests(); | |
| if (result != 0) { | |
| printf("%s\n", result); | |
| } | |
| else { | |
| printf("\nALL TESTS PASS\n"); | |
| } | |
| printf("Tests run: %d\n", tests_run); | |
| return result != 0; | |
| } |
| /* | |
| Unit testing of the code for a better code, a better assignment and a better future. | |
| Reference material - http://www.jera.com/techinfo/jtns/jtn002.html | |
| */ | |
| #ifndef _UNITTESTS_H_ /* Include guard */ | |
| #define _UNITTESTS_H_ | |
| #define assert_test(message, test) do { if (!(test)) return message; } while (0) | |
| #define run_test(test) do { char *message = test(); tests_run++; if (message) return message; } while (0) | |
| extern int tests_run; | |
| #endif |