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