class MapParser rule commands : commands command SEMICOLON { puts "GOT A COMMAND" } | /* none */ { result = 0 } command : global_blk | server_blk server_blk : SERVER SEP STRING SEP OBRACE server_opts EBRACE : SERVER SEP STRING OBRACE server_opts EBRACE global_blk : GLOBAL OBRACE global_opts EBRACE server_opts : server_opts server_opt SEMICOLON | /* none */ { result = 0 } server_opt : user_opt | port_opt | automount_opt | compress_opt | reconnect_opt user_opt : USER QUOTE STRING QUOTE port_opt : PORT INTEGER automount_opt : AUTOMOUNT boolean { puts ( "AUTOMOUNT => " + val[1] ) } compress_opt : COMPRESS boolean { puts ( "COMPRESS => " + val[1] ) } reconnect_opt : RECONNECT boolean { puts ( "RECONNECT => " + val[1] ) } boolean : BOOL_TRUE { result = true } | BOOL_FALSE { 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 tokens.push [:SEP, m] when m = scanner.scan( /(\s+|\n)/ ) # whitespace and newlines tokens.push [:SEP, m] when m = scanner.scan( /;/ ) tokens.push [:SEMICOLON, m] when m = scanner.scan( /\d+/ ) tokens.push [:NUMBER, m] when m = scanner.scan( /\{/ ) tokens.push [:OBRACE, m] when m = scanner.scan( /\}/ ) tokens.push [:EBRACE, 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