练习内容为“编写一个程序来检查 C 程序中的基本语法错误,例如不平衡的括号、方括号和大括号。不要忘记单引号和双引号、转义序列和注释。”
我选择通过将括号、方括号和大括号放在堆栈上来解决问题,并确保所有内容都是 LIFO 以及用于标记我们是否在评论、引用等中的各种计数器。
问题是我觉得我的代码虽然有效,但结构很差,而且不是特别惯用。我尝试在结构中实现状态变量(堆栈、escaped
、inString
等)并将测试分解为子例程。它没有多大帮助。有没有办法以更清洁的方式解决这个问题,同时仍然正确处理转义字符等?
#include <stdio.h>
#include <stdlib.h>
#define INITIALSTACK 8
#define FALSE 0
#define TRUE 1
typedef struct {
int position;
int maxLength;
char* array;
} stack;
int match(char, char);
stack create();
void delete(stack*);
void push(stack*, char);
char pop(stack*);
int main() {
char c, out;
stack elemStack = create();
int escaped, inString, inChar, inComment, startComment, i, lineNum;
int returnValue;
escaped = inString = inChar = inComment = startComment = 0;
lineNum = 1;
while ((c = getchar()) != EOF) {
if (c == '\n')
lineNum++;
/* Test if in escaped state or for escape character */
if (escaped) {
escaped = FALSE;
}
else if (c == '\\') {
escaped = TRUE;
}
/* Test if currently in double/single quote or a comment */
else if (inString) {
if (c == '"' && !escaped) {
inString = FALSE;
}
}
else if (inChar) {
if (escaped)
escaped = FALSE;
else if (c == '\'' && !escaped) {
inChar = FALSE;
}
}
else if (inComment) {
if (c == '*')
startComment = TRUE;
else if (c == '/' && startComment)
inComment = FALSE;
else
startComment = FALSE;
}
/* Test if we should be starting a comment, quote, or escaped character */
else if (c == '*' && startComment)
inComment = TRUE;
else if (c == '/')
startComment = TRUE;
else if (c == '"') {
inString = TRUE;
}
else if (c == '\'') {
inChar = TRUE;
}
/* Accept the character and check braces on the stack */
else {
startComment = FALSE;
if (c == '(' || c == '[' || c == '{')
push(&elemStack, c);
else if (c == ')' || c == ']' || c == '}') {
out = pop(&elemStack);
if (out == -1 || !match(out, c)) {
printf("Syntax error on line %d: %c matched with %c\n.", lineNum, out, c);
return -1;
}
}
}
}
if (inString || inChar) {
printf("Syntax error: Quote not terminated by end of file.\n");
returnValue = -1;
}
else if (!elemStack.position) {
printf("Syntax check passed on %d line(s).\n", lineNum);
returnValue = 0;
}
else {
printf("Syntax error: Reached end of file with %d unmatched elements.\n ",
elemStack.position);
for(i = 0; i < elemStack.position; ++i)
printf(" %c", elemStack.array[i]);
printf("\n");
returnValue = -1;
}
delete(&elemStack);
return returnValue;
}
int match(char left, char right) {
return ((left == '{' && right == '}') ||
(left == '(' && right == ')') ||
(left == '[' && right == ']'));
}
stack create() {
stack newStack;
newStack.array = malloc(INITIALSTACK * sizeof(char));
newStack.maxLength = INITIALSTACK;
newStack.position = 0;
return newStack;
}
void delete(stack* stack) {
free(stack -> array);
stack -> array = NULL;
}
void push(stack* stack, char elem) {
if (stack -> position >= stack -> maxLength) {
char* newArray = malloc(2 * (stack -> maxLength) * sizeof(char));
int i;
for (i = 0; i < stack -> maxLength; ++i)
newArray[i] = stack -> array[i];
free(stack -> array);
stack -> array = newArray;
}
stack -> array[stack -> position] = elem;
(stack -> position)++;
}
char pop(stack* stack) {
if (!(stack -> position)) {
printf("Pop attempted on empty stack.\n");
return -1;
}
else {
(stack -> position)--;
return stack -> array[stack -> position];
}
}