Class CodeRay::Scanners::C
In: lib/coderay/scanners/c.rb
Parent: Scanner

Methods

Included Modules

Streamable

Constants

RESERVED_WORDS = [ 'asm', 'break', 'case', 'continue', 'default', 'do', 'else', 'for', 'goto', 'if', 'return', 'switch', 'while', 'struct', 'union', 'enum', 'typedef', 'static', 'register', 'auto', 'extern', 'sizeof', 'volatile', 'const', # C89 'inline', 'restrict', # C99 ]
PREDEFINED_TYPES = [ 'int', 'long', 'short', 'char', 'void', 'signed', 'unsigned', 'float', 'double', 'bool', 'complex', # C99 ]
PREDEFINED_CONSTANTS = [ 'EOF', 'NULL', 'true', 'false', # C99 ]
IDENT_KIND = WordList.new(:ident). add(RESERVED_WORDS, :reserved). add(PREDEFINED_TYPES, :pre_type). add(PREDEFINED_CONSTANTS, :pre_constant)
ESCAPE = / [rbfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x

Public Instance methods

[Source]

     # File lib/coderay/scanners/c.rb, line 39
 39:     def scan_tokens tokens, options
 40: 
 41:       state = :initial
 42: 
 43:       until eos?
 44: 
 45:         kind = nil
 46:         match = nil
 47:         
 48:         case state
 49: 
 50:         when :initial
 51: 
 52:           if scan(/ \s+ | \\\n /x)
 53:             kind = :space
 54: 
 55:           elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
 56:             kind = :comment
 57: 
 58:           elsif match = scan(/ \# \s* if \s* 0 /x)
 59:             match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?
 60:             kind = :comment
 61: 
 62:           elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x)
 63:             kind = :operator
 64: 
 65:           elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
 66:             kind = IDENT_KIND[match]
 67:             if kind == :ident and check(/:(?!:)/)
 68:               match << scan(/:/)
 69:               kind = :label
 70:             end
 71: 
 72:           elsif match = scan(/L?"/)
 73:             tokens << [:open, :string]
 74:             if match[0] == ?L
 75:               tokens << ['L', :modifier]
 76:               match = '"'
 77:             end
 78:             state = :string
 79:             kind = :delimiter
 80: 
 81:           elsif scan(/#\s*(\w*)/)
 82:             kind = :preprocessor  # FIXME multiline preprocs
 83:             state = :include_expected if self[1] == 'include'
 84: 
 85:           elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox)
 86:             kind = :char
 87: 
 88:           elsif scan(/0[xX][0-9A-Fa-f]+/)
 89:             kind = :hex
 90: 
 91:           elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)
 92:             kind = :oct
 93: 
 94:           elsif scan(/(?:\d+)(?![.eEfF])/)
 95:             kind = :integer
 96: 
 97:           elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
 98:             kind = :float
 99: 
100:           else
101:             getch
102:             kind = :error
103: 
104:           end
105: 
106:         when :string
107:           if scan(/[^\\\n"]+/)
108:             kind = :content
109:           elsif scan(/"/)
110:             tokens << ['"', :delimiter]
111:             tokens << [:close, :string]
112:             state = :initial
113:             next
114:           elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
115:             kind = :char
116:           elsif scan(/ \\ | $ /x)
117:             tokens << [:close, :string]
118:             kind = :error
119:             state = :initial
120:           else
121:             raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
122:           end
123: 
124:         when :include_expected
125:           if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)
126:             kind = :include
127:             state = :initial
128: 
129:           elsif match = scan(/\s+/)
130:             kind = :space
131:             state = :initial if match.index ?\n
132: 
133:           else
134:             getch
135:             kind = :error
136: 
137:           end
138: 
139:         else
140:           raise_inspect 'Unknown state', tokens
141: 
142:         end
143: 
144:         match ||= matched
145:         if $DEBUG and not kind
146:           raise_inspect 'Error token %p in line %d' %
147:             [[match, kind], line], tokens
148:         end
149:         raise_inspect 'Empty token', tokens unless match
150: 
151:         tokens << [match, kind]
152: 
153:       end
154: 
155:       if state == :string
156:         tokens << [:close, :string]
157:       end
158: 
159:       tokens
160:     end

[Validate]