2023-05-02 13:51:17 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
#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)
|
2023-05-02 13:51:17 +02:00
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
#define INVALID_CHAR_CONSTS \
|
|
|
|
X('\a') X('\b') X('\f') X('\n') \
|
|
|
|
X('\r') X('\t') X('\v') X('\'')
|
2023-05-02 13:51:17 +02:00
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
#define ESCAPE_SEQS \
|
|
|
|
X('a') X('b') X('f') X('n') X('r') \
|
|
|
|
X('t') X('v') X('\\') X('?') X('\'')
|
2023-05-02 13:51:17 +02:00
|
|
|
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
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);
|
2023-05-02 13:51:17 +02:00
|
|
|
void print_line();
|
|
|
|
void ignore_line();
|
|
|
|
|
|
|
|
/* check c program on input for unabalanced parantheses
|
|
|
|
* string termination, comment termination and char constant
|
|
|
|
* validity */
|
|
|
|
int main()
|
|
|
|
{
|
2023-06-02 13:16:37 +02:00
|
|
|
print_error(check());
|
2023-05-02 13:51:17 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
void print_error(int err)
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
2023-06-02 13:16:37 +02:00
|
|
|
printf("error %d-%d: ", 0, 0);
|
|
|
|
switch (err) {
|
|
|
|
#define X(E, MSG) case E : printf("%s\n", MSG); break;
|
|
|
|
ERRORS
|
|
|
|
#undef X
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------- validation functions ------------------------
|
2023-06-02 13:16:37 +02:00
|
|
|
/* main validation function */
|
|
|
|
int check()
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
2023-06-02 13:16:37 +02:00
|
|
|
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;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
/* check multiline comment termination */
|
|
|
|
int check_comment()
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
2023-06-02 13:16:37 +02:00
|
|
|
int c = getchar();
|
|
|
|
while (c != EOF)
|
|
|
|
if (c == '/') {
|
|
|
|
if ((c = getchar()) == '*')
|
|
|
|
return OK;
|
|
|
|
} else
|
|
|
|
c = getchar();
|
|
|
|
return ERR_COMMENT_TERM;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* check string termination */
|
2023-06-02 13:16:37 +02:00
|
|
|
int check_string()
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
|
|
|
int c;
|
2023-06-02 13:16:37 +02:00
|
|
|
while ((c = getchar()) != EOF && c != '\n') {
|
|
|
|
if (c == '"')
|
|
|
|
return OK;
|
|
|
|
else if (c == '\\' && (c = check_escape_seq()))
|
|
|
|
return c;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
2023-06-02 13:16:37 +02:00
|
|
|
return ERR_STRING_TERM;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
/* check char constant validity and termination */
|
|
|
|
int check_char_const(char errmsg[])
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
2023-06-02 13:16:37 +02:00
|
|
|
int err;
|
2023-05-02 13:51:17 +02:00
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
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;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
2023-06-02 13:16:37 +02:00
|
|
|
if (getchar() != '\'')
|
|
|
|
return ERR_CHAR_TERM;
|
|
|
|
return OK;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
/* check if \(next input char) makes a valid escape char */
|
|
|
|
int check_escape_seq()
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
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;
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
2023-06-02 13:16:37 +02:00
|
|
|
int check_hex()
|
2023-05-02 13:51:17 +02:00
|
|
|
{
|
2023-06-02 13:16:37 +02:00
|
|
|
int c;
|
|
|
|
if ((c = getchar()))
|
2023-05-02 13:51:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------- utility functions --------------------------
|
|
|
|
/* ignore line of input */
|
|
|
|
void ignore_line()
|
|
|
|
{
|
|
|
|
int c;
|
2023-06-02 13:16:37 +02:00
|
|
|
while ((c = getchar()) != EOF && c != '\n')
|
2023-05-02 13:51:17 +02:00
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print first line of input */
|
|
|
|
void print_line()
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
while ((c = getchar()) != EOF && c != '\n')
|
|
|
|
putchar(c);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|