Как линия с двумя обратными слэшами преувеличивает C препроцессор?
Я решил взглянуть на источник стандартного модуля Haskell Data.List нашел что-то интересное. Код, очевидно, сначала обрабатывается препроцессором C, как набор #ifdef
, и только после этого компилируется компилятором Haskell. Однако препроцессор C не очень дружелюбен к исходному коду, отличному от самого C, как указано в документации :
Препроцессор C предназначен для использования только с исходными кодами C, С++ и Objective-C. Раньше он злоупотреблялся как обычный текстовый процессор. Он будет подавлять входные данные, которые не подчиняются C лексическим правилам. Например, апострофы будут интерпретироваться как начало символьных констант и вызвать ошибки. Кроме того, вы не можете полагаться на это, сохраняя характеристики ввода, которые не имеют существенного значения для языков C-семейства. Если Makefile предварительно обработан, все жесткие вкладки будут удалены, и Makefile не будет работать.
Но почему-то код Haskell все еще сохраняется при предварительной обработке C? Вероятно, этот фрагмент дает ключ:
#ifdef __GLASGOW_HASKELL__
import GHC.Num
import GHC.Real
import GHC.List
import GHC.Base
#endif
infix 5 \\ -- comment to fool cpp
-- -----------------------------------------------------------------------------
-- List functions
Как работает этот comment to fool cpp
? Похоже на интересный хак, но я не мог ничего сделать по этой теме. В Haskell эта строка объявляет инфиксный оператор \\
с приоритетом 5, и весь текст после --
игнорируется. Но что он делает с препроцессором C и каким образом это действительно "обмануто"?
Ответы
Ответ 1
Если вы просто нажмете это:
infix 5 \\
препроцессор C выдает следующее сообщение, когда строка находится в конце файла:
infix 5 \foo.c:8:10: warning: backslash-newline at end of file
И если это не в конце файла (спасибо @commenter), он просто "съедает" одну обратную косую черту (чтобы связать ее со следующей строкой новой строки), а выход неверен на стороне Haskell:
infix 5 \
НО, если после этого вы добавите комментарий типа Haskell, Haskell проигнорирует его (очевидно!), и это не проблема для препроцессора C, так как \
не находится в конце строки:
infix 5 \\ -- comment
cpp выдает точный текст, и Haskell может анализировать интересную часть, зачищая комментарий ``.
(обратите внимание, что он никогда не действителен C, но препроцессор не против)
Примечание: проблема аналогична, если вы хотите закончить строку комментария C/С++ //
с помощью \
: вы не можете без нее продолжить комментарий на следующей строке: не то, что вы хотите.