Chris@210: class VHDL < CodeRay::Scanners::Scanner Chris@210: Chris@210: register_for :vhdl Chris@210: Chris@210: RESERVED_WORDS = [ Chris@210: 'access','after','alias','all','assert','architecture','begin', Chris@210: 'block','body','buffer','bus','case','component','configuration','constant', Chris@210: 'disconnect','downto','else','elsif','end','entity','exit','file','for', Chris@210: 'function','generate','generic','group','guarded','if','impure','in', Chris@210: 'inertial','inout','is','label','library','linkage','literal','loop', Chris@210: 'map','new','next','null','of','on','open','others','out','package', Chris@210: 'port','postponed','procedure','process','pure','range','record','register', Chris@210: 'reject','report','return','select','severity','signal','shared','subtype', Chris@210: 'then','to','transport','type','unaffected','units','until','use','variable', Chris@210: 'wait','when','while','with','note','warning','error','failure','and', Chris@210: 'or','xor','not','nor', Chris@210: 'array' Chris@210: ] Chris@210: Chris@210: PREDEFINED_TYPES = [ Chris@210: 'bit','bit_vector','character','boolean','integer','real','time','string', Chris@210: 'severity_level','positive','natural','signed','unsigned','line','text', Chris@210: 'std_logic','std_logic_vector','std_ulogic','std_ulogic_vector','qsim_state', Chris@210: 'qsim_state_vector','qsim_12state','qsim_12state_vector','qsim_strength', Chris@210: 'mux_bit','mux_vector','reg_bit','reg_vector','wor_bit','wor_vector' Chris@210: ] Chris@210: Chris@210: PREDEFINED_CONSTANTS = [ Chris@210: Chris@210: ] Chris@210: Chris@210: IDENT_KIND = CodeRay::CaseIgnoringWordList.new(:ident). Chris@210: add(RESERVED_WORDS, :reserved). Chris@210: add(PREDEFINED_TYPES, :pre_type). Chris@210: add(PREDEFINED_CONSTANTS, :pre_constant) Chris@210: Chris@210: ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x Chris@210: UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x Chris@210: Chris@210: def scan_tokens tokens, options Chris@210: Chris@210: state = :initial Chris@210: Chris@210: until eos? Chris@210: Chris@210: kind = nil Chris@210: match = nil Chris@210: Chris@210: case state Chris@210: Chris@210: when :initial Chris@210: Chris@210: if scan(/ \s+ | \\\n /x) Chris@210: kind = :space Chris@210: Chris@210: elsif scan(/-- .*/x) Chris@210: kind = :comment Chris@210: Chris@210: elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x) Chris@210: kind = :operator Chris@210: Chris@210: elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) Chris@210: kind = IDENT_KIND[match.downcase] Chris@210: Chris@210: elsif match = scan(/[a-z]?"/i) Chris@210: tokens << [:open, :string] Chris@210: state = :string Chris@210: kind = :delimiter Chris@210: Chris@210: elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) Chris@210: kind = :char Chris@210: Chris@210: elsif scan(/(?:\d+)(?![.eEfF])/) Chris@210: kind = :integer Chris@210: Chris@210: elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) Chris@210: kind = :float Chris@210: Chris@210: else Chris@210: getch Chris@210: kind = :error Chris@210: Chris@210: end Chris@210: Chris@210: when :string Chris@210: if scan(/[^\\\n"]+/) Chris@210: kind = :content Chris@210: elsif scan(/"/) Chris@210: tokens << ['"', :delimiter] Chris@210: tokens << [:close, :string] Chris@210: state = :initial Chris@210: next Chris@210: elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) Chris@210: kind = :char Chris@210: elsif scan(/ \\ | $ /x) Chris@210: tokens << [:close, :string] Chris@210: kind = :error Chris@210: state = :initial Chris@210: else Chris@210: raise_inspect "else case \" reached; %p not handled." % peek(1), tokens Chris@210: end Chris@210: Chris@210: else Chris@210: raise_inspect 'Unknown state', tokens Chris@210: Chris@210: end Chris@210: Chris@210: match ||= matched Chris@210: if $DEBUG and not kind Chris@210: raise_inspect 'Error token %p in line %d' % Chris@210: [[match, kind], line], tokens Chris@210: end Chris@210: raise_inspect 'Empty token', tokens unless match Chris@210: Chris@210: tokens << [match, kind] Chris@210: Chris@210: end Chris@210: Chris@210: if state == :string Chris@210: tokens << [:close, :string] Chris@210: end Chris@210: Chris@210: tokens Chris@210: end Chris@210: Chris@210: end