C程序设计语言 (第二版) 练习 6-1

练习 6-1 上述getword函数不能正确处理下划线、字符串常量、注释及预处理控制指令。请编写一个更完善的getword函数。

注意:代码在win32控制台运行,在不同的IDE环境下,有部分可能需要变更。
IDE工具:Visual Studio 2010

 

代码块:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXWORD 100
#define NKEYS (sizeof keytab / sizeof(keytab[0]))
#define MAXOP 100
#define NUMBER '0'
#define MAXVAL 100
#define BUFSIZE 100
#define VAR '1'


char buf[BUFSIZE];
int bufp = 0;


struct key{
	char *word;
	int count;
};

int getch(void){
	return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c){
	if(bufp >= BUFSIZE){
		printf("Ungetch! Too many characters!\n");
	}
	else{
		buf[bufp++] = c;
	}
}

int getword(char *word, int lim) {
    int c;
    char *w = word;
    static int line_beg = 1; /* 1 at beginning of a new line */
    static int after_slash = 0; /* 1 after '\' */
    int after_star = 0; /* 1 after '*' */

    if(isspace(c = getch()))
        after_slash = 0;
    while(isspace(c)) {
        if(c == '\n')
            line_beg = 1;
        c = getch();
    }

    if(c != EOF)
        *w++ = c;

    if(c == '#' && line_beg == 1) { /* Preprocessor directive */
        while((c = getch()) != '\n' && c != EOF) /* Go to end of line */
            ;
        return getword(word, lim); /* Start over */
    }
    line_beg = 0;

    if(c == '\\') /* Set after_slash flag */
        after_slash = after_slash ? 0 : 1; /* Ignore '\\' comment */

    else if(c == '/' ) {
        if((c = getch()) == '*' && !after_slash) { /* Begin comment */
            while((c = getch()) != EOF) {
                if(c == '/') {
                    if(after_star) /* End comment */
                        return getword(word, lim); /* Start over */
                }
                else if(c == '*' && !after_slash)
                    after_star = 1;
                else if(c == '\\')
                    after_slash = after_slash ? 0 : 1; /* Ignore '\\' comments */
                else {
                    after_star = 0;
                    after_slash = 0;
                }
            }
        } /* End comment */

        after_slash = 0; /* Not after slash anymore */
        if(c != EOF)
            ungetch(c);
    }

    else if(c == '\"') {
        if(!after_slash) { /* String literal */
            --w; /* Reset w */
            while((c = getch()) != EOF) {
                if(c == '\"' && !after_slash)
                    break;
                else if(c == '\\')
                    after_slash = after_slash ? 0 : 1; /* Ignore '\\' comments */
                else
                    after_slash = 0;
                *w++ = c;
            }
            *w = '\0';
            if(c == EOF)
                return EOF;
            else
                return getword(word, lim); /* Start over. */
        }
        after_slash = 0; /* Not after a slash anymore. */
    }

    if(!isalpha(c) && c != '_') { /* It's a symbol. */
        *w = '\0';
        if(c != '\\')
            after_slash = 0;
        return c;
    }

    /* Reset this flag since a slash would have just returned. */
    after_slash = 0;

    for( ; --lim > 0; ++w) /* It's a word or letter. */
        if(!isalnum(*w = getch()) && *w != '_') {
            ungetch(*w);
            break;
        }
    *w = '\0';
    return word[0];

}

int binsearch(char *word, struct key tab[], int n){
	int cond;
	int low, high, mid;

	low = 0;
	high = n - 1;
	while(low <= high){
		mid = (low + high) / 2;
		if((cond = strcmp(word, tab[mid].word)) < 0){
			high = mid - 1;
		}
		else if(cond > 0){
			low = mid + 1;
		}
		else{
			return  mid;
		}
	}
	return -1;
}

int main(){
	struct key keytab[] = {{"auto", 0}, {"break", 0}, {"case", 0}, {"char", 0}, {"const", 0}, {"continue", 0}, {"default", 0},
	{"do", 0}, {"double", 0}, {"else", 0}, {"enum", 0}, {"extern", 0}, {"float", 0}, {"for", 0}, {"goto", 0}, {"if", 0}, {"int", 0},
	{"long", 0}, {"register", 0}, {"return", 0}, {"short", 0}, {"signed", 0}, {"sizeof", 0}, {"static", 0}, {"struct", 0}, {"switch", 0},
	{"typedef", 0}, {"unsigned", 0}, {"union", 0}, {"void", 0}, {"volatile", 0}, {"while", 0}};

	int n;
	char word[MAXWORD];

	while(getword(word, MAXWORD) != EOF){
		if(isalpha(word[0])){
			if((n = binsearch(word, keytab, NKEYS)) >= 0){
				keytab[n].count++;
			}
		}
	}
	for(n = 0; n < NKEYS; n++){
		if(keytab[n].count > 0){
			printf("%4d %s\n", keytab[n].count, keytab[n].word);
		}
	}

	system("pause");
	return 0;
}
01-18 08:43