| Class | CodeRay::Scanners::C |
| In: |
lib/coderay/scanners/c.rb
|
| Parent: | Scanner |
| 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 |
# 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