challenge 複数行のコメントアウト

言語の機能系の問題です。

ソースコードの複数行にまたがる範囲を、範囲の前後に何かを書き足すだけで実行しないようにしてください。 「その範囲を削除する」などはダメです。 何重まで入れ子にできるか、どのような制限があるかを明記してください。 例えばJavaであれば/*~*/で複数行のコメントアウトができますが、入れ子/* /* */ */にできません。 Pythonであれば"""~"""で文字列化することでコメントアウトでき、'''~'''も使えるので2重まで入れ子にできます。

このお題は、無制限に入れ子にできるCommon Lispからの挑戦状です。 プログラミングシンポジウムで前田敦司先生の発表を聞いて思いつきました。

Posted feedbacks - Nested

Flatten Hidden
1
2
3
4
5
実行させたくない箇所を
    function () {

    }
で括る。
{- Haskellではブロックコメントは無限にネストさせらる -}
http://www.sampou.org/haskell/report-revised-j/lexemes.html#sect2.3 に記述があります

	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{- 
コードがないとカバレッジにカウントされない
ようなので、あらためて,投稿します。
-}

main :: IO ()
main = putStrLn {- "Hello, world!"

{- Haskellではコメントは何段でもネストできます.

{-
main :: IO ()
main = putStrLn -} -} -} "Bonjour, trisstesse"

{- {-
*Main> :main
Bonjour, trisstesse
-}
-}
#3500 をOtherで投稿しちゃった。
Haskellで再投稿。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{- 
コードがないとカバレッジにカウントされない
ようなので、あらためて,投稿します。
-}

main :: IO ()
main = putStrLn {- "Hello, world!"

{- Haskellではコメントは何段でもネストできます.

{-
main :: IO ()
main = putStrLn -} -} -} "Bonjour, trisstesse"

{- {-
*Main> :main
Bonjour, trisstesse
-}
-}
C言語です。
複数行のコメントは二つに分けられる。

一つ目は/* */。
ただし、これは入れ子にできない。

二つ目はマクロ。
これは入れ子も可能。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>

int main()
{
#ifndef DEBUG1
    printf("one\n");
#ifndef DEBUG2
    printf("two\n");
    /*
    printf("three\n");
    */
#endif /* DEBUG2 */
    printf("four\n");
#endif /* DEBUG1 */

    return 0;
}


/*
$ gcc test.c -DDEBUG1 -DDEBUG2
$ ./a.out 
$ gcc test.c -DDEBUG1 
$ ./a.out 
$ gcc test.c -DDEBUG2
$ ./a.out 
one
four
$ gcc test.c
$ ./a.out 
one
two
four
$ 
*/
#if~はプリプロセッサディレクティブ、ですね。
「マクロ」は#defineで定義されたものの事を指すのではないかな。
そうですね。
適当な事書いてすいませんでした。
Dだとプリプロセッサに相当する部分は言語仕様に含まれている!コンパイル時に判断。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
module doukaku;
private import std.stdio;

void main() {
    static if (0) {
        these_lines();
        are_not();
        executed();
        static if (0) {
            nesting();
            is_allowed();
        }
    }
    /* C-style
       comment
       is also allowed. */
    writefln("ok");
}
Smalltalk のコメントアウトは通常 "〜" のようにダブルクオートで括るのですが、これだとコメント文中の " をエスケープする(二連にする)作業が必要になり、今回の目的には使えません。しかし、実行させたくない箇所の前後を [ と ]. で括って無名関数(ブロックと呼ぶ)化してしまうことで、入れ子状態になることを気にせず当該箇所のコードを実行させなくすることは可能です。ただしこの場合、括る内容はコンパイル可能なコードになっていなくてはいけない…という制約があります。あと、当然のことながらパーサーはコメントとして認識しないため、メソッドのコメントを抽出するようなリフレクション機能が使えなくなる…という欠点もあるので、安易には用いないほうがよいでしょう。
1
2
3
4
5
"通常のコメント(入れ子にはしにくい)"

