C言語関係掲示板

過去ログ

No663 中括弧を自動でつけるには?

[戻る] [ホームページ]
No.7328

中括弧を自動でつけるには?
投稿者---健一(2003/06/12 08:15:21)


こんにちわ。
if文、for文内に実行する命令が1文の場合には中括弧を省略することができます。

if(i=0; i<10; i++)
   a= a+i;

このプログラムへ自動的に以下のような中括弧をつける
ことができる方法、ツールは存在しないでしょうか?

if(i=0; i<10; i++)
{
   a= a+1;
}

数万ステップあるプログラムをコーディング規約へ
あわせようとしていまして
なにかいい方法がないかと探しています。

よろしくお願いします。

No.7330

Re:中括弧を自動でつけるには?
投稿者---たいちう(2003/06/12 09:22:50)


ツールが存在するかどうかはわかりませんが、
自前で作ることは可能でしょう。

1.if(またはfor)を見つける
2.ifの直後の'('に対応している')'を見つける
3.')'の後を調べ、'{'がなかったら入れる
4.その後の文を調べ、';'の後に'}'をいれる

この方針でできると思いますが、"文字列"や/*コメント*/などの
例外への対応も作りこまないと使い物にはならないでしょう。
インデントにも配慮したいし。

ツールが見つからなく、かつ、文字列処理に自信がある場合ご検討ください。

(私が今思いついていない例外ももっとあるかもしれません。)

No.7331

Re:中括弧を自動でつけるには?
投稿者---ちぇっこり(2003/06/12 09:47:06)


ちわ!
おもしろそうだったので、ちょっと考えてみましたが・・・
難しい部分がありますね(笑)

  if (a == NULL)
    i++;
    j++;
  k++;

って場合、「{」は入れれるでしょう!
しかし「}」の切れ目をどう判断するか!?
普通は、
  if(a == NULL)
  {
    i++;
    j++;
  }
  k++;
と見れます。
しかし・・jとkで段差がありますが保証はないですね!
単に、kのインデントを入れ忘れただけで、事実上は・・
  if(a == NULL)
  {
    i++;
    j++;
  k++;
  }
こうかも?
その区別のパターンが、確実に掴めるのなら、Cでも・・
エディタ・マクロでも出来そうですね。

C言語と直接関係ない話題ですみません。
不要なら削除願います。(削除ID: chekori)


No.7332

Re:中括弧を自動でつけるには?
投稿者---こん!(2003/06/12 10:10:07)


>  if (a == NULL)
>    i++;
>    j++;
>  k++;
>
>って場合、「{」は入れれるでしょう!
>しかし「}」の切れ目をどう判断するか!?
>普通は、
>  if(a == NULL)
>  {
>    i++;
>    j++;
>  }
>  k++;
>と見れます。

見かけのインデントに合わせてはまずいのではないですか?

やはり付けるなら
>  if(a == NULL)
>  {
>    i++;
>  }
>    j++;
>  k++;

でないと変換前と後で実際の処理が変わってしまいますよね。
あくまでも今有る膨大なステップのリストを規格化したコーディング規約に合わせたいというのが目
的の様ですから。


No.7335

Re:中括弧を自動でつけるには?
投稿者---ちぇっこり(2003/06/12 10:26:08)



>あくまでも今有る膨大なステップのリストを規格化したコーディング規約に合わせたいというのが目
>的の様ですから。

すみません・・・
 「if文、for文内に実行する命令が1文の場合には中括弧を省略することができます。」
と言うのを見落としてました。

これを見落としてましたので、てっきり命令数は不定かと。。

失礼しました。
  (削除ID: chekori)



No.7333

Re:中括弧を自動でつけるには?
投稿者---たいちう(2003/06/12 10:16:32)


ちぇっこり様
>   if (a == NULL)
>     i++;
>     j++;
>   k++;
>
> って場合、「{」は入れれるでしょう!
> しかし「}」の切れ目をどう判断するか!?
> 普通は、
>   if(a == NULL)
>   {
>     i++;
>     j++;
>   }
>   k++;
> と見れます。

人間ならば「{}を忘れたのかな?」と判断するかもしれませんが、
コンパイラはインデントを無視します。

現在の動作を変えずにコーディング規約に従うように書き換えるためには、
例外なく
  if (a == NULL)
  {
    i++;
  }
    j++;
  k++;
とすれば良いはずです。
このインデントがコーディング規約に従うとは思えませんが、
それは別の問題ということで。

No.7336

Re:中括弧を自動でつけるには?
投稿者---こん!(2003/06/12 10:58:22)


一案です。たたき台ぐらいにしてくらはい。

ざっと考えると穴は有るでしょうが

