#include #include #define MAX_NEST 100 // max ([{ nesting #define ERRORS \ X(ERR_COMMENT_TERM, "non-terminating comment") \ X(ERR_STRING_EXP, "expected string termination") \ X(ERR_CHAR_EMPTY, "empty character constant") \ X(ERR_CHAR_EXP, "expected character in character constant") \ X(ERR_CHAR_TERM, "expected character constant termination") \ X(ERR_ESCAPE_INV, "invalid escape sequence") \ X(ERR_HEX_INV, "invalid hex number") \ X(ERR_OCT_INV, "invalid octal number") #define X(err, msg) err, enum { OK, ERRORS }; #undef X #define BRACKETS \ X('(', ')') \ X('[', ']') \ X('{', '}') #define QUOTES \ X('"', check_string) \ X('\'', check_char_const) #define INVALID_CHAR_CONSTS \ X('\a') X('\b') X('\f') X('\n') \ X('\r') X('\t') X('\v') X('\'') #define ESCAPE_SEQS \ X('a') X('b') X('f') X('n') X('r') \ X('t') X('v') X('\\') X('?') X('\'') int check(); int check_comment(); int check_string(); int check_char_const(); int check_escape_seq(); int check_oct(); int check_hex(); void print_error(int err); void print_line(); void ignore_line(); /* check c program on input for unabalanced parantheses * string termination, comment termination and char constant * validity */ int main() { print_error(check()); return 0; } void print_error(int err) { printf("error %d-%d: ", 0, 0); switch (err) { #define X(E, MSG) case E : printf("%s\n", MSG); break; ERRORS #undef X } } // ---------------------- validation functions ------------------------ /* main validation function */ int check() { int c, err = 0; int bi = 0; char brackets[MAX_NEST]; while (!err && (c = getchar()) != EOF) switch (c) { case '/': if ((c = getchar()) == '/') { ignore_line(); break; } else if (c == '*') { err = check_comment(); break; } #define X(Q, CHECK) \ case Q: \ err = CHECK(); \ break; QUOTES #undef X #define X(ERR, L, R) \ case L: \ if (bi < MAX_NEST) \ brackets[i] = L; \ ++bi; \ break; \ case R: \ if (bi <= MAX_NEST && brackets[bi-1] != L) \ err = ERR; \ --bi; \ break; BRACKETS #undef X } if (!err && bi) switch (brackets[bi-1]) { #define X(ERR, L, R) case L: err = ERR; break; BRACKETS #undef X } return err; } /* check multiline comment termination */ int check_comment() { int c = getchar(); while (c != EOF) if (c == '/') { if ((c = getchar()) == '*') return OK; } else c = getchar(); return ERR_COMMENT_TERM; } /* check string termination */ int check_string() { int c; while ((c = getchar()) != EOF && c != '\n') { if (c == '"') return OK; else if (c == '\\' && (c = check_escape_seq())) return c; } return ERR_STRING_TERM; } /* check char constant validity and termination */ int check_char_const(char errmsg[]) { int err; switch (getchar()) { case EOF: return ERR_CHAR_EXP; case '\n': return ERR_CHAR_EXP; case '\'': return ERR_CHAR_EMPTY; case '\\': if ((err = check_escape_seq())) return err; } if (getchar() != '\'') return ERR_CHAR_TERM; return OK; } /* check if \(next input char) makes a valid escape char */ int check_escape_seq() { int c; switch (c = getchar()) { #define X(C) case C: return 0; ESCAPE_SEQS #undef X case 'x': return check_hex(); } if ('0' <= c && c < '8') return check_oct(); return ERR_ESCAPE_INV; } int check_hex() { int c; if ((c = getchar())) } // ----------------------- utility functions -------------------------- /* ignore line of input */ void ignore_line() { int c; while ((c = getchar()) != EOF && c != '\n') ; } /* print first line of input */ void print_line() { int c; while ((c = getchar()) != EOF && c != '\n') putchar(c); putchar('\n'); }