Почему вложенные комментарии запрещены? - PullRequest
15 голосов
/ 03 июня 2010

Почему вложенные комментарии запрещены в C ++, Java, несмотря на тот факт, что вложенные комментарии полезны, аккуратны и элегантны и могут использоваться для комментирования операторов, имеющих комментарии?

Ответы [ 7 ]

14 голосов
/ 03 июня 2010

C и C ++ делают это для простоты анализа. Таким образом, когда они попадают в начало комментария / *, анализатор может тривиально сканировать до конца. В противном случае потребуется настроить и поддерживать стек, а затем сообщать об ошибках, если токены комментариев не совпадают.

Что касается того, почему Java это делает, ответ прост - синтаксис Java был разработан для эмуляции C и C ++. Если бы были разрешены вложенные комментарии, это могло бы сбить с толку некоторых программистов на С, и было бы написано много злых постов в блоге!

8 голосов
/ 03 июня 2010

По крайней мере для C ++ это только частично верно, нет проблем с:

/*
//
//
*/

Однако, если у вас уже есть комментарий / * в разделе, который вы хотите закомментировать, вы можете сделать это, окружив его #if 0, который, я думаю, многие компиляторы оптимизируют. Как в:

#if 0
/*

*/
#endif
4 голосов
/ 04 июня 2010

Это отличается для каждого языка (семейства), но в целом они не «запрещены», а просто не поддерживаются. Поддержка их - выбор дизайна.

Одной из причин выбора (для более старых языков) может быть простота синтаксического анализа.

Примечание: я помню компилятор C ++, где была возможность позволить им вложить. Он был помечен как «нестандартный».

3 голосов
/ 15 ноября 2013

Рассмотрим следующий пример:

/* This is a comment /* Nested Comments */ are not allowed. */

Все, что находится между /* и */, рассматривается как комментарий. В приведенном выше примере от This до Comments все рассматривается как комментарии, включая /*. Следовательно, are not allowed. */ не лежит в комментарии. Это неправильная ошибка оператора C происходит.

Рассмотрим этот пример:

// This is an /* valid */ comment

Все, что находится в строке после //, рассматривается как комментарий. Поскольку /* valid */ находится в той же строке после //, он рассматривается как часть комментария.

3 голосов
/ 03 июня 2010

Соответствие / совместимость с C.

0 голосов
/ 10 сентября 2016

Проблема в том, что вы не можете просто «пропустить» блоки. блоки имеют неизвестное количество блоков внутри них, поэтому, чтобы узнать, когда этот блок будет завершен, вы не можете использовать обычный язык, вы должны использовать стек и проходить через каждый блок, пока стек не будет пустым, и в этот момент Вы знаете, что блок сделан.

Причина, по которой вы не можете пропустить блоки, состоит в том, что регулярное выражение для блока способно сопоставить / * только с "первым * /, который он видит позже", или "последним * /, которое он видит позже", или "nth * / потом видит".

Если мы пойдем с первым видимым токеном "* /", у нас может быть код, подобный

/*
    /*

    */
    the compiler matched /* with */ and this line and the next one will confuse it.
*/

Если мы пойдем с последним токеном «* /», который мы увидим, у нас будет код, в котором компилятор пропустит что-то между первым комментарием в файле и последним комментарием конца файла. В этом случае следующий код будет проанализирован как пустая строка.

/*
    /* hello, world! */
*/
int main(int argc, char ** argv) {
    return 0;
}
/* end of file */

Мы не можем пойти с третьим вариантом пропустить n внутренних блоков, не заставляя все комментарии иметь точное количество глубины, иначе он не найдет внутренний комментарий и не запутается.

На самом деле, существует четвертый вариант явного указания, что комментарий может быть отдельным комментарием, комментарием с двумя областями, комментарием с тремя областями и т. Д .; Но делать это уродливо, и каждый уровень глубины требует значительно более длинного выражения, и этот подход ограничивает комментарии до определенной глубины, которая может подходить некоторым людям, а не другим: что делать, если вы закомментируете закомментированный код три раза?

Общее решение может быть реализовано с помощью препроцессора, например:

<?php
function stripComments($code) {
    $stack = array();
    $codeOut = '';
    $stringStream = fopen('php://memory', 'r+');
    fwrite($stringStream, $code);  
    rewind($stringStream);  

    while (!feof($stringStream)) {
        $ch = fgetc($stringStream);

        $nextChar = fgetc($stringStream);
        if ($nextChar === false) {
            break;
        }

        if ($ch == '/' && $nextChar == '*') {
            array_push($stack, '/*');          
        } else if ($ch == '*' && $nextChar == '/') {
            if (count($stack) > 0) {
                array_pop($stack);
            } else {
                die('cannot pop from empty stack');
            }
        } else {
            if (count($stack) == 0) {
                $codeOut .= $ch;
                fseek($stringStream, -1, SEEK_CUR);
            }
        }               

        $prevChar = $ch;
    }
    return $codeOut;
};
?>

Что немного сложнее, чем то, что в настоящее время использует C:

function stripComments($code) {
    return preg_replace('/\/\*[^\*\/]*\*\//', '', $code);
}

Это не учитывает блоки /**/ внутри кавычек, требуется несколько более сложный стек, который может различать область видимости "/ *" и область видимости "\".

Преимущество наличия комментариев внутри комментариев состоит в том, что вы можете закомментировать блоки, содержащие комментарии, не разбирая комментарии вручную, что особенно неприятно для блоков, в которых комментарии находятся в каждой строке.

Резюме : Это можно сделать, но большинство языков не хотят обрабатывать комментарии, как если бы они были их собственными областями, так как для их анализа требуется больше усилий.

0 голосов
/ 15 декабря 2013

В языках, которые допускают комментарии произвольной длины, программисты очень часто случайно закомментируют или, в некоторых редких случаях, «раскомментируют» больше или меньше кода, чем нужно. Во многих случаях такие ошибки приводят к ошибкам компиляции, но в других случаях они могут привести к просто нарушенному коду. В современных редакторах с подсветкой синтаксиса правило, согласно которому каждый /* будет увеличивать счетчик вложенных комментариев, а каждый */, который будет уменьшать его, может не вызывать особых проблем, но без выделения синтаксиса даже при попытке выяснить, какой код комментируется и то, что код не был, могло быть главной головной болью.

Если кто-то разрабатывал язык с нуля, хорошим подходом может быть указание меток начала и конца комментария, которые содержат необязательную строку, и чтобы язык применял требование, чтобы строка в конце -комментарий комментария должен соответствовать строке в соответствующем знаке начала комментария. Предполагая, что синтаксис был <|String| и |String|>, компилятор мог бы затем принять <|1| <|2| |2|> |1|>, но отклонить <|1| <|2| |1|> |2|>. Даже если бы кто-то предпочитал использовать директивы #if, а не комментарии, была бы полезна возможность прикреплять маркеры для обеспечения соответствия каждой конечной директивы предполагаемой директиве start.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...