| Class | CodeRay::Scanners::CPlusPlus |
| In: |
lib/coderay/scanners/cpp.rb
|
| Parent: | Scanner |
| RESERVED_WORDS | = | [ 'and', 'and_eq', 'asm', 'bitand', 'bitor', 'break', 'case', 'catch', 'class', 'compl', 'const_cast', 'continue', 'default', 'delete', 'do', 'dynamic_cast', 'else', 'enum', 'export', 'for', 'goto', 'if', 'namespace', 'new', 'not', 'not_eq', 'or', 'or_eq', 'reinterpret_cast', 'return', 'sizeof', 'static_cast', 'struct', 'switch', 'template', 'throw', 'try', 'typedef', 'typeid', 'typename', 'union', 'while', 'xor', 'xor_eq' | www.cppreference.com/wiki/keywords/start | |
| PREDEFINED_TYPES | = | [ 'bool', 'char', 'double', 'float', 'int', 'long', 'short', 'signed', 'unsigned', 'wchar_t', 'string' | ||
| PREDEFINED_CONSTANTS | = | [ 'false', 'true', 'EOF', 'NULL', ] | ||
| PREDEFINED_VARIABLES | = | [ 'this' | ||
| DIRECTIVES | = | [ 'auto', 'const', 'explicit', 'extern', 'friend', 'inline', 'mutable', 'operator', 'private', 'protected', 'public', 'register', 'static', 'using', 'virtual', 'void', 'volatile' | ||
| IDENT_KIND | = | WordList.new(:ident). add(RESERVED_WORDS, :reserved). add(PREDEFINED_TYPES, :pre_type). add(PREDEFINED_VARIABLES, :local_variable). add(DIRECTIVES, :directive). add(PREDEFINED_CONSTANTS, :pre_constant) | ||
| ESCAPE | = | / [rbfntv\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/cpp.rb, line 51
51: def scan_tokens tokens, options
52:
53: state = :initial
54: label_expected = true
55: case_expected = false
56: label_expected_before_preproc_line = nil
57: in_preproc_line = false
58:
59: until eos?
60:
61: kind = nil
62: match = nil
63:
64: case state
65:
66: when :initial
67:
68: if match = scan(/ \s+ | \\\n /x)
69: if in_preproc_line && match != "\\\n" && match.index(?\n)
70: in_preproc_line = false
71: label_expected = label_expected_before_preproc_line
72: end
73: tokens << [match, :space]
74: next
75:
76: elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
77: kind = :comment
78:
79: elsif match = scan(/ \# \s* if \s* 0 /x)
80: match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?
81: kind = :comment
82:
83: elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x)
84: label_expected = match =~ /[;\{\}]/
85: if case_expected
86: label_expected = true if match == ':'
87: case_expected = false
88: end
89: kind = :operator
90:
91: elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
92: kind = IDENT_KIND[match]
93: if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/)
94: kind = :label
95: match << matched
96: else
97: label_expected = false
98: if kind == :reserved
99: case match
100: when 'class'
101: state = :class_name_expected
102: when 'case', 'default'
103: case_expected = true
104: end
105: end
106: end
107:
108: elsif scan(/\$/)
109: kind = :ident
110:
111: elsif match = scan(/L?"/)
112: tokens << [:open, :string]
113: if match[0] == ?L
114: tokens << ['L', :modifier]
115: match = '"'
116: end
117: state = :string
118: kind = :delimiter
119:
120: elsif scan(/#[ \t]*(\w*)/)
121: kind = :preprocessor
122: in_preproc_line = true
123: label_expected_before_preproc_line = label_expected
124: state = :include_expected if self[1] == 'include'
125:
126: elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox)
127: label_expected = false
128: kind = :char
129:
130: elsif scan(/0[xX][0-9A-Fa-f]+/)
131: label_expected = false
132: kind = :hex
133:
134: elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)
135: label_expected = false
136: kind = :oct
137:
138: elsif scan(/(?:\d+)(?![.eEfF])L?L?/)
139: label_expected = false
140: kind = :integer
141:
142: elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
143: label_expected = false
144: kind = :float
145:
146: else
147: getch
148: kind = :error
149:
150: end
151:
152: when :string
153: if scan(/[^\\"]+/)
154: kind = :content
155: elsif scan(/"/)
156: tokens << ['"', :delimiter]
157: tokens << [:close, :string]
158: state = :initial
159: label_expected = false
160: next
161: elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
162: kind = :char
163: elsif scan(/ \\ | $ /x)
164: tokens << [:close, :string]
165: kind = :error
166: state = :initial
167: label_expected = false
168: else
169: raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
170: end
171:
172: when :include_expected
173: if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)
174: kind = :include
175: state = :initial
176:
177: elsif match = scan(/\s+/)
178: kind = :space
179: state = :initial if match.index ?\n
180:
181: else
182: state = :initial
183: next
184:
185: end
186:
187: when :class_name_expected
188: if scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
189: kind = :class
190: state = :initial
191:
192: elsif match = scan(/\s+/)
193: kind = :space
194:
195: else
196: getch
197: kind = :error
198: state = :initial
199:
200: end
201:
202: else
203: raise_inspect 'Unknown state', tokens
204:
205: end
206:
207: match ||= matched
208: if $CODERAY_DEBUG and not kind
209: raise_inspect 'Error token %p in line %d' %
210: [[match, kind], line], tokens
211: end
212: raise_inspect 'Empty token', tokens unless match
213:
214: tokens << [match, kind]
215:
216: end
217:
218: if state == :string
219: tokens << [:close, :string]
220: end
221:
222: tokens
223: end