exc/k&r/01-a-tutorial-introduction/01-24-check.c

207 lines
4.8 KiB
C

#include <stdio.h>
#include <string.h>
#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');
}