c.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. Language: C
  3. Category: common, system
  4. Website: https://en.wikipedia.org/wiki/C_(programming_language)
  5. */
  6. /** @type LanguageFn */
  7. function c(hljs) {
  8. const regex = hljs.regex;
  9. // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does
  10. // not include such support nor can we be sure all the grammars depending
  11. // on it would desire this behavior
  12. const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] });
  13. const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)';
  14. const NAMESPACE_RE = '[a-zA-Z_]\\w*::';
  15. const TEMPLATE_ARGUMENT_RE = '<[^<>]+>';
  16. const FUNCTION_TYPE_RE = '('
  17. + DECLTYPE_AUTO_RE + '|'
  18. + regex.optional(NAMESPACE_RE)
  19. + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE)
  20. + ')';
  21. const TYPES = {
  22. className: 'type',
  23. variants: [
  24. { begin: '\\b[a-z\\d_]*_t\\b' },
  25. { match: /\batomic_[a-z]{3,6}\b/ }
  26. ]
  27. };
  28. // https://en.cppreference.com/w/cpp/language/escape
  29. // \\ \x \xFF \u2837 \u00323747 \374
  30. const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)';
  31. const STRINGS = {
  32. className: 'string',
  33. variants: [
  34. {
  35. begin: '(u8?|U|L)?"',
  36. end: '"',
  37. illegal: '\\n',
  38. contains: [ hljs.BACKSLASH_ESCAPE ]
  39. },
  40. {
  41. begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)",
  42. end: '\'',
  43. illegal: '.'
  44. },
  45. hljs.END_SAME_AS_BEGIN({
  46. begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,
  47. end: /\)([^()\\ ]{0,16})"/
  48. })
  49. ]
  50. };
  51. const NUMBERS = {
  52. className: 'number',
  53. variants: [
  54. { begin: '\\b(0b[01\']+)' },
  55. { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)' },
  56. { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' }
  57. ],
  58. relevance: 0
  59. };
  60. const PREPROCESSOR = {
  61. className: 'meta',
  62. begin: /#\s*[a-z]+\b/,
  63. end: /$/,
  64. keywords: { keyword:
  65. 'if else elif endif define undef warning error line '
  66. + 'pragma _Pragma ifdef ifndef include' },
  67. contains: [
  68. {
  69. begin: /\\\n/,
  70. relevance: 0
  71. },
  72. hljs.inherit(STRINGS, { className: 'string' }),
  73. {
  74. className: 'string',
  75. begin: /<.*?>/
  76. },
  77. C_LINE_COMMENT_MODE,
  78. hljs.C_BLOCK_COMMENT_MODE
  79. ]
  80. };
  81. const TITLE_MODE = {
  82. className: 'title',
  83. begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE,
  84. relevance: 0
  85. };
  86. const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';
  87. const C_KEYWORDS = [
  88. "asm",
  89. "auto",
  90. "break",
  91. "case",
  92. "continue",
  93. "default",
  94. "do",
  95. "else",
  96. "enum",
  97. "extern",
  98. "for",
  99. "fortran",
  100. "goto",
  101. "if",
  102. "inline",
  103. "register",
  104. "restrict",
  105. "return",
  106. "sizeof",
  107. "struct",
  108. "switch",
  109. "typedef",
  110. "union",
  111. "volatile",
  112. "while",
  113. "_Alignas",
  114. "_Alignof",
  115. "_Atomic",
  116. "_Generic",
  117. "_Noreturn",
  118. "_Static_assert",
  119. "_Thread_local",
  120. // aliases
  121. "alignas",
  122. "alignof",
  123. "noreturn",
  124. "static_assert",
  125. "thread_local",
  126. // not a C keyword but is, for all intents and purposes, treated exactly like one.
  127. "_Pragma"
  128. ];
  129. const C_TYPES = [
  130. "float",
  131. "double",
  132. "signed",
  133. "unsigned",
  134. "int",
  135. "short",
  136. "long",
  137. "char",
  138. "void",
  139. "_Bool",
  140. "_Complex",
  141. "_Imaginary",
  142. "_Decimal32",
  143. "_Decimal64",
  144. "_Decimal128",
  145. // modifiers
  146. "const",
  147. "static",
  148. // aliases
  149. "complex",
  150. "bool",
  151. "imaginary"
  152. ];
  153. const KEYWORDS = {
  154. keyword: C_KEYWORDS,
  155. type: C_TYPES,
  156. literal: 'true false NULL',
  157. // TODO: apply hinting work similar to what was done in cpp.js
  158. built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream '
  159. + 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set '
  160. + 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos '
  161. + 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp '
  162. + 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper '
  163. + 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow '
  164. + 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp '
  165. + 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan '
  166. + 'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
  167. };
  168. const EXPRESSION_CONTAINS = [
  169. PREPROCESSOR,
  170. TYPES,
  171. C_LINE_COMMENT_MODE,
  172. hljs.C_BLOCK_COMMENT_MODE,
  173. NUMBERS,
  174. STRINGS
  175. ];
  176. const EXPRESSION_CONTEXT = {
  177. // This mode covers expression context where we can't expect a function
  178. // definition and shouldn't highlight anything that looks like one:
  179. // `return some()`, `else if()`, `(x*sum(1, 2))`
  180. variants: [
  181. {
  182. begin: /=/,
  183. end: /;/
  184. },
  185. {
  186. begin: /\(/,
  187. end: /\)/
  188. },
  189. {
  190. beginKeywords: 'new throw return else',
  191. end: /;/
  192. }
  193. ],
  194. keywords: KEYWORDS,
  195. contains: EXPRESSION_CONTAINS.concat([
  196. {
  197. begin: /\(/,
  198. end: /\)/,
  199. keywords: KEYWORDS,
  200. contains: EXPRESSION_CONTAINS.concat([ 'self' ]),
  201. relevance: 0
  202. }
  203. ]),
  204. relevance: 0
  205. };
  206. const FUNCTION_DECLARATION = {
  207. begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
  208. returnBegin: true,
  209. end: /[{;=]/,
  210. excludeEnd: true,
  211. keywords: KEYWORDS,
  212. illegal: /[^\w\s\*&:<>.]/,
  213. contains: [
  214. { // to prevent it from being confused as the function title
  215. begin: DECLTYPE_AUTO_RE,
  216. keywords: KEYWORDS,
  217. relevance: 0
  218. },
  219. {
  220. begin: FUNCTION_TITLE,
  221. returnBegin: true,
  222. contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ],
  223. relevance: 0
  224. },
  225. // allow for multiple declarations, e.g.:
  226. // extern void f(int), g(char);
  227. {
  228. relevance: 0,
  229. match: /,/
  230. },
  231. {
  232. className: 'params',
  233. begin: /\(/,
  234. end: /\)/,
  235. keywords: KEYWORDS,
  236. relevance: 0,
  237. contains: [
  238. C_LINE_COMMENT_MODE,
  239. hljs.C_BLOCK_COMMENT_MODE,
  240. STRINGS,
  241. NUMBERS,
  242. TYPES,
  243. // Count matching parentheses.
  244. {
  245. begin: /\(/,
  246. end: /\)/,
  247. keywords: KEYWORDS,
  248. relevance: 0,
  249. contains: [
  250. 'self',
  251. C_LINE_COMMENT_MODE,
  252. hljs.C_BLOCK_COMMENT_MODE,
  253. STRINGS,
  254. NUMBERS,
  255. TYPES
  256. ]
  257. }
  258. ]
  259. },
  260. TYPES,
  261. C_LINE_COMMENT_MODE,
  262. hljs.C_BLOCK_COMMENT_MODE,
  263. PREPROCESSOR
  264. ]
  265. };
  266. return {
  267. name: "C",
  268. aliases: [ 'h' ],
  269. keywords: KEYWORDS,
  270. // Until differentiations are added between `c` and `cpp`, `c` will
  271. // not be auto-detected to avoid auto-detect conflicts between C and C++
  272. disableAutodetect: true,
  273. illegal: '</',
  274. contains: [].concat(
  275. EXPRESSION_CONTEXT,
  276. FUNCTION_DECLARATION,
  277. EXPRESSION_CONTAINS,
  278. [
  279. PREPROCESSOR,
  280. {
  281. begin: hljs.IDENT_RE + '::',
  282. keywords: KEYWORDS
  283. },
  284. {
  285. className: 'class',
  286. beginKeywords: 'enum class struct union',
  287. end: /[{;:<>=]/,
  288. contains: [
  289. { beginKeywords: "final class struct" },
  290. hljs.TITLE_MODE
  291. ]
  292. }
  293. ]),
  294. exports: {
  295. preprocessor: PREPROCESSOR,
  296. strings: STRINGS,
  297. keywords: KEYWORDS
  298. }
  299. };
  300. }
  301. export { c as default };