Skip to content

Commit 5b3c0b4

Browse files
committed
Tcl scanner by Eric Thomas
from Redmine
1 parent 3effca8 commit 5b3c0b4

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

lib/coderay/scanners/tcl.rb

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
module CodeRay
2+
module Scanners
3+
4+
# by Eric Thomas
5+
class Tcl < Scanner
6+
7+
register_for :tcl
8+
9+
# Taken from http://www.xilinx.com/itp/xilinx10/isehelp/ite_r_tcl_reserved_words.htm
10+
RESERVED_WORDS = %w(after append array auto_execok auto_import auto_load
11+
auto_load_index auto_qualify binary bgerrro break
12+
catch cd clock close concat continue dde default
13+
else elseif encoding eof error eval exec exit expr
14+
fblocked fconfigure fcopy file fileevent flush for
15+
foreach format gets glob global history if incr
16+
interp join lappend lindex list llength load lrange
17+
lrange lreplace lsearch lsort namespace open package
18+
pid pkg_mkIndex proc puts pwd read regexp regsub
19+
rename resource return scan seek set socket source
20+
split string subst switch tclLog tell time trace
21+
unknown unset update uplevel upvar vwait while)
22+
23+
PREDEFINED_TYPES = %w(variable)
24+
25+
# should we include 0 or 1?
26+
PREDEFINED_CONSTANTS = %w(true false yes no on off 1 0)
27+
28+
IDENT_KIND = WordList.new(:ident).
29+
add(RESERVED_WORDS, :reserved).
30+
add(PREDEFINED_TYPES, :pre_type).
31+
add(PREDEFINED_CONSTANTS, :pre_constant)
32+
33+
ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
34+
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
35+
36+
def scan_tokens tokens, options
37+
state = :initial
38+
39+
until eos?
40+
kind = nil
41+
match = nil
42+
43+
case state
44+
when :initial
45+
46+
if scan(/ \s+ | \\\n /x)
47+
kind = :space
48+
49+
elsif scan(/#.*/)
50+
kind = :comment
51+
52+
elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x)
53+
kind = :operator
54+
55+
elsif scan(/\$\S+/)
56+
kind = :variable
57+
58+
elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
59+
kind = IDENT_KIND[match]
60+
if kind == :ident and check(/:(?!:)/)
61+
match << scan(/:/)
62+
kind = :label
63+
end
64+
65+
elsif match = scan(/L?"/)
66+
tokens << [:open, :string]
67+
if match[0] == ?L
68+
tokens << ['L', :modifier]
69+
match = '"'
70+
end
71+
state = :string
72+
kind = :delimiter
73+
74+
elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox)
75+
kind = :char
76+
77+
elsif scan(/0[xX][0-9A-Fa-f]+/)
78+
kind = :hex
79+
80+
elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)
81+
kind = :oct
82+
83+
elsif scan(/(?:\d+)(?![.eEfF])/)
84+
kind = :integer
85+
86+
elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
87+
kind = :float
88+
89+
else
90+
getch
91+
kind = :error
92+
93+
end
94+
95+
when :string
96+
if scan(/[^\\\n"]+/)
97+
kind = :content
98+
elsif scan(/"/)
99+
tokens << ['"', :delimiter]
100+
tokens << [:close, :string]
101+
state = :initial
102+
next
103+
elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
104+
kind = :char
105+
elsif scan(/ \\ | $ /x)
106+
tokens << [:close, :string]
107+
kind = :error
108+
state = :initial
109+
else
110+
raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
111+
end
112+
113+
else
114+
raise_inspect 'Unknown state', tokens
115+
116+
end
117+
118+
match ||= matched
119+
if $DEBUG and not kind
120+
raise_inspect 'Error token %p in line %d' %
121+
[[match, kind], line], tokens
122+
end
123+
raise_inspect 'Empty token', tokens unless match
124+
125+
tokens << [match, kind]
126+
127+
end
128+
129+
if state == :string
130+
tokens << [:close, :string]
131+
end
132+
133+
tokens
134+
end
135+
end
136+
end
137+
end

0 commit comments

Comments
 (0)