Input There are two input files course data and queries See
Input:
There are two input files: course data and queries. See cs2123p2Driver.c for more information.
Read the infix expressions
Convert the infix to postfix
Evaluate the postfix expression, producing an array of booleans (one entry for each course).
Print the infix expression, the postfix form of the expression, and evaluated result. The driver does this.
Approaches for Evaluating Operators
Approach #1: Iterate over the list of courses and then evaluate the query for each course. The operator evaluation result is simply true or false (since only one course is considered).
For N courses, this approach evaluates the same query N times.
The operator result (i.e., a boolean) must be stacked.
Additional functions provided:
void printQueryResult(Course courseM[], int iNumCourse, QueryResult resultM[])
Prints the courses which have a corresponding element in the resultM array turned on.
int never(Course *pCourse, Attr attr)
Determines whether a course has a particular attribute (type and value). If it doesn\'t, never returns TRUE; otherwise, it returns FALSE.
int getCourseData(Course courseM[])
Gets course data and their corresponding attributes (type and values).
Use of union
Since the evaluation needs two types of elements, we will use union as shown in the include file.
Some Files for your use:
p2Query.txt - data file containing infix expressions which are evaluated as queries
p2Course.txt - course data file similar to program #0.
cs2123p2.h - include file for Program #2
cs2123p2Driver.c - driver program that I provided. It has several useful routines to help reduce your effort. Please review this code
Your coding:
Create your code in cs2123p2.c (not cs2123p2Driver.c). Based on what the driver calls, you need to create these functions:
int convertToPostFix(char *pszInfix, Out out)
It returns 0 if it converted successfully. Otherwise, it returns a value which indicates an error in
the infix data (e.g., missing left paren, missing right paren)
It populates the out array using the addOut function (provided in the driver).
void printCourseData(Course courseM[], int iNumCourse)
This was done in program #0.
void evaluatePostfix(PostfixOut out, Course courseM[], int iNumCourse
, QueryResult resultM[])
This evaluates a postfix expression (which is in out) using the courseM array. For each course satisfying the posftfix query,
it sets its corresponding position in resultM to TRUE.
int atLeastOne(Course *pCourse, Attr attr)
Determines whether a course has a particular attribute (type and value). If it does, atLeastOne returns TRUE; otherwise, it returns FALSE.
int only(Course *pCourse, Attr attr)
This looks at EACH attribute in the course\'s attrM array for the specified course. If the attribute\'s szAttrType matches the specified szAttrType, then its corresponding szAttrValue must match the specfied attribute value. If it doesn\'t match the attribute value, FALSE is returned. only examines each of the attributes for the specified course.
You will also have to provide code for AND and OR.
Requirements:
You should not have to modify cs2123p2Driver.c.
Make certain you free up allocated memory (e.g., stack).
Sample Output (partial):
ID Course Name
Attr Value
CS1083 Intro I
LANG JAVA
PROF ROBBINS
PROF HOLLAND
PROF SHERETTE
PROF ROBINSON
PROF ZHU
RECIT N
DEPT CS
MAT2233 Discrete Math
PREREQ MAT1214
PREREQ CS1713
PROF SHERETTE
PROF TANG
RECIT N
DEPT MAT
MAT3333 Math Found
PREREQ MAT1223
PREREQ CS1713
PROF SHERETTE
PROF TANG
RECIT N
DEPT MAT
CS1713 Intro II
PREREQ CS1083
LANG C
PROF CLARK
PROF HOLLAND
PROF SHERETTE
PROF ROBINSON
PROF ZHU
RECIT Y
DEPT CS
CS2123 Data Structures
PREREQ CS1713
LANG C
PROF CLARK
PROF SHERETTE
PROF ROBINSON
PROF KORKMAZ
PROF TOSUN
RECIT Y
DEPT CS
CS3843 Comp Org
PREREQ CS2123
LANG C
LANG IA32
PROF CLARK
PROF TIAN
PROF MUZAHID
RECIT Y
DEPT CS
CS3723 Pgm Lang
PREREQ CS3443
PREREQ MAT2233
LANG C
LANG CPP
LANG JAVA
LANG LISP
LANG PYTHON
PROF CLARK
RECIT N
DEPT CS
CS3423 Sys Pgm
PREREQ CS2123
PROF MAYNARD
PROF LAMA
PROF CLARK
LANG C
LANG PERL
LANG BASH
RECIT Y
DEPT CS
CS3443 App Pgm
PREREQ CS2123
PROF BYLANDER
PROF ROBINSON
PROF NIU
RECIT N
DEPT CS
LANG JAVA
CS4713 Compiler
PREREQ CS3723
PREREQ CS3843
PROF CLARK
RECIT N
DEPT CS
LANG JAVA
CS3343 Anlys of Algo
PREREQ CS2123
PREREQ MAT3333
PREREQ MAT2233
PROF SHERETTE
PROF GIBSON
PROF BYLANDER
RECIT Y
DEPT CS
LANG JAVA
Query # 1: RECIT = N
RECIT N =
Query Result:
ID Course Name
CS1083 Intro I
MAT2233 Discrete Math
MAT3333 Math Found
CS3723 Pgm Lang
CS3443 App Pgm
CS4713 Compiler
Query # 2: RECIT = Y
RECIT Y =
Query Result:
ID Course Name
CS1713 Intro II
CS2123 Data Structures
CS3843 Comp Org
CS3423 Sys Pgm
CS3343 Anlys of Algo
Query # 3: PROF = CLARK
PROF CLARK =
Query Result:
ID Course Name
CS1713 Intro II
CS2123 Data Structures
CS3843 Comp Org
CS3723 Pgm Lang
CS3423 Sys Pgm
CS4713 Compiler
Query # 4: PROF NEVER CLARK
PROF CLARK NEVER
Query Result:
ID Course Name
CS1083 Intro I
MAT2233 Discrete Math
MAT3333 Math Found
CS3443 App Pgm
CS3343 Anlys of Algo
Query # 5: PROF ONLY CLARK
PROF CLARK ONLY
Query Result:
ID Course Name
CS3723 Pgm Lang
CS4713 Compiler
Query # 6: PROF = CLARK AND RECIT = N
PROF CLARK = RECIT N = AND
Query Result:
ID Course Name
CS3723 Pgm Lang
CS4713 Compiler
Input files
p2Course.txt
p2Query.txt
Solution
cs2123p2Driver.c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include \"cs2123p2.h\"
static struct
 {
     char szSymbol[MAX_TOKEN + 1];   // token symbol such as \"(\"
     int iCategory;                  // CAT_OPERATOR, CAT_OPERAND, CAT_LPAREN or CAT_RPAREN
     int iPrecedence;                // 0 - lowest precedence, 3 - highest precedence
 } symbolDefM[] =
 {
       {\"(\",      CAT_LPAREN,   0}
     , {\")\",      CAT_RPAREN,   0}
     , {\"=\",      CAT_OPERATOR, 2}
     , {\"NEVER\", CAT_OPERATOR, 2}
     , {\"ONLY\",   CAT_OPERATOR, 2}
     , {\"AND\",    CAT_OPERATOR, 1}
     , {\"OR\",     CAT_OPERATOR, 1}
     , {\"\", 0, 0}
 };
 void push(Stack stack, Element value)
 {
     if (stack->iCount >= MAX_STACK_ELEM)
         ErrExit(ERR_STACK_USAGE
         , \"Attempt to PUSH more than %d values on the array stack\"
         , MAX_STACK_ELEM);
    stack->stackElementM[stack->iCount] = value;
     stack->iCount++;
 }
 Element pop(Stack stack)
 {
     if (isEmpty(stack))
         ErrExit(ERR_STACK_USAGE
         , \"Attempt to POP an empty array stack\");
     stack->iCount--;
     return stack->stackElementM[stack->iCount];
}
 Element topElement(Stack stack)
 {
     if (isEmpty(stack))
         ErrExit(ERR_STACK_USAGE
         , \"Attempt to examine topElement of an empty array stack\");
     return stack->stackElementM[stack->iCount-1];    // return the top
 }
 int isEmpty(Stack stack)
 {
     return stack->iCount <= 0;
 }
Stack newStack()
 {
     Stack stack = (Stack) malloc(sizeof(StackImp));
     stack->iCount = 0;
     return stack;
 }
void freeStack(Stack stack)
 {
     free (stack);
 }
 FILE *pFileCourse;    // Used with the -c Course File
 FILE *pFileQuery;       // Used with the -q Query File
 int main(int argc, char *argv[])
 {
     Course courseM[MAX_COURSE];     // Course array
     int iNumberOfCourses = 0;       // Number of courses
     char *pszCourseFileNm = NULL;     // Pointer to an argv[] for course file name
     char *pszQueryFileNm = NULL;        // Pointer to an argv[] for query file name
     processCommandSwitches(argc, argv, &pszCourseFileNm, &pszQueryFileNm);
    if (pszCourseFileNm == NULL)
         exitUsage(USAGE_ERR, ERR_MISSING_SWITCH, \"-c\");
     pFileCourse = fopen(pszCourseFileNm, \"r\");
     if (pFileCourse == NULL)
         exitUsage(USAGE_ERR, \"Invalid course file name, found \"
         , pszCourseFileNm);
     if (pszQueryFileNm == NULL)
         exitUsage(USAGE_ERR, ERR_MISSING_SWITCH, \"-q\");
     pFileQuery = fopen(pszQueryFileNm, \"r\");
     if (pFileQuery == NULL)
         exitUsage(USAGE_ERR, \"Invalid query file name, found \"
         , pszQueryFileNm);
     iNumberOfCourses = getCourseData(courseM);
     fclose(pFileCourse);
     printCourseData(courseM, iNumberOfCourses);
     readAndProcessQueries(courseM, iNumberOfCourses);
     fclose(pFileQuery);
     printf(\"\ \");
     fclose(stdout);
     return 0;
 }
 void readAndProcessQueries(Course courseM[], int iNumberOfCourses)
 {
     PostfixOut postfixOut = malloc(sizeof(PostfixOutImp));
     QueryResult queryResultM[MAX_COURSE];
     char szInputBuffer[100];            // entire input line
     int rc;
     int iLineCount = 0;
     while (fgets(szInputBuffer, 100, pFileQuery) != NULL)
     {
         iLineCount++;
         if (szInputBuffer[0] == \'\ \')
             continue;
         printf(\"Query # %d: %s\", iLineCount, szInputBuffer);
         postfixOut->iPostfixOutCount = 0;   // reset out to empty
         rc = convertToPostfix(szInputBuffer, postfixOut);
         switch (rc)
         {
             case 0: // ok so print the postfix and evaluate it
                 printPostfixOut(postfixOut);
                 evaluatePostfix(postfixOut, courseM, iNumberOfCourses, queryResultM);
                 printQueryResult(courseM, iNumberOfCourses, queryResultM);
                 break;
             case WARN_MISSING_LPAREN:
                 printf(\"\\tWarning: missing left parenthesis\ \");
                 break;
             case WARN_MISSING_RPAREN:
                 printf(\"\\tWarning: missing right parenthesis\ \");
                 break;
             case WARN_MISSING_OPERATOR:
                 printf(\"\\tWarning: missing operator\ \");
                 break;
             case WARN_MISSING_OPERAND:
                 printf(\"\\tWarning: missing operand\ \");
                 break;
             default:
                 printf(\"\\t warning = %d\ \", rc);
         }
       
     }
     printf(\"\ \");
     free(postfixOut);
 }
 void printQueryResult(Course courseM[], int iNumCourse, QueryResult resultM[])
 {
     int i;
     printf(\"\\tQuery Result:\ \");
     printf(\"\\t%-7s %-20s\ \", \"ID\", \"Course Name\");
     for (i = 0; i < iNumCourse; i++)
     {
         if (resultM[i])
             printf(\"\\t%-7s %-20s\ \", courseM[i].szCourseId
                 , courseM[i].szCourseName);
     }
 }
 int never(Course *pCourse, Attr attr)
 {
     int i = 100;
     if (pCourse == NULL)
         ErrExit(ERR_ALGORITHM
         , \"function never() received a NULL pointer\");
     for (i = 0; i < (pCourse->iNumberOfAttrs); i++)
     {
         if (strcmp(pCourse->attrM[i].szAttrType, attr.szAttrType) == 0
             && strcmp(pCourse->attrM[i].szAttrValue, attr.szAttrValue) == 0)
             return FALSE;
     }
     return TRUE;
 }
 void addPostfixOut(PostfixOut postfixOut, Element element)
 {
     if (postfixOut->iPostfixOutCount >= MAX_OUT_ITEM)
         ErrExit(ERR_OUT_OVERFLOW
         , \"Overflow in the postfixOut array\");
     postfixOut->postfixOutM[postfixOut->iPostfixOutCount] = element;
     postfixOut->iPostfixOutCount++;
 }
 void printPostfixOut(PostfixOut postfixOut)
 {
     int i;
     if (postfixOut == NULL)
     {
         printf(\"*** ERROR PostfixOut is NULL\ \");
         return;
     }
     printf(\"\\t\");
     for (i = 0; i < postfixOut->iPostfixOutCount; i++)
     {
         printf(\"%s \", postfixOut->postfixOutM[i].szToken);
         if ((i + 1) % 18 == 0)
             printf(\"\ \\t\");
     }
     printf(\"\ \");
 }
 void categorize(Element *pElement)
 {
     int i;
     for (i = 0; symbolDefM[i].szSymbol[0] != \'\\0\'; i++)
     {
         if (strcmp(pElement->szToken, symbolDefM[i].szSymbol) == 0)
         {   // matched, so use its precedence and category
             pElement->iPrecedence = symbolDefM[i].iPrecedence;
             pElement->iCategory = symbolDefM[i].iCategory;
             return;
         }
     }
     pElement->iPrecedence = 0;
     pElement->iCategory = CAT_OPERAND;
 }
 int getCourseData(Course courseM[])
 {
     char szInputBuffer[MAX_LINE_SIZE + 1]; // input buffer for fgets
    int iNumAttr = 0;                       // Number of attributes for the current course
     char szRecordType[11];                  // record type of either COURSE or ATTR
     int i = -1;                             // current course subscript. -1 indicates
                                             // not on a course yet
     int iScanfCnt;                          // scanf returns the number of successful inputs
     char *pszRemainingTxt;                  // After grabbing a token, this is the next
                                             // position. This will be after the delimiter
                                             // unless the string was terminated by a zero
                                             // byte, then it will be on the zero byte.
     while (fgets(szInputBuffer, MAX_LINE_SIZE, pFileCourse) != NULL)
     {
         if (szInputBuffer[0] == \'\ \')
             continue;
         pszRemainingTxt = getToken(szInputBuffer, szRecordType, sizeof(szRecordType) - 1);
         if (strcmp(szRecordType, \"COURSE\") == 0)
         {
             i++;
             if (i >= MAX_COURSE)
                 ErrExit(ERR_TOO_MANY_COURSE
                 , \"Invalid input file, max courses is %d\"
                 , MAX_COURSE);
             iNumAttr = 0;   // since we have a new course, reset his/her number of attributes
             courseM[i].iNumberOfAttrs = iNumAttr;
             iScanfCnt = sscanf(pszRemainingTxt, \"%7s %20[^\ ]\ \"
                 , courseM[i].szCourseId
                 , courseM[i].szCourseName);
             if (iScanfCnt < 2)
             {
                 WARNING(\"Expected ID and name, received %d successful values\ Input text: %s\ \"
                     , iScanfCnt, szInputBuffer);
                 continue;
             }
         }
         else if (strcmp(szRecordType, \"ATTR\") == 0)
         {
             if (i < 0)
                 ErrExit(ERR_BAD_COURSE
                 , \"ATTR record without COURSE\ Input Text: %s\ \"
                 , szInputBuffer);
             // what if we have too many attributes
             if (iNumAttr >= MAX_ATTR)
                 ErrExit(ERR_BAD_COURSE
                 , \"Too many attributes for Course ID %s, only %d attributes allowed\"
                 , courseM[i].szCourseId
                 , MAX_ATTR);
             iScanfCnt = sscanf(pszRemainingTxt, \"%10s %12s\"
                 , courseM[i].attrM[iNumAttr].szAttrType
                 , courseM[i].attrM[iNumAttr].szAttrValue);
             // Check for bad input. scanf returns the number of valid conversions
             if (iScanfCnt < 2)
             {
                 WARNING(
                     \"Expected attribute type and value, received %d successful values\"
                     , iScanfCnt);
                 continue;
             }
             iNumAttr++;
             courseM[i].iNumberOfAttrs = iNumAttr;
         }
         else
         {
             WARNING(\"Bad Command in input, found \'%s\'\"
                 , szRecordType);
             continue;
         }
     }
     return i + 1;
 }
 void processCommandSwitches(int argc, char *argv[], char **ppszCourseFileName
     , char **ppszQueryFileName)
 {
     int i;
     // Examine each of the command arguments other than the name of the program.
     for (i = 1; i < argc; i++)
     {
         // check for a switch
         if (argv[i][0] != \'-\')
             exitUsage(i, ERR_EXPECTED_SWITCH, argv[i]);
         // determine which switch it is
         switch (argv[i][1])
         {
         case \'c\':                   // Course File Name
             if (++i >= argc)
                 exitUsage(i, ERR_MISSING_ARGUMENT, argv[i - 1]);
             // check for too long of a file anme
             else
                 *ppszCourseFileName = argv[i];
             break;
         case \'q\':                   // Query File Name
             if (++i >= argc)
                 exitUsage(i, ERR_MISSING_ARGUMENT, argv[i - 1]);
             else
                 *ppszQueryFileName = argv[i];
             break;
         case \'?\':
             exitUsage(USAGE_ONLY, \"\", \"\");
             break;
         default:
             exitUsage(i, ERR_EXPECTED_SWITCH, argv[i]);
         }
     }
 }
void ErrExit(int iexitRC, char szFmt[], ... )
 {
     va_list args;               // This is the standard C variable argument list type
     va_start(args, szFmt);      // This tells the compiler where the variable arguments
                                 // begins. They begin after szFmt.
     printf(\"ERROR: \");
     vprintf(szFmt, args);       // vprintf receives a printf format string and a
                                 // va_list argument
     va_end(args);               // let the C environment know we are finished with the
                                 // va_list argument
     printf(\"\ \\tEncountered in file %s\ \", __FILE__); // this 2nd arg is filled in by
                                 // the pre-compiler
     exit(iexitRC);
 }
 void exitUsage(int iArg, char *pszMessage, char *pszDiagnosticInfo)
 {
     switch (iArg)
     {
         case USAGE_ERR:
             fprintf(stderr, \"Error: %s %s\ \"
                 , pszMessage
                 , pszDiagnosticInfo);
             break;
         case USAGE_ONLY:
             break;
         default:
             fprintf(stderr, \"Error: bad argument #%d. %s %s\ \"
                 , iArg
                 , pszMessage
                 , pszDiagnosticInfo);
     }
     // print the usage information for any type of command line error
     fprintf(stderr, \"p2 -c courseFileName -q queryFileName\ \");
     if (iArg == USAGE_ONLY)
         exit(USAGE_ONLY);
     else
         exit(ERR_COMMAND_LINE);
 }
 char * getToken(char *pszInputTxt, char szToken[], int iTokenSize)
 {
     int iDelimPos;                      // found position of delim
     int iCopy;                          // number of characters to copy
     char szDelims[20] = \" \ \ \";        // delimiters
     szToken[0] = \'\\0\';
     if (pszInputTxt == NULL)
         ErrExit(ERR_ALGORITHM
         , \"getToken passed a NULL pointer\");
     if (*pszInputTxt == \'\\0\')
         return NULL;
     iDelimPos = strcspn(pszInputTxt, szDelims);
     if (iDelimPos == 0)
         return NULL;
     if (iDelimPos > iTokenSize)
         iCopy = iTokenSize;             // truncated size
     else
         iCopy = iDelimPos;
     memcpy(szToken, pszInputTxt, iCopy);
     szToken[iCopy] = \'\\0\';              // null terminate
    // advance the position
     pszInputTxt += iDelimPos;
     if (*pszInputTxt == \'\\0\')
         return pszInputTxt;
     else
         return pszInputTxt + 1;
 }
 cs2123p2.h
#define MAX_STACK_ELEM 20          // Maximum number of elements in the stack array
 #define MAX_TOKEN 50               // Maximum number of actual characters for a token
 #define MAX_OUT_ITEM 50            // Maximum number of PostfixOut items
 #define MAX_COURSE 30              // Maximum number of courses
 #define MAX_ATTR 12                // Maximum number of attributes per course     
 #define MAX_LINE_SIZE 100          // Maximum number of character per input line
 #define ERR_COMMAND_LINE    900    // invalid command line argument
 #define ERR_STACK_USAGE    901
 #define ERR_OUT_OVERFLOW   902
 #define ERR_ALGORITHM      903     // Unexpected error in algorithm
 #define ERR_TOO_MANY_COURSE 1      // Too many courses
 #define ERR_TOO_MANY_ATTR 2        // Too many attributes
 #define ERR_BAD_COURSE 3           // Bad Course Data
 #define ERR_MISSING_SWITCH          \"missing switch\"
 #define ERR_EXPECTED_SWITCH         \"expected switch, found\"
 #define ERR_MISSING_ARGUMENT        \"missing argument for\"
 #define USAGE_ONLY          0      // user only requested usage information
 #define USAGE_ERR           -1     // usage error, show message and usage information
 #define WARN_MISSING_RPAREN 801
 #define WARN_MISSING_LPAREN 802
 #define WARN_MISSING_OPERATOR 803
 #define WARN_MISSING_OPERAND 804
 #define CAT_LPAREN 1        // (
 #define CAT_RPAREN 2        // )
 #define CAT_OPERATOR 3      // Operators are =, NEVER, ONLY /
 #define CAT_OPERAND 4       // These are attribute types or values
 #define FALSE 0
 #define TRUE 1
typedef struct
 {
     char szAttrType[11];        // Attr Type can be one of:
     char szAttrValue[MAX_TOKEN+1];       // This corresponds to the Attr Type:
 } Attr;
 typedef struct
 {
     char szCourseId[8];               // Course Identifier
     char szCourseName[21];            // Course Full Name
     int iNumberOfAttrs;              // Particular number of attributes for each course
     Attr attrM[MAX_ATTR];
 } Course;
typedef int QueryResult;
int getCourseData(Course courseM[]);
 void printCourseData(Course courseM[], int iNumCourse);
 typedef char Token[MAX_TOKEN + 1];
 typedef union
 {
     struct
     {
         Token szToken;      // token from the query
         int iCategory;      // category CAT_LPAREN, CAT_RPAREN, CAT_OPERATOR, CAT_OPERAND
         int iPrecedence;    // operator precedence with 0 being lowest
     };
     struct
     {
         Token szBoolean;    // This is to aid in debugging
         int bInclude;       // TRUE - intermediate include result, FALSE - intermediate don\'t include
     };
 } Element;
 typedef struct
 {
     int iCount;             // number of elements in stack. 0 is empty
     Element stackElementM[MAX_STACK_ELEM];
 } StackImp;
 typedef StackImp *Stack;
 typedef struct
 {
     int iPostfixOutCount;
     Element postfixOutM[MAX_OUT_ITEM];
 } PostfixOutImp;
 typedef PostfixOutImp *PostfixOut;
void printCourseData(Course courseM[], int iNumCourse);
 int convertToPostfix(char *pszInfix, PostfixOut postfixOut);
 int PrintOutRest(Stack stack2, int bFoundOperand2, Element popped2, PostfixOut out2);
 void evaluatePostfix(PostfixOut postfixOut, Course courseM[], int iNumCourse, QueryResult resultM[]);
 int atLeastOne(Course *pCourse, Attr attr);
 int only(Course *pCourse, Attr attr);
 void operatorCheck(Stack stack, Element element, Element popped, PostfixOut postfixOut);
 void rightParentCheck(Stack stack, Element popped, PostfixOut postfixOut);
 void push(Stack stack, Element value);
 Element pop(Stack stack);
 int isEmpty(Stack stack);
 Stack newStack();
 void freeStack(Stack stack);
 Element topElement(Stack stack);
 void categorize(Element *pElement);
 void addPostfixOut(PostfixOut postfixOut, Element element);
 void printPostfixOut(PostfixOut postfixOut);
 void printQueryResult(Course courseM[], int iNumCourse, QueryResult resultM[]);
 int getCourseData(Course courseM[]);
 void readAndProcessQueries(Course courseM[], int iNumberOfCourses);
 int never(Course *pCourse, Attr attr);
 void processCommandSwitches(int argc, char *argv[], char **ppszCourseFileName
     , char **ppszQueryFileName);
 void exitUsage(int iArg, char *pszMessage, char *pszDiagnosticInfo);
 void ErrExit(int iexitRC, char szFmt[], ...);
 char * getToken(char *pszInputTxt, char szToken[], int iTokenSize);
#define WARNING(szFmt, ...) do {    \\
     printf(\"\\tWARNING: \");          \\
     printf(szFmt, __VA_ARGS__);     \\
     printf(\"\ \");                   \\
     } while (0)
   
 cs2123p2.c
#include \"cs2123p2.h\"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
void printCourseData(Course courseM[], int iNumCourse)
 {
     int i;
     int j;
     printf(\"%-8s %-21s\ \\t\\t\\t\\t\\t\\t %-7s %-8s\ \"
            ,\"ID\"
            ,\"Course Name\"
            ,\"Attr\"
            ,\"Value\");
   
     for (i = 0; i < iNumCourse; i++)
     {
         printf(\"%-8s %-21s\ \", courseM[i].szCourseId, courseM[i].szCourseName);
         for (j = 0; j < courseM[i].iNumberOfAttrs; j++)
         {
             printf(\"\\t\\t\\t\\t\\t\\t%-7s %-8s\ \", courseM[i].attrM[j].szAttrType, courseM[i].attrM[j].szAttrValue);
         }
     }
 }
 int convertToPostfix(char *pszInfix, PostfixOut out){
         int bFoundOperand=TRUE;//Used to see if there\'s a missing Operand
         int bFoundOperator=TRUE;//Used to see if there\'s a missing Operator
         int bFoundLeftParen;//Used to find if there\'s a missing Left Parantheses
         Stack stack=newStack();//Stack where we cram everything in to
         Element element;//Store all values in here
         Element popped;//Structure used to a store a temp element structure
         pszInfix=getToken(pszInfix, element.szToken, MAX_TOKEN); //Used to input the token into the element structure
         categorize(&element); //Used to store values inside the element strucutre
    while (pszInfix!=NULL){
         categorize(&element);
         switch(element.iCategory)
             {
                 case CAT_LPAREN:
                     bFoundLeftParen=TRUE;
                     push(stack,element);
                     break;
                 case CAT_RPAREN:
                     bFoundLeftParen=FALSE;
                     while(!isEmpty(stack))
                     {
                         popped=pop(stack);
                         if(popped.iCategory == CAT_LPAREN)
                         {
                             bFoundLeftParen=TRUE;
                             break;
                         }
                         addPostfixOut(out, popped);
                     }
                     if(bFoundLeftParen==FALSE){
                         free(stack);
                         return WARN_MISSING_LPAREN;
                     }
                     break;
                 case CAT_OPERATOR:
                 if(bFoundOperator==TRUE)
                 {
                     free(stack);
                     return WARN_MISSING_OPERAND;
                     break;
                 }
                 else{
                     bFoundOperator=TRUE;
                     bFoundOperand=TRUE;
                     while(!isEmpty(stack))
                     {  
                         if((element.iPrecedence > topElement(stack).iPrecedence))
                             {
                                 break;
                             }
                             popped=pop(stack);
                             addPostfixOut(out, popped);
                         }
                             push(stack, element);
                             break;
                     }
                     case CAT_OPERAND:
                     if(bFoundOperator == FALSE){
                         free(stack);
                         return WARN_MISSING_OPERATOR;
                         break;
                     }
                     else if(bFoundOperator == FALSE){
                         free(stack);
                         return WARN_MISSING_OPERAND;
                         break;
                     }
                     else
                     {
                         addPostfixOut(out, element);
                         bFoundOperator=FALSE;
                         bFoundOperand=FALSE;
                         break;
                     }
                }
         pszInfix=getToken(pszInfix, element.szToken, MAX_TOKEN);
     }
return PrintOutRest(stack, bFoundOperand, popped, out);
 }
 int PrintOutRest(Stack stack2, int bFoundOperand2, Element popped2, PostfixOut out2)
 {
     while(!isEmpty(stack2))
         {
             if(bFoundOperand2==TRUE)
             {
                 free(stack2);
                 return WARN_MISSING_OPERAND;
             }
             popped2=pop(stack2);
             if(popped2.iCategory == CAT_LPAREN)
             {
                 free(stack2);
                 return WARN_MISSING_RPAREN;
             }
                      
              addPostfixOut(out2, popped2);
         }
     freeStack(stack2);
     return 0;
 }
void evaluatePostfix(PostfixOut postfixOut, Course courseM[], int iNumCourse, QueryResult resultM[])
 {  
    int i,j;
    Element postElem;
    Stack stack = newStack();
    Element temp1, temp2, booleanCheck;
    Attr tempAttr;
    for(i = 0; i < iNumCourse; i++){
        for(j = 0; j < postfixOut->iPostfixOutCount; j++)
        {
            postElem = postfixOut->postfixOutM[j];
           
           
            switch(postElem.iCategory)
            {
                case(CAT_OPERAND):
                    push(stack, postElem);
                    break;//END OF CASE OPERAND
               
               
                case(CAT_OPERATOR):  
                    //pop the last 2 elements
                    temp1 = pop(stack);
                    strcpy(tempAttr.szAttrValue, temp1.szToken);
                    temp2 = pop(stack);
                    strcpy(tempAttr.szAttrType, temp2.szToken);
                                       
                    //If token is an equal sign
                    if(strcmp(postElem.szToken, \"=\")==0)
                    {                                                  
                        postElem.bInclude = atLeastOne(&courseM[i], tempAttr);
                        push(stack, postElem);          
                               
                        break;
                    }
                    //If token is NEVER
                    if(strcmp(postElem.szToken, \"NEVER\")==0)
                    {
                        postElem.bInclude = never(&courseM[i], tempAttr);                  
                        push(stack, postElem);                  
                        break;
                    }
                    if(strcmp(postElem.szToken, \"ONLY\")==0)
                    {
                        postElem.bInclude = only(&courseM[i], tempAttr);                  
                        push(stack, postElem);                  
                        break;
                    }
                    if(strcmp(postElem.szToken, \"OR\")==0)
                    {                                              
                        if(temp1.bInclude == TRUE || temp2.bInclude == TRUE)
                            postElem.bInclude = TRUE;
                        else
                            postElem.bInclude = FALSE;      
                       
                        push(stack, postElem);          
                           
                    }
                    if(strcmp(postElem.szToken, \"AND\")==0)
                    {
                        if(temp1.bInclude == TRUE && temp2.bInclude == TRUE)
                            postElem.bInclude = TRUE;
                        else
                            postElem.bInclude = FALSE;
                        push(stack, postElem);
                    }  
            }//End of switch      
        }//End of inner for loop
        while( !isEmpty(stack))
        {
            booleanCheck = pop(stack);
            if(booleanCheck.bInclude == FALSE)
            {
                resultM[i] = FALSE;
                break;
            }
            else
            {
            resultM[i] = TRUE;
            }
        }//End of while loop
           
    }//End of outer for loop
    freeStack(stack);
   
 }//End of function
int atLeastOne(Course *pCourse, Attr attr)
 {
    int i = 100;
     if (pCourse == NULL)
         ErrExit(ERR_ALGORITHM
         , \"function never() received a NULL pointer\");
     for (i = 0; i < (pCourse->iNumberOfAttrs); i++)
     {  
         if (strcmp(pCourse->attrM[i].szAttrType, attr.szAttrType) == 0
             && strcmp(pCourse->attrM[i].szAttrValue, attr.szAttrValue) == 0)
             return TRUE;
     }
     return FALSE;
 }
int only(Course *pCourse, Attr attr)
 {
    int i = 100;
     if (pCourse == NULL)
         ErrExit(ERR_ALGORITHM
         , \"function never() received a NULL pointer\");
     for (i = 0; i < (pCourse->iNumberOfAttrs); i++)
     {
         if (strcmp(pCourse->attrM[i].szAttrType, attr.szAttrType) == 0
             && strcmp(pCourse->attrM[i].szAttrValue, attr.szAttrValue) != 0)
             return FALSE;
     }
     return TRUE;
 }



















