じゃあ入門卒業試験の課題としてこれはどうだ。
int match(const char *pattern, const char *string);
patternがstringとマッチするなら0で無い値、マッチしないなら0を返す。
pattern中の文字'?'は任意の1文字とマッチする。
'*'は0文字以上の任意の文字列とマッチする。
それ以外の文字は、その文字自身とマッチする。
トークンきりだし、構文解析、構文チェックまではCで書けるとして、
そのあとにネイティブコードを作るときはやっぱりアセンブラだよね。
Cでもできるのかな。
>>624 ネイティブコードを生成すること自体はCでも書けるだろ。
知識は必要だろうけど。
626 :
デフォルトの名無しさん:02/05/20 22:36
>>623 patternの中に*や?がひとつも含まれていなかったら、strcmp(string,pattern)と等価?それともstrstr(string,pattern)と等価?
>>624 アセンブリ言語コードを出力すればいいんじゃないの?
そういうコンパイラも多い。
>>628 そう。UnixのたいがいのCコンパイラと
8bitのころのPCのたいがいのCコンパイラ。
DOSだとLSI-C86もそうじゃなかったっけ。
631 :
デフォルトの名無しさん:02/05/20 22:39
>>629 ちょっとやってみよう。
再帰使うとうまくゆくかな・・・
いや再帰じゃないな・・・
>>632 出題者は再帰を使う回答を用意しますた。
>>623 じゃあ補足すると、これぐらいは全部通ればとりあえず合格?
あんまり書くと長くなりすぎるから省略。
assert( match("abc", "abc") != 0 );
assert( match("abc", "abcd") == 0 );
assert( match("?bc", "abc") != 0 );
assert( match("a?c", "abc") != 0 );
assert( match("ab?", "abc") != 0 );
assert( match("ab?", "ab") == 0 );
assert( match("ab*", "abc") != 0 );
assert( match("ab*", "ab") != 0 );
assert( match("a*c", "abbbbbc") != 0 );
assert( match("a*c", "abc") != 0 );
assert( match("a*c", "ac") != 0 );
// 最長一致なら以下のチェック.
assert( match("a*c", "acc") != 0 );
assert( match("a*d*g", "adgabcdefg") != 0 );
テストドライバその1
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s pattern string\n", argv[0]);
return 1;
}
printf("%smatched\n", match(argv[1], argv[2]) ? "" : "un");
return 0;
}
テストドライバその2
#include <stdio.h>
#include <string.h>
char line[1024];
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: %s pattern\n", argv[0]);
return 1;
}
while (fgets(line, sizeof(line), stdin) != NULL) {
char *eol = strchr(line, '\n');
if (eol != NULL) {
*eol = '\0';
}
if (match(argv[1], line)) {
puts(line);
}
}
return 0;
}
assert並べるほうがいいな。
同じテストを何度でも繰り返せ、実行一発で結果がわかる。
>>634 あ、そうですね。そのテストのほうが良いかも。
ちなみに
>>634で用意したテストプログラムは、
その1: patternとstringをコマンドライン引数で与えて
matchedまたはunmatchedをプリントする。
その2: patternをコマンドライン引数で与えて
標準入力から1行ずつ読み込み、マッチする行だけ出力する。
いずれもpatternはちゃんとクオートしないと切ねぇことになる。
テストドライバその2の方は、
むか〜しワタスィが書いた超簡易grepモドキそのものです。
サパーリ出来ません。
逝ってきます…
末尾に*がくると失敗するなぁ・・・・
やりなおそう。
あ、ちなみに私はあの入門書を読み終えたばかりの人じゃないです。
>>634 いかん、このassertだと * があったら無条件で1返せば通ってしまう(笑)
ので追加。
assert( match("a*c", "ab") == 0 );
あと複合系(もっと要る気が)
assert( match("a**?*", "ab") != 0 );
assert( match("a**?*", "a") == 0 );
と思ったけどできた。
644 :
デフォルトの名無しさん:02/05/20 23:15
あるモジュールAが別のモジュールBをよんで、さらにモジュールB
が別のモジュールCを呼んで...という具合にモジュールAを頂点とし
て呼ばれているモジュールすべてを洗い出すにはどうやって調べて
いけばよいのでしょうか?モジュールA、B、Cなどすべてのモジュ
ールのソースはあります。どなたか効率よく調べる方法がありましたら、
教えてくださいませんか。
末尾が?で終わるときに失敗するんですが、いいですか?
だめですよね?(^_^;)
M-.
>>644 クロスリファレンスや呼び出しツリーを作ってくれるツールを使えば?
644
もれはソースブラウザ(M$)でしらみつぶしかな。
あんまり引っ張っても何なので…
出題者が用意した回答です。
あんまり叩かないで(w
int match(const char *pattern, const char *string)
{
while (*pattern) {
switch (*pattern) {
case '?':
if (! *string) {
return 0;
}
pattern++;
string++;
break;
case '*':
pattern++;
do {
if (match(pattern, string)) {
return 1;
}
} while (*string++);
return 0;
default:
if (*pattern++ != *string++) {
return 0;
}
}
}
return ! *string;
}
ギブアップ 末尾に?があると失敗します。
int match(const char *pattern,const char *str)
{
for(;*str||*pattern;str++,pattern++){
if(*pattern=='?'){
str++,pattern++;
continue;
}
if(*pattern=='*'){
while(*pattern=='?'||*pattern=='*')
pattern++;
if(*pattern=='\0'){
return 1;
}
while(*str!=*pattern){
str++;
}
}
if(*str!=*pattern)
return 0;
}
return 1;
}
Visual C++の方に持っていって、デバッガにかけてみよう。
でないとどこが間違っているのかわからない(T_T)
ついでに正規表現版まで作ってくれ!!
>>653 どの正規表現?
.と*だけで良いなら何とか…
(正規表現の文法自体は正規文法でないという罠)
>>647,648,649
ありがとうございます。ckrefを使用してみます。
for(;*str||*pattern;str++,pattern++){
の部分を
for(;;str++,pattern++){
if(*str||*pattern){
break;
}
に変えたら成功した・・・・
もしかしたらforについて勘違いしている部分があるかも(汗
とりあえずperlでつかえるくらい。。ナンチッテ
グループとかは無理ですか?
あ!!
もしかしたらcontinueした時はforの条件式が評価されないんですか?
>>657 Perlの正規表現だと、それこそちょっとしたコンパイラ書くくらいの
手間がかかると思われ。
グループって[a-z]みたいなやつ?
暇潰しの課題にはちょっと面倒すぎるなあ。
やっと出来ました・・・・
forについての間違った認識を正すことが出来てよかったです。
ありがとうございました。
int match(const char *pattern,const char *str)
{
for(;*str||*pattern;str++,pattern++){
if(*pattern=='?')
goto loopend;
if(*pattern=='*'){
while(*pattern=='?'||*pattern=='*')
pattern++;
if(*pattern=='\0')
return 1;
while(*str!=*pattern)
str++;
}
if(*str!=*pattern)
return 0;
loopend: ;
}
return 1;
}
orとかは?
U(MA|FO)
みたいに
>>656 for(;*str||*pattern;str++,pattern++){
は条件式が真ならループは続いて、
for(;;str++,pattern++){
if(*str||*pattern){
break;
}
はifの条件式が真ならループを抜ける。
前者と後者じゃまったく逆の処理じゃないの?
>>662 すみません。
if!(*str||*pattern)) break;の間違いです。
じゃなくて、
if(!(*str||*pattern)) break;
665 :
デフォルトの名無しさん:02/05/21 00:35
あのなぁ。
if (*str) って書くなら、素直に if (*str != '\0') って書け。
省略すればいいって訳じゃないぜ。
if (isalpha(XXX)) とか、if (found) はこう書くべきだがな。
strtokを書いたことがある方に聞きます
staticな局所変数を使いました?
>>660 >goto loopend;
continue;じゃいかんの?
Cの文法に躍らされてる気がする。
そんなにまちがえるなら素直に状態遷移書けばいいのに