コンピュータは人間と違って自然に「文字(字句)」を認識することはできません。字句を識別させるには事前に何が字句かを定めて、その規則に沿ったプログラムを作る必要があります。
本連載では、これから組み込みシステムのプログラミングを学びたい人向けに、C言語を使ったマイコン制御プログラムの“イロハ”を解説していきます。
毎回少しずつステップアップしていけるよう、本文の最後で問題を出し、次回その解答と解説を紹介していきます。
C言語のソースプログラムを読み取り、その中に単語がいくつあるか表示します。ただし単語とは、先頭の文字がアルファベットまたはアンダースコア(_)で、2文字目以降の文字がアルファベットまたはアンダースコアまたは数字とします。ダブルコーテーション(”)で囲まれた文字列リテラルやコメントは単語に含みません。
人間は自然と単語(プログラム言語の予約語や識別子)を認識してプログラムを読むことができますが、コンピュータにとってプログラムは文字の並びにすぎません。ですからコンピュータに単語を識別させるには、「先頭の文字がアルファベットまたはアンダースコアで、2文字目以降の文字がアルファベットまたはアンダースコアまたは数字」のように単語がどんな文字の並びなのか定めて、その規則に従ってプログラムを作る必要があります。
今回の課題ではファイルを扱いますが、fgetcを用いて、ファイルの先頭から1文字ずつ文字を読み取りながら単語を探していきます。しかしそれだけでは、文字列やコメントの中身も単語と認識してしまうので、それらを単語と区別する機能も備えています。
それでは解答を発表します。
/* wowd counter */ #include <stdio.h> #include <ctype.h> void skip_word(void); void skip_string(void); void skip_const_char(void); void skip_comment(void); FILE *fp; int ch; int main(void) { int count; fp = fopen("words.c", "r"); if (fp == NULL) { printf("Can¥'t open file.¥n"); return 1; } count = 0; ch = fgetc(fp); while (ch != EOF) { if (isalpha(ch) || (ch == '_')) { count++; skip_word(); } else if (ch == '¥"') skip_string(); else if (ch == '¥'') skip_const_char(); else if (ch == '/') { ch =fgetc(fp); if (ch == '*') skip_comment(); } else ch = fgetc(fp); } fclose(fp); printf("%d words¥n", count); return 0; } void skip_word(void) { ch = fgetc(fp); while (isalnum(ch) || (ch == '_')) ch = fgetc(fp); } void skip_string(void) { ch = fgetc(fp); while (ch != '¥"') { if (ch == '¥¥') ch = fgetc(fp); ch = fgetc(fp); } ch = fgetc(fp); } void skip_const_char(void) { ch = fgetc(fp); while (ch != '¥'') { if (ch == '¥¥') ch = fgetc(fp); ch = fgetc(fp); } ch = fgetc(fp); } void skip_comment(void) { ch = fgetc(fp); for (;;) { if (ch == '*') { ch = fgetc(fp); if (ch == '/') break; } ch = fgetc(fp); } ch = fgetc(fp); }
words.cはいくつかの関数で構成されます。words.cの関数の一覧を以下に示します。
関数名 | 概要 |
---|---|
main | mainから実行が開始されます。 |
skip_word | 単語が見つかったら呼ばれる関数です。単語が終わるまで戻りません。 |
skip_string | 文字列が見つかったら呼ばれる関数です。文字列が終わるまで戻りません。 |
skip_const_char | 文字定数が見つかったら呼ばれる関数です。文字定数が終わるまで戻りません。 |
skip_comment | コメントが見つかったら呼ばれる関数です。コメントが終わるまで戻りません。 |
month.cを実行すると、次のような結果になります。
Copyright © ITmedia, Inc. All Rights Reserved.