Parent

Class Index [+]

Quicksearch

Rexical::Generator


Constants

REX_HEADER

REX_UTIL
REX_STUB

Attributes

grammar_file[RW]

grammar_lines[RW]
scanner_file[RW]
module_name[RW]
class_name[RW]
lineno[RW]
rules[RW]
exclusive_states[RW]
ignorecase[RW]
independent[RW]
debug[RW]

Public Class Methods

new(opts) click to toggle source

    # File lib/rexical/generator.rb, line 34
34:     def initialize(opts)
35:       @lineno  =  0
36:       @macro  =  {}
37:       @rules  =  []
38:       @exclusive_states = [nil]
39:       @grammar_lines  =  nil
40:       @scanner_header  =  ""
41:       @scanner_footer  =  ""
42:       @scanner_inner  =  ""
43:       @opt  =  opts
44:     end

Public Instance Methods

add_header( st ) click to toggle source

    # File lib/rexical/generator.rb, line 47
47:     def add_header( st )
48:       @scanner_header  +=  "#{st}\n"
49:     end
add_inner( st ) click to toggle source

    # File lib/rexical/generator.rb, line 57
57:     def add_inner( st )
58:       @scanner_inner  +=  "#{st}\n"
59:     end
add_macro( st ) click to toggle source

     # 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
add_option( st ) click to toggle source

    # 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
add_rule( rule_state, rule_expr, rule_action=nil ) click to toggle source

     # 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
next_line() click to toggle source
     # 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
parse() click to toggle source
     # 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
parse_action(st, lastmodes=[]) click to toggle source

     # 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
parse_rule(st) click to toggle source

     # 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
read_grammar() click to toggle source
     # File lib/rexical/generator.rb, line 128
128:     def read_grammar
129:       @grammar_lines = StringScanner.new File.read(grammar_file)
130:     end
write_scanner(f = scanner_io) click to toggle source
     # 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

Private Instance Methods

scanner_io() click to toggle source

     # File lib/rexical/generator.rb, line 371
371:     def scanner_io
372:       unless  scanner_file = @opt['--output-file']
373:         scanner_file  =  grammar_file + ".rb"
374:       end
375:       f = File.open(scanner_file, 'w')
376:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.