Object
# File lib/rexical/generator.rb, line 47
47: def add_header( st )
48: @scanner_header += "#{st}\n"
49: end
# File lib/rexical/generator.rb, line 57
57: def add_inner( st )
58: @scanner_inner += "#{st}\n"
59: end
# File lib/rexical/generator.rb, line 77
77: def add_macro( st )
78: ss = StringScanner.new(st)
79: ss.scan(/\s+/)
80: key = ss.scan(/\S+/)
81: ss.scan(/\s+/)
82: st = ss.post_match
83: len = st.size
84: ndx = 0
85: while ndx <= len
86: c = st[ndx,1]
87: ndx += 1
88: case c
89: when '\'
90: ndx += 1
91: next
92: when '#', ' '
93: ndx -= 1
94: break
95: end
96: end
97: expr = st[0,ndx]
98: expr.gsub!('\ ', ' ')
99: key = '{' + key + '}'
100: @macro.each_pair do |k, e|
101: expr.gsub!(k) { |m| e }
102: end
103: @macro[key] = expr
104: rescue
105: raise ParseError, "parse error in add_macro:'#{st}'"
106: end
# File lib/rexical/generator.rb, line 62
62: def add_option( st )
63: opts = st.split
64: opts.each do |opt|
65: case opt
66: when /ignorecase/
67: @opt['--ignorecase'] = true
68: when /stub/
69: @opt['--stub'] = true
70: when /independent/
71: @opt['--independent'] = true
72: end
73: end
74: end
# File lib/rexical/generator.rb, line 109
109: def add_rule( rule_state, rule_expr, rule_action=nil )
110: st = rule_expr.dup
111: @macro.each_pair do |k, e|
112: rule_expr.gsub!(k) { |m| e }
113: end
114: if rule_state.to_s[1,1] =~ /[A-Z]/
115: @exclusive_states << rule_state unless @exclusive_states.include?(rule_state)
116: exclusive_state = rule_state
117: start_state = nil
118: else
119: exclusive_state = nil
120: start_state = rule_state
121: end
122: rule = [exclusive_state, start_state, rule_expr, rule_action]
123: @rules << rule
124: rescue
125: raise ParseError, "parse error in add_rule:'#{st}'"
126: end
# File lib/rexical/generator.rb, line 132
132: def next_line
133: @lineno += 1
134: @grammar_lines.scan_until(/\n/).chomp
135: rescue
136: nil
137: end
# File lib/rexical/generator.rb, line 139
139: def parse
140: state1 = :HEAD
141: state2 = nil
142: state3 = nil
143: lastmodes = []
144: while st = next_line
145: case state1
146: when :FOOT
147: add_footer st
148:
149: when :HEAD
150: ss = StringScanner.new(st)
151: if ss.scan(/class/)
152: state1 = :CLASS
153: st = ss.post_match.strip
154: if st =~ /^(\S+)::(\S+)/
155: @module_name = $1
156: @class_name = $2
157: else
158: @module_name = nil
159: @class_name = st
160: end
161: else
162: add_header st
163: end
164:
165: when :CLASS
166: s = st.strip
167: next if s.size == 0 or s[0,1] == '#'
168:
169: ss = StringScanner.new(st)
170: if ss.scan(/option.*$/)
171: state2 = :OPTION
172: next
173: end
174: if ss.scan(/inner.*$/)
175: state2 = :INNER
176: next
177: end
178: if ss.scan(/macro.*$/)
179: state2 = :MACRO
180: next
181: end
182: if ss.scan(/rule.*$/)
183: state2 = :RULE
184: next
185: end
186: if ss.scan(/end.*$/)
187: state1 = :FOOT
188: next
189: end
190:
191: case state2
192: when :OPTION
193: add_option st
194:
195: when :INNER
196: add_inner st
197:
198: when :MACRO
199: add_macro st
200:
201: when :RULE
202: case state3
203: when nil
204: rule_state, rule_expr, rule_action = parse_rule(st)
205: if rule_action =~ /\s*\{/
206: lastmodes = parse_action(rule_action, lastmodes)
207: if lastmodes.empty?
208: add_rule rule_state, rule_expr, rule_action
209: else
210: state3 = :CONT
211: rule_action += "\n"
212: end
213: else
214: add_rule rule_state, rule_expr
215: end
216:
217: when :CONT
218: rule_action += "#{st}\n"
219: lastmodes = parse_action(st, lastmodes)
220: if lastmodes.empty?
221: state3 = nil
222: add_rule rule_state, rule_expr, rule_action
223: else
224: end
225:
226: end # case state3
227:
228: end # case state2
229:
230: end # case state1
231:
232: end # while
233:
234: end
# File lib/rexical/generator.rb, line 250
250: def parse_action(st, lastmodes=[])
251: modes = lastmodes
252: mode = lastmodes[1]
253: ss = StringScanner.new(st)
254: until ss.eos?
255: c = ss.scan(/./)
256: case c
257: when '#'
258: if (mode == :brace) or (mode == nil)
259: #p [c, mode, modes]
260: return modes
261: end
262: when '{'
263: if (mode == :brace) or (mode == nil)
264: mode = :brace
265: modes.push mode
266: end
267: when '}'
268: if (mode == :brace)
269: modes.pop
270: mode = modes[0]
271: end
272: when "'"
273: if (mode == :brace)
274: mode = :quote
275: modes.push mode
276: elsif (mode == :quote)
277: modes.pop
278: mode = modes[0]
279: end
280: when '"'
281: if (mode == :brace)
282: mode = :doublequote
283: modes.push mode
284: elsif (mode == :doublequote)
285: modes.pop
286: mode = modes[0]
287: end
288: when '`'
289: if (mode == :brace)
290: mode = :backquote
291: modes.push mode
292: elsif (mode == :backquote)
293: modes.pop
294: mode = modes[0]
295: end
296: end
297: end
298: #p [c, mode, modes]
299: return modes
300: end
# File lib/rexical/generator.rb, line 237
237: def parse_rule(st)
238: st.strip!
239: return if st.size == 0 or st[0,1] == '#'
240: ss = StringScanner.new(st)
241: ss.scan(/\s+/)
242: rule_state = ss.scan(/\:\S+/)
243: ss.scan(/\s+/)
244: rule_expr = ss.scan(/\S+/)
245: ss.scan(/\s+/)
246: [rule_state, rule_expr, ss.post_match]
247: end
# File lib/rexical/generator.rb, line 128
128: def read_grammar
129: @grammar_lines = StringScanner.new File.read(grammar_file)
130: end
# File lib/rexical/generator.rb, line 379
379: def write_scanner f = scanner_io
380: ## scan flag
381: flag = ""
382: flag += "i" if @opt['--ignorecase']
383: ## header
384: f.printf REX_HEADER, Rexical::VERSION, grammar_file
385:
386: unless @opt['--independent']
387: f.printf "require 'racc/parser'\n"
388: end
389:
390: @scanner_header.each_line do |s|
391: f.print s
392: end
393: if @module_name
394: f.puts "module #{@module_name}"
395: end
396: if @opt['--independent']
397: f.puts "class #{@class_name}"
398: else
399: f.puts "class #{@class_name} < Racc::Parser"
400: end
401:
402: ## utility method
403: f.print REX_UTIL
404:
405: ## scanner method
406:
407: f.print def next_token return if @ss.eos? text = @ss.peek(1) @lineno += 1 if text == "\\n" token = case @state
408:
409: exclusive_states.each do |es|
410: f.printf when #{es ? es.to_s : "nil"} case
411: rules.each do |rule|
412: exclusive_state, start_state, rule_expr, rule_action = *rule
413: if es == exclusive_state
414:
415: if rule_action
416: if start_state
417: f.print when (state == #{start_state}) and (text = @ss.scan(/#{rule_expr}/#{flag})) action #{rule_action}
418: else
419: f.print when (text = @ss.scan(/#{rule_expr}/#{flag})) action #{rule_action}
420: end
421: else
422: if start_state
423: f.print when (state == #{start_state}) and (text = @ss.scan(/#{rule_expr}/#{flag})) ;
424: else
425: f.print when (text = @ss.scan(/#{rule_expr}/#{flag})) ;
426: end
427: end
428:
429: end
430: end
431: f.print else text = @ss.string[@ss.pos .. -1] raise ScanError, "can not match: '" + text + "'" end # if
432: end
433: f.print else raise ScanError, "undefined state: '" + state.to_s + "'" end # case state
434: if @opt['--debug']
435: f.print p token
436: end
437: f.print token end # def next_token
438:
439: ## inner method
440: @scanner_inner.each_line do |s|
441: f.print s
442: end
443: f.puts "end # class"
444: f.puts "end # module" if @module_name
445:
446: ## footer
447: @scanner_footer.each_line do |s|
448: f.print s
449: end # case
450:
451: ## stub main
452: f.printf REX_STUB, @class_name, '"%s:%d:%s\n"' if @opt['--stub']
453: f.close
454:
455: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.