class CodeRay::Scanners::CPlusPlus

Scanner for C++.

Aliases: cplusplus, c++

Protected Instance Methods

scan_tokens(encoder, options) click to toggle source
# File lib/coderay/scanners/cpp.rb, line 54
def scan_tokens encoder, options

  state = :initial
  label_expected = true
  case_expected = false
  label_expected_before_preproc_line = nil
  in_preproc_line = false

  until eos?

    case state

    when :initial

      if match = scan(%r \s+ | \\\n /)
        if in_preproc_line && match != "\\\n" && match.index(\n\)
          in_preproc_line = false
          label_expected = label_expected_before_preproc_line
        end
        encoder.text_token match, :space

      elsif match = scan(%r // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !x)
        encoder.text_token match, :comment

      elsif match = scan(%r \# \s* if \s* 0 /)
        match << scan_until(%r ^\# (?:elif|else|endif) .*? $ | \z /m) unless eos?
        encoder.text_token match, :comment

      elsif match = scan(%r [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /)
        label_expected = match =~ %r[;\{\}]/
        if case_expected
          label_expected = true if match == ':'
          case_expected = false
        end
        encoder.text_token match, :operator

      elsif match = scan(%r [A-Za-z_][A-Za-z_0-9]* /)
        kind = IDENT_KIND[match]
        if kind == :ident && label_expected && !in_preproc_line && scan(%r:(?!:)/)
          kind = :label
          match << matched
        else
          label_expected = false
          if kind == :keyword
            case match
            when 'class'
              state = :class_name_expected
            when 'case', 'default'
              case_expected = true
            end
          end
        end
        encoder.text_token match, kind

      elsif match = scan(%r\$/)
        encoder.text_token match, :ident
      
      elsif match = scan(%rL?"/)
        encoder.begin_group :string
        if match[0] == LL
          encoder.text_token match, 'L', :modifier
          match = '"'
        end
        state = :string
        encoder.text_token match, :delimiter

      elsif match = scan(%r#[ \t]*(\w*)/)
        encoder.text_token match, :preprocessor
        in_preproc_line = true
        label_expected_before_preproc_line = label_expected
        state = :include_expected if self[1] == 'include'

      elsif match = scan(%r L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /x)
        label_expected = false
        encoder.text_token match, :char

      elsif match = scan(%r0[xX][0-9A-Fa-f]+/)
        label_expected = false
        encoder.text_token match, :hex

      elsif match = scan(%r(?:0[0-7]+)(?![89.eEfF])/)
        label_expected = false
        encoder.text_token match, :octal

      elsif match = scan(%r(?:\d+)(?![.eEfF])L?L?/)
        label_expected = false
        encoder.text_token match, :integer

      elsif match = scan(%r\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
        label_expected = false
        encoder.text_token match, :float

      else
        encoder.text_token getch, :error

      end

    when :string
      if match = scan(%r[^\\"]+/)
        encoder.text_token match, :content
      elsif match = scan(%r"/)
        encoder.text_token match, :delimiter
        encoder.end_group :string
        state = :initial
        label_expected = false
      elsif match = scan(%r \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /ox)
        encoder.text_token match, :char
      elsif match = scan(%r \\ | $ /)
        encoder.end_group :string
        encoder.text_token match, :error
        state = :initial
        label_expected = false
      else
        raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
      end

    when :include_expected
      if match = scan(%r<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)
        encoder.text_token match, :include
        state = :initial

      elsif match = scan(%r\s+/)
        encoder.text_token match, :space
        state = :initial if match.index \n\

      else
        state = :initial

      end
    
    when :class_name_expected
      if match = scan(%r [A-Za-z_][A-Za-z_0-9]* /)
        encoder.text_token match, :class
        state = :initial

      elsif match = scan(%r\s+/)
        encoder.text_token match, :space

      else
        encoder.text_token getch, :error
        state = :initial

      end
      
    else
      raise_inspect 'Unknown state', encoder

    end

  end

  if state == :string
    encoder.end_group :string
  end

  encoder
end