キーワード "//,/*,if,else,elseif,for,while"

 1.キーワードを探す。
 2.終端で終了。
 3.//は行末まで無視(或いは起動時オプション等で有効無効切り替え可能とする?)
 4./*は*/までを無視(同上)。
 5."if/else/elseif/for/while"だったら'{'を探す。
 6.'{'が見つかったら1.に戻る。
 7.空白、タブ、コメントブロックを無視し(ん?このコメントブロックの扱
   いは?)他の文字が現れたら一段前のインデント
 8.位置に"{\n"と見つかった位置分のインデントを挿入。
   (文字の前に見つかった時のインデントを入れてあげれば親切か?)
 9.';'を探す。
10.見つかったらその後ろに'\n'と、'{'を入れた位置のインデント位置に'}\n'を挿入。
11.1.へ・・・

 の様な処理になるのかな?(イリーガル処理を除く)

まぁ自分が作ったリストを変換するぐらいの用途だったらそんなあらゆる条件を網羅する
必要もありませんよね。

No.7337

Re:中括弧を自動でつけるには?
投稿者---こん!(2003/06/12 12:02:04)


>ざっと考えると穴は有るでしょうが

思いっきり穴が・・・

> 9.';'を探す。

if文の次がfor文だったら()の中に';'がぁ。てなチェックと。
if文の次がforループだったりwhileループだったりしたらそのブロックをくくっ
てやらないといけんわね。

No.7338

Re:中括弧を自動でつけるには?
投稿者---たいちう(2003/06/12 12:03:18)


do ... while ( ); への対応も必要か。
これは是非作りたくないプログラムですね。
STLのエキスパートなら呪文で解決できるのかも。

No.7342

Re:中括弧を自動でつけるには?
投稿者---こん!(2003/06/12 12:41:06)


>do ... while ( ); への対応も必要か。

うぐっ、忘れてた・・・
ついでにswitch()も・・・

No.7366

ありがとうございます(Re:中括弧を自動でつけるには?)
投稿者---健一(2003/06/13 02:55:10)


お返事ありがとうございます。
非常に参考になりました。

まず。
>if(i=0; i<10; i++)
なんて書き方はありませんね。
for文と間違ってました。はずかしい・・・

2chにも同じ質問をしたのですが、コードまで書いて頂きました(T_T)
すごく参考になりましたので、ご紹介させていただきます。

Perlを使う方法です。

2chには改行数等の制限がかかっているので、固まって書かれていた
コードをcygwinのastyleで整形して、1行目を変更したのが以下のコードです。

#!/bin/perl

if ( $ARGV[ 1 ] eq "" )
{
print "usage: curly.pl inputfilename outputfilename";
exit();
}

