/* 0 10 20 30 40 50 60 70 80 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */ /*----------------------------------------------------------------------------*/ /* Logic evaluator */ /* LOG32LLC Assignment 2 */ /* Sten M. Andersen */ /*----------------------------------------------------------------------------*/ #include #include #include // isprint() #define MAX_TOKEN_STRING_LENGTH 80 #define MAX_BUFF 80 typedef enum { false, true } BOOL; /*----------------------------------------------------------------------------*/ /* Error codes */ /*----------------------------------------------------------------------------*/ typedef enum { NO_ERROR, EXPECTED_OPER, EXPECTED_LEFT_PARENT, EXPECTED_RIGHT_PARENT, EXPECTED_UNARY, UNEXPECTED_ERROR, TOO_LONG_INPUT, } ERROR_CODE; /*----------------------------------------------------------------------------*/ /* Error messages */ /*----------------------------------------------------------------------------*/ char *error_messages[] = { "No error", "Seen %c when & v > = expected", "Seen %c when ( expected", // Not used here "Seen %c when ) expected", "Seen %c when 0 1 - ( expected", "Unexpected error", "Input string too long", }; /*----------------------------------------------------------------------------*/ /* Character codes */ /*----------------------------------------------------------------------------*/ // uc = upper case, lc = lower case typedef enum { UC_LETTER, LC_LETTER, DIGIT, SPECIAL, } CHAR_CODE; /*----------------------------------------------------------------------------*/ /* Token codes */ /*----------------------------------------------------------------------------*/ // Words are: AND OR NOT IMP IFF // Symbols are a, b, c, ... ,z. // number is a digit, sice only 0 and 1 are legal typedef enum { NO_TOKEN, WORD, SYMBOL, NUMBER, } TOKEN_CODE; /*----------------------------------------------------------------------------*/ /* Globals */ /*----------------------------------------------------------------------------*/ char buff[ MAX_BUFF ]; // Input buffer storage int opvalues[ MAX_BUFF ];// Truth value of each opeator in formula char ch; // The current char to be processed BOOL cont = true; // User tells us when to end int bufferpointer; // Keep a count, so we can point to error jmp_buf start; // On error: empty stack and go to start // This idea for how to extract tokens is from // Mak, R. (1991). Writing compilers and interpreters. An applied approach. // Brisbane: John Wiley & Son, Inc TOKEN_CODE token; char token_string[MAX_TOKEN_STRING_LENGTH]; // Token string char *tokenp = token_string; // Token string pointer CHAR_CODE char_table[256]; /*----------------------------------------------------------------------------*/ /* char_code Return the character code of ch */ /*----------------------------------------------------------------------------*/ #define char_code( ch ) char_table[ch] /*----------------------------------------------------------------------------*/ /* Function declarations */ /*----------------------------------------------------------------------------*/ void init(); void formula(); // The work horse void get_char(); // Puts the next char in global ch void get_token(); void get_word(); void get_symbol(); void get_number(); void get_special(); void error(int e); // Handles errors void print_value( int res ); void print_blanks( int n ); void print_help(); /*----------------------------------------------------------------------------*/ /* Initialise */ /*----------------------------------------------------------------------------*/ void init() { bufferpointer = 0; int i; for ( i = 0; i < MAX_BUFF; i++ ) { opvalues[ i ] = -1; buff[ i ] = NULL; } // Init character table for ( i = 0; i < 256; ++i ) char_table[ i ] = SPECIAL; for ( ch = '0'; ch <= '1'; ++ch ) char_table[ ch ] = DIGIT; for ( ch = 'A'; ch <= 'Z'; ++ch ) char_table[ ch ] = UC_LETTER; for ( ch = 'a'; ch <= 'z'; ++ch ) char_table[ ch ] = LC_LETTER; } /*----------------------------------------------------------------------------*/ /* Character routines */ /*----------------------------------------------------------------------------*/ void get_char() { // Gets char into ch and skips blanks ch = getchar(); if ( !isprint( ch ) ) ch = ' '; if ( bufferpointer < MAX_BUFF ) buff[ bufferpointer++ ] = ch; else error( TOO_LONG_INPUT ); } void skip_blanks() { do { get_char(); } while ( ch == ' ' ); } void get_token() { skip_blanks(); tokenp = token_string; switch ( char_code( ch ) ) { case UC_LETTER: get_word(); break; case LC_LETTER: get_symbol(); break; case DIGIT: get_number(); break; default: get_special(); break; } } void get_word() { while ( char_code( ch ) == UC_LETTER ) { *tokenp++ = ch; get_char(); } *tokenp = '\0'; token = WORD; if ( strcmp( token_string, "AND") == 0 ) ch = '&'; if ( strcmp( token_string, "OR" ) == 0 ) ch = 'v'; if ( strcmp( token_string, "NOT") == 0 ) ch = '-'; if ( strcmp( token_string, "IMP") == 0 ) ch = '>'; if ( strcmp( token_string, "IFF") == 0 ) ch = '='; } void get_symbol() { token = SYMBOL; } void get_number() { token = NUMBER; } void get_special() { token = SPECIAL; } /*----------------------------------------------------------------------------*/ /* Formula (the work horse) */ /*----------------------------------------------------------------------------*/ void formula(int* result) { char oper; int left, right, buffpnt; get_token(); /* switch( token ) { case WORD: if ( strcmp( token_string, "AND") == 0 ) ch = '&'; if ( strcmp( token_string, "OR" ) == 0 ) ch = 'v'; if ( strcmp( token_string, "NOT") == 0 ) ch = '-'; if ( strcmp( token_string, "IMP") == 0 ) ch = '>'; if ( strcmp( token_string, "IFF") == 0 ) ch = '='; break; case NUMBER: break; case SYMBOL: break; // default: } */ switch ( ch ) { case 'q': // User wants to quit cont = false; return; case 'h': // User needs help print_help(); return; case '0': *result = false; break; case '1': *result = true; break; case '-': formula( &right ); *result = opvalues[ bufferpointer-1 ] = !right; ; break; case '(': formula( &left ); get_token(); if ( ch != '&' && ch != 'v' && ch != '>' && ch != '=' ) error( EXPECTED_OPER ); oper = ch; buffpnt = bufferpointer-1; formula( &right ); get_token(); if ( ch != ')' ) error( EXPECTED_RIGHT_PARENT ); switch( oper ) { case '&': *result = opvalues[ buffpnt ] = left && right; break; case 'v': *result = opvalues[ buffpnt ] = left || right; break; case '>': *result = opvalues[ buffpnt ] = !left || right; break; case '=': *result = opvalues[ buffpnt] = (left == right); break; default: // Should never reach this stage error( UNEXPECTED_ERROR ); } break; default: // error msg error( EXPECTED_UNARY ); } } /*----------------------------------------------------------------------------*/ /* Printing functions */ /*----------------------------------------------------------------------------*/ void print_help() { printf("\nLogic evaluator Ver 0.8 by Sten M. Andersen\n"); printf("-------------------------------------------\n"); printf("h this help menu\n"); printf("q quit\n\n"); printf("formula ::= '0' | '1'\n"); printf(" | '-' formula\n"); printf(" | '(' formula ('&' | 'v' | '>' | '=') formula ')'\n\n"); } // Prints out error #e, the offending formula, and points to error void error(int e) { printf( "\n" ); printf( error_messages[ e ], ch ); // printf( error_messages[ e ] ); printf( "\n%s\n", buff); print_blanks( bufferpointer-1 ); // Better way? printf( "^\n" ); fflush( stdin );; longjmp( start, 0 ); } void print_value( int res ) { printf( "\n%s\n", buff ); // Print formated formula from buffer int i; for ( i = 0; i < MAX_BUFF; i++ ) { // Print each operator's value if ( opvalues[ i ] != -1 ) printf( "%i", opvalues[ i ] ); else printf(" "); // If not an operator, print a blank } printf( "Value: %i\n", res ); // Print out formula's final value } void print_blanks( int n ) { int i; // There must be a better way, .e.g., a format-thingy for ( i = 0; i < n; i++ ) printf(" "); } /*----------------------------------------------------------------------------*/ /* Main */ /*----------------------------------------------------------------------------*/ int main(int argc, char **argv) { int res; while ( cont ) { setjmp( start ); init(); printf("Formula (h=help): "); formula( &res ); if ( ch != 'q' && ch != 'h' ) print_value( res ); } return (0); }