module Rouge module Lexers class C < RegexLexer tag 'c' filenames '*.c', '*.h', '*.idc' mimetypes 'text/x-chdr', 'text/x-csrc' # optional comment or whitespace ws = %r((?:\s|//.*?\n|/[*].*?[*]/)+) id = /[a-zA-Z_][a-zA-Z0-9_]*/ keywords = %w( auto break case const continue default do else enum extern for goto if register restricted return sizeof static struct switch typedef union volatile virtual while ) keywords_type = %w(int long float short double char unsigned signed void) __reserved = %w( asm int8 based except int16 stdcall cdecl fastcall int32 declspec finally int61 try leave ) state :whitespace do rule /^#if\s+0\b/, 'Comment.Preproc', :if_0 rule /^#/, 'Comment.Preproc', :macro rule /^#{ws}#if\s+0\b/, 'Comment.Preproc', :if_0 rule /^#{ws}#/, 'Comment.Preproc', :macro rule /^(\s*)(#{id}:(?!:))/ do group 'Text' group 'Name.Label' end rule /\s+/m, 'Text' rule /\\\n/, 'Text' # line continuation rule %r(//(\n|(.|\n)*?[^\\]\n)), 'Comment.Single' rule %r(/(\\\n)?[*](.|\n)*?[*](\\\n)?/), 'Comment.Multiline' end state :statements do rule /L?"/, 'Literal.String', :string rule %r(L?'(\\.|\\[0-7]{1,3}|\\x[a-f0-9]{1,2}|[^\\'\n])')i, 'Literal.String.Char' rule %r((\d+\.\d*|\.\d+|\d+)[e][+-]?\d+[lu]*)i, 'Literal.Number.Float' rule /0x[0-9a-f]+[lu]*/i, 'Literal.Number.Hex' rule /0[0-7]+[lu]*/i, 'Literal.Number.Oct' rule /\d+[lu]*/i, 'Literal.Number.Integer' rule %r(\*/), 'Error' rule %r([~!%^&*+=\|?:<>/-]), 'Operator' rule /[()\[\],.]/, 'Punctuation' rule /\bcase\b/, 'Keyword', :case rule /(?:#{keywords.join('|')})\b/, 'Keyword' rule /(?:#{keywords_type.join('|')})\b/, 'Keyword.Type' rule /(?:_{0,2}inline|naked|restrict|thread|typename)\b/, 'Keyword.Reserved' rule /__(?:#{__reserved.join('|')})\b/, 'Keyword.Reserved' rule /(?:true|false|NULL)\b/, 'Name.Builtin' rule id, 'Name' end state :case do rule /:/, 'Punctuation', :pop! mixin :statements end state :root do mixin :whitespace # functions rule %r( ([\w*\s]+?[\s*]) # return arguments (#{id}) # function name (\s*\([^;]*?\)) # signature (#{ws})({) # open brace )mx do |m| # TODO: do this better. delegate C, m[1] token 'Name.Function', m[2] delegate C, m[3] delegate C, m[4] token 'Punctuation', m[5] push :function end # function declarations rule %r( ([\w*\s]+?[\s*]) # return arguments (#{id}) # function name (\s*\([^;]*?\)) # signature (#{ws})(;) # semicolon )mx do |m| # TODO: do this better. delegate C, m[1] token 'Name.Function' delegate C, m[3] delegate C, m[4] token 'Punctuation' push :statement end rule(//) { push :statement } end state :statement do rule /;/, 'Punctuation', :pop! mixin :whitespace mixin :statements rule /[{}]/, 'Punctuation' end state :function do mixin :whitespace mixin :statements rule /;/, 'Punctuation' rule /{/, 'Punctuation', :function rule /}/, 'Punctuation', :pop! end state :string do rule /"/, 'Literal.String', :pop! rule /\\([\\abfnrtv"']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})/, 'Literal.String.Escape' rule /[^\\"\n]+/, 'Literal.String' rule /\\\n/, 'Literal.String' rule /\\/, 'Literal.String' # stray backslash end state :macro do rule %r([^/\n]+), 'Comment.Preproc' rule %r(/[*].*?[*]/)m, 'Comment.Multiliine' rule %r(//.*$), 'Comment.Single' rule %r(/), 'Comment.Preproc' rule /(?<=\\)\n/, 'Comment.Preproc' rule /\n/, 'Comment.Preproc', :pop! end state :if_0 do rule /^\s*#if.*?(?