演習5-20 K&R プログラミング言語C
2010年02月22日
演習5-20
関数引数型を扱うために tokentype
の値に FUNCARGS
を追加する。"(
" の後に "*
" と ")
" 以外の文字が続くと tokentype
を FUNCARGS
にする。
引数の中身については手抜きする。
const
などの修飾子については、main
関数内でループ内で最初に修飾子のチェックを行う。
#include <stdio.h> #include <string.h> #include <ctype.h> #define MAXTOKEN 100 #define BUFSIZE 100 #define TRUE 1 #define FALSE 0 char buf[BUFSIZE]; /* ungetch 用のバッファ */ int bufp = 0; /* buf 中の次の空き位置 */ int getch(void); void ungetch(int); enum { NAME, PARENS, BRACKETS, FUNCARGS }; void dcl(void); void dirdcl(void); void parse_error(void); int match_qualifier(char*); char *qualifiers[] = { "extern", "static", "auto", "register", "const", "volatile", "signed", "unsigned", "short", "long" }; int gettoken(void); int tokentype; /* 最後のトークンの型 */ char token[MAXTOKEN]; /* 最後のトークン文字列 */ char name[MAXTOKEN]; /* 識別名 */ char datatype[MAXTOKEN]; /* データ型 = char, int など */ char qualifiertype[MAXTOKEN]; /* 修飾子 = const など */ char out[1000]; /* 出力文字列 */ int is_error = 0; int main(void) /* 宣言を言葉による記述に変換する */ { while (gettoken() != EOF) { if (match_qualifier(token) > 0) { /* 修飾子 */ strcpy(qualifiertype, strcat(token, " ")); gettoken(); } else { qualifiertype[0] = '\0'; } strcpy(datatype, token); /* データ型 */ out[0] = '\0'; dcl(); /* 行の残りを解析 */ if (tokentype != '\n') { fprintf(stderr, "syntax error\n"); parse_error(); } if (is_error) { is_error = 0; } else { printf("%s: %s %s%s\n", name, out, qualifiertype, datatype); } } return 0; } /* dcl : 宣言子を解析する */ void dcl(void) { int ns; for (ns = 0; gettoken() == '*'; ) /* '*' を数える */ ns++; dirdcl(); while (ns-- > 0) strcat(out, " pointer to"); } /* dirdcl : 直前の宣言子を解析する */ void dirdcl(void) { int type; if (tokentype == '(') { /* ( dcl ) */ dcl(); if (tokentype != ')') { fprintf(stderr, "error : missing )\n"); parse_error(); return; } } else if (tokentype == NAME) /* variable name */ strcpy(name, token); else { fprintf(stderr, "error : expected name or (dcl)\n"); parse_error(); return; } while ((type = gettoken()) == PARENS || type == BRACKETS || type == FUNCARGS) if (type == PARENS) { strcat(out, " function returning"); } else if (type == FUNCARGS) { strcat(out, " function "); strcat(out, token); strcat(out, " returning"); } else { strcat(out, " array"); strcat(out, token); strcat(out, " of"); } } int gettoken(void) /* 次のトークンを返す */ { int c, getch(void); void ungetch(int); char *p = token; while ((c = getch()) == ' ' || c == '\t') ; if (c == '(') { if ((c = getch()) == ')') { strcpy(token, "()"); return tokentype = PARENS; } else { if (c == '*') { ungetch(c); return tokentype = '('; } else { *p++ = '('; for (*p++ = c; (*p++ = getch()) != ')'; ) ; *p = '\0'; return tokentype = FUNCARGS; } } } 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; } else return tokentype = c; } /* エラー処理, 行末まで読み飛す */ void parse_error(void) { int c; if (tokentype != '\n') while ((c = getch()) != '\n') ; tokentype = '\n'; is_error = 1; } /* 文字列 s が修飾子リスト(qualifiers)のいずれかにマッチするか */ int match_qualifier(char *s) { int i, len; len = sizeof qualifiers / sizeof qualifiers[0]; for (i = 0; i < len; i++) { if (strcmp(qualifiers[i], s) == 0) { return TRUE; } } return FALSE; } int getch(void) /* (押し戻された可能性もある) 1文字をとってくる */ { return (bufp > 0) ? buf[--bufp] : getchar(); } void ungetch(int c) /* 文字を入力に押し戻す */ { if (bufp > BUFSIZE) fprintf(stderr, "ungetch : too many characters\n"); else buf[bufp++] = c; }
実行結果
$ ./dcl static int *func(void *) func: function (void *) returning pointer to static int
プログラミング言語C 第2版 ANSI規格準拠
posted with amazlet at 09.11.27
B.W. カーニハン D.M. リッチー
共立出版
売り上げランキング: 9726
共立出版
売り上げランキング: 9726