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