C程序设计语言 (第二版) 练习 5-20
练习 5-20 扩展dcl程序的功能,使它能够处理包含其他成分的声明,例如带有函数参数类型的声明、带有类似于const限定符的声明等。
注意:代码在win32控制台运行,在不同的IDE环境下,有部分可能需要变更。
IDE工具:Visual Studio 2010
代码块:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAXTOKEN 100enum { NAME, PARENS, BRACKETS };
enum { ERR_YES, ERR_NO };void dcl(void);
void dirdcl(void);int gettoken(void);
int tokentype;
char token[MAXTOKEN];
char name[MAXTOKEN];
char datatype[MAXTOKEN];
char out[1000];
int errtoken = ERR_NO;int main() {while (gettoken() != EOF) {strcpy(datatype, token);out[0] = '\0';dcl(); if (tokentype != '\n')printf("syntax error\n");printf("%s: %s %s\n", name, out, datatype);}return 0;
}void dcl(void) {int ns;for (ns = 0; gettoken() == '*'; ) ns++;dirdcl();while (ns-- > 0)strcat(out, " pointer to");
}void paramdcl(void);void dirdcl(void) {int type;if (tokentype == '(') { dcl();if (tokentype != ')') {printf("missing )\n");errtoken = ERR_YES;}} else if (tokentype == NAME) strcpy(name, token);else {printf("error: expected name or (dcl)\n");errtoken = ERR_YES;}while ((type=gettoken()) == PARENS || type == BRACKETS || type == '(')if (type == PARENS)strcat(out, " function returning");else if (type == '(') {strcat(out, " function expecting");paramdcl();strcat(out, " and returning");} else {strcat(out, " array");strcat(out, token);strcat(out, " of");}
}void dclspec(void);void paramdcl(void) {do {dclspec();} while (tokentype == ',');if (tokentype != ')')printf("error: missing ) in parameter declaration");
}int typespecifier(void);
int typequalifier(void);void dclspec(void) {char temp[MAXTOKEN];temp[0] = '\0';gettoken();do {if (tokentype != NAME) {errtoken = ERR_YES;dcl();} else if (typespecifier() || typequalifier()) {strcat(temp, " ");strcat(temp, token);gettoken();} else {printf("error: unknown type in param list\n");errtoken = ERR_YES;}} while (tokentype != ',' && tokentype != ')');strcat(out, temp);if (tokentype == ',')strcat(out, ",");
}int compare(const void *s, const void *t);int typespecifier(void) {static char *type[] = { "char", "int", "void" };char *pt = token;if (bsearch(&pt, type, sizeof(type)/sizeof(char *), sizeof(char *), compare) == NULL)return 0;return 1;
}int typequalifier(void) {static char *type[] = { "const", "volatile" };char *pt = token;if (bsearch(&pt, type, sizeof(type)/sizeof(char *), sizeof(char *), compare) == NULL)return 0;return 1;
}int compare(const void *s, const void *t) {char **chs;char **cht;chs = (char **) s;cht = (char **) t;return strcmp(*chs, *cht);
}int getch(void);
void ungetch(int);int gettoken(void) {int c;char *p = token;if (errtoken == ERR_YES) {errtoken = ERR_NO;return tokentype;}while ((c = getch()) == ' ' || c == '\t');if (c == '(') {if ((c = getch()) == ')') {strcpy(token, "()");return tokentype = PARENS;} else {ungetch(c);return tokentype = '(';}} else if (c == '[') {for (*p++ = c; (*p++ = getch()) != ']'; );*p = '\0';return tokentype = BRACKETS;} else if (isalpha(c)) {for (*p++ = c; isalnum(c = getch()); )*p++ = c;*p = '\0';ungetch(c);return tokentype = NAME;}return tokentype = c;
}#define BUFSIZE 100char buf[BUFSIZE];
int bufp = 0; int getch(void) {return (bufp > 0) ? buf[--bufp] : getchar();
}void ungetch(int c) { if (bufp >= BUFSIZE)printf("ungetch: too many characters\n");elsebuf[bufp++] = c;
}