xref: /aosp_15_r20/external/antlr/runtime/Ruby/lib/antlr3/task.rb (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot#!/usr/bin/ruby
2*16467b97STreehugger Robot# encoding: utf-8
3*16467b97STreehugger Robot
4*16467b97STreehugger Robotrequire 'antlr3'
5*16467b97STreehugger Robotrequire 'set'
6*16467b97STreehugger Robotrequire 'rake'
7*16467b97STreehugger Robotrequire 'rake/tasklib'
8*16467b97STreehugger Robotrequire 'shellwords'
9*16467b97STreehugger Robot
10*16467b97STreehugger Robotmodule ANTLR3
11*16467b97STreehugger Robot
12*16467b97STreehugger Robot=begin rdoc ANTLR3::CompileTask
13*16467b97STreehugger Robot
14*16467b97STreehugger RobotA rake task-generating utility concerning ANTLR grammar file
15*16467b97STreehugger Robotcompilation. This is a general utility -- the grammars do
16*16467b97STreehugger Robotnot have to be targetted for Ruby output; it handles all
17*16467b97STreehugger Robotknown ANTLR language targets.
18*16467b97STreehugger Robot
19*16467b97STreehugger Robot  require 'antlr3/task'
20*16467b97STreehugger Robot
21*16467b97STreehugger Robot  ANTLR3::CompileTask.define(
22*16467b97STreehugger Robot    :name => 'grammars', :output_directory => 'lib/parsers'
23*16467b97STreehugger Robot  ) do | t |
24*16467b97STreehugger Robot    t.grammar_set( 'antlr/MainParser.g', 'antlr/MainTree.g' )
25*16467b97STreehugger Robot
26*16467b97STreehugger Robot    t.grammar_set( 'antlr/Template.g' ) do | gram |
27*16467b97STreehugger Robot      gram.output_directory = 'lib/parsers/template'
28*16467b97STreehugger Robot      gram.debug = true
29*16467b97STreehugger Robot    end
30*16467b97STreehugger Robot  end
31*16467b97STreehugger Robot
32*16467b97STreehugger Robot
33*16467b97STreehugger RobotTODO: finish documentation
34*16467b97STreehugger Robot
35*16467b97STreehugger Robot=end
36*16467b97STreehugger Robot
37*16467b97STreehugger Robotclass CompileTask < Rake::TaskLib
38*16467b97STreehugger Robot  attr_reader :grammar_sets, :options
39*16467b97STreehugger Robot  attr_accessor :name
40*16467b97STreehugger Robot
41*16467b97STreehugger Robot  def self.define( *grammar_files )
42*16467b97STreehugger Robot    lib = new( *grammar_files )
43*16467b97STreehugger Robot    block_given? and yield( lib )
44*16467b97STreehugger Robot    lib.define
45*16467b97STreehugger Robot    return( lib )
46*16467b97STreehugger Robot  end
47*16467b97STreehugger Robot
48*16467b97STreehugger Robot  def initialize( *grammar_files )
49*16467b97STreehugger Robot    grammar_files = [ grammar_files ].flatten!
50*16467b97STreehugger Robot    options = Hash === grammar_files.last ? grammar_files.pop : {}
51*16467b97STreehugger Robot    @grammar_sets = []
52*16467b97STreehugger Robot    @name = options.fetch( :name, 'antlr-grammars' )
53*16467b97STreehugger Robot    @options = options
54*16467b97STreehugger Robot    @namespace = Rake.application.current_scope
55*16467b97STreehugger Robot    grammar_files.empty? or grammar_set( grammar_files )
56*16467b97STreehugger Robot  end
57*16467b97STreehugger Robot
58*16467b97STreehugger Robot  def target_files
59*16467b97STreehugger Robot    @grammar_sets.inject( [] ) do | list, set |
60*16467b97STreehugger Robot      list.concat( set.target_files )
61*16467b97STreehugger Robot    end
62*16467b97STreehugger Robot  end
63*16467b97STreehugger Robot
64*16467b97STreehugger Robot  def grammar_set( *grammar_files )
65*16467b97STreehugger Robot    grammar_files = [ grammar_files ].flatten!
66*16467b97STreehugger Robot    options = @options.merge(
67*16467b97STreehugger Robot      Hash === grammar_files.last ? grammar_files.pop : {}
68*16467b97STreehugger Robot    )
69*16467b97STreehugger Robot    set = GrammarSet.new( grammar_files, options )
70*16467b97STreehugger Robot    block_given? and yield( set )
71*16467b97STreehugger Robot    @grammar_sets << set
72*16467b97STreehugger Robot    return( set )
73*16467b97STreehugger Robot  end
74*16467b97STreehugger Robot
75*16467b97STreehugger Robot  def compile_task
76*16467b97STreehugger Robot    full_name = ( @namespace + [ @name, 'compile' ] ).join( ':' )
77*16467b97STreehugger Robot    Rake::Task[ full_name ]
78*16467b97STreehugger Robot  end
79*16467b97STreehugger Robot
80*16467b97STreehugger Robot  def compile!
81*16467b97STreehugger Robot    compile_task.invoke
82*16467b97STreehugger Robot  end
83*16467b97STreehugger Robot
84*16467b97STreehugger Robot  def clobber_task
85*16467b97STreehugger Robot    full_name = ( @namespace + [ @name, 'clobber' ] ).join( ':' )
86*16467b97STreehugger Robot    Rake::Task[ full_name ]
87*16467b97STreehugger Robot  end
88*16467b97STreehugger Robot
89*16467b97STreehugger Robot  def clobber!
90*16467b97STreehugger Robot    clobber_task.invoke
91*16467b97STreehugger Robot  end
92*16467b97STreehugger Robot
93*16467b97STreehugger Robot  def define
94*16467b97STreehugger Robot    namespace( @name ) do
95*16467b97STreehugger Robot      desc( "trash all ANTLR-generated source code" )
96*16467b97STreehugger Robot      task( 'clobber' ) do
97*16467b97STreehugger Robot        for set in @grammar_sets
98*16467b97STreehugger Robot          set.clean
99*16467b97STreehugger Robot        end
100*16467b97STreehugger Robot      end
101*16467b97STreehugger Robot
102*16467b97STreehugger Robot      for set in @grammar_sets
103*16467b97STreehugger Robot        set.define_tasks
104*16467b97STreehugger Robot      end
105*16467b97STreehugger Robot
106*16467b97STreehugger Robot      desc( "compile ANTLR grammars" )
107*16467b97STreehugger Robot      task( 'compile' => target_files )
108*16467b97STreehugger Robot    end
109*16467b97STreehugger Robot  end
110*16467b97STreehugger Robot
111*16467b97STreehugger Robot
112*16467b97STreehugger Robot#class CompileTask::GrammarSet
113*16467b97STreehugger Robotclass GrammarSet
114*16467b97STreehugger Robot  attr_accessor :antlr_jar, :debug,
115*16467b97STreehugger Robot                :trace, :profile, :compile_options,
116*16467b97STreehugger Robot                :java_options
117*16467b97STreehugger Robot  attr_reader :load_path, :grammars
118*16467b97STreehugger Robot  attr_writer :output_directory
119*16467b97STreehugger Robot
120*16467b97STreehugger Robot  def initialize( grammar_files, options = {} )
121*16467b97STreehugger Robot    @load_path = grammar_files.map { | f | File.dirname( f ) }
122*16467b97STreehugger Robot    @load_path.push( '.', @output_directory )
123*16467b97STreehugger Robot
124*16467b97STreehugger Robot    if extra_load = options[ :load_path ]
125*16467b97STreehugger Robot      extra_load = [ extra_load ].flatten
126*16467b97STreehugger Robot      @load_path.unshift( extra_load )
127*16467b97STreehugger Robot    end
128*16467b97STreehugger Robot    @load_path.uniq!
129*16467b97STreehugger Robot
130*16467b97STreehugger Robot    @grammars = grammar_files.map do | file |
131*16467b97STreehugger Robot      GrammarFile.new( self, file )
132*16467b97STreehugger Robot    end
133*16467b97STreehugger Robot    @output_directory = '.'
134*16467b97STreehugger Robot    dir = options[ :output_directory ] and @output_directory = dir.to_s
135*16467b97STreehugger Robot
136*16467b97STreehugger Robot    @antlr_jar = options.fetch( :antlr_jar, ANTLR3.antlr_jar )
137*16467b97STreehugger Robot    @debug = options.fetch( :debug, false )
138*16467b97STreehugger Robot    @trace = options.fetch( :trace, false )
139*16467b97STreehugger Robot    @profile = options.fetch( :profile, false )
140*16467b97STreehugger Robot    @compile_options =
141*16467b97STreehugger Robot      case opts = options[ :compile_options ]
142*16467b97STreehugger Robot      when Array then opts
143*16467b97STreehugger Robot      else Shellwords.shellwords( opts.to_s )
144*16467b97STreehugger Robot      end
145*16467b97STreehugger Robot    @java_options =
146*16467b97STreehugger Robot      case opts = options[ :java_options ]
147*16467b97STreehugger Robot      when Array then opts
148*16467b97STreehugger Robot      else Shellwords.shellwords( opts.to_s )
149*16467b97STreehugger Robot      end
150*16467b97STreehugger Robot  end
151*16467b97STreehugger Robot
152*16467b97STreehugger Robot  def target_files
153*16467b97STreehugger Robot    @grammars.map { | gram | gram.target_files }.flatten
154*16467b97STreehugger Robot  end
155*16467b97STreehugger Robot
156*16467b97STreehugger Robot  def output_directory
157*16467b97STreehugger Robot    @output_directory || '.'
158*16467b97STreehugger Robot  end
159*16467b97STreehugger Robot
160*16467b97STreehugger Robot  def define_tasks
161*16467b97STreehugger Robot    file( @antlr_jar )
162*16467b97STreehugger Robot
163*16467b97STreehugger Robot    for grammar in @grammars
164*16467b97STreehugger Robot      deps = [ @antlr_jar ]
165*16467b97STreehugger Robot      if  vocab = grammar.token_vocab and
166*16467b97STreehugger Robot          tfile = find_tokens_file( vocab, grammar )
167*16467b97STreehugger Robot        file( tfile )
168*16467b97STreehugger Robot        deps << tfile
169*16467b97STreehugger Robot      end
170*16467b97STreehugger Robot      grammar.define_tasks( deps )
171*16467b97STreehugger Robot    end
172*16467b97STreehugger Robot  end
173*16467b97STreehugger Robot
174*16467b97STreehugger Robot  def clean
175*16467b97STreehugger Robot    for grammar in @grammars
176*16467b97STreehugger Robot      grammar.clean
177*16467b97STreehugger Robot    end
178*16467b97STreehugger Robot    if test( ?d, output_directory ) and ( Dir.entries( output_directory ) - %w( . .. ) ).empty?
179*16467b97STreehugger Robot      rmdir( output_directory )
180*16467b97STreehugger Robot    end
181*16467b97STreehugger Robot  end
182*16467b97STreehugger Robot
183*16467b97STreehugger Robot  def find_tokens_file( vocab, grammar )
184*16467b97STreehugger Robot    gram = @grammars.find { | gram | gram.name == vocab } and
185*16467b97STreehugger Robot      return( gram.tokens_file )
186*16467b97STreehugger Robot    file = locate( "#{ vocab }.tokens" ) and return( file )
187*16467b97STreehugger Robot    warn( Util.tidy( <<-END, true ) )
188*16467b97STreehugger Robot    | unable to locate .tokens file `#{ vocab }' referenced in #{ grammar.path }
189*16467b97STreehugger Robot    | -- ignoring dependency
190*16467b97STreehugger Robot    END
191*16467b97STreehugger Robot    return( nil )
192*16467b97STreehugger Robot  end
193*16467b97STreehugger Robot
194*16467b97STreehugger Robot  def locate( file_name )
195*16467b97STreehugger Robot    dir = @load_path.find do | dir |
196*16467b97STreehugger Robot      File.file?( File.join( dir, file_name ) )
197*16467b97STreehugger Robot    end
198*16467b97STreehugger Robot    dir and return( File.join( dir, file_name ) )
199*16467b97STreehugger Robot  end
200*16467b97STreehugger Robot
201*16467b97STreehugger Robot  def compile( grammar )
202*16467b97STreehugger Robot    dir = output_directory
203*16467b97STreehugger Robot    test( ?d, dir ) or FileUtils.mkpath( dir )
204*16467b97STreehugger Robot    sh( build_command( grammar ) )
205*16467b97STreehugger Robot  end
206*16467b97STreehugger Robot
207*16467b97STreehugger Robot  def build_command( grammar )
208*16467b97STreehugger Robot    parts = [ 'java', '-cp', @antlr_jar ]
209*16467b97STreehugger Robot    parts.concat( @java_options )
210*16467b97STreehugger Robot    parts << 'org.antlr.Tool' << '-fo' << output_directory
211*16467b97STreehugger Robot    parts << '-debug' if @debug
212*16467b97STreehugger Robot    parts << '-profile' if @profile
213*16467b97STreehugger Robot    parts << '-trace' if @trace
214*16467b97STreehugger Robot    parts.concat( @compile_options )
215*16467b97STreehugger Robot    parts << grammar.path
216*16467b97STreehugger Robot    return parts.map! { | t | escape( t ) }.join( ' ' )
217*16467b97STreehugger Robot  end
218*16467b97STreehugger Robot
219*16467b97STreehugger Robot  def escape( token )
220*16467b97STreehugger Robot    token = token.to_s.dup
221*16467b97STreehugger Robot    token.empty? and return( %('') )
222*16467b97STreehugger Robot    token.gsub!( /([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1" )
223*16467b97STreehugger Robot    token.gsub!( /\n/, "'\n'" )
224*16467b97STreehugger Robot    return( token )
225*16467b97STreehugger Robot  end
226*16467b97STreehugger Robot
227*16467b97STreehugger Robotend
228*16467b97STreehugger Robot
229*16467b97STreehugger Robotclass GrammarFile
230*16467b97STreehugger Robot  LANGUAGES = {
231*16467b97STreehugger Robot    "ActionScript" => [ ".as" ],
232*16467b97STreehugger Robot    "CSharp2" => [ ".cs" ],
233*16467b97STreehugger Robot    "C" => [ ".c", ".h" ],
234*16467b97STreehugger Robot    "ObjC" => [ ".m", ".h" ],
235*16467b97STreehugger Robot    "CSharp3" => [ ".cs" ],
236*16467b97STreehugger Robot    "Cpp" => [ ".cpp", ".h" ],
237*16467b97STreehugger Robot    "Ruby" => [ ".rb" ],
238*16467b97STreehugger Robot    "Java" => [ ".java" ],
239*16467b97STreehugger Robot    "JavaScript" => [ ".js" ],
240*16467b97STreehugger Robot    "Python" => [ ".py" ],
241*16467b97STreehugger Robot    "Delphi" => [ ".pas" ],
242*16467b97STreehugger Robot    "Perl5" => [ ".pm" ]
243*16467b97STreehugger Robot  }.freeze
244*16467b97STreehugger Robot  GRAMMAR_TYPES = %w(lexer parser tree combined)
245*16467b97STreehugger Robot
246*16467b97STreehugger Robot  ##################################################################
247*16467b97STreehugger Robot  ######## CONSTRUCTOR #############################################
248*16467b97STreehugger Robot  ##################################################################
249*16467b97STreehugger Robot
250*16467b97STreehugger Robot  def initialize( group, path, options = {} )
251*16467b97STreehugger Robot    @group = group
252*16467b97STreehugger Robot    @path = path.to_s
253*16467b97STreehugger Robot    @imports = []
254*16467b97STreehugger Robot    @language = 'Java'
255*16467b97STreehugger Robot    @token_vocab = nil
256*16467b97STreehugger Robot    @tasks_defined = false
257*16467b97STreehugger Robot    @extra_dependencies = []
258*16467b97STreehugger Robot    if extra = options[ :extra_dependencies ]
259*16467b97STreehugger Robot      extra = [ extra ].flatten
260*16467b97STreehugger Robot      @extra_dependencies.concat( extra )
261*16467b97STreehugger Robot    end
262*16467b97STreehugger Robot
263*16467b97STreehugger Robot    study
264*16467b97STreehugger Robot    yield( self ) if block_given?
265*16467b97STreehugger Robot    fetch_imports
266*16467b97STreehugger Robot  end
267*16467b97STreehugger Robot
268*16467b97STreehugger Robot  ##################################################################
269*16467b97STreehugger Robot  ######## ATTRIBUTES AND ATTRIBUTE-ISH METHODS ####################
270*16467b97STreehugger Robot  ##################################################################
271*16467b97STreehugger Robot  attr_reader :type, :name, :language, :source,
272*16467b97STreehugger Robot              :token_vocab, :imports, :imported_grammars,
273*16467b97STreehugger Robot              :path, :group
274*16467b97STreehugger Robot
275*16467b97STreehugger Robot  for attr in [ :output_directory, :load_path, :antlr_jar ]
276*16467b97STreehugger Robot    class_eval( <<-END )
277*16467b97STreehugger Robot      def #{ attr }
278*16467b97STreehugger Robot        @group.#{ attr }
279*16467b97STreehugger Robot      end
280*16467b97STreehugger Robot    END
281*16467b97STreehugger Robot  end
282*16467b97STreehugger Robot
283*16467b97STreehugger Robot  def lexer_files
284*16467b97STreehugger Robot    if lexer? then base = @name
285*16467b97STreehugger Robot    elsif combined? then base = @name + 'Lexer'
286*16467b97STreehugger Robot    else return( [] )
287*16467b97STreehugger Robot    end
288*16467b97STreehugger Robot    return( file_names( base ) )
289*16467b97STreehugger Robot  end
290*16467b97STreehugger Robot
291*16467b97STreehugger Robot  def parser_files
292*16467b97STreehugger Robot    if parser? then base = @name
293*16467b97STreehugger Robot    elsif combined? then base = @name + 'Parser'
294*16467b97STreehugger Robot    else return( [] )
295*16467b97STreehugger Robot    end
296*16467b97STreehugger Robot    return( file_names( base ) )
297*16467b97STreehugger Robot  end
298*16467b97STreehugger Robot
299*16467b97STreehugger Robot  def tree_parser_files
300*16467b97STreehugger Robot    return( tree? ? file_names( @name ) : [] )
301*16467b97STreehugger Robot  end
302*16467b97STreehugger Robot
303*16467b97STreehugger Robot  def file_names( base )
304*16467b97STreehugger Robot    LANGUAGES.fetch( @language ).map do | ext |
305*16467b97STreehugger Robot      File.join( output_directory, base + ext )
306*16467b97STreehugger Robot    end
307*16467b97STreehugger Robot  end
308*16467b97STreehugger Robot
309*16467b97STreehugger Robot  for type in GRAMMAR_TYPES
310*16467b97STreehugger Robot    class_eval( <<-END )
311*16467b97STreehugger Robot      def #{ type }?
312*16467b97STreehugger Robot        @type == #{ type.inspect }
313*16467b97STreehugger Robot      end
314*16467b97STreehugger Robot    END
315*16467b97STreehugger Robot  end
316*16467b97STreehugger Robot
317*16467b97STreehugger Robot  def delegate_files( delegate_suffix )
318*16467b97STreehugger Robot    file_names( "#{ name }_#{ delegate_suffix }" )
319*16467b97STreehugger Robot  end
320*16467b97STreehugger Robot
321*16467b97STreehugger Robot  def tokens_file
322*16467b97STreehugger Robot    File.join( output_directory, name + '.tokens' )
323*16467b97STreehugger Robot  end
324*16467b97STreehugger Robot
325*16467b97STreehugger Robot  def target_files( all = true )
326*16467b97STreehugger Robot    targets = [ tokens_file ]
327*16467b97STreehugger Robot
328*16467b97STreehugger Robot    for target_type in %w( lexer parser tree_parser )
329*16467b97STreehugger Robot      for file in self.send( :"#{ target_type }_files" )
330*16467b97STreehugger Robot        targets << file
331*16467b97STreehugger Robot      end
332*16467b97STreehugger Robot    end
333*16467b97STreehugger Robot
334*16467b97STreehugger Robot    if all
335*16467b97STreehugger Robot      for grammar in @imported_grammars
336*16467b97STreehugger Robot        targets.concat( grammar.target_files )
337*16467b97STreehugger Robot      end
338*16467b97STreehugger Robot    end
339*16467b97STreehugger Robot
340*16467b97STreehugger Robot    return targets
341*16467b97STreehugger Robot  end
342*16467b97STreehugger Robot
343*16467b97STreehugger Robot  def update
344*16467b97STreehugger Robot    touch( @path )
345*16467b97STreehugger Robot  end
346*16467b97STreehugger Robot
347*16467b97STreehugger Robot  def all_imported_files
348*16467b97STreehugger Robot    imported_files = []
349*16467b97STreehugger Robot    for grammar in @imported_grammars
350*16467b97STreehugger Robot      imported_files.push( grammar.path, *grammar.all_imported_files )
351*16467b97STreehugger Robot    end
352*16467b97STreehugger Robot    return imported_files
353*16467b97STreehugger Robot  end
354*16467b97STreehugger Robot
355*16467b97STreehugger Robot  def clean
356*16467b97STreehugger Robot    deleted = []
357*16467b97STreehugger Robot    for target in target_files
358*16467b97STreehugger Robot      if test( ?f, target )
359*16467b97STreehugger Robot        rm( target )
360*16467b97STreehugger Robot        deleted << target
361*16467b97STreehugger Robot      end
362*16467b97STreehugger Robot    end
363*16467b97STreehugger Robot
364*16467b97STreehugger Robot    for grammar in @imported_grammars
365*16467b97STreehugger Robot      deleted.concat( grammar.clean )
366*16467b97STreehugger Robot    end
367*16467b97STreehugger Robot
368*16467b97STreehugger Robot    return deleted
369*16467b97STreehugger Robot  end
370*16467b97STreehugger Robot
371*16467b97STreehugger Robot  def define_tasks( shared_depends )
372*16467b97STreehugger Robot    unless @tasks_defined
373*16467b97STreehugger Robot      depends = [ @path, *all_imported_files ]
374*16467b97STreehugger Robot      for f in depends
375*16467b97STreehugger Robot        file( f )
376*16467b97STreehugger Robot      end
377*16467b97STreehugger Robot      depends = shared_depends + depends
378*16467b97STreehugger Robot
379*16467b97STreehugger Robot      target_files.each do | target |
380*16467b97STreehugger Robot        file( target => ( depends - [ target ] ) ) do   # prevents recursive .tokens file dependencies
381*16467b97STreehugger Robot          @group.compile( self )
382*16467b97STreehugger Robot        end
383*16467b97STreehugger Robot      end
384*16467b97STreehugger Robot
385*16467b97STreehugger Robot      @tasks_defined = true
386*16467b97STreehugger Robot    end
387*16467b97STreehugger Robot  end
388*16467b97STreehugger Robot
389*16467b97STreehugger Robotprivate
390*16467b97STreehugger Robot
391*16467b97STreehugger Robot  def fetch_imports
392*16467b97STreehugger Robot    @imported_grammars = @imports.map do | imp |
393*16467b97STreehugger Robot      file = group.locate( "#{ imp }.g" ) or raise( Util.tidy( <<-END ) )
394*16467b97STreehugger Robot      | #{ @path }: unable to locate imported grammar file #{ imp }.g
395*16467b97STreehugger Robot      | search directories ( @load_path ):
396*16467b97STreehugger Robot      |   - #{ load_path.join( "\n  - " ) }
397*16467b97STreehugger Robot      END
398*16467b97STreehugger Robot      Imported.new( self, file )
399*16467b97STreehugger Robot    end
400*16467b97STreehugger Robot  end
401*16467b97STreehugger Robot
402*16467b97STreehugger Robot  def study
403*16467b97STreehugger Robot    @source = File.read( @path )
404*16467b97STreehugger Robot    @source =~ /^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/ or
405*16467b97STreehugger Robot      raise Grammar::FormatError[ @source, @path ]
406*16467b97STreehugger Robot    @name = $2
407*16467b97STreehugger Robot    @type = $1 || 'combined'
408*16467b97STreehugger Robot    if @source =~ /^\s*options\s*\{(.*?)\}/m
409*16467b97STreehugger Robot      option_block = $1
410*16467b97STreehugger Robot      if option_block =~ /\s*language\s*=\s*(\S+)\s*;/
411*16467b97STreehugger Robot        @language = $1
412*16467b97STreehugger Robot        LANGUAGES.has_key?( @language ) or
413*16467b97STreehugger Robot          raise( Grammar::FormatError, "Unknown ANTLR target language: %p" % @language )
414*16467b97STreehugger Robot      end
415*16467b97STreehugger Robot      option_block =~ /\s*tokenVocab\s*=\s*(\S+)\s*;/ and
416*16467b97STreehugger Robot        @token_vocab = $1
417*16467b97STreehugger Robot    end
418*16467b97STreehugger Robot
419*16467b97STreehugger Robot    @source.scan( /^\s*import\s+(\w+\s*(?:,\s*\w+\s*)*);/ ) do
420*16467b97STreehugger Robot      list = $1.strip
421*16467b97STreehugger Robot      @imports.concat( list.split( /\s*,\s*/ ) )
422*16467b97STreehugger Robot    end
423*16467b97STreehugger Robot  end
424*16467b97STreehugger Robotend # class Grammar
425*16467b97STreehugger Robot
426*16467b97STreehugger Robotclass GrammarFile::Imported < GrammarFile
427*16467b97STreehugger Robot  def initialize( owner, path )
428*16467b97STreehugger Robot    @owner = owner
429*16467b97STreehugger Robot    @path = path.to_s
430*16467b97STreehugger Robot    @imports = []
431*16467b97STreehugger Robot    @language = 'Java'
432*16467b97STreehugger Robot    @token_vocab = nil
433*16467b97STreehugger Robot    study
434*16467b97STreehugger Robot    fetch_imports
435*16467b97STreehugger Robot  end
436*16467b97STreehugger Robot
437*16467b97STreehugger Robot  for attr in [ :load_path, :output_directory, :antlr_jar, :verbose, :group ]
438*16467b97STreehugger Robot    class_eval( <<-END )
439*16467b97STreehugger Robot      def #{ attr }
440*16467b97STreehugger Robot        @owner.#{ attr }
441*16467b97STreehugger Robot      end
442*16467b97STreehugger Robot    END
443*16467b97STreehugger Robot  end
444*16467b97STreehugger Robot
445*16467b97STreehugger Robot  def delegate_files( suffix )
446*16467b97STreehugger Robot    @owner.delegate_files( "#{ @name }_#{ suffix }" )
447*16467b97STreehugger Robot  end
448*16467b97STreehugger Robot
449*16467b97STreehugger Robot  def target_files
450*16467b97STreehugger Robot    targets = [ tokens_file ]
451*16467b97STreehugger Robot    targets.concat( @owner.delegate_files( @name ) )
452*16467b97STreehugger Robot    return( targets )
453*16467b97STreehugger Robot  end
454*16467b97STreehugger Robotend
455*16467b97STreehugger Robot
456*16467b97STreehugger Robotclass GrammarFile::FormatError < StandardError
457*16467b97STreehugger Robot  attr_reader :file, :source
458*16467b97STreehugger Robot
459*16467b97STreehugger Robot  def self.[]( *args )
460*16467b97STreehugger Robot    new( *args )
461*16467b97STreehugger Robot  end
462*16467b97STreehugger Robot
463*16467b97STreehugger Robot  def initialize( source, file = nil )
464*16467b97STreehugger Robot    @file = file
465*16467b97STreehugger Robot    @source = source
466*16467b97STreehugger Robot    message = ''
467*16467b97STreehugger Robot    if file.nil? # inline
468*16467b97STreehugger Robot      message << "bad inline grammar source:\n"
469*16467b97STreehugger Robot      message << ( "-" * 80 ) << "\n"
470*16467b97STreehugger Robot      message << @source
471*16467b97STreehugger Robot      message[ -1 ] == ?\n or message << "\n"
472*16467b97STreehugger Robot      message << ( "-" * 80 ) << "\n"
473*16467b97STreehugger Robot      message << "could not locate a grammar name and type declaration matching\n"
474*16467b97STreehugger Robot      message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/"
475*16467b97STreehugger Robot    else
476*16467b97STreehugger Robot      message << 'bad grammar source in file %p\n' % @file
477*16467b97STreehugger Robot      message << ( "-" * 80 ) << "\n"
478*16467b97STreehugger Robot      message << @source
479*16467b97STreehugger Robot      message[ -1 ] == ?\n or message << "\n"
480*16467b97STreehugger Robot      message << ( "-" * 80 ) << "\n"
481*16467b97STreehugger Robot      message << "could not locate a grammar name and type declaration matching\n"
482*16467b97STreehugger Robot      message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/"
483*16467b97STreehugger Robot    end
484*16467b97STreehugger Robot    super( message )
485*16467b97STreehugger Robot  end
486*16467b97STreehugger Robotend # error Grammar::FormatError
487*16467b97STreehugger Robotend # class CompileTask
488*16467b97STreehugger Robotend # module ANTLR3
489