open( INP, $ARGV[ 0 ] ) || die ( "$ARGV[0] not found" );
open( OUT, ">$ARGV[1]" );
$before = "\{\n";
$after = "\}\n";
$flag = 0;
@list = <INP>;
foreach $line ( @list )
{
print( OUT $line );

if ( $flag == 0 )
{
if ( ( $line = ~ / ( ^ \s* ) for [ \( ] / ) || ( $line = ~ / ( ^ \s* ) if [ \( ] / ) )
{
$pre = $1;
print( OUT $pre . $before )
;
$flag = 1;
}
}
else
{
print( OUT $pre . $after );
$flag = 0;
}
}

if ( $flag == 1 )
{
print( OUT $pre . $after );
}

close( INP );
close( OUT );
exit();

cygwinにPerlをいれて実行してみて気づいたのは、
実はすでに中括弧が入っていた部分もありました。
中括弧が無ければ、ばっちし下記のように変換されます。

for(i=0; i<10; i++)
{
   a= a+i;
}

でも上記のようにすでに中括弧が入っていると

for(i=0; i<10; i++)
{
{
{
   a= a+i;
}

となってしまいます。それと

for(i=0; i<10; i++)
  if(i<5)
    a= a+i;
else
a= a-i;

を変換すると、

for(i=0; i<10; i++)
{
  if(i<5)
}
    a= a+i;
else
a= a-i;

となってしまいます。
でもすごいヒントをもらいました。
perlは初めてですが、勉強して直そうと思います。

No.7399

Re:ありがとうございます(Re:中括弧を自動でつけるには?)
投稿者---こん!(2003/06/13 21:58:45)


>>if(i=0; i<10; i++)
>なんて書き方はありませんね。

なにげにさらっと読み飛ばしてました・・・

>Perlを使う方法です。

ちょいと見づらいので代理アップしときます。
リストアップする時はC言語ソース⇒HTML形式ツール使ってインデント付けましょうね。
>#!/bin/perl
>
>if ( $ARGV[ 1 ] eq "" )
>{
>    print "usage: curly.pl inputfilename outputfilename";
>    exit();
>}
>
>open( INP, $ARGV[ 0 ] ) || die ( "$ARGV[0] not found" );
>open( OUT, ">$ARGV[1]" );
>$before = "\{\n";
>$after = "\}\n";
>$flag = 0;
>@list = <INP>;
>foreach $line ( @list )
>{
>    print( OUT $line );
>
>    if ( $flag == 0 )
>    {
>        if ( ( $line = ~ / ( ^ \s* ) for [ \( ] / ) || ( $line = ~ / ( ^ \s* ) if [ \( ] / ) )
>                {
>                    $pre = $1;
>                    print( OUT $pre . $before )
>                    ;
>                    $flag = 1;
>                }
>    }
>    else
>    {
>        print( OUT $pre . $after );
>        $flag = 0;
>    }
>}
>
>if ( $flag == 1 )
>{
>    print( OUT $pre . $after );
>}
>
>close( INP );
>close( OUT );
>exit();
>

>cygwinにPerlをいれて実行してみて気づいたのは、
>実はすでに中括弧が入っていた部分もありました。
>中括弧が無ければ、ばっちし下記のように変換されます。
>
>for(i=0; i<10; i++)
>{
>   a= a+i;
>}
>
>でも上記のようにすでに中括弧が入っていると
>
>for(i=0; i<10; i++)
>{
>{
>{
>   a= a+i;
>}
>
>となってしまいます。それと
>
>for(i=0; i<10; i++)
>  if(i<5)
>     a= a+i;
>    else
>        a= a-i;
>
>を変換すると、
>
>for(i=0; i<10; i++)
>{
>  if(i<5)
>}
>     a= a+i;
>    else
>        a= a-i;
>
>となってしまいます。


No.7464

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/17 21:16:31)


行内で if や for の括弧が完結していなければだめだとか、
単純な文が 2行以上になるとおかしくなることがあるとか、
コメントや、文字列や、ラベルなどを全く処理しないとか、
そんないい加減なプログラムで、よければこんなもんでどうでしょうか。
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int statement(const char *s)
{
    char buf[1024]; int i, j, t;

    if (fgets(buf, sizeof buf, stdin) == NULL) return EOF;
    for (i = 0; buf[i]==' ' || buf[i]=='\t'; i++)
        ;
    j = i;
    if (buf[i] == '{') {
        fputs(buf, stdout);
        while (statement(NULL) == 0)
            ;
        return 0;
    }
    if (buf[i] == '}') {
        fputs(buf, stdout);
        return 1;
    }
    for (; isalnum(buf[i] & 0xFF); i++)
        ;
    i -= j;
    if (i == 2 && !memcmp(buf+j, "if", i)
     || i == 2 && !memcmp(buf+j, "do", i)
     || i == 3 && !memcmp(buf+j, "for", i)
     || i == 4 && !memcmp(buf+j, "else", i)
     || i == 5 && !memcmp(buf+j, "while", i)
     || i == 6 && !memcmp(buf+j, "switch", i)
     || i == 7 && !memcmp(buf+j, "else if", i)) {
        if (s) printf("%s{\n", s);
        fputs(buf, stdout);
        if (strchr(buf, '{'))
            while (statement(NULL) == 0)
                ;
        else {
            buf[j] = '\0';
            statement(buf);
        }
        if (s) printf("%s}\n", s);
        return 0;
    }
    if (s) printf("%s{\n", s);
    fputs(buf, stdout);
    if (s) printf("%s}\n", s);
    return 0;
}

int main(void)
{
    while (statement(NULL) != EOF)
        ;
    return 0;
}


No.7473

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/17 23:19:40)


"else if" は絶対にマッチしませんね。無駄でした。
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define X(w)  (memcmp(buf+i, w, j) == 0)

int statement(const char *s)
{
    char buf[1024];  int i, j;

    if (fgets(buf, sizeof buf, stdin) == NULL) return EOF;
    for (i = 0; buf[i]==' ' || buf[i]=='\t'; i++)
        ;
    if (buf[i] == '{') {
        fputs(buf, stdout);
        while (statement(NULL) == 0)
            ;
        return 0;
    }
    if (buf[i] == '}') return fputs(buf, stdout), 1;
    for (j = i; isalnum(buf[j] & 0xFF); j++)
        ;
    if (s) printf("%s{\n", s);
    fputs(buf, stdout);
    j -= i;
    if (j && (X("if") || X("do") || X("for") || X("else") || X("while") || X("switch")))
        if (strchr(buf, '{'))
            while (statement(NULL) == 0)
                ;
        else
            buf[i] = '\0', statement(buf);
    if (s) printf("%s}\n", s);
    return 0;
}

int main(void)
{
    while (statement(NULL) != EOF)
        ;
    return 0;
}


No.7476

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/18 02:02:22)


> #define X(w)  (memcmp(buf+i, w, j) == 0)

訂正です。

#define X(w)  (j == strlen(w) && memcmp(buf+i, w, j) == 0)

元のままだと、f = 3; が for文になってしまいます。

No.7481

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/18 02:35:07)


> #define X(w)  (j == strlen(w) && memcmp(buf+i, w, j) == 0)

さらに、訂正です。

#define X(w)  (j == sizeof(w)-1 && memcmp(buf+i, w, j) == 0)


No.7486

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/18 10:54:19)


やっぱりだめですね。

    for (i = 0; i < 10; i++)
        if (i < 5)
            a = a + 1;
        else
            a = a - 1;
が

    for (i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            a = a + 1;
        }
    }
        else
        {
            a = a - 1;
        }

になってしまいます。

失礼しました。


No.7501

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/18 13:08:44)


こうして、プログラムはだんだん複雑になってきましたが、
まだまだ完璧ではありません。
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define X(w)  (j == sizeof(w)-1 && memcmp(buf+i, w, j) == 0)

#define BUFSIZE  1024

static char buf2[BUFSIZE], *p;

char *getline(char *s)
{
    if (p == NULL) return fgets(s, BUFSIZE, stdin);
    strcpy(s, p);
    p = NULL;
    return s;
}

int statement(const char *s)
{
    char buf[1024], c;  int i, j;

    if (getline(buf) == NULL) return EOF;
    for (i = 0; buf[i]==' ' || buf[i]=='\t'; i++)
        ;
    if (buf[i] == '{') {
        fputs(buf, stdout);
        while (statement(NULL) == 0)
            ;
        return 0;
    }
    if (buf[i] == '}') return fputs(buf, stdout), 1;
    for (j = i; isalnum(buf[j] & 0xFF); j++)
        ;
    if (s) printf("%s{\n", s);
    fputs(buf, stdout);
    j -= i;
    if (X("if")) {
        if (strchr(buf, '{'))
            while (statement(NULL) == 0)
                ;
        else
            buf[i] = '\0', statement(buf);
        while (fgets(buf2, BUFSIZE, stdin)) {
            if (sscanf(buf2, " else%c", &c) == 1 && !isalnum(c & 0xFF)) {
                fputs(buf2, stdout);
                if (strchr(buf2, '{'))
                    while (statement(NULL) == 0)
                        ;
                else
                    statement(buf);
            } else {
                p = buf2;
                break;
            }
        }
    }
    else if (X("do") || X("for") || X("while") || X("switch"))
        if (strchr(buf, '{'))
            while (statement(NULL) == 0)
                ;
        else
            buf[i] = '\0', statement(buf);
    if (s) printf("%s}\n", s);
    return 0;
}

int main(void)
{
    while (statement(NULL) != EOF)
        ;
    return 0;
}


No.7581

Re:中括弧を自動でつけるには?
投稿者---かずま(2003/06/19 18:11:02)


また、訂正です。元のプログラムだと、

if_name = "input_file.txt";

が if文と解釈されてしまいます。
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define X(w)  (j == sizeof(w)-1 && memcmp(buf+i, w, j) == 0)
#define ISALNUM(c)  (isalnum((c) & 0xFF) || (c) == '_')

int statement(const char *s)
{
    static char buf2[1024], *p;
    char buf[1024], c;  int i, j;

    if (p)
        strcpy(buf, p), p = NULL;
    else if (fgets(buf, sizeof buf, stdin) == NULL)
        return EOF;
    for (i = 0; buf[i]==' ' || buf[i]=='\t'; i++)
        ;
    if (buf[i] == '{') {
        fputs(buf, stdout);
        while (statement(NULL) == 0)
            ;
        return 0;
    }
    if (buf[i] == '}') return fputs(buf, stdout), 1;
    for (j = i; ISALNUM(buf[j]); j++)
        ;
    if (s) printf("%s{\n", s);
    fputs(buf, stdout);
    j -= i;
    if (X("if")) {
        if (strchr(buf, '{'))
            while (statement(NULL) == 0)
                ;
        else
            buf[i] = '\0', statement(buf);
        while (fgets(buf2, sizeof buf2, stdin)) {
            if (sscanf(buf2, " else%c", &c) == 1 && !ISALNUM(c)) {
                fputs(buf2, stdout);
                if (strchr(buf2, '{'))
                    while (statement(NULL) == 0)
                        ;
                else
                    statement(buf);
            } else {
                p = buf2;
                    break;
            }
        }
    }
    else if (X("do") || X("for") || X("while") || X("switch"))
        if (strchr(buf, '{'))
            while (statement(NULL) == 0)
                ;
        else
            buf[i] = '\0', statement(buf);
    if (s) printf("%s}\n", s);
    return 0;
}

int main(void)
{
    while (statement(NULL) != EOF)
        ;
    return 0;
}