class MapParser rule commands : commands command_blk SEMICOLON { puts "GOT A COMMAND" } | /* none */ { puts "no command found" } command_blk : global_blk | server_blk server_blk : SERVER STRING OBRACE server_opts EBRACE { puts "[server #{val[1]}]" } global_blk : GLOBAL OBRACE global_opts EBRACE server_opts : server_opts server_opt SEMICOLON | /* none */ server_opt : user_opt { puts "=> user opt" } | port_opt { puts "=> port opt" } | automount_opt { puts "=> automount opt" } | compress_opt { puts "=> compress opt" } | reconnect_opt { puts "=> reconnect opt" } | server_map_blk { puts "=> server_map blk" } server_map_blk : MAP STRING OBRACE server_map_opts EBRACE server_map_opts : server_map_opts server_map_opt SEMICOLON | /* none */ server_map_opt : remote_opt | local_opt | user_opt | port_opt | compress_opt user_opt : USER STRING { puts "* user = #{val[1]}" } port_opt : PORT NUMBER { puts "* port = #{val[1]}" } automount_opt : AUTOMOUNT boolean { puts "* automount = #{@bool_result}" } compress_opt : COMPRESS boolean { puts "* compress = #{@bool_result}" } reconnect_opt : RECONNECT boolean { puts ( "* reconnect = #{@bool_result}" ) } boolean : BOOL_TRUE { @bool_result = true } | BOOL_FALSE { @bool_result = false } end ---- header ---- # calc.rb : generated by racc # require 'strscan' #require 'map.rb' ---- inner ---- def parse( str ) puts "parse start..." tokens = [] scanner = StringScanner.new( str ) puts ( "scanner?" + scanner.string ) until scanner.eos? puts "scanning.. at #{scanner.pos}" case when m = scanner.scan( /\/\/.*$/ ) # comments when m = scanner.scan( /(\s+|\n)/ ) # whitespace and newlines when m = scanner.scan( /\{/ ) tokens.push [:OBRACE, m] when m = scanner.scan( /\}/ ) tokens.push [:EBRACE, m] when m = scanner.scan( /;/ ) tokens.push [:SEMICOLON, m] when m = scanner.scan( /\d+/ ) tokens.push [:NUMBER, m] when m = scanner.scan( /user/i ) tokens.push [:USER, m] when m = scanner.scan( /automount/i ) tokens.push [:AUTOMOUNT, m] when m = scanner.scan( /reconnect/i ) tokens.push [:RECONNECT, m] when m = scanner.scan( /compress/i ) tokens.push [:COMPRESS, m] when m = scanner.scan( /port/i ) tokens.push [:PORT, m] when m = scanner.scan( /(true|1|yes)/i ) tokens.push [:BOOL_TRUE, m] when m = scanner.scan( /(false|0|no)/i ) tokens.push [:BOOL_FALSE, m] when m = scanner.scan( /".+?"/i ) tokens.push [:STRING, m] when m = scanner.scan( /map/i ) tokens.push [:MAP, m] when m = scanner.scan( /server/i ) tokens.push [:SERVER, m] when m = scanner.scan( /./ ) tokens.push [:UNMATCHED, m] puts "UNMATCHED #{m} after #{scanner.pre_match}" end end puts "tokenization ok" tokens.push [false, false] @last_value = yyparse( tokens, :each ) puts "parse end... " end def on_error(error_token_id, error_value, value_stack) msg = "parse error " msg << "after #{value_stack.last} " if value_stack.length > 1 #msg << "after #{value_stack.last} " unless value_stack.empty? msg << "on #{token_to_str(error_token_id)} #{error_value}" raise ParseError, msg end ---- footer ---- puts "GOO" bigstr = "" STDIN.read.split(/\n/).each do |a| puts "READING #{a}" bigstr = bigstr + a end puts "PARSING NOW..." parser = MapParser.new begin val = parser.parse( bigstr ) print '= ', val, "\n" rescue ParseError puts $! end