[ #ブロック式を代用したコメントアウト ].

[[[ #入れ子にもできる ]]].
コメントアウトしたい文字列をヒアドキュメント扱いします。 文字列 'EOF' の部分は任意の文字列なので、これが重複しない限りネストできます。
1
2
3
4
5
6
7
8
cat << 'EOF' > /dev/null
  foo
  # bar
  baz
  cat << 'ABC' > /dev/null
    what's the next of baz?
  ABC
EOF
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/usr/local/bin/ruby -Ke
=begin
コメント。
ネスト不可。
=end
if false
  これは
  ネスト可
  if false
    でも文法違反したらダメ!
  end
end
%文字列がネストできるって知ってた?
1
2
3
4
5
if false then %{
   if false then %{
      nested comment
   }; end
}; end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# ループで
{last;
    {last;
        print "NEST OK\n";
    }
}

# ヒアドキュメントで
<<A;
<<B;
    print "NEST OK\n"
B
A
Javaの場合、範囲を
    if (false) { 
と
    }
で囲むことにより実行しない(コード生成もされない)部分を指定します。
もちろん false 部分は
    if (DEBUG) {
としておいて
    static final boolean DEBUG = false;
と定数宣言する事ができます。入れ子の制限はありません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private static final boolean DEBUG = false;

public void foo() `
    if (DEBUG) {
        System.err.println("enter foo");
     }
    // do anything
    if (DEBUG) {
        System.err.println("exit foo");
    }
}
何もしないマクロで囲む。入れ子も可能です。
1
2
3
4
5
6
7
(defmacro comment-out (&body body))

(print "hello.")
(comment-out
(print "how r u?")
)
(print "good bye.")
緊急回避ならば(when nil~)や(unless t~)なんてのもアリ??
#Ifディレクティブかなぁ。ネストもOK。
制限は同一行にコード記述不可です。
条件式が不成立なら中身は構文チェックされないんですね。試して初めて知りました。
1
2
3
#If False Then
    ほげほげ
#End If
C#では、入れ子不可のブロックコメントと、入れ子可のifディレクティブが使えます。
1
2
3
4
5
6
/*
...
*/
#if true
...
#endif
Lua5.1 では -- が1行コメントで --[[ から --]] までがブロックコメントになります。この性質を利用すると --[[ を ---[[ と書き換えるだけでコメントアウトを解除できて便利です。ブロックコメントをネストするには --[=[ ... --]=] のように任意の数の等号を挟みます。この例では B だけが表示されます(シンタクスハイライトは残念ながらブロックコメントに対応していないようですが…)。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
--[[
  print("A")
--]]

---[[
  print("B")
--]]

--[===[
--[==[
--[=[
--[[
  print("C")
--]]
--]=]
--]==]
--]===]
1
2
3
4
5
6
7
8
9
// 文字列として変数に割り当てる
val a = """
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
"""

//いくらでも入れ子にできる
/*
aaaa /* bbbb /* cccc */ */ /* */
*/
comment reader macro
1
1 #| comment #| nested comment |# comment |#    ;; => 1
↑は1行で書いてしまったが、もちろん複数行可能です。
1
2
3
1 #| comment
#| nested comment
|# comment |#          ;; => 1
最初、正にこれを探してました ^^;
SRFI-30。Gaucheならデフォルトでサポート。
1
2
3
4
;; (use srfi-30)
(print 1) #| comment
#| nested comment |#
comment |#
elispは #| ~ |# をサポートしていないため、言語仕様上複数行コメントはできない。 しかし、式をquoteすることでお手軽コメントアウトもどきはできる。 言うまでもないが、評価結果はlistである。どうせGCされる運命なんだけどね。 某所で見かけて以来、自分も使うようになった。
1
2
3
4
'(progn
   ;; 式をquoteすることで事実上コメントアウトになる
   (switch-to-buffer "*scratch*")
   (goto-char (point-max)))
PHPの複数行のコメントはC同様/* */で入れ子に出来ませんが、
ヒアドキュメント構文("<<<")で使われないリテラルにしてしまえば
入れ子もなんとか可能です。
ただし、ヒアドキュメント内の変数は展開されるため
内容によってはエラーとなります。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php
/*
	普通のコメント
 */

$a=array(0);

<<< ENDOFEND

<<< END
	リテラル化で疑似コメント
END;

	$a[0]  '0'  ']' が抜けると構文エラー
	$a[0] 自体が定義されていないと警告表示

ENDOFEND;
?>

	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/*
Java風コメントアウト
*/

`
バッククォートで囲んだ部分は文字列リテラルになる
`
if (false){
  // コメントアウトではないけど if 文を使うことも
}
1
2
3
4
if(0){
    cat("言語の仕様として複数行をコメントアウトする機能はありません\n")
    文法的に問題なければ日本語も書けます
}
日本語が文法的に問題ないというのが逆にびっくりですが、長い名前の変数が1つ書いてあると見なされているわけでしょうか?
そのようです。
ただ、"。+ 改行" の場合など(文字コードの関係かと思ったのですがよく分かりません・・・)
おかしな挙動をすることがあるので、オフィシャルにサポートするものではなさそうです。
1
2
3
4
5
6
7
8
> 文法的に問題なければ日本語も書けます <- "これはオブジェクトです"
> 文法的に問題なければ日本語も書けます
[1] "これはオブジェクトです"

> if(0){
+ あ。
 エラー: syntax error, unexpected $undefined, expecting '\n' or ';' or '}' ( "if(0){" の)
> }
Pythonの場合、"""~"""か'''~'''で囲うことで
複数行文字列にするのがおそらく唯一の方法です。
1
2
3
4
5
6
7
'''
if x:
    """
    a = b
    """
    b = c
'''
いろいろためしてたら、こんなのできました。 頭がこんがらがるので、なんでこうなるとか、'''も使うとどうなるとかは考えたくないです。 書き方及び制限事項 ・トップレベルのコメントは(""" 〜 """)で囲む ・それ以降のコメントは(""",(""", 〜 """),""")で囲む ・ただし、トップレベルのコメント開始位置は正しいインデント位置から始めないといけない
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
print "not a comment?"

("""

print comment 1?

  (""",(""",
       print comment 2?

   (""",(""",
     print comment 3?
             (""",(""",
    print comm(ry 
   """),""")
  print comment 3!
 """),""")

    print comment 2!
          """),""")
    print comment 1!

""")

print "not a comment!"
StandardMLは何重でも可。
1
2
3
(* comment1
(* comment2 (* comment3 *) *)
*)
無制限に。
1
2
3
(* comment1
(* comment 2 (* comment3 *) *)
*)
StandardMLのコメントはネスト可能だが、コメントの開始記号と終端記号は必ず対になっていなければならないらしい。無制限じゃないです。
SWI-prologには
入れ子にできる、C風範囲コメントがあります。
1
2
3
4
5
6
7
8
crossp([],[]).
crossp([X|Xs],[I|Is]):-member(I,X),crossp(Xs,Is).
/*
        /*
         * comment
         */
 */
:-findall(X,crossp([[1,2,3],[uno,due,tre],[un,doux,trois]],X),Xs),writeln(Xs).
ネストはできませんが /**/  形式によるコメントがかけます。

あとは、他の言語と同じようにコメントアウトする箇所が構文的に問題ないのであれば if (false) {} や fun{}で囲むしかないと思います。
Ocamlにはあてはまらない要素が多いのでOthersでF#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(*
c.f. Comments are delimited by (* and *) and """may be nested""".

一応ネストできますが無制限かどうかは不明。
*)
// C/C++ styleでも可能。

//条件コンパイル用ですがこういう形も
(*IF-FSHARP  ...F#のコード... ENDIF-FSHARP*)
or  (*F#  ...F#のコード...  F#*)

(*IF-CAML*)  ...OCamlのコード...  (*ENDIF-CAML*)
or (*IF-OCAML*)  ...OCamlのコード... (*ENDIF-OCAML*)
再投稿
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(*
c.f. Comments are delimited by (* and *) and """may be nested""".

一応ネストできますが無制限かどうかは不明。
*)
// C/C++ styleでも可能。

//条件コンパイル用ですがこういう形も
(*IF-FSHARP  ...F#のコード... ENDIF-FSHARP*)
or  (*F#  ...F#のコード...  F#*)

(*IF-CAML*)  ...OCamlのコード...  (*ENDIF-CAML*)
or (*IF-OCAML*)  ...OCamlのコード... (*ENDIF-OCAML*)
ソースコード中で使われることは意図してなさそうですが
#@n で n 文字読み飛ばすことができます。
1
2
#@18
this is a comment
1
2
3
4
5
6
7
// 行コメント

『・文字列によるコメントアウト
  → 自由に書けるが入れ子に出来ない』。
 
「「ブロックによるコメントアウト。
  構文エラーを許さないが、入れ子に出来る。」」。
GASで複数行をコメントアウトするには、 /* ... */ かマクロを使います。/* ... */ は入れ子にできませんが、マクロは入れ子にできます。
1
2
3
4
5
6
7
8
9
/*
 * コメント
 */

.if DEBUG1
.if DEBUG1
    /* コード */
.endif
.endif
% PostScript の場合通常のコメントは % 以降の1行コメントのみ.

{ 複数行のときは
とりあえずスタックに
積んで捨てるかなぁ...
% ネストも
  {
     問題ない筈
  } pop 
} pop
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
%!PS

% 1 line comment

{
  hogehoge
  fugafuga 
  {
     foo
  } pop
} pop

PHPは<?php ...?>の内側しか実行されないので、余計な出力を捨てると可能。JSPでも同等の事が可能。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
$a = range(1,100);
#コメントアウト
ob_start();?>
array_keys($a);
<?php ob_end_clean();
    array_shift($a);
ob_start();?>
array_pop($a);
<?php ob_end_clean();
array_flip($a);
Erlangにブロックコメントはありません。行頭に%をつけるのみです。
eppというプリプロセッサが使えますが、マクロの展開のみで複数行にわたってコメントアウトというような用途にはあまり使えません。。。

実行結果
%% デバック(debug)オプション付きでコンパイル
1> c(comment, [{d, debug}]).
{ok,comment}
%% デバックメッセージが表示される
2> comment:start().
start debug
DEBUG comment:13 debug
ok
%% デバック(debug)オプションなし
3> c(comment).
{ok,comment}
4> comment:start().
start
void
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-module(comment).
-compile(export_all).

-ifdef(debug).
-define(DEBUG(X), io:format("DEBUG ~p:~p ~p~n",[?MODULE,?LINE,X])).
-else.
-define(DEBUG(X), void).
-endif.

-ifdef(debug).
start()->
    % これはコメント。
    io:format("start debug~n"),
    ?DEBUG(debug).
-else.
start()->
    % こういう分け方は可能。
    io:format("start~n"),
    ?DEBUG(debug).
-endif.

% これは文法エラーではじかれる
-ifdef(debug).
hello
-endif.

% 入れ子も可能だけど、定義は先にしておかなければいけない。
-ifdef(debug).
-ifdef(trace).
-define(TRACE(X), io:format("TRACE ~p:~p ~p~n",[?MODULE,?LINE,X])).
-endif.
-endif.
Cのコードで#if 0が使われていないので、C++で投稿します。Cでも使えるので心苦しい感じもします(言語指定をC/C++プリプロセッサにしたほうがよかったかもしれません)。ともあれ、#if 0から#endifで囲った範囲はコンパイル対象から外れ、何重にも重ねられます。通常の複数行コメント/* */は二重以上にできません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <iostream>

int main()
{
#if 0
    std::cout << "表示されませんよ" << std::endl;
#if 0
    std::cout << "中に誰もいませんよ" << std::endl;
#endif
#endif
}

まだ、XML系が1つも出ていないので、代表としてXHTMLを投稿します。ところで、現在どう書く?の言語の選択肢にXAMLとXSLTがあるんですけど、彼らもXMLレベルのコメントの構文は同じなんですよね。そんなことを気にしたら投稿できないですけど。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
  <head>
    <title>XHTML+XMLコメントの例</title>
  </head>
  <body>
    <p>本文。<!--ここはコメント--></p>
    <!--
    <p>あーあー、見えない。</p>
    -->
  </body>
</html>

SQL Serverでは範囲コメントは/* ~ */で、入れ子も可能です。

System Message: WARNING/2 (<string>, line 1); backlink

Inline emphasis start-string without end-string.
1
2
/* hoge /* piyo */ foo */
SELECT * FROM SomeTable;

間に何を書いてもいい、という意味でのコメントとしては3重ネストまでかな。

1
2
3
4
5
6
7
/*
'''
"""
abc
"""
'''
*/

Index

Feed

Other

Link

Pathtraq

loading...